commit 2e7a41c1671a2c8ba9c0eea064dd4c1bd3c11553 Author: amaliyya <149059131+amaliaputrirchm@users.noreply.github.com> Date: Wed Aug 20 15:42:27 2025 +0700 first commit diff --git a/monitoring/.gitignore b/monitoring/.gitignore new file mode 100644 index 0000000..79c113f --- /dev/null +++ b/monitoring/.gitignore @@ -0,0 +1,45 @@ +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release diff --git a/monitoring/.metadata b/monitoring/.metadata new file mode 100644 index 0000000..fdb4416 --- /dev/null +++ b/monitoring/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "fcf2c11572af6f390246c056bc905eca609533a0" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: android + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: ios + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: linux + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: macos + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: web + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: windows + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/monitoring/README.md b/monitoring/README.md new file mode 100644 index 0000000..798bed5 --- /dev/null +++ b/monitoring/README.md @@ -0,0 +1,16 @@ +# monitoring + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. diff --git a/monitoring/analysis_options.yaml b/monitoring/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/monitoring/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/monitoring/android/.gitignore b/monitoring/android/.gitignore new file mode 100644 index 0000000..be3943c --- /dev/null +++ b/monitoring/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/monitoring/android/app/build.gradle.kts b/monitoring/android/app/build.gradle.kts new file mode 100644 index 0000000..a9a14b5 --- /dev/null +++ b/monitoring/android/app/build.gradle.kts @@ -0,0 +1,43 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.monitoring" + compileSdk = flutter.compileSdkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.monitoring" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/monitoring/android/app/src/debug/AndroidManifest.xml b/monitoring/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/monitoring/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/monitoring/android/app/src/main/AndroidManifest.xml b/monitoring/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..eb5c3ec --- /dev/null +++ b/monitoring/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/monitoring/android/app/src/main/kotlin/com/example/monitoring/MainActivity.kt b/monitoring/android/app/src/main/kotlin/com/example/monitoring/MainActivity.kt new file mode 100644 index 0000000..c1c1d2e --- /dev/null +++ b/monitoring/android/app/src/main/kotlin/com/example/monitoring/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.monitoring + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/monitoring/android/app/src/main/res/drawable-v21/launch_background.xml b/monitoring/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/monitoring/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/monitoring/android/app/src/main/res/drawable/launch_background.xml b/monitoring/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/monitoring/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/monitoring/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/monitoring/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/monitoring/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/monitoring/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/monitoring/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/monitoring/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/monitoring/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/monitoring/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/monitoring/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/monitoring/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/monitoring/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/monitoring/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/monitoring/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/monitoring/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/monitoring/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/monitoring/android/app/src/main/res/values-night/styles.xml b/monitoring/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/monitoring/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/monitoring/android/app/src/main/res/values/styles.xml b/monitoring/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/monitoring/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/monitoring/android/app/src/profile/AndroidManifest.xml b/monitoring/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/monitoring/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/monitoring/android/build.gradle.kts b/monitoring/android/build.gradle.kts new file mode 100644 index 0000000..46cc7e1 --- /dev/null +++ b/monitoring/android/build.gradle.kts @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/monitoring/android/gradle.properties b/monitoring/android/gradle.properties new file mode 100644 index 0000000..f018a61 --- /dev/null +++ b/monitoring/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/monitoring/android/gradle/wrapper/gradle-wrapper.properties b/monitoring/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ac3b479 --- /dev/null +++ b/monitoring/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/monitoring/android/settings.gradle.kts b/monitoring/android/settings.gradle.kts new file mode 100644 index 0000000..ab39a10 --- /dev/null +++ b/monitoring/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/monitoring/assets/404.png b/monitoring/assets/404.png new file mode 100644 index 0000000..8ef7c63 Binary files /dev/null and b/monitoring/assets/404.png differ diff --git a/monitoring/assets/default_profile.png b/monitoring/assets/default_profile.png new file mode 100644 index 0000000..9d60fde Binary files /dev/null and b/monitoring/assets/default_profile.png differ diff --git a/monitoring/assets/logo.png b/monitoring/assets/logo.png new file mode 100644 index 0000000..45d6ac2 Binary files /dev/null and b/monitoring/assets/logo.png differ diff --git a/monitoring/devtools_options.yaml b/monitoring/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/monitoring/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/monitoring/ios/.gitignore b/monitoring/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/monitoring/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/monitoring/ios/Flutter/AppFrameworkInfo.plist b/monitoring/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..7c56964 --- /dev/null +++ b/monitoring/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/monitoring/ios/Flutter/Debug.xcconfig b/monitoring/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/monitoring/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/monitoring/ios/Flutter/Release.xcconfig b/monitoring/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/monitoring/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/monitoring/ios/Runner.xcodeproj/project.pbxproj b/monitoring/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..eab3ce3 --- /dev/null +++ b/monitoring/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,616 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/monitoring/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/monitoring/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/monitoring/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/monitoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/monitoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/monitoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/monitoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/monitoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/monitoring/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/monitoring/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/monitoring/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..e3773d4 --- /dev/null +++ b/monitoring/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/monitoring/ios/Runner.xcworkspace/contents.xcworkspacedata b/monitoring/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/monitoring/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/monitoring/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/monitoring/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/monitoring/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/monitoring/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/monitoring/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/monitoring/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/monitoring/ios/Runner/AppDelegate.swift b/monitoring/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..6266644 --- /dev/null +++ b/monitoring/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..7353c41 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..6ed2d93 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cd7b00 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..fe73094 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..321773c Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..502f463 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..e9f5fea Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..84ac32a Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..8953cba Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..0467bf1 Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/monitoring/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/monitoring/ios/Runner/Base.lproj/LaunchScreen.storyboard b/monitoring/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/monitoring/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/monitoring/ios/Runner/Base.lproj/Main.storyboard b/monitoring/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/monitoring/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/monitoring/ios/Runner/Info.plist b/monitoring/ios/Runner/Info.plist new file mode 100644 index 0000000..b5d0bdc --- /dev/null +++ b/monitoring/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Monitoring + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + monitoring + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/monitoring/ios/Runner/Runner-Bridging-Header.h b/monitoring/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/monitoring/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/monitoring/ios/RunnerTests/RunnerTests.swift b/monitoring/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/monitoring/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/monitoring/lib/config.dart b/monitoring/lib/config.dart new file mode 100644 index 0000000..a7fb541 --- /dev/null +++ b/monitoring/lib/config.dart @@ -0,0 +1,5 @@ +// String baseUrl = 'http://10.10.9.217:8000/api'; +// String baseUrl = 'http://192.168.43.24:8000/api'; +// String baseUrl = 'http://10.75.50.24:8000/api'; +// String baseUrl = 'http://10.0.2.2:8000/api'; +String baseUrl = 'http://10.75.50.24:8000/api'; diff --git a/monitoring/lib/features/berita_detail_screen.dart b/monitoring/lib/features/berita_detail_screen.dart new file mode 100644 index 0000000..613744d --- /dev/null +++ b/monitoring/lib/features/berita_detail_screen.dart @@ -0,0 +1 @@ +// TODO Implement this library. diff --git a/monitoring/lib/main.dart b/monitoring/lib/main.dart new file mode 100644 index 0000000..1df0377 --- /dev/null +++ b/monitoring/lib/main.dart @@ -0,0 +1,35 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:monitoring/screens/home_screen.dart'; +import 'package:monitoring/screens/splash_screen.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +final GlobalKey navigatorKey = GlobalKey(); + +void main() => runApp(const MonitoringSantriApp()); + +class MonitoringSantriApp extends StatelessWidget { + const MonitoringSantriApp({super.key}); + + void _handleLogin(String token, Map user) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('token', token); + await prefs.setString('user', jsonEncode(user)); + + navigatorKey.currentState!.pushAndRemoveUntil( + MaterialPageRoute(builder: (_) => HomeScreen(token: token, user: user)), + (route) => false, + ); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Santri Login App', + theme: ThemeData(primarySwatch: Colors.indigo), + debugShowCheckedModeBanner: false, + navigatorKey: navigatorKey, + home: SplashScreen(onLoginSuccess: _handleLogin), + ); + } +} diff --git a/monitoring/lib/models/berita_model.dart b/monitoring/lib/models/berita_model.dart new file mode 100644 index 0000000..c5434b2 --- /dev/null +++ b/monitoring/lib/models/berita_model.dart @@ -0,0 +1,28 @@ +class BeritaModel { + final int id; + final String judul; + final String? ringkasan; + final String? gambarUrl; + final String? kategori; + final String? penulis; + + BeritaModel({ + required this.id, + required this.judul, + this.ringkasan, + this.gambarUrl, + this.kategori, + this.penulis, + }); + + factory BeritaModel.fromJson(Map json) { + return BeritaModel( + id: json['id'], + judul: json['judul'], + ringkasan: json['ringkasan'], + gambarUrl: json['gambar_url'], + kategori: json['kategori'], + penulis: json['penulis'], + ); + } +} diff --git a/monitoring/lib/screens/feature_grid.dart b/monitoring/lib/screens/feature_grid.dart new file mode 100644 index 0000000..3fda93e --- /dev/null +++ b/monitoring/lib/screens/feature_grid.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; + +import 'features/absensi_screen.dart'; +import 'features/nilai_screen.dart'; +import 'features/kesehatan_screen.dart'; +import 'features/prestasi_screen.dart'; +import 'features/pelanggaran_screen.dart'; +import 'features/berita_screen.dart'; +import 'features/alumni_screen.dart'; +import 'features/pembayaran_screen.dart'; + +class FeatureGrid extends StatelessWidget { + final String token; + + const FeatureGrid({super.key, required this.token}); + + final List<_FeatureItem> _items = const [ + _FeatureItem('Absensi', Icons.how_to_reg), + _FeatureItem('Nilai', Icons.grade), + _FeatureItem('Kesehatan', Icons.local_hospital), + _FeatureItem('Prestasi', Icons.emoji_events), + _FeatureItem('Pelanggaran', Icons.report), + _FeatureItem('Berita', Icons.article), + _FeatureItem('Alumni', Icons.people), + _FeatureItem('Pembayaran', Icons.attach_money), + ]; + + @override + Widget build(BuildContext context) { + return GridView.builder( + itemCount: _items.length, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + itemBuilder: (context, index) { + final item = _items[index]; + + return GestureDetector( + onTap: () { + Widget? destination; + + switch (item.label) { + case 'Absensi': + destination = AbsensiScreen(token: token); + break; + case 'Nilai': + destination = NilaiScreen(token: token); + break; + case 'Kesehatan': + destination = KesehatanScreen(token: token); + break; + case 'Prestasi': + destination = PrestasiScreen(token: token); + break; + case 'Pelanggaran': + destination = PelanggaranScreen(token: token); + break; + case 'Berita': + destination = BeritaScreen(token: token); + break; + case 'Alumni': + destination = AlumniScreen(token: token); + break; + case 'Pembayaran': + destination = PembayaranScreen(token: token); + break; + } + + if (destination != null) { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => destination!), + ); + } + }, + child: Container( + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFF43A047), Color(0xFFFFEB3B)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.08), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(item.icon, size: 32, color: Colors.white), + const SizedBox(height: 8), + Text( + item.label, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + }, + ); + } +} + +class _FeatureItem { + final String label; + final IconData icon; + + const _FeatureItem(this.label, this.icon); +} diff --git a/monitoring/lib/screens/features/absensi_screen.dart b/monitoring/lib/screens/features/absensi_screen.dart new file mode 100644 index 0000000..cce25bc --- /dev/null +++ b/monitoring/lib/screens/features/absensi_screen.dart @@ -0,0 +1,167 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; + +class AbsensiScreen extends StatefulWidget { + final String token; + const AbsensiScreen({super.key, required this.token}); + + @override + State createState() => _AbsensiScreenState(); +} + +class _AbsensiScreenState extends State { + List data = []; + List filteredData = []; + bool loading = true; + + int selectedMonth = DateTime.now().month; + + final List months = [ + 'Januari', + 'Februari', + 'Maret', + 'April', + 'Mei', + 'Juni', + 'Juli', + 'Agustus', + 'September', + 'Oktober', + 'November', + 'Desember', + ]; + + @override + void initState() { + super.initState(); + fetchAbsensi(); + } + + Future fetchAbsensi() async { + final url = Uri.parse('$baseUrl/absensi'); + + try { + final response = await http.get( + url, + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final resData = json.decode(response.body); + setState(() { + data = resData['data']; + loading = false; + applyMonthFilter(); + }); + } else { + setState(() => loading = false); + } + } catch (e) { + setState(() => loading = false); + } + } + + void applyMonthFilter() { + setState(() { + filteredData = + data.where((item) { + final date = DateTime.tryParse(item['tanggal'] ?? ''); + return date != null && date.month == selectedMonth; + }).toList(); + }); + } + + Color getStatusColor(String status) { + switch (status.toLowerCase()) { + case 'hadir': + return Colors.green; + case 'sakit': + return Colors.orange; + case 'izin': + return Colors.blue; + default: + return Colors.grey; + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Absensi'), + actions: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: selectedMonth, + items: List.generate(12, (index) { + final monthName = months[index]; + return DropdownMenuItem( + value: index + 1, + child: Text(monthName), + ); + }), + onChanged: (value) { + if (value != null) { + setState(() { + selectedMonth = value; + applyMonthFilter(); + }); + } + }, + ), + ), + ), + ], + ), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : filteredData.isEmpty + ? const Center(child: Text('Tidak ada data absensi bulan ini.')) + : ListView.builder( + itemCount: filteredData.length, + itemBuilder: (context, index) { + final item = filteredData[index]; + final tanggal = item['tanggal'] ?? '-'; + final status = item['status'] ?? '-'; + final keterangan = item['keterangan'] ?? ''; + + return ListTile( + leading: const Icon( + Icons.calendar_today, + color: Colors.green, + ), + title: Text(tanggal), + subtitle: keterangan.isNotEmpty ? Text(keterangan) : null, + trailing: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + color: getStatusColor(status).withOpacity(0.1), + border: Border.all(color: getStatusColor(status)), + borderRadius: BorderRadius.circular(20), + ), + child: Text( + status.toUpperCase(), + style: TextStyle( + color: getStatusColor(status), + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ), + ); + }, + ), + ); + } +} diff --git a/monitoring/lib/screens/features/alumni_screen.dart b/monitoring/lib/screens/features/alumni_screen.dart new file mode 100644 index 0000000..3789a9a --- /dev/null +++ b/monitoring/lib/screens/features/alumni_screen.dart @@ -0,0 +1,203 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'dart:convert'; + +class AlumniScreen extends StatefulWidget { + final String token; + const AlumniScreen({super.key, required this.token}); + + @override + State createState() => _AlumniScreenState(); +} + +class _AlumniScreenState extends State { + List data = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchAlumni(); + } + + Future fetchAlumni() async { + final url = '$baseUrl/alumni'; + + try { + final response = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final jsonData = json.decode(response.body); + debugPrint('Data diterima: ${json.encode(jsonData)}'); + + if (jsonData != null && + jsonData['data'] != null && + jsonData['data'] is List) { + setState(() { + data = jsonData['data']; + loading = false; + }); + } else { + debugPrint('Format JSON tidak sesuai: $jsonData'); + setState(() => loading = false); + } + } else { + debugPrint('Gagal ambil alumni: ${response.body}'); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Gagal mengambil alumni: $e'); + setState(() => loading = false); + } + } + + Future _launchWhatsApp(String number) async { + final uri = Uri.parse("https://wa.me/$number"); + if (await canLaunchUrl(uri)) { + await launchUrl(uri, mode: LaunchMode.externalApplication); + } else { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Gagal membuka WhatsApp'))); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Data Alumni')), + body: loading + ? const Center(child: CircularProgressIndicator()) + : data.isEmpty + ? const Center(child: Text('Tidak ada data alumni.')) + : ListView.builder( + padding: const EdgeInsets.all(12), + itemCount: data.length, + itemBuilder: (context, index) { + final alumni = data[index]; + return Card( + elevation: 3, + margin: const EdgeInsets.only(bottom: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon( + Icons.person, + color: Colors.green, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + alumni['nama'] ?? '-', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + Chip( + label: Text( + 'Angkatan ${alumni['angkatan'] ?? 'Tidak Diketahui'}', + style: const TextStyle(fontSize: 12), + ), + backgroundColor: Colors.green.shade50, + labelStyle: const TextStyle( + color: Colors.green, + ), + ), + ], + ), + const SizedBox(height: 12), + Row( + children: [ + const Icon( + Icons.work_outline, + size: 20, + color: Colors.black54, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + alumni['aktivitas_setelah_lulus'] ?? '-', + style: const TextStyle(fontSize: 14), + ), + ), + ], + ), + const SizedBox(height: 6), + Row( + children: [ + const Icon( + Icons.phone_android, + size: 20, + color: Colors.black54, + ), + const SizedBox(width: 8), + Text( + alumni['kontak'] ?? '-', + style: const TextStyle(fontSize: 14), + ), + if ((alumni['kontak'] ?? '') + .toString() + .isNotEmpty) + IconButton( + icon: const FaIcon( + FontAwesomeIcons.whatsapp, + color: Colors.green, + ), + tooltip: 'Hubungi di WhatsApp', + onPressed: () { + _launchWhatsApp( + alumni['kontak'].toString(), + ); + }, + ), + ], + ), + if (alumni['keterangan'] != null && + alumni['keterangan'].toString().isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon( + Icons.info_outline, + size: 20, + color: Colors.black54, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + alumni['keterangan'], + style: const TextStyle(fontSize: 14), + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + ), + ); + } +} diff --git a/monitoring/lib/screens/features/berita_detail_screen.dart b/monitoring/lib/screens/features/berita_detail_screen.dart new file mode 100644 index 0000000..48fd627 --- /dev/null +++ b/monitoring/lib/screens/features/berita_detail_screen.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:monitoring/models/berita_model.dart'; + +class BeritaDetailScreen extends StatelessWidget { + final BeritaModel berita; + + const BeritaDetailScreen({super.key, required this.berita}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFF8F9FA), + appBar: AppBar( + title: const Text('Detail Berita'), + + backgroundColor: Color(0xFF43A047), + foregroundColor: Colors.white, + elevation: 0, + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Gambar + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: + berita.gambarUrl != null + ? Image.network( + berita.gambarUrl!, + width: double.infinity, + height: 200, + fit: BoxFit.cover, + errorBuilder: + (_, __, ___) => Image.asset( + 'assets/404.png', + width: double.infinity, + height: 200, + fit: BoxFit.cover, + ), + ) + : Image.asset( + 'assets/404.png', + width: double.infinity, + height: 200, + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 16), + + // Judul + Text( + berita.judul, + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + const SizedBox(height: 8), + + // Kategori dan Penulis + Row( + children: [ + Chip( + label: Text(berita.kategori ?? 'Umum'), + backgroundColor: Colors.pink.shade100, + ), + const SizedBox(width: 8), + Text( + 'Oleh ${berita.penulis ?? '-'}', + style: const TextStyle(fontSize: 14, color: Colors.grey), + ), + ], + ), + const SizedBox(height: 16), + + // Ringkasan atau isi + Text( + berita.ringkasan ?? 'Tidak ada isi berita.', + textAlign: TextAlign.justify, + style: const TextStyle(fontSize: 16, height: 1.5), + ), + ], + ), + ), + ); + } +} diff --git a/monitoring/lib/screens/features/berita_detail_screen_gak_dipakek.dart b/monitoring/lib/screens/features/berita_detail_screen_gak_dipakek.dart new file mode 100644 index 0000000..9595d0e --- /dev/null +++ b/monitoring/lib/screens/features/berita_detail_screen_gak_dipakek.dart @@ -0,0 +1,450 @@ +// Lengkap: CRUD layanan Flutter (Tanpa Edit) +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; + +class Service { + final int id; + final String name; + final int price; + final String? imageUrl; + + Service({ + required this.id, + required this.name, + required this.price, + this.imageUrl, + }); + + factory Service.fromJson(Map json) { + return Service( + id: json['id'], + name: json['name'], + price: json['price'], + imageUrl: json['image'], + ); + } +} + +class DataLayananPage extends StatefulWidget { + final String token; + + const DataLayananPage({super.key, required this.token}); + + @override + State createState() => _DataLayananPageState(); +} + +class _DataLayananPageState extends State { + List categories = []; + Map> servicesByCategory = {}; + int? selectedCategoryId; + bool loadingCategories = true; + bool loadingServices = false; + + String? imagePath; + + @override + void initState() { + super.initState(); + fetchCategories(); + } + + Future fetchCategories() async { + setState(() => loadingCategories = true); + try { + final response = await http.get( + Uri.parse('$baseUrl/categories'), + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + setState(() { + categories = data is List ? data : data['categories']; + if (categories.isNotEmpty) { + selectedCategoryId = categories[0]['id']; + fetchServicesByCategory(selectedCategoryId!); + } + }); + } + } catch (e) { + print(e); + } finally { + setState(() => loadingCategories = false); + } + } + + Future fetchServicesByCategory(int categoryId) async { + setState(() => loadingServices = true); + try { + final response = await http.get( + Uri.parse('$baseUrl/api/services?category_id=$categoryId'), + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + final List services = + (data as List).map((item) => Service.fromJson(item)).toList(); + + setState(() { + servicesByCategory[categoryId] = services; + }); + } + } catch (e) { + print(e); + } finally { + setState(() => loadingServices = false); + } + } + + Future addService({ + required String name, + required String price, + required String description, + required int categoryId, + required File? imageFile, + }) async { + final url = Uri.parse('$baseUrl/api/services'); + final request = + http.MultipartRequest('POST', url) + ..headers.addAll({ + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }) + ..fields['name'] = name + ..fields['category_id'] = categoryId.toString() + ..fields['price'] = price + ..fields['description'] = description; + + if (imageFile != null) { + request.files.add( + await http.MultipartFile.fromPath('image', imageFile.path), + ); + } + + final response = await request.send(); + + if (response.statusCode == 201) { + print("Layanan berhasil ditambahkan."); + await fetchServicesByCategory(categoryId); + } else { + final respStr = await response.stream.bytesToString(); + print("Gagal tambah layanan: $respStr"); + } + } + + Future deleteService(int id, int categoryId) async { + final url = Uri.parse('$baseUrl/services/$id'); + + final response = await http.delete( + url, + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ); + + if (response.statusCode == 200) { + print("Layanan berhasil dihapus."); + await fetchServicesByCategory(categoryId); + } else { + print("Gagal hapus layanan: ${response.body}"); + } + } + + void showAddServiceDialog() { + final nameController = TextEditingController(); + final priceController = TextEditingController(); + final descriptionController = TextEditingController(); + + int? selectedDialogCategoryId = selectedCategoryId; + String? previewImagePath; + + imagePath = null; + + showDialog( + context: context, + builder: + (context) => StatefulBuilder( + builder: (context, setStateDialog) { + return AlertDialog( + title: const Text('Tambah Layanan'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + DropdownButtonFormField( + value: selectedDialogCategoryId, + items: + categories.map>((category) { + return DropdownMenuItem( + value: category['id'], + child: Text(category['name']), + ); + }).toList(), + onChanged: + (value) => setStateDialog( + () => selectedDialogCategoryId = value, + ), + decoration: const InputDecoration( + labelText: 'Kategori', + ), + ), + TextField( + controller: nameController, + decoration: const InputDecoration( + labelText: 'Nama Layanan', + ), + ), + TextField( + controller: priceController, + keyboardType: TextInputType.number, + decoration: const InputDecoration(labelText: 'Harga'), + ), + TextField( + controller: descriptionController, + decoration: const InputDecoration( + labelText: 'Deskripsi', + ), + ), + ElevatedButton( + onPressed: () async { + final picker = ImagePicker(); + final pickedFile = await picker.pickImage( + source: ImageSource.gallery, + ); + if (pickedFile != null) { + setStateDialog(() { + previewImagePath = pickedFile.path; + imagePath = pickedFile.path; + }); + } + }, + child: const Text('Pilih Gambar'), + ), + if (previewImagePath != null) + Image.file(File(previewImagePath!), height: 100), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Batal'), + ), + ElevatedButton( + onPressed: () async { + if (nameController.text.isEmpty || + priceController.text.isEmpty || + descriptionController.text.isEmpty || + selectedDialogCategoryId == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Semua field harus diisi'), + ), + ); + return; + } + await addService( + name: nameController.text, + price: priceController.text, + description: descriptionController.text, + categoryId: selectedDialogCategoryId!, + imageFile: imagePath != null ? File(imagePath!) : null, + ); + Navigator.pop(context); + }, + child: const Text('Simpan'), + ), + ], + ); + }, + ), + ); + } + + void selectCategory(int categoryId) async { + if (selectedCategoryId == categoryId) return; + setState(() => selectedCategoryId = categoryId); + await fetchServicesByCategory(categoryId); + } + + @override + Widget build(BuildContext context) { + final primaryColor = const Color(0xFFF06292); + final backgroundColor = const Color(0xFFFFF6F9); + + final services = + selectedCategoryId != null + ? (servicesByCategory[selectedCategoryId!] ?? []) + : []; + + return Scaffold( + backgroundColor: backgroundColor, + appBar: AppBar( + title: const Text('Data Layanan'), + backgroundColor: primaryColor, + ), + floatingActionButton: FloatingActionButton( + backgroundColor: primaryColor, + onPressed: showAddServiceDialog, + child: const Icon(Icons.add), + ), + body: Column( + children: [ + SizedBox( + height: 60, + child: + loadingCategories + ? const Center(child: CircularProgressIndicator()) + : ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: categories.length, + itemBuilder: (context, index) { + final category = categories[index]; + final isSelected = category['id'] == selectedCategoryId; + + return GestureDetector( + onTap: () => selectCategory(category['id']), + child: Container( + margin: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 10, + ), + padding: const EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + color: + isSelected + ? primaryColor + : Colors.pink.shade100, + borderRadius: BorderRadius.circular(20), + ), + child: Center( + child: Text( + category['name'], + style: TextStyle( + color: + isSelected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + }, + ), + ), + const Divider(), + Expanded( + child: + loadingServices + ? const Center(child: CircularProgressIndicator()) + : services.isEmpty + ? const Center(child: Text('Belum ada layanan.')) + : ListView.builder( + itemCount: services.length, + itemBuilder: (context, index) { + final service = services[index]; + return Card( + margin: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 8, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + elevation: 4, + child: ListTile( + contentPadding: const EdgeInsets.all(10), + leading: + service.imageUrl != null && + service.imageUrl!.isNotEmpty + ? ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Image.network( + service.imageUrl!, + width: 60, + height: 60, + fit: BoxFit.cover, + errorBuilder: + (context, error, stackTrace) => + const Icon( + Icons.broken_image, + size: 60, + ), + ), + ) + : const Icon( + Icons.image, + size: 60, + color: Colors.grey, + ), + title: Text( + service.name, + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + subtitle: Text("Rp ${service.price}"), + trailing: IconButton( + icon: const Icon(Icons.delete, color: Colors.red), + onPressed: () async { + final confirm = await showDialog( + context: context, + builder: + (context) => AlertDialog( + title: const Text('Hapus Layanan'), + content: const Text( + 'Apakah Anda yakin ingin menghapus layanan ini?', + ), + actions: [ + TextButton( + onPressed: + () => Navigator.pop( + context, + false, + ), + child: const Text('Batal'), + ), + ElevatedButton( + onPressed: + () => Navigator.pop( + context, + true, + ), + child: const Text('Hapus'), + ), + ], + ), + ); + + if (confirm == true) { + await deleteService( + service.id, + selectedCategoryId!, + ); + } + }, + ), + ), + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/monitoring/lib/screens/features/berita_screen.dart b/monitoring/lib/screens/features/berita_screen.dart new file mode 100644 index 0000000..c966008 --- /dev/null +++ b/monitoring/lib/screens/features/berita_screen.dart @@ -0,0 +1,143 @@ +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:monitoring/config.dart'; +import 'package:monitoring/models/berita_model.dart'; +import 'package:monitoring/screens/features/berita_detail_screen.dart'; + +class BeritaScreen extends StatefulWidget { + final String token; + const BeritaScreen({super.key, required this.token}); + + @override + State createState() => _BeritaScreenState(); +} + +class _BeritaScreenState extends State { + List beritaList = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchBerita(); + } + + Future fetchBerita() async { + try { + final dio = Dio( + BaseOptions( + baseUrl: '$baseUrl', + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ), + ); + + final res = await dio.get('/berita'); + final List raw = res.data['data']; + setState(() { + beritaList = raw.map((e) => BeritaModel.fromJson(e)).toList(); + loading = false; + }); + } catch (e) { + debugPrint('Gagal: $e'); + setState(() => loading = false); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Berita'), + backgroundColor: Color(0xFF43A047), + foregroundColor: Colors.white, + ), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : ListView.builder( + itemCount: beritaList.length, + padding: const EdgeInsets.all(12), + itemBuilder: (context, index) { + final berita = beritaList[index]; + return Card( + margin: const EdgeInsets.only(bottom: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 2, + child: Column( + children: [ + if (berita.gambarUrl != null) + ClipRRect( + borderRadius: const BorderRadius.vertical( + top: Radius.circular(12), + ), + child: Image.network( + berita.gambarUrl!, + height: 160, + width: double.infinity, + fit: BoxFit.cover, + errorBuilder: + (_, __, ___) => Image.asset('assets/404.png'), + ), + ), + Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + berita.judul, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 6), + Text( + berita.ringkasan ?? '-', + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 8), + Text( + 'Kategori: ${berita.kategori ?? '-'} - oleh ${berita.penulis ?? '-'}', + style: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + Align( + alignment: Alignment.centerRight, + child: GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: + (context) => BeritaDetailScreen( + berita: berita, + ), + ), + ); + }, + child: Text( + 'Selengkapnya...', + style: TextStyle(color: Colors.blue), + ), + ), + ), + ], + ), + ), + ], + ), + ); + }, + ), + ); + } +} diff --git a/monitoring/lib/screens/features/change_password_screen.dart b/monitoring/lib/screens/features/change_password_screen.dart new file mode 100644 index 0000000..e70007a --- /dev/null +++ b/monitoring/lib/screens/features/change_password_screen.dart @@ -0,0 +1,206 @@ +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:monitoring/config.dart'; + +class ChangePasswordScreen extends StatefulWidget { + final String token; + const ChangePasswordScreen({super.key, required this.token}); + + @override + State createState() => _ChangePasswordScreenState(); +} + +class _ChangePasswordScreenState extends State { + final _formKey = GlobalKey(); + final _oldPassController = TextEditingController(); + final _newPassController = TextEditingController(); + final _confirmPassController = TextEditingController(); + + bool _loading = false; + bool _obscureOld = true; + bool _obscureNew = true; + bool _obscureConfirm = true; + + Future _submit() async { + if (!_formKey.currentState!.validate()) return; + + setState(() => _loading = true); + + try { + final dio = Dio( + BaseOptions( + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ), + ); + + final response = await dio.post( + '$baseUrl/password', + data: { + 'old_password': _oldPassController.text.trim(), + 'new_password': _newPassController.text.trim(), + 'confirm_password': _confirmPassController.text.trim(), + }, + ); + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(response.data['message'] ?? 'Berhasil')), + ); + Navigator.pop(context); + } + } on DioException catch (e) { + final msg = + e.response?.data['message'] ?? + e.response?.data.toString() ?? + 'Gagal mengganti password'; + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg))); + } catch (_) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Terjadi kesalahan saat mengganti password'), + ), + ); + } finally { + setState(() => _loading = false); + } + } + + @override + void dispose() { + _oldPassController.dispose(); + _newPassController.dispose(); + _confirmPassController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + const fieldPadding = EdgeInsets.symmetric(vertical: 8); + + return Scaffold( + appBar: AppBar(title: const Text('Ganti Password')), + body: SingleChildScrollView( + padding: const EdgeInsets.all(20), + child: Form( + key: _formKey, + child: Column( + children: [ + const Text( + 'Untuk alasan keamanan, gunakan password baru yang kuat dan mudah diingat.', + style: TextStyle(fontSize: 14, color: Colors.black87), + ), + const SizedBox(height: 16), + + /// Old password + Padding( + padding: fieldPadding, + child: TextFormField( + controller: _oldPassController, + obscureText: _obscureOld, + decoration: InputDecoration( + labelText: 'Password Saat Ini', + border: const OutlineInputBorder(), + suffixIcon: IconButton( + icon: Icon( + _obscureOld ? Icons.visibility_off : Icons.visibility, + ), + onPressed: + () => setState(() => _obscureOld = !_obscureOld), + ), + ), + validator: + (val) => + val == null || val.isEmpty ? 'Wajib diisi' : null, + ), + ), + + /// New password + Padding( + padding: fieldPadding, + child: TextFormField( + controller: _newPassController, + obscureText: _obscureNew, + decoration: InputDecoration( + labelText: 'Password Baru', + border: const OutlineInputBorder(), + suffixIcon: IconButton( + icon: Icon( + _obscureNew ? Icons.visibility_off : Icons.visibility, + ), + onPressed: + () => setState(() => _obscureNew = !_obscureNew), + ), + ), + validator: (val) { + if (val == null || val.isEmpty) return 'Wajib diisi'; + if (val.length < 6) return 'Minimal 6 karakter'; + return null; + }, + ), + ), + + /// Confirm password + Padding( + padding: fieldPadding, + child: TextFormField( + controller: _confirmPassController, + obscureText: _obscureConfirm, + decoration: InputDecoration( + labelText: 'Konfirmasi Password Baru', + border: const OutlineInputBorder(), + suffixIcon: IconButton( + icon: Icon( + _obscureConfirm + ? Icons.visibility_off + : Icons.visibility, + ), + onPressed: + () => setState( + () => _obscureConfirm = !_obscureConfirm, + ), + ), + ), + validator: + (val) => + val != _newPassController.text + ? 'Password tidak cocok' + : null, + ), + ), + + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: _loading ? null : _submit, + icon: const Icon(Icons.lock_open), + label: + _loading + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : const Text('Simpan Password'), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 14), + backgroundColor: Colors.green, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/monitoring/lib/screens/features/edit_profile_screen.dart b/monitoring/lib/screens/features/edit_profile_screen.dart new file mode 100644 index 0000000..1bfd3ba --- /dev/null +++ b/monitoring/lib/screens/features/edit_profile_screen.dart @@ -0,0 +1,261 @@ +import 'dart:io'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:http_parser/http_parser.dart'; +import 'package:monitoring/config.dart'; + +class EditProfileScreen extends StatefulWidget { + final String token; + + const EditProfileScreen({super.key, required this.token}); + + @override + State createState() => _EditProfileScreenState(); +} + +class _EditProfileScreenState extends State { + final _formKey = GlobalKey(); + bool _loading = true; + bool _saving = false; + + final _nameController = TextEditingController(); + final _alamatController = TextEditingController(); + final _tempatLahirController = TextEditingController(); + final _tanggalLahirController = TextEditingController(); + + String? _jenisKelamin; + String? _fotoUrl; + File? _selectedImage; + + @override + void initState() { + super.initState(); + fetchProfile(); + } + + Future fetchProfile() async { + try { + final dio = Dio( + BaseOptions( + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ), + ); + + final response = await dio.get('$baseUrl/santri/me'); + final data = response.data; + + final user = data['user']; + final santri = data['santri']; + + setState(() { + _nameController.text = user['name'] ?? ''; + _alamatController.text = santri['alamat'] ?? ''; + _tempatLahirController.text = santri['tempat_lahir'] ?? ''; + _tanggalLahirController.text = santri['tanggal_lahir'] ?? ''; + _jenisKelamin = santri['jenis_kelamin']; + _fotoUrl = santri['foto_url']; + _loading = false; + }); + } catch (e) { + debugPrint('Gagal ambil profil: $e'); + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Gagal mengambil profil'))); + Navigator.pop(context); + } + } + + Future pickImage() async { + final picked = await ImagePicker().pickImage(source: ImageSource.gallery); + if (picked != null) { + setState(() { + _selectedImage = File(picked.path); + }); + } + } + + Future saveProfile() async { + if (!_formKey.currentState!.validate()) return; + + setState(() => _saving = true); + + try { + final dio = Dio( + BaseOptions( + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + 'Content-Type': 'multipart/form-data', + }, + ), + ); + + final formData = FormData.fromMap({ + 'name': _nameController.text.trim(), + 'alamat': _alamatController.text.trim(), + 'tempat_lahir': _tempatLahirController.text.trim(), + 'tanggal_lahir': _tanggalLahirController.text.trim(), + 'jenis_kelamin': _jenisKelamin, + if (_selectedImage != null) + 'foto': await MultipartFile.fromFile( + _selectedImage!.path, + filename: _selectedImage!.path.split('/').last, + contentType: MediaType('image', 'jpeg'), + ), + }); + + final response = await dio.post('$baseUrl/santri/me', data: formData); + + final message = response.data['message'] ?? 'Profil berhasil diperbarui'; + + if (context.mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(message))); + Navigator.pop(context, true); // Kembali & beri sinyal refresh + } + } on DioException catch (e) { + final msg = + e.response?.data['message'] ?? + e.response?.data.toString() ?? + 'Gagal memperbarui profil'; + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg))); + } finally { + setState(() => _saving = false); + } + } + + @override + void dispose() { + _nameController.dispose(); + _alamatController.dispose(); + _tempatLahirController.dispose(); + _tanggalLahirController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + const fieldSpace = SizedBox(height: 16); + + return Scaffold( + appBar: AppBar(title: const Text('Edit Profil')), + body: + _loading + ? const Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Form( + key: _formKey, + child: Column( + children: [ + if (_fotoUrl != null && _selectedImage == null) + CircleAvatar( + backgroundImage: NetworkImage(_fotoUrl!), + radius: 45, + ), + if (_selectedImage != null) + CircleAvatar( + backgroundImage: FileImage(_selectedImage!), + radius: 45, + ), + TextButton.icon( + onPressed: pickImage, + icon: const Icon(Icons.photo), + label: const Text('Ubah Foto'), + ), + fieldSpace, + + TextFormField( + controller: _nameController, + decoration: const InputDecoration( + labelText: 'Nama Lengkap', + border: OutlineInputBorder(), + ), + validator: (val) => val!.isEmpty ? 'Wajib diisi' : null, + ), + fieldSpace, + + TextFormField( + controller: _alamatController, + decoration: const InputDecoration( + labelText: 'Alamat', + border: OutlineInputBorder(), + ), + ), + fieldSpace, + + TextFormField( + controller: _tempatLahirController, + decoration: const InputDecoration( + labelText: 'Tempat Lahir', + border: OutlineInputBorder(), + ), + ), + fieldSpace, + + TextFormField( + controller: _tanggalLahirController, + decoration: const InputDecoration( + labelText: 'Tanggal Lahir', + hintText: 'YYYY-MM-DD', + border: OutlineInputBorder(), + ), + ), + fieldSpace, + + DropdownButtonFormField( + value: _jenisKelamin, + decoration: const InputDecoration( + labelText: 'Jenis Kelamin', + border: OutlineInputBorder(), + ), + items: const [ + DropdownMenuItem( + value: 'L', + child: Text('Laki-laki'), + ), + DropdownMenuItem( + value: 'P', + child: Text('Perempuan'), + ), + ], + onChanged: (val) => setState(() => _jenisKelamin = val), + ), + + const SizedBox(height: 28), + SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: _saving ? null : saveProfile, + icon: const Icon(Icons.save), + label: + _saving + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ) + : const Text('Simpan Perubahan'), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + backgroundColor: Colors.green, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/monitoring/lib/screens/features/kesehatan_screen.dart b/monitoring/lib/screens/features/kesehatan_screen.dart new file mode 100644 index 0000000..a4869a5 --- /dev/null +++ b/monitoring/lib/screens/features/kesehatan_screen.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; + +import 'package:monitoring/config.dart'; + +class KesehatanScreen extends StatefulWidget { + final String token; + const KesehatanScreen({super.key, required this.token}); + + @override + State createState() => _KesehatanScreenState(); +} + +class _KesehatanScreenState extends State { + List data = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchKesehatan(); + } + + Future fetchKesehatan() async { + final url = '$baseUrl/kesehatan'; + + try { + final response = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final res = json.decode(response.body); + setState(() { + data = res['data'] ?? []; + loading = false; + }); + } else { + debugPrint('Gagal ambil data kesehatan: ${response.statusCode}'); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Gagal ambil kesehatan: $e'); + setState(() => loading = false); + } + } + + Widget _buildCard(Map item) { + return Card( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + elevation: 3, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon(Icons.local_hospital, color: Colors.green), + const SizedBox(width: 8), + Expanded( + child: Text( + item['keluhan'] ?? '-', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 12), + _infoRow('Diagnosis', item['diagnosis']), + _infoRow('Saran', item['saran']), + _infoRow('Kelas', item['kelas_nama']), + _infoRow('Tanggal', _formatDate(item['created_at'])), + ], + ), + ), + ); + } + + Widget _infoRow(String label, String? value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 90, + child: Text( + '$label:', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Expanded( + child: Text( + value ?? '-', + style: const TextStyle(color: Colors.black87), + ), + ), + ], + ), + ); + } + + String _formatDate(String? datetime) { + if (datetime == null) return '-'; + final date = DateTime.tryParse(datetime); + if (date == null) return '-'; + return '${date.day.toString().padLeft(2, '0')}-${date.month.toString().padLeft(2, '0')}-${date.year}'; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Catatan Kesehatan')), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : data.isEmpty + ? const Center(child: Text('Tidak ada catatan kesehatan.')) + : RefreshIndicator( + onRefresh: fetchKesehatan, + child: ListView.builder( + physics: const AlwaysScrollableScrollPhysics(), + itemCount: data.length, + itemBuilder: (context, index) => _buildCard(data[index]), + ), + ), + ); + } +} diff --git a/monitoring/lib/screens/features/nilai_screen.dart b/monitoring/lib/screens/features/nilai_screen.dart new file mode 100644 index 0000000..6b12046 --- /dev/null +++ b/monitoring/lib/screens/features/nilai_screen.dart @@ -0,0 +1,147 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'package:intl/intl.dart'; +import 'package:monitoring/config.dart'; + +class NilaiScreen extends StatefulWidget { + final String token; + const NilaiScreen({super.key, required this.token}); + + @override + State createState() => _NilaiScreenState(); +} + +class _NilaiScreenState extends State { + List data = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchNilai(); + } + + Future fetchNilai() async { + final url = '$baseUrl/nilai'; + + try { + final response = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final res = json.decode(response.body); + setState(() { + data = res['data'] ?? []; + loading = false; + }); + } else { + debugPrint( + 'Gagal ambil nilai: ${response.statusCode} - ${response.body}', + ); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Error nilai: $e'); + setState(() => loading = false); + } + } + + String formatTanggal(String? tanggal) { + if (tanggal == null) return '-'; + try { + final date = DateTime.parse(tanggal); + return DateFormat('dd MMM yyyy', 'id_ID').format(date); + } catch (e) { + return tanggal; + } + } + + Widget _buildCard(Map item) { + return Card( + elevation: 3, + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item['mapel'] ?? '-', + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 4), + Row( + children: [ + Chip( + label: Text(item['jenis_nilai'] ?? '-'), + backgroundColor: Colors.indigo.shade50, + labelStyle: const TextStyle(color: Colors.indigo), + ), + const SizedBox(width: 8), + Text( + 'Nilai: ${item['nilai']}', + style: const TextStyle(fontSize: 14), + ), + ], + ), + const SizedBox(height: 8), + _infoRow( + Icons.calendar_today, + 'Tanggal', + formatTanggal(item['tanggal']), + ), + _infoRow(Icons.school, 'Semester', item['semester']), + if ((item['keterangan'] ?? '').toString().isNotEmpty) + _infoRow(Icons.info_outline, 'Catatan', item['keterangan']), + ], + ), + ), + ); + } + + Widget _infoRow(IconData icon, String label, String? value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Row( + children: [ + Icon(icon, size: 18, color: Colors.grey.shade600), + const SizedBox(width: 8), + Text('$label: ', style: const TextStyle(fontWeight: FontWeight.bold)), + Expanded( + child: Text( + value ?? '-', + style: const TextStyle(color: Colors.black87), + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Nilai Akademik')), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : data.isEmpty + ? const Center(child: Text('Belum ada data nilai.')) + : RefreshIndicator( + onRefresh: fetchNilai, + child: ListView.builder( + physics: const AlwaysScrollableScrollPhysics(), + itemCount: data.length, + itemBuilder: (context, i) => _buildCard(data[i]), + ), + ), + ); + } +} diff --git a/monitoring/lib/screens/features/pelanggaran_screen.dart b/monitoring/lib/screens/features/pelanggaran_screen.dart new file mode 100644 index 0000000..eb2d6d1 --- /dev/null +++ b/monitoring/lib/screens/features/pelanggaran_screen.dart @@ -0,0 +1,90 @@ +// lib/screens/features/pelanggaran_screen.dart +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; + +class PelanggaranScreen extends StatefulWidget { + final String token; + + const PelanggaranScreen({super.key, required this.token}); + + @override + State createState() => _PelanggaranScreenState(); +} + +class _PelanggaranScreenState extends State { + List _pelanggaranList = []; + bool _loading = true; + + @override + void initState() { + super.initState(); + fetchPelanggaran(); + } + + Future fetchPelanggaran() async { + try { + final response = await http.get( + Uri.parse("http://10.75.50.24:8000/api/pelanggaran"), + headers: { + "Authorization": "Bearer ${widget.token}", + "Accept": "application/json", + }, + ); + + final data = jsonDecode(response.body); + if (data["success"] == true) { + setState(() { + _pelanggaranList = data["data"]; + _loading = false; + }); + } else { + throw Exception("Gagal mengambil data"); + } + } catch (e) { + setState(() { + _loading = false; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("Error: $e")), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Data Pelanggaran"), + backgroundColor: const Color(0xFF43A047), + ), + body: _loading + ? const Center(child: CircularProgressIndicator()) + : _pelanggaranList.isEmpty + ? const Center(child: Text("Tidak ada data pelanggaran.")) + : ListView.builder( + itemCount: _pelanggaranList.length, + itemBuilder: (context, index) { + final item = _pelanggaranList[index]; + return Card( + margin: + const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + child: ListTile( + // title: Text(item["nama_santri"] ?? "-"), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Kelas: ${item["nama_kelas"] ?? '-'}"), + Text("Jenis: ${item["jenis_pelanggaran"] ?? '-'}"), + Text("Hukuman: ${item["hukuman"] ?? '-'}"), + Text("Guru Penegur: ${item["nama_penginput"] ?? '-'}"), + ], + ), + // trailing: const Icon(Icons.arrow_forward_ios, size: 16), + ), + ); + }, + ), + ); + } +} \ No newline at end of file diff --git a/monitoring/lib/screens/features/pembayaran_screen.dart b/monitoring/lib/screens/features/pembayaran_screen.dart new file mode 100644 index 0000000..a5747ae --- /dev/null +++ b/monitoring/lib/screens/features/pembayaran_screen.dart @@ -0,0 +1,246 @@ +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:monitoring/config.dart'; +// import halaman tambah pembayaran jika ada +import 'tambah_pembayaran_screen.dart'; + +class Pembayaran { + final int id; + final int santriId; + final int? kelasId; + final String tanggal; + final int jumlah; + final String jenis; + final String? keterangan; + final String? bukti; + final String status; + final String? santriName; + + Pembayaran({ + required this.id, + required this.santriId, + this.kelasId, + required this.tanggal, + required this.jumlah, + required this.jenis, + this.keterangan, + this.bukti, + required this.status, + this.santriName, + }); + + factory Pembayaran.fromJson(Map json) { + return Pembayaran( + id: json['id'], + santriId: json['santri_id'], + kelasId: json['kelas_id'], + tanggal: json['tanggal'], + jumlah: json['jumlah'], + jenis: json['jenis_pembayaran'], + keterangan: json['keterangan'], + bukti: json['bukti_pembayaran'], + status: json['status'], + santriName: json['santri_name'], + ); + } +} + +class PembayaranScreen extends StatefulWidget { + final String token; + const PembayaranScreen({super.key, required this.token}); + + @override + State createState() => _PembayaranScreenState(); +} + +class _PembayaranScreenState extends State { + List pembayaranList = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchPembayaran(); + } + + Future fetchPembayaran() async { + try { + final dio = Dio( + BaseOptions( + baseUrl: '$baseUrl', + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ), + ); + + final response = await dio.get('/pembayaran'); + final data = response.data as List; + + setState(() { + pembayaranList = data.map((e) => Pembayaran.fromJson(e)).toList(); + loading = false; + }); + } catch (e) { + debugPrint('Error fetch pembayaran: $e'); + setState(() => loading = false); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Data Pembayaran')), + floatingActionButton: FloatingActionButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => TambahPembayaranScreen(token: widget.token), + ), + ).then((_) => fetchPembayaran()); // refresh setelah kembali + }, + backgroundColor: Colors.teal, + child: const Icon(Icons.add), + ), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : pembayaranList.isEmpty + ? const Center(child: Text('Belum ada data pembayaran')) + : ListView.builder( + padding: const EdgeInsets.all(12), + itemCount: pembayaranList.length, + itemBuilder: (context, index) { + final bayar = pembayaranList[index]; + + return Card( + elevation: 2, + margin: const EdgeInsets.only(bottom: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + bayar.jenis, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + const SizedBox(height: 4), + Text('Tanggal: ${bayar.tanggal}'), + Text('Jumlah: Rp${bayar.jumlah}'), + if (bayar.keterangan != null) + Text('Keterangan: ${bayar.keterangan}'), + Text('Status: ${bayar.status}'), + if (bayar.bukti != null) + Padding( + padding: const EdgeInsets.only(top: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Bukti Pembayaran:', + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + if (bayar.bukti != null) + SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: () { + showDialog( + context: context, + builder: + (_) => AlertDialog( + title: const Text( + 'Bukti Pembayaran', + ), + content: ClipRRect( + borderRadius: + BorderRadius.circular( + 8, + ), + child: Image.network( + bayar.bukti!, + fit: BoxFit.cover, + errorBuilder: + ( + context, + error, + stackTrace, + ) => const Text( + 'Gagal memuat gambar', + style: TextStyle( + color: Colors.red, + ), + ), + loadingBuilder: ( + context, + child, + loadingProgress, + ) { + if (loadingProgress == + null) + return child; + return const SizedBox( + height: 100, + child: Center( + child: + CircularProgressIndicator(), + ), + ); + }, + ), + ), + actions: [ + TextButton( + onPressed: + () => Navigator.pop( + context, + ), + child: const Text( + 'Tutup', + ), + ), + ], + ), + ); + }, + icon: const Icon( + Icons.image, + color: Colors.white, + ), + label: const Text( + 'Lihat Bukti Pembayaran', + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.teal, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 10, + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + ), + ); + } +} diff --git a/monitoring/lib/screens/features/prestasi_screen.dart b/monitoring/lib/screens/features/prestasi_screen.dart new file mode 100644 index 0000000..0c0bb19 --- /dev/null +++ b/monitoring/lib/screens/features/prestasi_screen.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; + +import 'package:monitoring/config.dart'; + +class PrestasiScreen extends StatefulWidget { + final String token; + const PrestasiScreen({super.key, required this.token}); + + @override + State createState() => _PrestasiScreenState(); +} + +class _PrestasiScreenState extends State { + List data = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchPrestasi(); + } + + Future fetchPrestasi() async { + final url = '${baseUrl}/prestasi'; // Ganti jika pakai emulator + + try { + final response = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final res = json.decode(response.body); + setState(() { + data = res['data'] ?? []; + loading = false; + }); + } else { + debugPrint( + 'Gagal ambil prestasi: ${response.statusCode} - ${response.body}', + ); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Error prestasi: $e'); + setState(() => loading = false); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Riwayat Prestasi')), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : data.isEmpty + ? const Center(child: Text('Belum ada data prestasi.')) + : ListView.builder( + itemCount: data.length, + padding: const EdgeInsets.all(12), + itemBuilder: (context, index) { + final item = data[index]; + return Card( + margin: const EdgeInsets.only(bottom: 12), + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon( + Icons.emoji_events, + color: Colors.amber, + size: 28, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + item['nama_prestasi'] ?? '-', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Text('Jenis: ${item['jenis_prestasi'] ?? '-'}'), + Text('Tingkat: ${item['tingkat'] ?? '-'}'), + Text('Peringkat: ${item['peringkat'] ?? '-'}'), + Text('Tanggal: ${item['tanggal_prestasi'] ?? '-'}'), + if (item['deskripsi'] != null && + item['deskripsi'].toString().isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 6), + child: Text( + item['deskripsi'], + style: const TextStyle(color: Colors.black54), + ), + ), + const Divider(height: 20), + Text('Santri: ${item['santri']?['nama'] ?? '-'}'), + Text('Kelas: ${item['kelas']?['nama_kelas'] ?? '-'}'), + ], + ), + ), + ); + }, + ), + ); + } +} diff --git a/monitoring/lib/screens/features/profile_screen.dart b/monitoring/lib/screens/features/profile_screen.dart new file mode 100644 index 0000000..5987c9c --- /dev/null +++ b/monitoring/lib/screens/features/profile_screen.dart @@ -0,0 +1,187 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; +import 'dart:convert'; + +import 'edit_profile_screen.dart'; +import 'change_password_screen.dart'; + +class ProfileScreen extends StatefulWidget { + final String token; + const ProfileScreen({super.key, required this.token}); + + @override + State createState() => _ProfileScreenState(); +} + +class _ProfileScreenState extends State { + Map? userData; + Map? santriData; + String? fotoUrl; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchProfile(); + } + + Future fetchProfile() async { + final url = '$baseUrl/santri/me'; + try { + final res = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (res.statusCode == 200) { + final jsonRes = json.decode(res.body); + setState(() { + userData = jsonRes['user']; + santriData = jsonRes['santri']; + fotoUrl = santriData?['foto_url']; + loading = false; + }); + } else { + debugPrint('Gagal ambil profil: ${res.body}'); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Error profile: $e'); + setState(() => loading = false); + } + } + + void _logout() { + Navigator.pushNamedAndRemoveUntil(context, '/login', (_) => false); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Profil'), + actions: [ + IconButton( + onPressed: _logout, + icon: const Icon(Icons.logout), + tooltip: 'Logout', + ), + ], + ), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : userData == null || santriData == null + ? const Center(child: Text('Data tidak ditemukan')) + : SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: CircleAvatar( + radius: 50, + backgroundImage: + fotoUrl != null + ? NetworkImage(fotoUrl!) + : const AssetImage('assets/default_profile.png') + as ImageProvider, + backgroundColor: Colors.grey[300], + ), + ), + const SizedBox(height: 20), + Center( + child: Text( + userData!['name'] ?? '-', + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 16), + // _buildInfoTile('Username', userData!['username']), + // _buildInfoTile('Email', userData!['email']), + // _buildInfoTile('Role', userData!['role']), + const Divider(), + _buildInfoTile('NIS', santriData!['nis']), + _buildInfoTile('Alamat', santriData!['alamat']), + _buildInfoTile('Tempat Lahir', santriData!['tempat_lahir']), + _buildInfoTile( + 'Tanggal Lahir', + santriData!['tanggal_lahir'], + ), + _buildInfoTile( + 'Jenis Kelamin', + santriData!['jenis_kelamin'] == 'L' + ? 'Laki-laki' + : 'Perempuan', + ), + const SizedBox(height: 24), + + // ✅ PERBAIKAN NAVIGASI EDIT + ElevatedButton.icon( + onPressed: () async { + final result = await Navigator.push( + context, + MaterialPageRoute( + builder: + (_) => EditProfileScreen(token: widget.token), + ), + ); + if (result == true) { + fetchProfile(); // Refresh profil setelah edit + } + }, + icon: const Icon(Icons.edit), + label: const Text('Edit Profil'), + ), + + const SizedBox(height: 12), + + ElevatedButton.icon( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.orange, + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: + (_) => + ChangePasswordScreen(token: widget.token), + ), + ); + }, + icon: const Icon(Icons.lock), + label: const Text('Ganti Password'), + ), + ], + ), + ), + ); + } + + Widget _buildInfoTile(String label, String? value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + '$label:', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Expanded(child: Text(value ?? '-')), + ], + ), + ); + } +} diff --git a/monitoring/lib/screens/features/tambah_pembayaran_screen.dart b/monitoring/lib/screens/features/tambah_pembayaran_screen.dart new file mode 100644 index 0000000..93044aa --- /dev/null +++ b/monitoring/lib/screens/features/tambah_pembayaran_screen.dart @@ -0,0 +1,211 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:monitoring/config.dart'; + +class TambahPembayaranScreen extends StatefulWidget { + final String token; + const TambahPembayaranScreen({super.key, required this.token}); + + @override + State createState() => _TambahPembayaranScreenState(); +} + +class _TambahPembayaranScreenState extends State { + final formKey = GlobalKey(); + String jenis = 'SPP'; + String tanggal = ''; + int jumlah = 0; + String keterangan = ''; + File? bukti; + bool isLoading = false; + + Future submit() async { + if (!formKey.currentState!.validate()) return; + + if (bukti == null) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Bukti belum dipilih'))); + return; + } + setState(() => isLoading = true); + + final dio = Dio( + BaseOptions( + baseUrl: '$baseUrl', + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ), + ); + + final formData = FormData.fromMap({ + 'tanggal': tanggal, + 'jenis_pembayaran': jenis, + 'jumlah': jumlah, + 'keterangan': keterangan, + 'bukti_pembayaran': await MultipartFile.fromFile(bukti!.path), + }); + + try { + final response = await dio.post('/pembayaran', data: formData); + if (response.statusCode == 201) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Pembayaran berhasil dikirim')), + ); + Navigator.pop(context); + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Gagal mengirim pembayaran')), + ); + } + } catch (e) { + debugPrint('Gagal kirim pembayaran: $e'); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e'))); + } finally { + setState(() => isLoading = false); // selesai loading + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Tambah Pembayaran')), + body: Padding( + padding: const EdgeInsets.all(16), + child: Form( + key: formKey, + child: ListView( + children: [ + DropdownButtonFormField( + value: jenis, + items: const [ + DropdownMenuItem(value: 'SPP', child: Text('SPP')), + DropdownMenuItem( + value: 'Uang Makan', + child: Text('Uang Makan'), + ), + DropdownMenuItem( + value: 'Uang Asrama', + child: Text('Uang Asrama'), + ), + DropdownMenuItem( + value: 'Uang Kegiatan', + child: Text('Uang Kegiatan'), + ), + DropdownMenuItem( + value: 'Uang Seragam', + child: Text('Uang Seragam'), + ), + DropdownMenuItem(value: 'Lainnya', child: Text('Lainnya')), + ], + onChanged: (val) => setState(() => jenis = val!), + decoration: const InputDecoration( + labelText: 'Jenis Pembayaran', + ), + ), + const SizedBox(height: 12), + TextFormField( + decoration: const InputDecoration(labelText: 'Jumlah'), + keyboardType: TextInputType.number, + onChanged: (val) => jumlah = int.tryParse(val) ?? 0, + validator: + (val) => + val == null || val.isEmpty + ? 'Jumlah wajib diisi' + : null, + ), + const SizedBox(height: 12), + TextFormField( + decoration: const InputDecoration(labelText: 'Tanggal'), + controller: TextEditingController(text: tanggal), + readOnly: true, + onTap: () async { + final picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2022), + lastDate: DateTime(2030), + ); + if (picked != null) { + setState(() { + tanggal = picked.toIso8601String().split('T')[0]; + }); + } + }, + validator: + (val) => + val == null || val.isEmpty + ? 'Tanggal wajib diisi' + : null, + ), + const SizedBox(height: 12), + TextFormField( + decoration: const InputDecoration(labelText: 'Keterangan'), + maxLines: 2, + onChanged: (val) => keterangan = val, + ), + const SizedBox(height: 12), + ElevatedButton.icon( + onPressed: () async { + final picked = await FilePicker.platform.pickFiles( + type: FileType.image, + ); + if (picked != null && picked.files.first.path != null) { + setState(() { + bukti = File(picked.files.first.path!); + }); + } + }, + icon: const Icon(Icons.attach_file), + label: const Text('Pilih Bukti Pembayaran'), + ), + if (bukti != null) ...[ + const SizedBox(height: 10), + const Text( + 'Preview Bukti:', + style: TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 8), + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + bukti!, + height: 200, + width: double.infinity, + fit: BoxFit.cover, + ), + ), + ], + const SizedBox(height: 24), + ElevatedButton.icon( + onPressed: isLoading ? null : submit, + icon: + isLoading + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : const Icon(Icons.save), + label: Text(isLoading ? 'Proses...' : 'Kirim Pembayaran'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.teal, + padding: const EdgeInsets.symmetric(vertical: 14), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/monitoring/lib/screens/forgot_password_screen.dart b/monitoring/lib/screens/forgot_password_screen.dart new file mode 100644 index 0000000..5b9b825 --- /dev/null +++ b/monitoring/lib/screens/forgot_password_screen.dart @@ -0,0 +1,111 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import '../config.dart'; // baseUrl disimpan di file ini + +class ForgotPasswordScreen extends StatefulWidget { + const ForgotPasswordScreen({Key? key}) : super(key: key); + + @override + State createState() => _ForgotPasswordScreenState(); +} + +class _ForgotPasswordScreenState extends State { + final _formKey = GlobalKey(); + final _nisController = TextEditingController(); + final _newPassController = TextEditingController(); + final _confirmPassController = TextEditingController(); + + bool _loading = false; + + Future _resetPassword() async { + if (!_formKey.currentState!.validate()) return; + + setState(() => _loading = true); + + final response = await http.post( + Uri.parse('$baseUrl/forgot-password/reset'), + headers: {'Accept': 'application/json'}, + body: { + 'nis': _nisController.text, + 'new_password': _newPassController.text, + 'confirm_password': _confirmPassController.text, + }, + ); + + final data = jsonDecode(response.body); + setState(() => _loading = false); + + if (response.statusCode == 200) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(data['message'])), + ); + Navigator.pop(context); // kembali ke halaman login + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(data['message'] ?? 'Gagal mereset password')), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text("Reset Password")), + body: Padding( + padding: const EdgeInsets.all(20), + child: Form( + key: _formKey, + child: Column( + children: [ + TextFormField( + controller: _nisController, + decoration: const InputDecoration( + labelText: "NIS", + border: OutlineInputBorder(), + ), + validator: (val) => + val == null || val.isEmpty ? 'NIS wajib diisi' : null, + ), + const SizedBox(height: 16), + TextFormField( + controller: _newPassController, + obscureText: true, + decoration: const InputDecoration( + labelText: "Password Baru", + border: OutlineInputBorder(), + ), + validator: (val) => + val == null || val.length < 6 ? 'Minimal 6 karakter' : null, + ), + const SizedBox(height: 16), + TextFormField( + controller: _confirmPassController, + obscureText: true, + decoration: const InputDecoration( + labelText: "Konfirmasi Password", + border: OutlineInputBorder(), + ), + validator: (val) => + val != _newPassController.text ? 'Tidak cocok' : null, + ), + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _loading ? null : _resetPassword, + child: _loading + ? const CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2, + ) + : const Text("Reset Password"), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/monitoring/lib/screens/home_screen.dart b/monitoring/lib/screens/home_screen.dart new file mode 100644 index 0000000..d05dcd2 --- /dev/null +++ b/monitoring/lib/screens/home_screen.dart @@ -0,0 +1,148 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../main.dart'; +import '../widgets/feature_grid.dart'; +import 'features/profile_screen.dart'; +import 'splash_screen.dart'; // ✅ Tambahkan ini + +class HomeScreen extends StatefulWidget { + final String token; + final Map user; + + const HomeScreen({super.key, required this.token, required this.user}); + + @override + State createState() => _HomeScreenState(); +} + +class _HomeScreenState extends State { + void logout() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove('token'); + await prefs.remove('user'); + + if (!mounted) return; // ✅ Hindari error context async + + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: + (_) => SplashScreen( + onLoginSuccess: (token, user) { + Navigator.pushReplacement( + navigatorKey.currentContext!, + MaterialPageRoute( + builder: (_) => HomeScreen(token: token, user: user), + ), + ); + }, + ), + ), + (route) => false, + ); + } + + Widget buildBanner(String name) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient( + colors: [Color(0xFFA5D6A7), Color(0xFF66BB6A)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Monas SMA Bina Insan Mandiri', + style: TextStyle(color: Colors.white70, fontSize: 12), + ), + const SizedBox(height: 4), + Text( + 'Selamat Datang, $name', + style: const TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + final name = widget.user['name'] ?? 'Santri'; + + return Scaffold( + drawer: Drawer( + child: ListView( + padding: EdgeInsets.zero, + children: [ + DrawerHeader( + decoration: const BoxDecoration(color: Color(0xFF43A047)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon( + Icons.account_circle, + size: 64, + color: Colors.white, + ), + const SizedBox(height: 8), + Text( + name, + style: const TextStyle(color: Colors.white, fontSize: 18), + ), + const Text('Santri', style: TextStyle(color: Colors.white70)), + ], + ), + ), + ListTile( + leading: const Icon(Icons.person), + title: const Text('Profil'), + onTap: () { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => ProfileScreen(token: widget.token), + ), + ); + }, + ), + ListTile( + leading: const Icon(Icons.logout), + title: const Text('Logout'), + onTap: () { + Navigator.pop(context); + logout(); + }, + ), + ], + ), + ), + appBar: AppBar(backgroundColor: const Color(0xFF43A047), elevation: 0), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 12), + buildBanner(name), + const SizedBox(height: 20), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: FeatureGrid(token: widget.token), + ), + ), + ], + ), + ); + } +} diff --git a/monitoring/lib/screens/login_screen.dart b/monitoring/lib/screens/login_screen.dart new file mode 100644 index 0000000..4359eee --- /dev/null +++ b/monitoring/lib/screens/login_screen.dart @@ -0,0 +1,152 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; +import 'forgot_password_screen.dart'; + +class LoginScreen extends StatefulWidget { + final Function(String token, Map user) onLoginSuccess; + + const LoginScreen({super.key, required this.onLoginSuccess}); + + @override + State createState() => _LoginScreenState(); +} + +class _LoginScreenState extends State { + final TextEditingController _usernameController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + bool _isLoading = false; + String _error = ''; + + Future login() async { + setState(() { + _isLoading = true; + _error = ''; + }); + + final url = Uri.parse('$baseUrl/login'); + final response = await http.post( + url, + headers: {'Accept': 'application/json'}, + body: { + 'username': _usernameController.text.trim(), + 'password': _passwordController.text.trim(), + }, + ); + + setState(() { + _isLoading = false; + }); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + final token = data['access_token']; + final user = Map.from(data['user']); + + widget.onLoginSuccess(token, user); + } else { + final data = json.decode(response.body); + setState(() { + _error = data['message'] ?? 'Login gagal'; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [Color(0xFF43A047), Color(0xFFFFF176)], // Hijau ke kuning + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + padding: const EdgeInsets.all(16.0), + child: Center( + child: SingleChildScrollView( + child: Card( + elevation: 12, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'Login Santri', + style: TextStyle( + fontSize: 28, + fontWeight: FontWeight.bold, + color: Color(0xFF388E3C), // Hijau Tua + ), + ), + const SizedBox(height: 24), + if (_error.isNotEmpty) + Text( + _error, + style: const TextStyle(color: Colors.red), + ), + TextField( + controller: _usernameController, + decoration: const InputDecoration( + labelText: 'Username', + prefixIcon: Icon(Icons.person), + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 16), + TextField( + controller: _passwordController, + obscureText: true, + decoration: const InputDecoration( + labelText: 'Password', + prefixIcon: Icon(Icons.lock), + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 24), + _isLoading + ? const CircularProgressIndicator() + : SizedBox( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF8BC34A), // Hijau Muda + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onPressed: login, + child: const Text( + 'Login', + style: TextStyle(fontSize: 16, color: Colors.white), + ), + ), + ), + const SizedBox(height: 16), + TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => const ForgotPasswordScreen()), + ); + }, + child: const Text( + 'Lupa Password?', + style: TextStyle(color: Color(0xFF388E3C)), + ), + ), + ], + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/monitoring/lib/screens/reset_password_screen.dart b/monitoring/lib/screens/reset_password_screen.dart new file mode 100644 index 0000000..b46fa39 --- /dev/null +++ b/monitoring/lib/screens/reset_password_screen.dart @@ -0,0 +1,121 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import '../config.dart'; + +class ResetPasswordScreen extends StatefulWidget { + final int userId; + + const ResetPasswordScreen({Key? key, required this.userId}) : super(key: key); + + @override + State createState() => _ResetPasswordScreenState(); +} + +class _ResetPasswordScreenState extends State { + final TextEditingController _passwordController = TextEditingController(); + final TextEditingController _confirmController = TextEditingController(); + bool _isLoading = false; + + Future _resetPassword() async { + final password = _passwordController.text.trim(); + final confirmPassword = _confirmController.text.trim(); + + if (password.isEmpty || confirmPassword.isEmpty) { + _showMessage('Semua kolom harus diisi.'); + return; + } + + if (password != confirmPassword) { + _showMessage('Password tidak sama.'); + return; + } + + setState(() => _isLoading = true); + + try { + final response = await http.post( + Uri.parse('$baseUrl/forgot-password/reset'), + body: { + 'user_id': widget.userId.toString(), + 'password': password, + 'password_confirmation': confirmPassword, + }, + ); + + final data = jsonDecode(response.body); + + if (response.statusCode == 200) { + _showMessage(data['message'] ?? 'Password berhasil diubah'); + Navigator.popUntil(context, (route) => route.isFirst); // Kembali ke login + } else { + _showMessage(data['message'] ?? 'Gagal reset password.'); + } + } catch (e) { + _showMessage('Gagal menghubungi server.'); + } finally { + setState(() => _isLoading = false); + } + } + + void _showMessage(String message) { + showDialog( + context: context, + builder: (_) => AlertDialog( + title: const Text('Informasi'), + content: Text(message), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('OK'), + ), + ], + ), + ); + } + + @override + void dispose() { + _passwordController.dispose(); + _confirmController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Reset Password Baru')), + body: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + children: [ + TextField( + controller: _passwordController, + obscureText: true, + decoration: const InputDecoration( + labelText: 'Password Baru', + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 16), + TextField( + controller: _confirmController, + obscureText: true, + decoration: const InputDecoration( + labelText: 'Konfirmasi Password', + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 24), + _isLoading + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: _resetPassword, + child: const Text('Reset Password'), + ), + ], + ), + ), + ); + } +} diff --git a/monitoring/lib/screens/splash_screen.dart b/monitoring/lib/screens/splash_screen.dart new file mode 100644 index 0000000..410e657 --- /dev/null +++ b/monitoring/lib/screens/splash_screen.dart @@ -0,0 +1,60 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:monitoring/screens/login_screen.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class SplashScreen extends StatefulWidget { + final Function(String token, Map user) onLoginSuccess; + + const SplashScreen({super.key, required this.onLoginSuccess}); + + @override + State createState() => _SplashScreenState(); +} + +class _SplashScreenState extends State { + bool isLoading = true; + + @override + void initState() { + super.initState(); + checkLoginStatus(); + } + + Future checkLoginStatus() async { + final prefs = await SharedPreferences.getInstance(); + final token = prefs.getString('token'); + final userJson = prefs.getString('user'); + + if (token != null && userJson != null) { + final user = jsonDecode(userJson); + widget.onLoginSuccess(token, Map.from(user)); + } else { + setState(() => isLoading = false); + } + } + + @override + Widget build(BuildContext context) { + if (isLoading) { + return const Scaffold(body: Center(child: CircularProgressIndicator())); + } + + return Scaffold( + appBar: AppBar(title: const Text('Santri App')), + body: Center( + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => LoginScreen(onLoginSuccess: widget.onLoginSuccess), + ), + ); + }, + child: const Text('Login as Santri'), + ), + ), + ); + } +} diff --git a/monitoring/lib/widgets/berita_carousel.dart b/monitoring/lib/widgets/berita_carousel.dart new file mode 100644 index 0000000..0976420 --- /dev/null +++ b/monitoring/lib/widgets/berita_carousel.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:monitoring/config.dart'; + +class Berita { + final int id; + final String judul; + final String? gambarUrl; + + Berita({required this.id, required this.judul, this.gambarUrl}); + + factory Berita.fromJson(Map json) { + return Berita( + id: json['id'], + judul: json['judul'] ?? '', + gambarUrl: json['gambar_url'], + ); + } +} + +class BeritaCarousel extends StatefulWidget { + const BeritaCarousel({ + super.key, + required this.token, + required bool isCircleStyle, + }); + final String token; + + @override + State createState() => _BeritaCarouselState(); +} + +class _BeritaCarouselState extends State { + List _beritaList = []; + bool _loading = true; + + @override + void initState() { + super.initState(); + fetchBerita(); + } + + Future fetchBerita() async { + try { + final dio = Dio( + BaseOptions( + baseUrl: '$baseUrl', + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ), + ); + + final response = await dio.get('/berita/published'); + final List raw = response.data['data']; + setState(() { + _beritaList = raw.map((e) => Berita.fromJson(e)).toList(); + _loading = false; + }); + } catch (e) { + debugPrint('Gagal ambil berita: $e'); + setState(() => _loading = false); + } + } + + @override + Widget build(BuildContext context) { + if (_loading) return const Center(child: CircularProgressIndicator()); + if (_beritaList.isEmpty) return const Text('Tidak ada berita.'); + + return SizedBox( + height: 160, + child: PageView.builder( + itemCount: _beritaList.length, + controller: PageController(viewportFraction: 0.85), + itemBuilder: (context, index) { + final berita = _beritaList[index]; + return Container( + margin: const EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + image: DecorationImage( + image: + berita.gambarUrl != null + ? NetworkImage(berita.gambarUrl!) + : const AssetImage('assets/404.png') as ImageProvider, + fit: BoxFit.cover, + ), + ), + child: Container( + alignment: Alignment.bottomLeft, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.black54, + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(12), + bottomRight: Radius.circular(12), + ), + ), + child: Text( + berita.judul, + style: const TextStyle(color: Colors.white, fontSize: 14), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + ); + }, + ), + ); + } +} diff --git a/monitoring/lib/widgets/feature_grid.dart b/monitoring/lib/widgets/feature_grid.dart new file mode 100644 index 0000000..ac305c3 --- /dev/null +++ b/monitoring/lib/widgets/feature_grid.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; + +import '../screens/features/absensi_screen.dart'; +import '../screens/features/nilai_screen.dart'; +import '../screens/features/kesehatan_screen.dart'; +import '../screens/features/prestasi_screen.dart'; +import '../screens/features/pelanggaran_screen.dart'; +import '../screens/features/berita_screen.dart'; +import '../screens/features/alumni_screen.dart'; +import '../screens/features/pembayaran_screen.dart'; + +class FeatureGrid extends StatelessWidget { + final String token; + + const FeatureGrid({super.key, required this.token}); + + final List<_FeatureItem> _items = const [ + _FeatureItem('Absensi', Icons.how_to_reg), + _FeatureItem('Nilai', Icons.grade), + _FeatureItem('Kesehatan', Icons.local_hospital), + _FeatureItem('Prestasi', Icons.emoji_events), + _FeatureItem('Pelanggaran', Icons.report), + _FeatureItem('Berita', Icons.article), + _FeatureItem('Alumni', Icons.people), + _FeatureItem('Pembayaran', Icons.attach_money), + ]; + + @override + Widget build(BuildContext context) { + return GridView.builder( + itemCount: _items.length, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + itemBuilder: (context, index) { + final item = _items[index]; + + return GestureDetector( + onTap: () { + Widget? destination; + + switch (item.label) { + case 'Absensi': + destination = AbsensiScreen(token: token); + break; + case 'Nilai': + destination = NilaiScreen(token: token); + break; + case 'Kesehatan': + destination = KesehatanScreen(token: token); + break; + case 'Prestasi': + destination = PrestasiScreen(token: token); + break; + case 'Pelanggaran': + destination = PelanggaranScreen(token: token); + break; + case 'Berita': + destination = BeritaScreen(token: token); + break; + case 'Alumni': + destination = AlumniScreen(token: token); + break; + case 'Pembayaran': + destination = PembayaranScreen(token: token); + break; + } + + if (destination != null) { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => destination!), + ); + } + }, + child: Container( + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFF43A047), Color(0xFFFFEB3B)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.08), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(item.icon, size: 32, color: Colors.white), + const SizedBox(height: 8), + Text( + item.label, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + }, + ); + } +} + +class _FeatureItem { + final String label; + final IconData icon; + + const _FeatureItem(this.label, this.icon); +} diff --git a/monitoring/linux/.gitignore b/monitoring/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/monitoring/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/monitoring/linux/CMakeLists.txt b/monitoring/linux/CMakeLists.txt new file mode 100644 index 0000000..240bad4 --- /dev/null +++ b/monitoring/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "monitoring") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.monitoring") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/monitoring/linux/flutter/CMakeLists.txt b/monitoring/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/monitoring/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/monitoring/linux/flutter/generated_plugin_registrant.cc b/monitoring/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..3ccd551 --- /dev/null +++ b/monitoring/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,23 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); + flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/monitoring/linux/flutter/generated_plugin_registrant.h b/monitoring/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/monitoring/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/monitoring/linux/flutter/generated_plugins.cmake b/monitoring/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..9ce94c4 --- /dev/null +++ b/monitoring/linux/flutter/generated_plugins.cmake @@ -0,0 +1,26 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux + flutter_secure_storage_linux + url_launcher_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/monitoring/linux/runner/CMakeLists.txt b/monitoring/linux/runner/CMakeLists.txt new file mode 100644 index 0000000..e97dabc --- /dev/null +++ b/monitoring/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/monitoring/linux/runner/main.cc b/monitoring/linux/runner/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/monitoring/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/monitoring/linux/runner/my_application.cc b/monitoring/linux/runner/my_application.cc new file mode 100644 index 0000000..952dbf0 --- /dev/null +++ b/monitoring/linux/runner/my_application.cc @@ -0,0 +1,130 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "monitoring"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "monitoring"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/monitoring/linux/runner/my_application.h b/monitoring/linux/runner/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/monitoring/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/monitoring/local.properties b/monitoring/local.properties new file mode 100644 index 0000000..1ef74e3 --- /dev/null +++ b/monitoring/local.properties @@ -0,0 +1,8 @@ +## This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Wed Jul 16 13:13:55 WIB 2025 +sdk.dir=C\:\\Users\\ASUS\\AppData\\Local\\Android diff --git a/monitoring/macos/.gitignore b/monitoring/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/monitoring/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/monitoring/macos/Flutter/Flutter-Debug.xcconfig b/monitoring/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/monitoring/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/monitoring/macos/Flutter/Flutter-Release.xcconfig b/monitoring/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/monitoring/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/monitoring/macos/Flutter/GeneratedPluginRegistrant.swift b/monitoring/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..6d6171a --- /dev/null +++ b/monitoring/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,22 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import file_picker +import file_selector_macos +import flutter_secure_storage_macos +import path_provider_foundation +import shared_preferences_foundation +import url_launcher_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) +} diff --git a/monitoring/macos/Runner.xcodeproj/project.pbxproj b/monitoring/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..702cea6 --- /dev/null +++ b/monitoring/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* monitoring.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "monitoring.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* monitoring.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* monitoring.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/monitoring.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/monitoring"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/monitoring.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/monitoring"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/monitoring.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/monitoring"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/monitoring/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/monitoring/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/monitoring/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/monitoring/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/monitoring/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..3dd6171 --- /dev/null +++ b/monitoring/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/monitoring/macos/Runner.xcworkspace/contents.xcworkspacedata b/monitoring/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/monitoring/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/monitoring/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/monitoring/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/monitoring/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/monitoring/macos/Runner/AppDelegate.swift b/monitoring/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..b3c1761 --- /dev/null +++ b/monitoring/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a2ec33f --- /dev/null +++ b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000..82b6f9d Binary files /dev/null and b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000..13b35eb Binary files /dev/null and b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000..0a3f5fa Binary files /dev/null and b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000..bdb5722 Binary files /dev/null and b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000..f083318 Binary files /dev/null and b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000..326c0e7 Binary files /dev/null and b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000..2f1632c Binary files /dev/null and b/monitoring/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/monitoring/macos/Runner/Base.lproj/MainMenu.xib b/monitoring/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..80e867a --- /dev/null +++ b/monitoring/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/monitoring/macos/Runner/Configs/AppInfo.xcconfig b/monitoring/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..d24cd00 --- /dev/null +++ b/monitoring/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = monitoring + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/monitoring/macos/Runner/Configs/Debug.xcconfig b/monitoring/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/monitoring/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/monitoring/macos/Runner/Configs/Release.xcconfig b/monitoring/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/monitoring/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/monitoring/macos/Runner/Configs/Warnings.xcconfig b/monitoring/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/monitoring/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/monitoring/macos/Runner/DebugProfile.entitlements b/monitoring/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..dddb8a3 --- /dev/null +++ b/monitoring/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/monitoring/macos/Runner/Info.plist b/monitoring/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/monitoring/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/monitoring/macos/Runner/MainFlutterWindow.swift b/monitoring/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..3cc05eb --- /dev/null +++ b/monitoring/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/monitoring/macos/Runner/Release.entitlements b/monitoring/macos/Runner/Release.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/monitoring/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/monitoring/macos/RunnerTests/RunnerTests.swift b/monitoring/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61f3bd1 --- /dev/null +++ b/monitoring/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/monitoring/pubspec.lock b/monitoring/pubspec.lock new file mode 100644 index 0000000..cc2142f --- /dev/null +++ b/monitoring/pubspec.lock @@ -0,0 +1,746 @@ +# Generated by pub +# See https://dart.dev/tools/pub/glossary#lockfile +packages: + archive: + dependency: transitive + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" + async: + dependency: transitive + description: + name: async + sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" + url: "https://pub.dev" + source: hosted + version: "2.13.0" + boolean_selector: + dependency: transitive + description: + name: boolean_selector + sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + carousel_slider: + dependency: "direct main" + description: + name: carousel_slider + sha256: "9c695cc963bf1d04a47bd6021f68befce8970bcd61d24938e1fb0918cf5d9c42" + url: "https://pub.dev" + source: hosted + version: "4.2.1" + characters: + dependency: transitive + description: + name: characters + sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + clock: + dependency: transitive + description: + name: clock + sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b + url: "https://pub.dev" + source: hosted + version: "1.1.2" + collection: + dependency: "direct main" + description: + name: collection + sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" + url: "https://pub.dev" + source: hosted + version: "1.19.1" + cross_file: + dependency: transitive + description: + name: cross_file + sha256: "7caf6a750a0c04effbb52a676dce9a4a592e10ad35c34d6d2d0e4811160d5670" + url: "https://pub.dev" + source: hosted + version: "0.3.4+2" + crypto: + dependency: transitive + description: + name: crypto + sha256: "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + cupertino_icons: + dependency: "direct main" + description: + name: cupertino_icons + sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 + url: "https://pub.dev" + source: hosted + version: "1.0.8" + dio: + dependency: "direct main" + description: + name: dio + sha256: "253a18bbd4851fecba42f7343a1df3a9a4c1d31a2c1b37e221086b4fa8c8dbc9" + url: "https://pub.dev" + source: hosted + version: "5.8.0+1" + dio_web_adapter: + dependency: transitive + description: + name: dio_web_adapter + sha256: "7586e476d70caecaf1686d21eee7247ea43ef5c345eab9e0cc3583ff13378d78" + url: "https://pub.dev" + source: hosted + version: "2.1.1" + fake_async: + dependency: transitive + description: + name: fake_async + sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" + url: "https://pub.dev" + source: hosted + version: "1.3.3" + ffi: + dependency: transitive + description: + name: ffi + sha256: "289279317b4b16eb2bb7e271abccd4bf84ec9bdcbe999e278a94b804f5630418" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + file: + dependency: transitive + description: + name: file + sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 + url: "https://pub.dev" + source: hosted + version: "7.0.1" + file_picker: + dependency: "direct main" + description: + name: file_picker + sha256: ef9908739bdd9c476353d6adff72e88fd00c625f5b959ae23f7567bd5137db0a + url: "https://pub.dev" + source: hosted + version: "10.2.0" + file_selector_linux: + dependency: transitive + description: + name: file_selector_linux + sha256: "54cbbd957e1156d29548c7d9b9ec0c0ebb6de0a90452198683a7d23aed617a33" + url: "https://pub.dev" + source: hosted + version: "0.9.3+2" + file_selector_macos: + dependency: transitive + description: + name: file_selector_macos + sha256: "8c9250b2bd2d8d4268e39c82543bacbaca0fda7d29e0728c3c4bbb7c820fd711" + url: "https://pub.dev" + source: hosted + version: "0.9.4+3" + file_selector_platform_interface: + dependency: transitive + description: + name: file_selector_platform_interface + sha256: a3994c26f10378a039faa11de174d7b78eb8f79e4dd0af2a451410c1a5c3f66b + url: "https://pub.dev" + source: hosted + version: "2.6.2" + file_selector_windows: + dependency: transitive + description: + name: file_selector_windows + sha256: "320fcfb6f33caa90f0b58380489fc5ac05d99ee94b61aa96ec2bff0ba81d3c2b" + url: "https://pub.dev" + source: hosted + version: "0.9.3+4" + flutter: + dependency: "direct main" + description: flutter + source: sdk + version: "0.0.0" + flutter_lints: + dependency: "direct dev" + description: + name: flutter_lints + sha256: "5398f14efa795ffb7a33e9b6a08798b26a180edac4ad7db3f231e40f82ce11e1" + url: "https://pub.dev" + source: hosted + version: "5.0.0" + flutter_plugin_android_lifecycle: + dependency: transitive + description: + name: flutter_plugin_android_lifecycle + sha256: f948e346c12f8d5480d2825e03de228d0eb8c3a737e4cdaa122267b89c022b5e + url: "https://pub.dev" + source: hosted + version: "2.0.28" + flutter_secure_storage: + dependency: "direct dev" + description: + name: flutter_secure_storage + sha256: "9cad52d75ebc511adfae3d447d5d13da15a55a92c9410e50f67335b6d21d16ea" + url: "https://pub.dev" + source: hosted + version: "9.2.4" + flutter_secure_storage_linux: + dependency: transitive + description: + name: flutter_secure_storage_linux + sha256: be76c1d24a97d0b98f8b54bce6b481a380a6590df992d0098f868ad54dc8f688 + url: "https://pub.dev" + source: hosted + version: "1.2.3" + flutter_secure_storage_macos: + dependency: transitive + description: + name: flutter_secure_storage_macos + sha256: "6c0a2795a2d1de26ae202a0d78527d163f4acbb11cde4c75c670f3a0fc064247" + url: "https://pub.dev" + source: hosted + version: "3.1.3" + flutter_secure_storage_platform_interface: + dependency: transitive + description: + name: flutter_secure_storage_platform_interface + sha256: cf91ad32ce5adef6fba4d736a542baca9daf3beac4db2d04be350b87f69ac4a8 + url: "https://pub.dev" + source: hosted + version: "1.1.2" + flutter_secure_storage_web: + dependency: transitive + description: + name: flutter_secure_storage_web + sha256: f4ebff989b4f07b2656fb16b47852c0aab9fed9b4ec1c70103368337bc1886a9 + url: "https://pub.dev" + source: hosted + version: "1.2.1" + flutter_secure_storage_windows: + dependency: transitive + description: + name: flutter_secure_storage_windows + sha256: b20b07cb5ed4ed74fc567b78a72936203f587eba460af1df11281c9326cd3709 + url: "https://pub.dev" + source: hosted + version: "3.1.2" + flutter_test: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + fluttertoast: + dependency: "direct main" + description: + name: fluttertoast + sha256: "25e51620424d92d3db3832464774a6143b5053f15e382d8ffbfd40b6e795dcf1" + url: "https://pub.dev" + source: hosted + version: "8.2.12" + font_awesome_flutter: + dependency: "direct main" + description: + name: font_awesome_flutter + sha256: d3a89184101baec7f4600d58840a764d2ef760fe1c5a20ef9e6b0e9b24a07a3a + url: "https://pub.dev" + source: hosted + version: "10.8.0" + http: + dependency: "direct main" + description: + name: http + sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2" + url: "https://pub.dev" + source: hosted + version: "0.13.6" + http_parser: + dependency: "direct main" + description: + name: http_parser + sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" + url: "https://pub.dev" + source: hosted + version: "4.1.2" + image: + dependency: "direct main" + description: + name: image + sha256: "8e9d133755c3e84c73288363e6343157c383a0c6c56fc51afcc5d4d7180306d6" + url: "https://pub.dev" + source: hosted + version: "3.3.0" + image_picker: + dependency: "direct main" + description: + name: image_picker + sha256: "021834d9c0c3de46bf0fe40341fa07168407f694d9b2bb18d532dc1261867f7a" + url: "https://pub.dev" + source: hosted + version: "1.1.2" + image_picker_android: + dependency: transitive + description: + name: image_picker_android + sha256: "317a5d961cec5b34e777b9252393f2afbd23084aa6e60fcf601dcf6341b9ebeb" + url: "https://pub.dev" + source: hosted + version: "0.8.12+23" + image_picker_for_web: + dependency: transitive + description: + name: image_picker_for_web + sha256: "717eb042ab08c40767684327be06a5d8dbb341fe791d514e4b92c7bbe1b7bb83" + url: "https://pub.dev" + source: hosted + version: "3.0.6" + image_picker_ios: + dependency: transitive + description: + name: image_picker_ios + sha256: "05da758e67bc7839e886b3959848aa6b44ff123ab4b28f67891008afe8ef9100" + url: "https://pub.dev" + source: hosted + version: "0.8.12+2" + image_picker_linux: + dependency: transitive + description: + name: image_picker_linux + sha256: "34a65f6740df08bbbeb0a1abd8e6d32107941fd4868f67a507b25601651022c9" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_macos: + dependency: transitive + description: + name: image_picker_macos + sha256: "1b90ebbd9dcf98fb6c1d01427e49a55bd96b5d67b8c67cf955d60a5de74207c1" + url: "https://pub.dev" + source: hosted + version: "0.2.1+2" + image_picker_platform_interface: + dependency: transitive + description: + name: image_picker_platform_interface + sha256: "886d57f0be73c4b140004e78b9f28a8914a09e50c2d816bdd0520051a71236a0" + url: "https://pub.dev" + source: hosted + version: "2.10.1" + image_picker_windows: + dependency: transitive + description: + name: image_picker_windows + sha256: "6ad07afc4eb1bc25f3a01084d28520496c4a3bb0cb13685435838167c9dcedeb" + url: "https://pub.dev" + source: hosted + version: "0.2.1+1" + intl: + dependency: "direct main" + description: + name: intl + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.dev" + source: hosted + version: "0.18.1" + js: + dependency: transitive + description: + name: js + sha256: f2c445dce49627136094980615a031419f7f3eb393237e4ecd97ac15dea343f3 + url: "https://pub.dev" + source: hosted + version: "0.6.7" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0" + url: "https://pub.dev" + source: hosted + version: "10.0.9" + leak_tracker_flutter_testing: + dependency: transitive + description: + name: leak_tracker_flutter_testing + sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573 + url: "https://pub.dev" + source: hosted + version: "3.0.9" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3" + url: "https://pub.dev" + source: hosted + version: "3.0.1" + lints: + dependency: transitive + description: + name: lints + sha256: c35bb79562d980e9a453fc715854e1ed39e24e7d0297a880ef54e17f9874a9d7 + url: "https://pub.dev" + source: hosted + version: "5.1.1" + lottie: + dependency: "direct main" + description: + name: lottie + sha256: a93542cc2d60a7057255405f62252533f8e8956e7e06754955669fd32fb4b216 + url: "https://pub.dev" + source: hosted + version: "2.7.0" + matcher: + dependency: transitive + description: + name: matcher + sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2 + url: "https://pub.dev" + source: hosted + version: "0.12.17" + material_color_utilities: + dependency: transitive + description: + name: material_color_utilities + sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec + url: "https://pub.dev" + source: hosted + version: "0.11.1" + meta: + dependency: transitive + description: + name: meta + sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c + url: "https://pub.dev" + source: hosted + version: "1.16.0" + mime: + dependency: transitive + description: + name: mime + sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" + url: "https://pub.dev" + source: hosted + version: "2.0.0" + path: + dependency: transitive + description: + name: path + sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" + url: "https://pub.dev" + source: hosted + version: "1.9.1" + path_provider: + dependency: "direct main" + description: + name: path_provider + sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" + url: "https://pub.dev" + source: hosted + version: "2.1.5" + path_provider_android: + dependency: transitive + description: + name: path_provider_android + sha256: d0d310befe2c8ab9e7f393288ccbb11b60c019c6b5afc21973eeee4dda2b35e9 + url: "https://pub.dev" + source: hosted + version: "2.2.17" + path_provider_foundation: + dependency: transitive + description: + name: path_provider_foundation + sha256: "4843174df4d288f5e29185bd6e72a6fbdf5a4a4602717eed565497429f179942" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: "07c8f0b1913bcde1ff0d26e57ace2f3012ccbf2b204e070290dad3bb22797646" + url: "https://pub.dev" + source: hosted + version: "6.1.0" + platform: + dependency: transitive + description: + name: platform + sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" + url: "https://pub.dev" + source: hosted + version: "3.1.6" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" + shared_preferences: + dependency: "direct main" + description: + name: shared_preferences + sha256: "6e8bf70b7fef813df4e9a36f658ac46d107db4b4cfe1048b477d4e453a8159f5" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "20cbd561f743a342c76c151d6ddb93a9ce6005751e7aa458baad3858bfbfb6ac" + url: "https://pub.dev" + source: hosted + version: "2.4.10" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "6a52cfcdaeac77cad8c97b539ff688ccfc458c007b4db12be584fbe5c0e49e03" + url: "https://pub.dev" + source: hosted + version: "2.5.4" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 + url: "https://pub.dev" + source: hosted + version: "2.4.3" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + sky_engine: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" + source_span: + dependency: transitive + description: + name: source_span + sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c" + url: "https://pub.dev" + source: hosted + version: "1.10.1" + stack_trace: + dependency: transitive + description: + name: stack_trace + sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" + url: "https://pub.dev" + source: hosted + version: "1.12.1" + stream_channel: + dependency: transitive + description: + name: stream_channel + sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + string_scanner: + dependency: transitive + description: + name: string_scanner + sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" + url: "https://pub.dev" + source: hosted + version: "1.4.1" + term_glyph: + dependency: transitive + description: + name: term_glyph + sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" + url: "https://pub.dev" + source: hosted + version: "1.2.2" + test_api: + dependency: transitive + description: + name: test_api + sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd + url: "https://pub.dev" + source: hosted + version: "0.7.4" + typed_data: + dependency: transitive + description: + name: typed_data + sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 + url: "https://pub.dev" + source: hosted + version: "1.4.0" + url_launcher: + dependency: "direct main" + description: + name: url_launcher + sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 + url: "https://pub.dev" + source: hosted + version: "6.3.2" + url_launcher_android: + dependency: transitive + description: + name: url_launcher_android + sha256: "8582d7f6fe14d2652b4c45c9b6c14c0b678c2af2d083a11b604caeba51930d79" + url: "https://pub.dev" + source: hosted + version: "6.3.16" + url_launcher_ios: + dependency: transitive + description: + name: url_launcher_ios + sha256: "7f2022359d4c099eea7df3fdf739f7d3d3b9faf3166fb1dd390775176e0b76cb" + url: "https://pub.dev" + source: hosted + version: "6.3.3" + url_launcher_linux: + dependency: transitive + description: + name: url_launcher_linux + sha256: "4e9ba368772369e3e08f231d2301b4ef72b9ff87c31192ef471b380ef29a4935" + url: "https://pub.dev" + source: hosted + version: "3.2.1" + url_launcher_macos: + dependency: transitive + description: + name: url_launcher_macos + sha256: "17ba2000b847f334f16626a574c702b196723af2a289e7a93ffcb79acff855c2" + url: "https://pub.dev" + source: hosted + version: "3.2.2" + url_launcher_platform_interface: + dependency: transitive + description: + name: url_launcher_platform_interface + sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + url_launcher_web: + dependency: transitive + description: + name: url_launcher_web + sha256: "4bd2b7b4dc4d4d0b94e5babfffbca8eac1a126c7f3d6ecbc1a11013faa3abba2" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + url_launcher_windows: + dependency: transitive + description: + name: url_launcher_windows + sha256: "3284b6d2ac454cf34f114e1d3319866fdd1e19cdc329999057e44ffe936cfa77" + url: "https://pub.dev" + source: hosted + version: "3.1.4" + vector_math: + dependency: transitive + description: + name: vector_math + sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803" + url: "https://pub.dev" + source: hosted + version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02 + url: "https://pub.dev" + source: hosted + version: "15.0.0" + web: + dependency: transitive + description: + name: web + sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" + url: "https://pub.dev" + source: hosted + version: "1.1.1" + win32: + dependency: transitive + description: + name: win32 + sha256: "329edf97fdd893e0f1e3b9e88d6a0e627128cc17cc316a8d67fda8f1451178ba" + url: "https://pub.dev" + source: hosted + version: "5.13.0" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" +sdks: + dart: ">=3.7.0 <4.0.0" + flutter: ">=3.27.0" diff --git a/monitoring/pubspec.yaml b/monitoring/pubspec.yaml new file mode 100644 index 0000000..d446493 --- /dev/null +++ b/monitoring/pubspec.yaml @@ -0,0 +1,109 @@ +name: monitoring +description: "A new Flutter project." +# The following line prevents the package from being accidentally published to +# pub.dev using `flutter pub publish`. This is preferred for private packages. +publish_to: 'none' # Remove this line if you wish to publish to pub.dev + +# The following defines the version and build number for your application. +# A version number is three numbers separated by dots, like 1.2.43 +# followed by an optional build number separated by a +. +# Both the version and the builder number may be overridden in flutter +# build by specifying --build-name and --build-number, respectively. +# In Android, build-name is used as versionName while build-number used as versionCode. +# Read more about Android versioning at https://developer.android.com/studio/publish/versioning +# In iOS, build-name is used as CFBundleShortVersionString while build-number is used as CFBundleVersion. +# Read more about iOS versioning at +# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html +# In Windows, build-name is used as the major, minor, and patch parts +# of the product and file versions while build-number is used as the build suffix. +version: 1.0.0+1 + +environment: + sdk: ">=3.7.0 <4.0.0" + + +# Dependencies specify other packages that your package needs in order to work. +# To automatically upgrade your package dependencies to the latest versions +# consider running `flutter pub upgrade --major-versions`. Alternatively, +# dependencies can be manually updated by changing the version numbers below to +# the latest version available on pub.dev. To see which dependencies have newer +# versions available, run `flutter pub outdated`. +dependencies: + flutter: + sdk: flutter + cupertino_icons: ^1.0.2 + dio: ^5.4.0 + http: ^0.13.6 + http_parser: ^4.0.2 + fluttertoast: ^8.2.4 + image_picker: ^1.0.0 + collection: ^1.17.2 + + # The following adds the Cupertino Icons font to your application. + # Use with the CupertinoIcons class for iOS style icons. + shared_preferences: ^2.5.3 + carousel_slider: ^4.2.1 + lottie: ^2.7.0 + url_launcher: ^6.2.5 + font_awesome_flutter: ^10.6.0 + intl: ^0.18.1 + path_provider: ^2.0.12 + image: ^3.0.0 + file_picker: ^10.2.0 + +dev_dependencies: + flutter_test: + sdk: flutter + flutter_secure_storage: ^9.0.0 + + # The "flutter_lints" package below contains a set of recommended lints to + # encourage good coding practices. The lint set provided by the package is + # activated in the `analysis_options.yaml` file located at the root of your + # package. See that file for information about deactivating specific lint + # rules and activating additional ones. + flutter_lints: ^5.0.0 + +# For information on the generic Dart part of this file, see the +# following page: https://dart.dev/tools/pub/pubspec + +# The following section is specific to Flutter packages. +flutter: + assets: + - assets/ + # The following line ensures that the Material Icons font is + # included with your application, so that you can use the icons in + # the material Icons class. + uses-material-design: true + + # To add assets to your application, add an assets section, like this: + # assets: + # - images/a_dot_burr.jpeg + # - images/a_dot_ham.jpeg + + # An image asset can refer to one or more resolution-specific "variants", see + # https://flutter.dev/to/resolution-aware-images + + # For details regarding adding assets from package dependencies, see + # https://flutter.dev/to/asset-from-package + + # To add custom fonts to your application, add a fonts section here, + # in this "flutter" section. Each entry in this list should have a + # "family" key with the font family name, and a "fonts" key with a + # list giving the asset and other descriptors for the font. For + # example: + # fonts: + # - family: Schyler + # fonts: + # - asset: fonts/Schyler-Regular.ttf + # - asset: fonts/Schyler-Italic.ttf + # style: italic + # - family: Trajan Pro + # fonts: + # - asset: fonts/TrajanPro.ttf + # - asset: fonts/TrajanPro_Bold.ttf + # weight: 700 + # + # For details regarding fonts from package dependencies, + # see https://flutter.dev/to/font-from-package +Variable name: ANDROID_SDK_ROOT +Variable value: C:\Users\\AppData\Local\Android\Sdk diff --git a/monitoring/test/widget_test.dart b/monitoring/test/widget_test.dart new file mode 100644 index 0000000..9a384ea --- /dev/null +++ b/monitoring/test/widget_test.dart @@ -0,0 +1,29 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:monitoring/main.dart'; + +void main() { + testWidgets('Monitoring Santri App smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MonitoringSantriApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/monitoring/web/favicon.png b/monitoring/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/monitoring/web/favicon.png differ diff --git a/monitoring/web/icons/Icon-192.png b/monitoring/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/monitoring/web/icons/Icon-192.png differ diff --git a/monitoring/web/icons/Icon-512.png b/monitoring/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/monitoring/web/icons/Icon-512.png differ diff --git a/monitoring/web/icons/Icon-maskable-192.png b/monitoring/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/monitoring/web/icons/Icon-maskable-192.png differ diff --git a/monitoring/web/icons/Icon-maskable-512.png b/monitoring/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/monitoring/web/icons/Icon-maskable-512.png differ diff --git a/monitoring/web/index.html b/monitoring/web/index.html new file mode 100644 index 0000000..e6e0cf8 --- /dev/null +++ b/monitoring/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + monitoring + + + + + + diff --git a/monitoring/web/manifest.json b/monitoring/web/manifest.json new file mode 100644 index 0000000..8b1b984 --- /dev/null +++ b/monitoring/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "monitoring", + "short_name": "monitoring", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/monitoring/windows/.gitignore b/monitoring/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/monitoring/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/monitoring/windows/CMakeLists.txt b/monitoring/windows/CMakeLists.txt new file mode 100644 index 0000000..d3cd9f3 --- /dev/null +++ b/monitoring/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(monitoring LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "monitoring") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/monitoring/windows/flutter/CMakeLists.txt b/monitoring/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..903f489 --- /dev/null +++ b/monitoring/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/monitoring/windows/flutter/generated_plugin_registrant.cc b/monitoring/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..602b168 --- /dev/null +++ b/monitoring/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,20 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); + FlutterSecureStorageWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); +} diff --git a/monitoring/windows/flutter/generated_plugin_registrant.h b/monitoring/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/monitoring/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/monitoring/windows/flutter/generated_plugins.cmake b/monitoring/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..b918cf8 --- /dev/null +++ b/monitoring/windows/flutter/generated_plugins.cmake @@ -0,0 +1,26 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows + flutter_secure_storage_windows + url_launcher_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/monitoring/windows/runner/CMakeLists.txt b/monitoring/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..394917c --- /dev/null +++ b/monitoring/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/monitoring/windows/runner/Runner.rc b/monitoring/windows/runner/Runner.rc new file mode 100644 index 0000000..102e3b8 --- /dev/null +++ b/monitoring/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "monitoring" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "monitoring" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "monitoring.exe" "\0" + VALUE "ProductName", "monitoring" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/monitoring/windows/runner/flutter_window.cpp b/monitoring/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..955ee30 --- /dev/null +++ b/monitoring/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/monitoring/windows/runner/flutter_window.h b/monitoring/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/monitoring/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/monitoring/windows/runner/main.cpp b/monitoring/windows/runner/main.cpp new file mode 100644 index 0000000..62a1397 --- /dev/null +++ b/monitoring/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"monitoring", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/monitoring/windows/runner/resource.h b/monitoring/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/monitoring/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/monitoring/windows/runner/resources/app_icon.ico b/monitoring/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000..c04e20c Binary files /dev/null and b/monitoring/windows/runner/resources/app_icon.ico differ diff --git a/monitoring/windows/runner/runner.exe.manifest b/monitoring/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..153653e --- /dev/null +++ b/monitoring/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/monitoring/windows/runner/utils.cpp b/monitoring/windows/runner/utils.cpp new file mode 100644 index 0000000..3a0b465 --- /dev/null +++ b/monitoring/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/monitoring/windows/runner/utils.h b/monitoring/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/monitoring/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/monitoring/windows/runner/win32_window.cpp b/monitoring/windows/runner/win32_window.cpp new file mode 100644 index 0000000..60608d0 --- /dev/null +++ b/monitoring/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/monitoring/windows/runner/win32_window.h b/monitoring/windows/runner/win32_window.h new file mode 100644 index 0000000..e901dde --- /dev/null +++ b/monitoring/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_ diff --git a/website/.editorconfig b/website/.editorconfig new file mode 100644 index 0000000..8f0de65 --- /dev/null +++ b/website/.editorconfig @@ -0,0 +1,18 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 + +[docker-compose.yml] +indent_size = 4 diff --git a/website/.env.example b/website/.env.example new file mode 100644 index 0000000..35db1dd --- /dev/null +++ b/website/.env.example @@ -0,0 +1,65 @@ +APP_NAME=Laravel +APP_ENV=local +APP_KEY= +APP_DEBUG=true +APP_URL=http://localhost + +APP_LOCALE=en +APP_FALLBACK_LOCALE=en +APP_FAKER_LOCALE=en_US + +APP_MAINTENANCE_DRIVER=file +# APP_MAINTENANCE_STORE=database + +PHP_CLI_SERVER_WORKERS=4 + +BCRYPT_ROUNDS=12 + +LOG_CHANNEL=stack +LOG_STACK=single +LOG_DEPRECATIONS_CHANNEL=null +LOG_LEVEL=debug + +DB_CONNECTION=sqlite +# DB_HOST=127.0.0.1 +# DB_PORT=3306 +# DB_DATABASE=laravel +# DB_USERNAME=root +# DB_PASSWORD= + +SESSION_DRIVER=database +SESSION_LIFETIME=120 +SESSION_ENCRYPT=false +SESSION_PATH=/ +SESSION_DOMAIN=null + +BROADCAST_CONNECTION=log +FILESYSTEM_DISK=local +QUEUE_CONNECTION=database + +CACHE_STORE=database +# CACHE_PREFIX= + +MEMCACHED_HOST=127.0.0.1 + +REDIS_CLIENT=phpredis +REDIS_HOST=127.0.0.1 +REDIS_PASSWORD=null +REDIS_PORT=6379 + +MAIL_MAILER=log +MAIL_SCHEME=null +MAIL_HOST=127.0.0.1 +MAIL_PORT=2525 +MAIL_USERNAME=null +MAIL_PASSWORD=null +MAIL_FROM_ADDRESS="hello@example.com" +MAIL_FROM_NAME="${APP_NAME}" + +AWS_ACCESS_KEY_ID= +AWS_SECRET_ACCESS_KEY= +AWS_DEFAULT_REGION=us-east-1 +AWS_BUCKET= +AWS_USE_PATH_STYLE_ENDPOINT=false + +VITE_APP_NAME="${APP_NAME}" diff --git a/website/.gitattributes b/website/.gitattributes new file mode 100644 index 0000000..fcb21d3 --- /dev/null +++ b/website/.gitattributes @@ -0,0 +1,11 @@ +* text=auto eol=lf + +*.blade.php diff=html +*.css diff=css +*.html diff=html +*.md diff=markdown +*.php diff=php + +/.github export-ignore +CHANGELOG.md export-ignore +.styleci.yml export-ignore diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 0000000..462db28 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,72 @@ +<<<<<<< HEAD +# Miscellaneous +*.class +*.log +*.pyc +*.swp +.DS_Store +.atom/ +.build/ +.buildlog/ +.history +.svn/ +.swiftpm/ +migrate_working_dir/ + +# IntelliJ related +*.iml +*.ipr +*.iws +.idea/ + +# The .vscode folder contains launch configuration and tasks you configure in +# VS Code which you may wish to be included in version control, so this line +# is commented out by default. +#.vscode/ + +# Flutter/Dart/Pub related +**/doc/api/ +**/ios/Flutter/.last_build_id +.dart_tool/ +.flutter-plugins +.flutter-plugins-dependencies +.pub-cache/ +.pub/ +/build/ + +# Symbolication related +app.*.symbols + +# Obfuscation related +app.*.map.json + +# Android Studio will place build artifacts here +/android/app/debug +/android/app/profile +/android/app/release +======= +*.log +.DS_Store +.env +.env.backup +.env.production +.phpactor.json +.phpunit.result.cache +/.fleet +/.idea +/.nova +/.phpunit.cache +/.vscode +/.zed +/auth.json +/node_modules +/public/build +/public/hot +/public/storage +/storage/*.key +/storage/pail +/vendor +Homestead.json +Homestead.yaml +Thumbs.db +>>>>>>> 8cb5aba (upload web) diff --git a/website/.metadata b/website/.metadata new file mode 100644 index 0000000..fdb4416 --- /dev/null +++ b/website/.metadata @@ -0,0 +1,45 @@ +# This file tracks properties of this Flutter project. +# Used by Flutter tool to assess capabilities and perform upgrades etc. +# +# This file should be version controlled and should not be manually edited. + +version: + revision: "fcf2c11572af6f390246c056bc905eca609533a0" + channel: "stable" + +project_type: app + +# Tracks metadata for the flutter migrate command +migration: + platforms: + - platform: root + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: android + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: ios + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: linux + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: macos + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: web + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + - platform: windows + create_revision: fcf2c11572af6f390246c056bc905eca609533a0 + base_revision: fcf2c11572af6f390246c056bc905eca609533a0 + + # User provided section + + # List of Local paths (relative to this file) that should be + # ignored by the migrate tool. + # + # Files that are not part of the templates will be ignored by default. + unmanaged_files: + - 'lib/main.dart' + - 'ios/Runner.xcodeproj/project.pbxproj' diff --git a/website/README.md b/website/README.md new file mode 100644 index 0000000..1826fa3 --- /dev/null +++ b/website/README.md @@ -0,0 +1,80 @@ +<<<<<<< HEAD +# monitoring + +A new Flutter project. + +## Getting Started + +This project is a starting point for a Flutter application. + +A few resources to get you started if this is your first Flutter project: + +- [Lab: Write your first Flutter app](https://docs.flutter.dev/get-started/codelab) +- [Cookbook: Useful Flutter samples](https://docs.flutter.dev/cookbook) + +For help getting started with Flutter development, view the +[online documentation](https://docs.flutter.dev/), which offers tutorials, +samples, guidance on mobile development, and a full API reference. +======= +

Laravel Logo

+ +

+Build Status +Total Downloads +Latest Stable Version +License +

+ +## About Laravel + +Laravel is a web application framework with expressive, elegant syntax. We believe development must be an enjoyable and creative experience to be truly fulfilling. Laravel takes the pain out of development by easing common tasks used in many web projects, such as: + +- [Simple, fast routing engine](https://laravel.com/docs/routing). +- [Powerful dependency injection container](https://laravel.com/docs/container). +- Multiple back-ends for [session](https://laravel.com/docs/session) and [cache](https://laravel.com/docs/cache) storage. +- Expressive, intuitive [database ORM](https://laravel.com/docs/eloquent). +- Database agnostic [schema migrations](https://laravel.com/docs/migrations). +- [Robust background job processing](https://laravel.com/docs/queues). +- [Real-time event broadcasting](https://laravel.com/docs/broadcasting). + +Laravel is accessible, powerful, and provides tools required for large, robust applications. + +## Learning Laravel + +Laravel has the most extensive and thorough [documentation](https://laravel.com/docs) and video tutorial library of all modern web application frameworks, making it a breeze to get started with the framework. + +You may also try the [Laravel Bootcamp](https://bootcamp.laravel.com), where you will be guided through building a modern Laravel application from scratch. + +If you don't feel like reading, [Laracasts](https://laracasts.com) can help. Laracasts contains thousands of video tutorials on a range of topics including Laravel, modern PHP, unit testing, and JavaScript. Boost your skills by digging into our comprehensive video library. + +## Laravel Sponsors + +We would like to extend our thanks to the following sponsors for funding Laravel development. If you are interested in becoming a sponsor, please visit the [Laravel Partners program](https://partners.laravel.com). + +### Premium Partners + +- **[Vehikl](https://vehikl.com)** +- **[Tighten Co.](https://tighten.co)** +- **[Kirschbaum Development Group](https://kirschbaumdevelopment.com)** +- **[64 Robots](https://64robots.com)** +- **[Curotec](https://www.curotec.com/services/technologies/laravel)** +- **[DevSquad](https://devsquad.com/hire-laravel-developers)** +- **[Redberry](https://redberry.international/laravel-development)** +- **[Active Logic](https://activelogic.com)** + +## Contributing + +Thank you for considering contributing to the Laravel framework! The contribution guide can be found in the [Laravel documentation](https://laravel.com/docs/contributions). + +## Code of Conduct + +In order to ensure that the Laravel community is welcoming to all, please review and abide by the [Code of Conduct](https://laravel.com/docs/contributions#code-of-conduct). + +## Security Vulnerabilities + +If you discover a security vulnerability within Laravel, please send an e-mail to Taylor Otwell via [taylor@laravel.com](mailto:taylor@laravel.com). All security vulnerabilities will be promptly addressed. + +## License + +The Laravel framework is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT). +>>>>>>> 8cb5aba (upload web) diff --git a/website/analysis_options.yaml b/website/analysis_options.yaml new file mode 100644 index 0000000..0d29021 --- /dev/null +++ b/website/analysis_options.yaml @@ -0,0 +1,28 @@ +# This file configures the analyzer, which statically analyzes Dart code to +# check for errors, warnings, and lints. +# +# The issues identified by the analyzer are surfaced in the UI of Dart-enabled +# IDEs (https://dart.dev/tools#ides-and-editors). The analyzer can also be +# invoked from the command line by running `flutter analyze`. + +# The following line activates a set of recommended lints for Flutter apps, +# packages, and plugins designed to encourage good coding practices. +include: package:flutter_lints/flutter.yaml + +linter: + # The lint rules applied to this project can be customized in the + # section below to disable rules from the `package:flutter_lints/flutter.yaml` + # included above or to enable additional rules. A list of all available lints + # and their documentation is published at https://dart.dev/lints. + # + # Instead of disabling a lint rule for the entire project in the + # section below, it can also be suppressed for a single line of code + # or a specific dart file by using the `// ignore: name_of_lint` and + # `// ignore_for_file: name_of_lint` syntax on the line or in the file + # producing the lint. + rules: + # avoid_print: false # Uncomment to disable the `avoid_print` rule + # prefer_single_quotes: true # Uncomment to enable the `prefer_single_quotes` rule + +# Additional information about this file can be found at +# https://dart.dev/guides/language/analysis-options diff --git a/website/android/.gitignore b/website/android/.gitignore new file mode 100644 index 0000000..be3943c --- /dev/null +++ b/website/android/.gitignore @@ -0,0 +1,14 @@ +gradle-wrapper.jar +/.gradle +/captures/ +/gradlew +/gradlew.bat +/local.properties +GeneratedPluginRegistrant.java +.cxx/ + +# Remember to never publicly share your keystore. +# See https://flutter.dev/to/reference-keystore +key.properties +**/*.keystore +**/*.jks diff --git a/website/android/app/build.gradle.kts b/website/android/app/build.gradle.kts new file mode 100644 index 0000000..a9a14b5 --- /dev/null +++ b/website/android/app/build.gradle.kts @@ -0,0 +1,43 @@ +plugins { + id("com.android.application") + id("kotlin-android") + // The Flutter Gradle Plugin must be applied after the Android and Kotlin Gradle plugins. + id("dev.flutter.flutter-gradle-plugin") +} + +android { + namespace = "com.example.monitoring" + compileSdk = flutter.compileSdkVersion + + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + + kotlinOptions { + jvmTarget = JavaVersion.VERSION_11.toString() + } + + defaultConfig { + // TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html). + applicationId = "com.example.monitoring" + // You can update the following values to match your application needs. + // For more information, see: https://flutter.dev/to/review-gradle-config. + minSdk = flutter.minSdkVersion + targetSdk = flutter.targetSdkVersion + versionCode = flutter.versionCode + versionName = flutter.versionName + } + + buildTypes { + release { + // TODO: Add your own signing config for the release build. + // Signing with the debug keys for now, so `flutter run --release` works. + signingConfig = signingConfigs.getByName("debug") + } + } +} + +flutter { + source = "../.." +} diff --git a/website/android/app/src/debug/AndroidManifest.xml b/website/android/app/src/debug/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/website/android/app/src/debug/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/website/android/app/src/main/AndroidManifest.xml b/website/android/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..eb5c3ec --- /dev/null +++ b/website/android/app/src/main/AndroidManifest.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/website/android/app/src/main/kotlin/com/example/monitoring/MainActivity.kt b/website/android/app/src/main/kotlin/com/example/monitoring/MainActivity.kt new file mode 100644 index 0000000..c1c1d2e --- /dev/null +++ b/website/android/app/src/main/kotlin/com/example/monitoring/MainActivity.kt @@ -0,0 +1,5 @@ +package com.example.monitoring + +import io.flutter.embedding.android.FlutterActivity + +class MainActivity : FlutterActivity() diff --git a/website/android/app/src/main/res/drawable-v21/launch_background.xml b/website/android/app/src/main/res/drawable-v21/launch_background.xml new file mode 100644 index 0000000..f74085f --- /dev/null +++ b/website/android/app/src/main/res/drawable-v21/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/website/android/app/src/main/res/drawable/launch_background.xml b/website/android/app/src/main/res/drawable/launch_background.xml new file mode 100644 index 0000000..304732f --- /dev/null +++ b/website/android/app/src/main/res/drawable/launch_background.xml @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/website/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/website/android/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..db77bb4 Binary files /dev/null and b/website/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/website/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/website/android/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..17987b7 Binary files /dev/null and b/website/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/website/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/website/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..09d4391 Binary files /dev/null and b/website/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/website/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/website/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..d5f1c8d Binary files /dev/null and b/website/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/website/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/website/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..4d6372e Binary files /dev/null and b/website/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/website/android/app/src/main/res/values-night/styles.xml b/website/android/app/src/main/res/values-night/styles.xml new file mode 100644 index 0000000..06952be --- /dev/null +++ b/website/android/app/src/main/res/values-night/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/website/android/app/src/main/res/values/styles.xml b/website/android/app/src/main/res/values/styles.xml new file mode 100644 index 0000000..cb1ef88 --- /dev/null +++ b/website/android/app/src/main/res/values/styles.xml @@ -0,0 +1,18 @@ + + + + + + + diff --git a/website/android/app/src/profile/AndroidManifest.xml b/website/android/app/src/profile/AndroidManifest.xml new file mode 100644 index 0000000..399f698 --- /dev/null +++ b/website/android/app/src/profile/AndroidManifest.xml @@ -0,0 +1,7 @@ + + + + diff --git a/website/android/build.gradle.kts b/website/android/build.gradle.kts new file mode 100644 index 0000000..46cc7e1 --- /dev/null +++ b/website/android/build.gradle.kts @@ -0,0 +1,18 @@ +allprojects { + repositories { + google() + mavenCentral() + } +} + +val newBuildDir: Directory = rootProject.layout.buildDirectory.dir("../../build").get() +rootProject.layout.buildDirectory.value(newBuildDir) + +subprojects { + val newSubprojectBuildDir: Directory = newBuildDir.dir(project.name) + project.layout.buildDirectory.value(newSubprojectBuildDir) +} + +tasks.register("clean") { + delete(rootProject.layout.buildDirectory) +} diff --git a/website/android/gradle.properties b/website/android/gradle.properties new file mode 100644 index 0000000..f018a61 --- /dev/null +++ b/website/android/gradle.properties @@ -0,0 +1,3 @@ +org.gradle.jvmargs=-Xmx8G -XX:MaxMetaspaceSize=4G -XX:ReservedCodeCacheSize=512m -XX:+HeapDumpOnOutOfMemoryError +android.useAndroidX=true +android.enableJetifier=true diff --git a/website/android/gradle/wrapper/gradle-wrapper.properties b/website/android/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..ac3b479 --- /dev/null +++ b/website/android/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip diff --git a/website/android/settings.gradle.kts b/website/android/settings.gradle.kts new file mode 100644 index 0000000..ab39a10 --- /dev/null +++ b/website/android/settings.gradle.kts @@ -0,0 +1,25 @@ +pluginManagement { + val flutterSdkPath = run { + val properties = java.util.Properties() + file("local.properties").inputStream().use { properties.load(it) } + val flutterSdkPath = properties.getProperty("flutter.sdk") + require(flutterSdkPath != null) { "flutter.sdk not set in local.properties" } + flutterSdkPath + } + + includeBuild("$flutterSdkPath/packages/flutter_tools/gradle") + + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +plugins { + id("dev.flutter.flutter-plugin-loader") version "1.0.0" + id("com.android.application") version "8.7.3" apply false + id("org.jetbrains.kotlin.android") version "2.1.0" apply false +} + +include(":app") diff --git a/website/app/Http/Controllers/AbsensiController.php b/website/app/Http/Controllers/AbsensiController.php new file mode 100644 index 0000000..68a51c6 --- /dev/null +++ b/website/app/Http/Controllers/AbsensiController.php @@ -0,0 +1,149 @@ +get('kelas_id'); + $tanggal = $request->get('tanggal', date('Y-m-d')); + $santris = collect(); + $absensis = collect(); + if ($kelasId) { + $santris = Santri::where('kelas_id', $kelasId)->get(); + $absensis = Absensi::where('kelas_id', $kelasId)->where('tanggal', $tanggal)->get()->keyBy('santri_id'); + } + $view = auth()->user()->isGuru() ? 'guru.absensis.index' : 'absensis.index'; + return view($view, compact('kelasList', 'kelasId', 'tanggal', 'santris', 'absensis')); + } + + /** + * Show the form for creating a new resource. + */ + public function create(Request $request) + { + $kelasId = $request->get('kelas_id'); + $tanggal = $request->get('tanggal', date('Y-m-d')); + $kelas = Kelas::all(); + $santris = collect(); + if ($kelasId) { + $santris = Santri::where('kelas_id', $kelasId)->get(); + } + $view = auth()->user()->isGuru() ? 'guru.absensis.create' : 'absensis.create'; + return view($view, compact('kelas', 'santris', 'tanggal', 'kelasId')); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + $request->validate([ + 'kelas_id' => 'required|exists:kelas,id', + 'tanggal' => 'required|date', + 'absensi' => 'required|array', + 'absensi.*.santri_id' => 'required|exists:santris,id', + 'absensi.*.status' => 'required|in:hadir,izin,sakit,alfa', + 'absensi.*.keterangan' => 'nullable|string', + ]); + foreach ($request->absensi as $absen) { + \App\Models\Absensi::updateOrCreate( + [ + 'santri_id' => $absen['santri_id'], + 'kelas_id' => $request->kelas_id, + 'tanggal' => $request->tanggal, + ], + [ + 'status' => $absen['status'], + 'keterangan' => $absen['keterangan'] ?? null, + ] + ); + } + $route = auth()->user()->isGuru() ? 'guru.absensis.index' : 'absensis.index'; + return redirect()->route($route, ['kelas_id' => $request->kelas_id, 'tanggal' => $request->tanggal]) + ->with('success', 'Absensi berhasil disimpan'); + } + + /** + * Display the specified resource. + */ + public function show($santri_id) + { + $santri = \App\Models\Santri::findOrFail($santri_id); + $absensis = \App\Models\Absensi::where('santri_id', $santri_id)->orderBy('tanggal', 'desc')->get(); + $view = auth()->user()->isGuru() ? 'guru.absensis.show' : 'absensis.show'; + return view($view, compact('santri', 'absensis')); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Absensi $absensi) + { + $kelas = Kelas::all(); + $santri = $absensi->santri; + $view = auth()->user()->isGuru() ? 'guru.absensis.edit' : 'absensis.edit'; + return view($view, compact('absensi', 'kelas', 'santri')); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, Absensi $absensi) + { + $request->validate([ + 'status' => 'required|in:hadir,izin,sakit,alfa', + 'keterangan' => 'nullable|string', + ]); + $absensi->update([ + 'status' => $request->status, + 'keterangan' => $request->keterangan, + ]); + $route = auth()->user()->isGuru() ? 'guru.absensis.index' : 'absensis.index'; + return redirect()->route($route, [ + 'kelas_id' => $absensi->kelas_id, + 'tanggal' => $absensi->tanggal + ])->with('success', 'Absensi berhasil diupdate'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Absensi $absensi) + { + $kelas_id = $absensi->kelas_id; + $tanggal = $absensi->tanggal; + $absensi->delete(); + $route = auth()->user()->isGuru() ? 'guru.absensis.index' : 'absensis.index'; + return redirect()->route($route, [ + 'kelas_id' => $kelas_id, + 'tanggal' => $tanggal + ])->with('success', 'Absensi berhasil dihapus'); + } +} + +namespace App\Http\Controllers\API; + +use App\Http\Controllers\Controller; +use App\Models\Absensi; +use Illuminate\Http\Request; + +class AbsensiApiController extends Controller +{ + public function index(Request $request) + { + $user = $request->user(); + $absensi = Absensi::where('user_id', $user->id)->get(); + return response()->json($absensi); + } +} diff --git a/website/app/Http/Controllers/AlumniController.php b/website/app/Http/Controllers/AlumniController.php new file mode 100644 index 0000000..d2346cc --- /dev/null +++ b/website/app/Http/Controllers/AlumniController.php @@ -0,0 +1,100 @@ +latest()->paginate(10); + return view('alumnis.index', compact('alumnis')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + return view('alumnis.create'); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + $validated = $request->validate([ + 'nama_santri' => 'required|string|max:255', + 'tahun_lulus' => 'required|integer|min:2000|max:' . date('Y'), + 'aktivitas_setelah_lulus' => 'required|string', + 'kontak' => 'nullable|string', + 'keterangan' => 'nullable|string', + ]); + \App\Models\Alumni::create($validated); + return redirect()->route('alumnis.index')->with('success', 'Data alumni berhasil ditambahkan.'); + } + + /** + * Display the specified resource. + */ + public function show(Alumni $alumni) + { + $alumni->load('santri'); + return view('alumnis.show', compact('alumni')); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Alumni $alumni) + { + return view('alumnis.edit', compact('alumni')); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, Alumni $alumni) + { + $validated = $request->validate([ + 'nama_santri' => 'required|string|max:255', + 'tahun_lulus' => 'required|integer|min:2000|max:' . date('Y'), + 'aktivitas_setelah_lulus' => 'required|string', + 'kontak' => 'nullable|string', + 'keterangan' => 'nullable|string', + ]); + $alumni->update($validated); + return redirect()->route('alumnis.index')->with('success', 'Data alumni berhasil diupdate.'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Alumni $alumni) + { + $alumni->delete(); + return redirect()->route('alumnis.index')->with('success', 'Data alumni berhasil dihapus.'); + } +} + +namespace App\Http\Controllers\API; + +use App\Http\Controllers\Controller; +use App\Models\Alumni; +use Illuminate\Http\Request; + +class AlumniApiController extends Controller +{ + public function index(Request $request) + { + $alumni = Alumni::latest()->get(); + return response()->json($alumni); + } +} diff --git a/website/app/Http/Controllers/Api/AbsensiController.php b/website/app/Http/Controllers/Api/AbsensiController.php new file mode 100644 index 0000000..859b27b --- /dev/null +++ b/website/app/Http/Controllers/Api/AbsensiController.php @@ -0,0 +1,46 @@ +user(); + $santri = $user->santri; + + if (!$santri) { + return response()->json([ + 'success' => false, + 'message' => 'Santri tidak ditemukan untuk user ini', + 'data' => [], + ], 404); + } + + $absensi = Absensi::where('santri_id', $santri->id) + ->orderBy('tanggal', 'desc') + ->get() + ->map(function ($item) { + return [ + 'id' => $item->id, + 'santri_id' => $item->santri_id, + 'kelas_id' => $item->kelas_id, + 'tanggal' => $item->tanggal, + 'status' => $item->status, + 'keterangan' => $item->keterangan, + 'created_at' => $item->created_at, + 'updated_at' => $item->updated_at, + ]; + }); + + return response()->json([ + 'success' => true, + 'message' => 'Data absensi berhasil diambil', + 'data' => $absensi, + ]); + } +} diff --git a/website/app/Http/Controllers/Api/AlumniController.php b/website/app/Http/Controllers/Api/AlumniController.php new file mode 100644 index 0000000..eec9b59 --- /dev/null +++ b/website/app/Http/Controllers/Api/AlumniController.php @@ -0,0 +1,28 @@ +get(); + + $data = $alumnis->map(function ($alumni) { + return [ + 'id' => $alumni->id, + 'nama' => $alumni->nama_santri, + 'angkatan' => $alumni->tahun_lulus, + 'aktivitas_setelah_lulus' => $alumni->aktivitas_setelah_lulus, + 'kontak' => $alumni->kontak, + 'keterangan' => $alumni->keterangan, + ]; + }); + + return response()->json(['data' => $data]); + } +} \ No newline at end of file diff --git a/website/app/Http/Controllers/Api/AuthController.php b/website/app/Http/Controllers/Api/AuthController.php new file mode 100644 index 0000000..0b024a4 --- /dev/null +++ b/website/app/Http/Controllers/Api/AuthController.php @@ -0,0 +1,69 @@ +validate([ + 'username' => 'required|string', + 'password' => 'required|string' + ]); + + $user = User::where('username', $request->username) + ->where('role', 'santri') + ->first(); + + if (!$user || !Hash::check($request->password, $user->password)) { + return response()->json([ + 'message' => 'Username atau password salah, atau bukan akun santri' + ], 401); + } + + $token = $user->createToken('auth_token')->plainTextToken; + + $userArray = $user->toArray(); + $userArray['token'] = $token; + + return response()->json([ + 'message' => 'Login berhasil', + 'access_token' => $token, + 'token_type' => 'Bearer', + 'user' => $userArray + ]); + } + + public function logout(Request $request) + { + $request->user()->currentAccessToken()->delete(); + + return response()->json(['message' => 'Logout berhasil']); + } + + public function me(Request $request) + { + return response()->json($request->user()); + } + + public function resetPassword(Request $request) + { + $request->validate([ + 'username' => 'required|exists:users,username', + 'password' => 'required|min:6|confirmed', + ]); + + $user = User::where('username', $request->username)->first(); + $user->password = Hash::make($request->password); + $user->save(); + + return response()->json(['message' => 'Password berhasil direset.']); + } + +} diff --git a/website/app/Http/Controllers/Api/BeritaController.php b/website/app/Http/Controllers/Api/BeritaController.php new file mode 100644 index 0000000..1ed8379 --- /dev/null +++ b/website/app/Http/Controllers/Api/BeritaController.php @@ -0,0 +1,53 @@ +latest()->get(); + + return response()->json([ + 'success' => true, + 'message' => 'Daftar berita', + 'data' => $beritas->map(fn($item) => $this->transform($item)), + ]); + } + + public function show($id) + { + $berita = Berita::find($id); + + if (!$berita || $berita->status !== 'published') { + return response()->json([ + 'success' => false, + 'message' => 'Berita tidak ditemukan', + ], 404); + } + + return response()->json([ + 'success' => true, + 'message' => 'Detail berita', + 'data' => $this->transform($berita), + ]); + } + + private function transform(Berita $berita) + { + return [ + 'id' => $berita->id, + 'judul' => $berita->judul, + 'kategori' => $berita->kategori, + 'ringkasan' => $berita->ringkasan, + 'isi' => $berita->isi, + 'penulis' => $berita->penulis, + 'gambar_url' => $berita->gambar ? asset('storage/' . $berita->gambar) : null, + 'created_at' => $berita->created_at->toDateTimeString(), + ]; + } +} diff --git a/website/app/Http/Controllers/Api/CatatanKesehatanController.php b/website/app/Http/Controllers/Api/CatatanKesehatanController.php new file mode 100644 index 0000000..bd23e9c --- /dev/null +++ b/website/app/Http/Controllers/Api/CatatanKesehatanController.php @@ -0,0 +1,74 @@ +user(); + $santri = $user->santri; + + if (!$santri) { + return response()->json([ + 'success' => false, + 'message' => 'Data santri tidak ditemukan', + 'data' => [], + ], 404); + } + + $catatan = CatatanKesehatan::with(['santri', 'kelas']) + ->where('santri_id', $santri->id) + ->orderBy('created_at', 'desc') + ->get() + ->map(function ($item) { + return [ + 'id' => $item->id, + 'santri_id' => $item->santri_id, + 'santri_nama' => $item->santri->nama ?? '-', + 'kelas_id' => $item->kelas_id, + 'kelas_nama' => $item->kelas->nama_kelas ?? '-', + 'keluhan' => $item->keluhan, + 'diagnosis' => $item->diagnosis, + 'saran' => $item->saran, + 'created_at' => $item->created_at, + 'updated_at' => $item->updated_at, + ]; + }); + + return response()->json([ + 'success' => true, + 'message' => 'Data catatan kesehatan berhasil diambil', + 'data' => $catatan, + ]); + } + + public function notifikasi(Request $request) + { + $user = $request->user(); + $santri = $user->santri; + + if (!$santri) { + return response()->json([ + 'success' => false, + 'message' => 'Santri tidak ditemukan', + 'data' => [], + ]); + } + + $notifikasi = CatatanKesehatan::with(['santri', 'kelas']) + ->where('santri_id', $santri->id) + ->whereNotNull('keluhan') + ->get(); + + return response()->json([ + 'success' => true, + 'message' => 'Notifikasi kesehatan ditemukan', + 'data' => $notifikasi, + ]); + } +} diff --git a/website/app/Http/Controllers/Api/FcmTokenController.php b/website/app/Http/Controllers/Api/FcmTokenController.php new file mode 100644 index 0000000..967e95e --- /dev/null +++ b/website/app/Http/Controllers/Api/FcmTokenController.php @@ -0,0 +1,30 @@ +validate([ + 'token' => 'required|string', + ]); + $user = Auth::user(); + if (!$user) { + return response()->json(['message' => 'Unauthorized'], 401); + } + // Simpan atau update token + $fcmToken = FcmToken::updateOrCreate( + [ + 'user_id' => $user->id, + 'token' => $request->token, + ], + [] + ); + return response()->json(['success' => true]); + } +} \ No newline at end of file diff --git a/website/app/Http/Controllers/Api/ForgotPasswordController.php b/website/app/Http/Controllers/Api/ForgotPasswordController.php new file mode 100644 index 0000000..9680d52 --- /dev/null +++ b/website/app/Http/Controllers/Api/ForgotPasswordController.php @@ -0,0 +1,41 @@ +validate([ + 'nis' => 'required|exists:santris,nis' + ]); + + return response()->json(['message' => 'NIS valid']); + } + + public function resetPassword(Request $request) + { + $request->validate([ + 'nis' => 'required|exists:santris,nis', + 'new_password' => 'required|min:6', + 'confirm_password' => 'required|same:new_password' + ]); + + $santri = Santri::where('nis', $request->nis)->first(); + + if (!$santri || !$santri->user) { + return response()->json(['message' => 'User tidak ditemukan'], 404); + } + + $santri->user->update([ + 'password' => Hash::make($request->new_password) + ]); + + return response()->json(['message' => 'Password berhasil direset']); + } +} diff --git a/website/app/Http/Controllers/Api/KelasController.php b/website/app/Http/Controllers/Api/KelasController.php new file mode 100644 index 0000000..8645c8d --- /dev/null +++ b/website/app/Http/Controllers/Api/KelasController.php @@ -0,0 +1,27 @@ +json($kelas); + } + + // GET /api/kelas/{id} + public function show($id) + { + $kelas = Kelas::find($id); + if (!$kelas) { + return response()->json(['message' => 'Kelas tidak ditemukan'], 404); + } + return response()->json($kelas); + } +} \ No newline at end of file diff --git a/website/app/Http/Controllers/Api/NilaiSantriController.php b/website/app/Http/Controllers/Api/NilaiSantriController.php new file mode 100644 index 0000000..b4ebb26 --- /dev/null +++ b/website/app/Http/Controllers/Api/NilaiSantriController.php @@ -0,0 +1,54 @@ +user(); + $santri = $user->santri; + + if (!$santri) { + return response()->json([ + 'success' => false, + 'message' => 'Data santri tidak ditemukan', + 'data' => [] + ]); + } + + $nilai = NilaiSantri::with(['mapel', 'semester']) // eager load relasi + ->where('santri_id', $santri->id) + ->orderBy('mapel_id') + ->orderByDesc('tanggal') + ->get() + ->map(function ($item) { + return [ + 'id' => $item->id, + 'santri_id' => $item->santri_id, + 'kelas_id' => $item->kelas_id, + 'mapel_id' => $item->mapel_id, + 'mapel' => $item->mapel->nama_mapel ?? '-', + 'semester_id' => $item->semester_id, + 'semester' => $item->semester->semester . ' - ' . $item->semester->tahun_ajaran, + 'tanggal' => $item->tanggal, + 'jenis_nilai' => $item->jenis_nilai, + 'nilai' => $item->nilai, + 'keterangan' => $item->keterangan, + 'created_at' => $item->created_at, + 'updated_at' => $item->updated_at, + ]; + }); + + return response()->json([ + 'success' => true, + 'message' => 'Data nilai berhasil diambil', + 'data' => $nilai + ]); + } +} \ No newline at end of file diff --git a/website/app/Http/Controllers/Api/PelanggaranController.php b/website/app/Http/Controllers/Api/PelanggaranController.php new file mode 100644 index 0000000..08970a6 --- /dev/null +++ b/website/app/Http/Controllers/Api/PelanggaranController.php @@ -0,0 +1,50 @@ +user(); + + // Jika user adalah guru, batasi data berdasarkan user_id + $query = Pelanggaran::with(['santri', 'kelas', 'user'])->orderByDesc('created_at'); + + if ($user->role === 'guru') { + $query->where('user_id', $user->id); + } + // Jika user adalah santri, batasi data berdasarkan santri_id + elseif ($user->santri) { + $query->where('santri_id', $user->santri->id); + } + + $pelanggarans = $query->get()->map(function ($item) { + return [ + 'id' => $item->id, + 'santri_id' => $item->santri_id, + 'nama_santri' => $item->santri->nama ?? null, + 'kelas_id' => $item->kelas_id, + 'nama_kelas' => $item->kelas->nama_kelas ?? null, + 'jenis_pelanggaran' => $item->jenis_pelanggaran, + 'hukuman' => $item->hukuman, + 'keterangan_hukuman' => $item->keterangan_hukuman, + 'hukuman_selesai' => $item->hukuman_selesai, + 'user_id' => $item->user_id, + 'nama_penginput' => $item->user->name ?? null, + 'created_at' => $item->created_at->toDateTimeString(), + 'updated_at' => $item->updated_at->toDateTimeString(), + ]; + }); + + return response()->json([ + 'success' => true, + 'message' => 'Data pelanggaran berhasil diambil.', + 'data' => $pelanggarans, + ]); + } +} diff --git a/website/app/Http/Controllers/Api/PembayaranController.php b/website/app/Http/Controllers/Api/PembayaranController.php new file mode 100644 index 0000000..43cb989 --- /dev/null +++ b/website/app/Http/Controllers/Api/PembayaranController.php @@ -0,0 +1,78 @@ +user()->id; + + $pembayaran = Pembayaran::where('santri_id', $santriId) + ->with('santri') + ->latest('tanggal') + ->get() + ->map(function ($item) { + return [ + 'id' => $item->id, + 'santri_id' => $item->santri_id, + 'kelas_id' => $item->kelas_id, + 'tanggal' => $item->tanggal, + 'jumlah' => $item->jumlah, + 'jenis_pembayaran' => $item->jenis_pembayaran, + 'keterangan' => $item->keterangan, + 'bukti_pembayaran' => $item->bukti_pembayaran ? asset('storage/' . $item->bukti_pembayaran) : null, + 'status' => $item->status, + 'created_at' => $item->created_at, + 'updated_at' => $item->updated_at, + 'santri_name' => $item->santri->name ?? null, + ]; + }); + + return response()->json($pembayaran); + } + + // ✅ POST: /api/pembayaran + public function store(Request $request) + { + $request->validate([ + 'tanggal' => 'required|date', + 'jenis_pembayaran' => 'required|string', + 'jumlah' => 'required|numeric', + 'keterangan' => 'nullable|string', + 'bukti_pembayaran' => 'required|image|mimes:jpg,jpeg,png|max:2048', + ]); + + $pembayaran = new Pembayaran(); + $pembayaran->santri_id = $request->user()->id; + + // Ambil kelas_id dari relasi user → santri → kelas + $pembayaran->kelas_id = $request->user()->santri->kelas_id ?? null; + + $pembayaran->tanggal = $request->tanggal; + $pembayaran->jenis_pembayaran = $request->jenis_pembayaran; + $pembayaran->jumlah = $request->jumlah; + $pembayaran->keterangan = $request->keterangan; + $pembayaran->status = 'menunggu'; + + if ($request->hasFile('bukti_pembayaran')) { + $file = $request->file('bukti_pembayaran'); + $path = $file->store('bukti_pembayaran', 'public'); + $pembayaran->bukti_pembayaran = $path; + } + + $pembayaran->save(); + + return response()->json([ + 'success' => true, + 'message' => 'Pembayaran berhasil dikirim', + 'data' => $pembayaran + ], 201); + } +} diff --git a/website/app/Http/Controllers/Api/PrestasiController.php b/website/app/Http/Controllers/Api/PrestasiController.php new file mode 100644 index 0000000..5ef0eb8 --- /dev/null +++ b/website/app/Http/Controllers/Api/PrestasiController.php @@ -0,0 +1,52 @@ +user(); + + $prestasis = Prestasi::with(['santri', 'kelas']) + ->where('user_id', $user->id) + ->latest() + ->get(); + + return response()->json([ + 'status' => true, + 'message' => 'Data prestasi berhasil diambil', + 'authenticated_user_id' => $user->id, + 'user_prestasi_count' => $prestasis->count(), + 'data' => $prestasis->map(function ($item) { + return [ + 'id' => $item->id, + 'user_id' => $item->user_id, + 'santri_id' => $item->santri_id, + 'kelas_id' => $item->kelas_id, + 'nama_prestasi' => $item->nama_prestasi, + 'jenis_prestasi' => $item->jenis_prestasi, + 'tingkat' => $item->tingkat, + 'peringkat' => $item->peringkat, + 'tanggal_prestasi' => $item->tanggal_prestasi, + 'deskripsi' => $item->deskripsi, + 'sertifikat_url' => $item->sertifikat ? asset('storage/' . $item->sertifikat) : null, + 'created_at' => $item->created_at->toDateTimeString(), + 'updated_at' => $item->updated_at->toDateTimeString(), + 'santri' => $item->santri ? [ + 'id' => $item->santri->id, + 'nama' => $item->santri->nama, + ] : null, + 'kelas' => $item->kelas ? [ + 'id' => $item->kelas->id, + 'nama_kelas' => $item->kelas->nama_kelas, + ] : null, + ]; + }), + ]); + } +} diff --git a/website/app/Http/Controllers/Api/ProfileController.php b/website/app/Http/Controllers/Api/ProfileController.php new file mode 100644 index 0000000..6301e8a --- /dev/null +++ b/website/app/Http/Controllers/Api/ProfileController.php @@ -0,0 +1,134 @@ +user(); + $santri = $user->santri; + + if (!$santri) { + return response()->json(['message' => 'Data santri tidak ditemukan'], 404); + } + + return response()->json([ + 'user' => [ + 'id' => $user->id, + 'name' => $user->name, + 'username' => $user->username, + 'email' => $user->email, + 'role' => $user->role, + ], + 'santri' => [ + 'nis' => $santri->nis, + 'alamat' => $santri->alamat, + 'tempat_lahir' => $santri->tempat_lahir, + 'tanggal_lahir' => $santri->tanggal_lahir, + 'jenis_kelamin' => $santri->jenis_kelamin, + 'foto_url' => $santri->foto ? asset('storage/' . $santri->foto) : null, + ], + ]); + } + + /** + * Update profil user & santri + */ + public function updateSantriProfile(Request $request) + { + $user = $request->user(); + $santri = $user->santri; + + if (!$santri) { + return response()->json(['message' => 'Data santri tidak ditemukan'], 404); + } + + $validator = Validator::make($request->all(), [ + 'name' => 'sometimes|string|max:255', // user.name + 'alamat' => 'sometimes|string|max:255', + 'tempat_lahir' => 'sometimes|string|max:100', + 'tanggal_lahir' => 'sometimes|date', + 'jenis_kelamin' => 'sometimes|in:L,P', + 'foto' => 'sometimes|image|mimes:jpeg,png,jpg|max:2048', + ]); + + if ($validator->fails()) { + return response()->json(['errors' => $validator->errors()], 422); + } + + // Update user.name + if ($request->has('name')) { + $user->name = $request->name; + $user->save(); + } + + // Update data santri + $santri->alamat = $request->get('alamat', $santri->alamat); + $santri->tempat_lahir = $request->get('tempat_lahir', $santri->tempat_lahir); + $santri->tanggal_lahir = $request->get('tanggal_lahir', $santri->tanggal_lahir); + $santri->jenis_kelamin = $request->get('jenis_kelamin', $santri->jenis_kelamin); + + if ($request->hasFile('foto')) { + // Hapus foto lama jika ada + if ($santri->foto && Storage::disk('public')->exists($santri->foto)) { + Storage::disk('public')->delete($santri->foto); + } + + $santri->foto = $request->file('foto')->store('foto_profile', 'public'); + } + + $santri->save(); + + return response()->json([ + 'message' => 'Profil berhasil diperbarui', + 'user' => $user, + 'santri' => $santri, + 'foto_url' => $santri->foto ? asset('storage/' . $santri->foto) : null, + ]); + + } + public function changePassword(Request $request) + { + $request->validate([ + 'old_password' => 'required', + 'new_password' => 'required|min:6', + 'confirm_password' => 'same:new_password' + ]); + + $user = auth()->user(); + + if (!Hash::check($request->old_password, $user->password)) { + return response()->json(['message' => 'Password lama salah'], 422); + } + + $user->update(['password' => bcrypt($request->new_password)]); + return response()->json(['message' => 'Password berhasil diperbarui']); + } + public function updatePassword(Request $request) + { + $request->validate([ + 'old_password' => 'required|string', + 'new_password' => 'required|string|min:6', + ]); + + if (!Hash::check($request->old_password, $request->user()->password)) { + return response()->json(['message' => 'Password lama salah'], 403); + } + + $request->user()->update([ + 'password' => Hash::make($request->new_password) + ]); + + return response()->json(['message' => 'Password berhasil diubah']); + } +} diff --git a/website/app/Http/Controllers/Auth/AuthenticatedSessionController.php b/website/app/Http/Controllers/Auth/AuthenticatedSessionController.php new file mode 100644 index 0000000..4993ffc --- /dev/null +++ b/website/app/Http/Controllers/Auth/AuthenticatedSessionController.php @@ -0,0 +1,55 @@ +authenticate(); + + $request->session()->regenerate(); + + // Redirect sesuai role + $user = Auth::user(); + if ($user->isAdmin()) { + return redirect()->intended(route('admin.dashboard', absolute: false)); + } elseif ($user->isGuru()) { + return redirect()->intended(route('guru.dashboard', absolute: false)); + } + // Default fallback + return redirect('/'); + } + + /** + * Destroy an authenticated session. + */ + public function destroy(Request $request): RedirectResponse + { + Auth::guard('web')->logout(); + + $request->session()->invalidate(); + + $request->session()->regenerateToken(); + + return redirect('/'); + } +} diff --git a/website/app/Http/Controllers/Auth/ConfirmablePasswordController.php b/website/app/Http/Controllers/Auth/ConfirmablePasswordController.php new file mode 100644 index 0000000..86ff86e --- /dev/null +++ b/website/app/Http/Controllers/Auth/ConfirmablePasswordController.php @@ -0,0 +1,40 @@ +validate([ + 'username' => $request->user()->username, + 'password' => $request->password, + ])) { + throw ValidationException::withMessages([ + 'password' => __('auth.password'), + ]); + } + + $request->session()->put('auth.password_confirmed_at', time()); + + return redirect()->intended(route('dashboard', absolute: false)); + } +} diff --git a/website/app/Http/Controllers/Auth/EmailVerificationNotificationController.php b/website/app/Http/Controllers/Auth/EmailVerificationNotificationController.php new file mode 100644 index 0000000..f64fa9b --- /dev/null +++ b/website/app/Http/Controllers/Auth/EmailVerificationNotificationController.php @@ -0,0 +1,24 @@ +user()->hasVerifiedEmail()) { + return redirect()->intended(route('dashboard', absolute: false)); + } + + $request->user()->sendEmailVerificationNotification(); + + return back()->with('status', 'verification-link-sent'); + } +} diff --git a/website/app/Http/Controllers/Auth/EmailVerificationPromptController.php b/website/app/Http/Controllers/Auth/EmailVerificationPromptController.php new file mode 100644 index 0000000..ee3cb6f --- /dev/null +++ b/website/app/Http/Controllers/Auth/EmailVerificationPromptController.php @@ -0,0 +1,21 @@ +user()->hasVerifiedEmail() + ? redirect()->intended(route('dashboard', absolute: false)) + : view('auth.verify-email'); + } +} diff --git a/website/app/Http/Controllers/Auth/NewPasswordController.php b/website/app/Http/Controllers/Auth/NewPasswordController.php new file mode 100644 index 0000000..710567e --- /dev/null +++ b/website/app/Http/Controllers/Auth/NewPasswordController.php @@ -0,0 +1,62 @@ + $request]); + } + + /** + * Handle an incoming new password request. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function store(Request $request): RedirectResponse + { + $request->validate([ + 'token' => ['required'], + 'username' => ['required', 'string'], + 'password' => ['required', 'confirmed', Rules\Password::defaults()], + ]); + + // Here we will attempt to reset the user's password. If it is successful we + // will update the password on an actual user model and persist it to the + // database. Otherwise we will parse the error and return the response. + $status = Password::reset( + $request->only('username', 'password', 'password_confirmation', 'token'), + function (User $user) use ($request) { + $user->forceFill([ + 'password' => Hash::make($request->password), + 'remember_token' => Str::random(60), + ])->save(); + + event(new PasswordReset($user)); + } + ); + + // If the password was successfully reset, we will redirect the user back to + // the application's home authenticated view. If there is an error we can + // redirect them back to where they came from with their error message. + return $status == Password::PASSWORD_RESET + ? redirect()->route('login')->with('status', __($status)) + : back()->withInput($request->only('username')) + ->withErrors(['username' => __($status)]); + } +} diff --git a/website/app/Http/Controllers/Auth/PasswordController.php b/website/app/Http/Controllers/Auth/PasswordController.php new file mode 100644 index 0000000..6916409 --- /dev/null +++ b/website/app/Http/Controllers/Auth/PasswordController.php @@ -0,0 +1,29 @@ +validateWithBag('updatePassword', [ + 'current_password' => ['required', 'current_password'], + 'password' => ['required', Password::defaults(), 'confirmed'], + ]); + + $request->user()->update([ + 'password' => Hash::make($validated['password']), + ]); + + return back()->with('status', 'password-updated'); + } +} diff --git a/website/app/Http/Controllers/Auth/PasswordResetLinkController.php b/website/app/Http/Controllers/Auth/PasswordResetLinkController.php new file mode 100644 index 0000000..6395fe7 --- /dev/null +++ b/website/app/Http/Controllers/Auth/PasswordResetLinkController.php @@ -0,0 +1,44 @@ +validate([ + 'username' => ['required', 'string'], + ]); + + // We will send the password reset link to this user. Once we have attempted + // to send the link, we will examine the response then see the message we + // need to show to the user. Finally, we'll send out a proper response. + $status = Password::sendResetLink( + $request->only('username') + ); + + return $status == Password::RESET_LINK_SENT + ? back()->with('status', __($status)) + : back()->withInput($request->only('username')) + ->withErrors(['username' => __($status)]); + } +} diff --git a/website/app/Http/Controllers/Auth/RegisteredUserController.php b/website/app/Http/Controllers/Auth/RegisteredUserController.php new file mode 100644 index 0000000..ad9099c --- /dev/null +++ b/website/app/Http/Controllers/Auth/RegisteredUserController.php @@ -0,0 +1,50 @@ +validate([ + 'name' => ['required', 'string', 'max:255'], + 'username' => ['required', 'string', 'max:255', 'unique:'.User::class], + 'password' => ['required', 'confirmed', Rules\Password::defaults()], + ]); + + $user = User::create([ + 'name' => $request->name, + 'username' => $request->username, + 'password' => Hash::make($request->password), + ]); + + event(new Registered($user)); + + Auth::login($user); + + return redirect(route('dashboard', absolute: false)); + } +} diff --git a/website/app/Http/Controllers/Auth/VerifyEmailController.php b/website/app/Http/Controllers/Auth/VerifyEmailController.php new file mode 100644 index 0000000..2617c96 --- /dev/null +++ b/website/app/Http/Controllers/Auth/VerifyEmailController.php @@ -0,0 +1,19 @@ +intended(route('dashboard', absolute: false)); + } +} diff --git a/website/app/Http/Controllers/BeritaController.php b/website/app/Http/Controllers/BeritaController.php new file mode 100644 index 0000000..fe67562 --- /dev/null +++ b/website/app/Http/Controllers/BeritaController.php @@ -0,0 +1,137 @@ +latest()->paginate(10); + return view('beritas.index', compact('beritas')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + return view('beritas.create'); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + $validated = $request->validate([ + 'judul' => 'required|string|max:255', + 'kategori' => 'required|string|max:255', + 'ringkasan' => 'required|string', + 'isi' => 'required|string', + 'gambar' => 'nullable|image|mimes:jpg,jpeg,png,gif|max:5120', + 'penulis' => 'required|string|max:255', + 'status' => 'required|in:draft,published', + ]); + + // Handle file upload + if ($request->hasFile('gambar')) { + $path = $request->file('gambar')->store('berita', 'public'); + $validated['gambar'] = $path; + } + + $validated['user_id'] = Auth::id(); + Berita::create($validated); + + return redirect()->route('beritas.index') + ->with('success', 'Berita berhasil ditambahkan!'); + } + + /** + * Display the specified resource. + */ + public function show(Berita $berita) + { + $berita->load('user'); + return view('beritas.show', compact('berita')); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Berita $berita) + { + return view('beritas.edit', compact('berita')); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, Berita $berita) + { + $validated = $request->validate([ + 'judul' => 'required|string|max:255', + 'kategori' => 'required|string|max:255', + 'ringkasan' => 'required|string', + 'isi' => 'required|string', + 'gambar' => 'nullable|image|mimes:jpg,jpeg,png,gif|max:5120', + 'penulis' => 'required|string|max:255', + 'status' => 'required|in:draft,published', + ]); + + // Handle file upload + if ($request->hasFile('gambar')) { + // Delete old image if exists + if ($berita->gambar) { + Storage::disk('public')->delete($berita->gambar); + } + + $path = $request->file('gambar')->store('berita', 'public'); + $validated['gambar'] = $path; + } + + $berita->update($validated); + + return redirect()->route('beritas.index') + ->with('success', 'Berita berhasil diperbarui!'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Berita $berita) + { + // Delete image if exists + if ($berita->gambar) { + Storage::disk('public')->delete($berita->gambar); + } + + $berita->delete(); + + return redirect()->route('beritas.index') + ->with('success', 'Berita berhasil dihapus!'); + } +} + +namespace App\Http\Controllers\API; + +use App\Http\Controllers\Controller; +use App\Models\Berita; +use Illuminate\Http\Request; + +class BeritaApiController extends Controller +{ + public function index(Request $request) + { + $berita = Berita::latest()->get(); + return response()->json($berita); + } +} diff --git a/website/app/Http/Controllers/CatatanKesehatanController.php b/website/app/Http/Controllers/CatatanKesehatanController.php new file mode 100644 index 0000000..8934316 --- /dev/null +++ b/website/app/Http/Controllers/CatatanKesehatanController.php @@ -0,0 +1,130 @@ +latest(); + + // filter berdasarkan search + if ($request->has('search') && $request->search != '') { + $query->whereHas('santri', function ($q) use ($request) { + $q->where('nama', 'like', '%' . $request->search . '%'); + // sesuaikan 'nama' dengan kolom di tabel santris + }); + } + + $catatanKesehatans = $query->paginate(10)->withQueryString(); + + $view = auth()->user()->isGuru() ? 'guru.catatan_kesehatans.index' : 'catatan_kesehatans.index'; + return view($view, compact('catatanKesehatans')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + $santris = Santri::all(); + $kelas = Kelas::all(); + $view = auth()->user()->isGuru() ? 'guru.catatan_kesehatans.create' : 'catatan_kesehatans.create'; + return view($view, compact('santris', 'kelas')); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + $validated = $request->validate([ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'keluhan' => 'required|string', + 'diagnosis' => 'required|string', + 'saran' => 'nullable|string', + ]); + + CatatanKesehatan::create($validated); + + return redirect()->route('catatan_kesehatans.index') + ->with('success', 'Catatan kesehatan berhasil ditambahkan.'); + } + + /** + * Display the specified resource. + */ + public function show(CatatanKesehatan $catatanKesehatan) + { + $catatanKesehatan->load(['santri', 'kelas']); + $view = auth()->user()->isGuru() ? 'guru.catatan_kesehatans.show' : 'catatan_kesehatans.show'; + return view($view, compact('catatanKesehatan')); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(CatatanKesehatan $catatanKesehatan) + { + $santris = Santri::all(); + $kelas = Kelas::all(); + $view = auth()->user()->isGuru() ? 'guru.catatan_kesehatans.edit' : 'catatan_kesehatans.edit'; + return view($view, compact('catatanKesehatan', 'santris', 'kelas')); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, CatatanKesehatan $catatanKesehatan) + { + $validated = $request->validate([ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'keluhan' => 'required|string', + 'diagnosis' => 'required|string', + 'saran' => 'nullable|string', + ]); + $catatanKesehatan->update($validated); + return redirect()->route('catatan_kesehatans.index')->with('success', 'Catatan kesehatan berhasil diupdate.'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(CatatanKesehatan $catatanKesehatan) + { + $catatanKesehatan->delete(); + return redirect()->route('catatan_kesehatans.index')->with('success', 'Catatan kesehatan berhasil dihapus.'); + } +} + +namespace App\Http\Controllers\API; + +use App\Http\Controllers\Controller; +use App\Models\CatatanKesehatan; +use Illuminate\Http\Request; + +class KesehatanApiController extends Controller +{ + public function index(Request $request) + { + $user = $request->user(); + $catatan = CatatanKesehatan::where('user_id', $user->id)->get(); + return response()->json($catatan); + } + public function notifikasi(Request $request) + { + $user = $request->user(); + $notifikasi = CatatanKesehatan::where('user_id', $user->id)->whereNotNull('keluhan')->get(); + return response()->json($notifikasi); + } +} diff --git a/website/app/Http/Controllers/Controller.php b/website/app/Http/Controllers/Controller.php new file mode 100644 index 0000000..8677cd5 --- /dev/null +++ b/website/app/Http/Controllers/Controller.php @@ -0,0 +1,8 @@ +has('search') && $request->search != '') { + $query->where('nama', 'like', '%' . $request->search . '%'); + // ganti 'nama' dengan nama kolom di tabel gurus + } + + $gurus = $query->paginate(10)->withQueryString(); + + return view('gurus.index', compact('gurus')); + } + + + public function create() + { + $codeGuruBaru = Guru::generateCodeGuru(); + return view('gurus.create', compact('codeGuruBaru')); + } + + + public function store(Request $request) + { + $codeGuruBaru = Guru::generateCodeGuru(); + + $request->validate([ + 'nama' => 'required|string|max:255', + 'alamat' => 'required|string', + 'tanggal_lahir' => 'required|date', + 'jenis_kelamin' => 'required|in:L,P', + 'username' => 'required|string|max:255|unique:users', + 'password' => 'required|string|confirmed|min:6', + ]); + + // buat user dulu + $user = User::create([ + 'name' => $request->nama, + 'username' => $request->username, + 'password' => bcrypt($request->password), + 'role' => 'guru', + ]); + + // ambil kode guru otomatis + $kodeBaru = Guru::generateCodeGuru(); + + // simpan guru + Guru::create([ + 'user_id' => $user->id, + 'nama' => $request->nama, + 'code_guru' => $codeGuruBaru, + 'alamat' => $request->alamat, + 'tanggal_lahir' => $request->tanggal_lahir, + 'jenis_kelamin' => $request->jenis_kelamin, + ]); + + return redirect()->route('gurus.index')->with('success', 'Data guru berhasil ditambahkan.'); + } + + /** + * Display the specified resource. + */ + public function show(Guru $guru) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Guru $guru) + { + return view('gurus.edit', compact('guru')); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Guru $guru) + { + $guru->delete(); + return redirect()->route('gurus.index')->with('success', 'Guru berhasil dihapus'); + } + + public function profile() + { + $user = Auth::user(); + $guru = \App\Models\Guru::where('user_id', $user->id)->firstOrFail(); + return view('guru.profile', compact('guru')); + } + + public function editProfile() + { + $user = Auth::user(); + $guru = \App\Models\Guru::where('user_id', $user->id)->firstOrFail(); + return view('guru.edit_profile', compact('guru')); + } + + public function updateProfile(Request $request) + { + $user = Auth::user(); + $guru = \App\Models\Guru::where('user_id', $user->id)->firstOrFail(); + $validated = $request->validate([ + 'nama' => 'required|string|max:255', + 'code_guru' => 'required|string|max:50', + 'alamat' => 'nullable|string', + 'tanggal_lahir' => 'nullable|date', + 'jenis_kelamin' => 'required|in:L,P', + 'foto' => 'nullable|image|mimes:jpg,jpeg,png|max:2048', + ]); + if ($request->hasFile('foto')) { + if ($guru->foto && \Storage::disk('public')->exists('foto_guru/' . $guru->foto)) { + \Storage::disk('public')->delete('foto_guru/' . $guru->foto); + } + $file = $request->file('foto'); + $filename = uniqid() . '.' . $file->getClientOriginalExtension(); + $file->storeAs('foto_guru', $filename, 'public'); + $validated['foto'] = $filename; + } + $guru->update($validated); + return redirect()->route('guru.profile')->with('success', 'Profil berhasil diperbarui'); + } +} diff --git a/website/app/Http/Controllers/JadwalController.php b/website/app/Http/Controllers/JadwalController.php new file mode 100644 index 0000000..a06e94c --- /dev/null +++ b/website/app/Http/Controllers/JadwalController.php @@ -0,0 +1,82 @@ +get(); + $view = auth()->user()->isGuru() ? 'guru.jadwals.index' : 'jadwals.index'; + return view($view, compact('jadwals')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + $gurus = Guru::all(); + $kelas = Kelas::all(); + $mapels = MataPelajaran::all(); // pakai $mapel, bukan $mapels + $view = auth()->user()->isGuru() ? 'guru.jadwals.create' : 'jadwals.create'; + return view($view, compact('kelas', 'mapels', 'gurus')); // kirim $mapel + } + + /** + * Store a newly created resource in storage. + */ + public function store(StoreJadwalRequest $request) + { + Jadwal::create($request->validated()); + return redirect()->route('jadwals.index')->with('success', 'Jadwal berhasil ditambahkan'); + } + + /** + * Display the specified resource. + */ + public function show(Jadwal $jadwal) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Jadwal $jadwal) + { + $kelas = Kelas::all(); + $mapels = MataPelajaran::all(); + $view = auth()->user()->isGuru() ? 'guru.jadwals.edit' : 'jadwals.edit'; + return view($view, compact('jadwal', 'kelas', 'mapels')); + } + + /** + * Update the specified resource in storage. + */ + public function update(UpdateJadwalRequest $request, Jadwal $jadwal) + { + $jadwal->update($request->validated()); + return redirect()->route('jadwals.index')->with('success', 'Jadwal berhasil diupdate'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Jadwal $jadwal) + { + $jadwal->delete(); + return redirect()->route('jadwals.index')->with('success', 'Jadwal berhasil dihapus'); + } +} diff --git a/website/app/Http/Controllers/KelasController.php b/website/app/Http/Controllers/KelasController.php new file mode 100644 index 0000000..2884c60 --- /dev/null +++ b/website/app/Http/Controllers/KelasController.php @@ -0,0 +1,74 @@ +get(); + return view('kelas.index', compact('kelas')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + $gurus = Guru::all(); + return view('kelas.create', compact('gurus')); + } + + /** + * Store a newly created resource in storage. + */ + public function store(StoreKelasRequest $request) + { + Kelas::create($request->validated()); + return redirect()->route('kelas.index')->with('success', 'Kelas berhasil ditambahkan'); + } + + /** + * Display the specified resource. + */ + public function show(Kelas $kelas) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Kelas $kela) + { + $gurus = Guru::all(); + return view('kelas.edit', ['kela' => $kela, 'gurus' => $gurus]); + } + + /** + * Update the specified resource in storage. + */ + public function update(UpdateKelasRequest $request, Kelas $kela) + { + $kela->update($request->validated()); + return redirect()->route('kelas.index')->with('success', 'Kelas berhasil diupdate'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Kelas $kela) + { + $kela->delete(); + return redirect()->route('kelas.index')->with('success', 'Kelas berhasil dihapus'); + } +} diff --git a/website/app/Http/Controllers/MataPelajaranController.php b/website/app/Http/Controllers/MataPelajaranController.php new file mode 100644 index 0000000..ab3cd8a --- /dev/null +++ b/website/app/Http/Controllers/MataPelajaranController.php @@ -0,0 +1,71 @@ +validated()); + return redirect()->route('mata_pelajarans.index')->with('success', 'Mata pelajaran berhasil ditambahkan'); + } + + /** + * Display the specified resource. + */ + public function show(MataPelajaran $mataPelajaran) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(MataPelajaran $mataPelajaran) + { + return view('mata_pelajarans.edit', compact('mataPelajaran')); + } + + /** + * Update the specified resource in storage. + */ + public function update(UpdateMataPelajaranRequest $request, MataPelajaran $mataPelajaran) + { + $mataPelajaran->update($request->validated()); + return redirect()->route('mata_pelajarans.index')->with('success', 'Mata pelajaran berhasil diupdate'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(MataPelajaran $mataPelajaran) + { + $mataPelajaran->delete(); + return redirect()->route('mata_pelajarans.index')->with('success', 'Mata pelajaran berhasil dihapus'); + } +} diff --git a/website/app/Http/Controllers/NilaiSantriController.php b/website/app/Http/Controllers/NilaiSantriController.php new file mode 100644 index 0000000..b03c59e --- /dev/null +++ b/website/app/Http/Controllers/NilaiSantriController.php @@ -0,0 +1,171 @@ +kelas_id; + $mapelId = $request->mapel_id; + $tanggal = $request->tanggal ?? now()->toDateString(); + + $santris = collect(); + $nilaiSantris = collect(); + + if ($kelasId && $mapelId) { + $santris = Santri::where('kelas_id', $kelasId)->get(); + $nilaiSantris = NilaiSantri::where('kelas_id', $kelasId) + ->where('mapel_id', $mapelId) + ->where('tanggal', $tanggal) + ->get() + ->keyBy('santri_id'); + } + + $view = auth()->user()->isGuru() ? 'guru.nilai_santris.index' : 'nilai_santris.index'; + + return view($view, compact( + 'kelasList', + 'mapelList', + 'kelasId', + 'mapelId', + 'tanggal', + 'santris', + 'nilaiSantris' + )); + } + + public function create(Request $request) + { + $kelas = Kelas::all(); + $mapelList = MataPelajaran::all(); + $semesters = Semester::all(); + + $kelasId = $request->kelas_id; + $mapelId = $request->mapel_id; + $tanggal = $request->tanggal ?? now()->toDateString(); + $santris = $kelasId ? Santri::where('kelas_id', $kelasId)->get() : collect(); + + $view = auth()->user()->isGuru() ? 'guru.nilai_santris.create' : 'nilai_santris.create'; + + return view($view, compact( + 'kelas', + 'mapelList', + 'semesters', + 'santris', + 'kelasId', + 'mapelId', + 'tanggal' + )); + } + + public function store(Request $request) + { + $request->validate([ + 'kelas_id' => 'required|exists:kelas,id', + 'mapel_id' => 'required|exists:mata_pelajarans,id', + 'semester_id' => 'required|exists:semesters,id', + 'jenis_nilai' => 'required|string', + 'tanggal' => 'required|date', + 'nilai' => 'required|array', + 'nilai.*.santri_id' => 'required|exists:santris,id', + 'nilai.*.nilai' => 'required|numeric|min:0|max:100', + 'nilai.*.keterangan' => 'nullable|string', + ]); + + foreach ($request->nilai as $n) { + NilaiSantri::updateOrCreate( + [ + 'santri_id' => $n['santri_id'], + 'kelas_id' => $request->kelas_id, + 'mapel_id' => $request->mapel_id, + 'tanggal' => $request->tanggal, + ], + [ + 'semester_id' => $request->semester_id, + 'jenis_nilai' => $request->jenis_nilai, + 'nilai' => $n['nilai'], + 'keterangan' => $n['keterangan'] ?? null, + ] + ); + } + + $route = auth()->user()->isGuru() ? 'guru.nilai_santris.index' : 'nilai_santris.index'; + + return redirect()->route($route, [ + 'kelas_id' => $request->kelas_id, + 'mapel_id' => $request->mapel_id, + 'tanggal' => $request->tanggal, + ])->with('success', 'Nilai santri berhasil disimpan.'); + } + + public function edit(NilaiSantri $nilaiSantri) + { + $kelas = Kelas::all(); + $mapelList = MataPelajaran::all(); + $semesters = Semester::all(); + $santri = $nilaiSantri->santri; + + $view = auth()->user()->isGuru() ? 'guru.nilai_santris.edit' : 'nilai_santris.edit'; + + return view($view, compact( + 'nilaiSantri', + 'kelas', + 'mapelList', + 'semesters', + 'santri' + )); + } + + public function update(Request $request, NilaiSantri $nilaiSantri) + { + $request->validate([ + 'nilai' => 'required|numeric|min:0|max:100', + 'keterangan' => 'nullable|string', + 'semester_id' => 'required|exists:semesters,id', + 'jenis_nilai' => 'required|string', + ]); + + $nilaiSantri->update([ + 'nilai' => $request->nilai, + 'keterangan' => $request->keterangan, + 'semester_id' => $request->semester_id, + 'jenis_nilai' => $request->jenis_nilai, + ]); + + $route = auth()->user()->isGuru() ? 'guru.nilai_santris.index' : 'nilai_santris.index'; + + return redirect()->route($route, [ + 'kelas_id' => $nilaiSantri->kelas_id, + 'mapel_id' => $nilaiSantri->mapel_id, + 'tanggal' => $nilaiSantri->tanggal, + ])->with('success', 'Nilai santri berhasil diperbarui.'); + } + + public function destroy(NilaiSantri $nilaiSantri) + { + $kelas_id = $nilaiSantri->kelas_id; + $mapel_id = $nilaiSantri->mapel_id; + $tanggal = $nilaiSantri->tanggal; + + $nilaiSantri->delete(); + + $route = auth()->user()->isGuru() ? 'guru.nilai_santris.index' : 'nilai_santris.index'; + + return redirect()->route($route, [ + 'kelas_id' => $kelas_id, + 'mapel_id' => $mapel_id, + 'tanggal' => $tanggal, + ])->with('success', 'Nilai santri berhasil dihapus.'); + } +} diff --git a/website/app/Http/Controllers/PelanggaranController.php b/website/app/Http/Controllers/PelanggaranController.php new file mode 100644 index 0000000..e8b9ba4 --- /dev/null +++ b/website/app/Http/Controllers/PelanggaranController.php @@ -0,0 +1,123 @@ +orderBy('created_at', 'desc'); + + // filter berdasarkan role guru + if ($user->role === 'guru') { + $query->where('user_id', $user->id); + } + + // filter search nama santri + if ($request->has('search') && $request->search != '') { + $query->whereHas('santri', function ($q) use ($request) { + $q->where('nama', 'like', '%' . $request->search . '%'); + }); + } + + $pelanggarans = $query->paginate(10); + + $view = $user->role === 'guru' ? 'guru.pelanggarans.index' : 'pelanggarans.index'; + return view($view, compact('pelanggarans')); + } + + + public function create() + { + $santris = Santri::all(); + $kelas = Kelas::all(); + + $view = auth()->user()->isGuru() ? 'guru.pelanggarans.create' : 'pelanggarans.create'; + return view($view, compact('santris', 'kelas')); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'jenis_pelanggaran' => 'required|string|max:255', + 'hukuman' => 'required|in:Teguran Lisan,Teguran Tertulis,Skorsing,Lainnya', + 'keterangan_hukuman' => 'nullable|string|max:255', + 'hukuman_selesai' => 'nullable', + ]); + + $validated['user_id'] = Auth::id(); + $validated['hukuman_selesai'] = $request->has('hukuman_selesai') ? 'selesai' : 'belum'; + + Pelanggaran::create($validated); + + return redirect()->route('pelanggarans.index')->with('success', 'Data pelanggaran berhasil ditambahkan.'); + } + + public function update(Request $request, Pelanggaran $pelanggaran) + { + $validated = $request->validate([ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'jenis_pelanggaran' => 'required|string|max:255', + 'hukuman' => 'required|in:Teguran Lisan,Teguran Tertulis,Skorsing,Lainnya', + 'keterangan_hukuman' => 'nullable|string|max:255', + 'hukuman_selesai' => 'nullable', + ]); + + $validated['hukuman_selesai'] = $request->has('hukuman_selesai') ? 'selesai' : 'belum'; + + $pelanggaran->update($validated); + + return redirect()->route('pelanggarans.index')->with('success', 'Data pelanggaran berhasil diperbarui.'); + } + + + public function show(Pelanggaran $pelanggaran) + { + $this->authorizeAccess($pelanggaran); + + $view = auth()->user()->isGuru() ? 'guru.pelanggarans.show' : 'pelanggarans.show'; + return view($view, compact('pelanggaran')); + } + + public function edit(Pelanggaran $pelanggaran) + { + $this->authorizeAccess($pelanggaran); + + $santris = Santri::all(); + $kelas = Kelas::all(); + + $view = auth()->user()->isGuru() ? 'guru.pelanggarans.edit' : 'pelanggarans.edit'; + return view($view, compact('pelanggaran', 'santris', 'kelas')); + } + + public function destroy(Pelanggaran $pelanggaran) + { + $this->authorizeAccess($pelanggaran); + + $pelanggaran->delete(); + + return redirect()->route('pelanggarans.index')->with('success', 'Data pelanggaran berhasil dihapus.'); + } + + protected function authorizeAccess(Pelanggaran $pelanggaran) + { + $user = Auth::user(); + + if ($user->role === 'guru' && $pelanggaran->user_id !== $user->id) { + abort(403, 'Unauthorized'); + } + } +} diff --git a/website/app/Http/Controllers/PembayaranApiController.php b/website/app/Http/Controllers/PembayaranApiController.php new file mode 100644 index 0000000..a102e27 --- /dev/null +++ b/website/app/Http/Controllers/PembayaranApiController.php @@ -0,0 +1,44 @@ +user(); + + $query = Pembayaran::where('user_id', $user->id); + + // cek apakah ada parameter search nama + if ($request->filled('search')) { + $query->where('nama', 'like', '%' . $request->search . '%'); + } + + $pembayaran = $query->get(); + + return response()->json($pembayaran); + } + + public function store(Request $request) + { + $validated = $request->validate([ + 'tanggal' => 'required|date', + 'jenis_pembayaran' => 'required|string', + 'jumlah' => 'required|integer|min:0', + 'keterangan' => 'nullable|string', + 'status' => 'required|in:lunas,belum_lunas', + 'bukti' => 'nullable|file|mimes:jpeg,png,jpg,gif,webp,pdf|max:2048', + ]); + $validated['user_id'] = $request->user()->id; + if ($request->hasFile('bukti')) { + $validated['bukti'] = $request->file('bukti')->store('bukti_pembayaran', 'public'); + } + $pembayaran = Pembayaran::create($validated); + return response()->json($pembayaran, 201); + } +} \ No newline at end of file diff --git a/website/app/Http/Controllers/PembayaranController.php b/website/app/Http/Controllers/PembayaranController.php new file mode 100644 index 0000000..6da71d4 --- /dev/null +++ b/website/app/Http/Controllers/PembayaranController.php @@ -0,0 +1,106 @@ +latest()->paginate(10); + return view('pembayarans.index', compact('pembayarans')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + $santris = Santri::all(); + $kelas = Kelas::all(); + return view('pembayarans.create', compact('santris', 'kelas')); + } + + /** + * Store a newly created resource in storage. + */ + public function store(Request $request) + { + $validated = $request->validate([ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'tanggal' => 'required|date', + 'jenis_pembayaran' => 'required|string', + 'jumlah' => 'required|integer|min:0', + 'keterangan' => 'nullable|string', + 'status' => 'menunggu', + 'bukti_pembayaran' => 'nullable|file|mimes:jpeg,png,jpg,gif,webp,pdf|max:2048', + ]); + if ($request->hasFile('bukti_pembayaran')) { + $validated['bukti_pembayaran'] = $request->file('bukti_pembayaran')->store('bukti_pembayaran', 'public'); + } + Pembayaran::create($validated); + return redirect()->route('pembayarans.index')->with('success', 'Pembayaran berhasil ditambahkan.'); + } + + /** + * Display the specified resource. + */ + public function show(Pembayaran $pembayaran) + { + $pembayaran->load(['santri', 'kelas']); + return view('pembayarans.show', compact('pembayaran')); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Pembayaran $pembayaran) + { + $santris = Santri::all(); + $kelas = Kelas::all(); + return view('pembayarans.edit', compact('pembayaran', 'santris', 'kelas')); + } + + /** + * Update the specified resource in storage. + */ + public function update(Request $request, Pembayaran $pembayaran) + { + $validated = $request->validate([ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'tanggal' => 'required|date', + 'jenis_pembayaran' => 'required|string', + 'jumlah' => 'required|integer|min:0', + 'keterangan' => 'nullable|string', + 'status' => 'required|in:menunggu,diterima,ditolak', + 'bukti_pembayaran' => 'nullable|file|mimes:jpeg,png,jpg,gif,webp,pdf|max:2048', + ]); + if ($request->hasFile('bukti_pembayaran')) { + // Hapus file lama jika ada + if ($pembayaran->bukti_pembayaran && \Storage::disk('public')->exists($pembayaran->bukti_pembayaran)) { + \Storage::disk('public')->delete($pembayaran->bukti_pembayaran); + } + $validated['bukti_pembayaran'] = $request->file('bukti_pembayaran')->store('bukti_pembayaran', 'public'); + } + $pembayaran->update($validated); + return redirect()->route('pembayarans.index')->with('success', 'Pembayaran berhasil diupdate.'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Pembayaran $pembayaran) + { + $pembayaran->delete(); + return redirect()->route('pembayarans.index')->with('success', 'Pembayaran berhasil dihapus.'); + } +} diff --git a/website/app/Http/Controllers/PrestasiController.php b/website/app/Http/Controllers/PrestasiController.php new file mode 100644 index 0000000..dac4e62 --- /dev/null +++ b/website/app/Http/Controllers/PrestasiController.php @@ -0,0 +1,132 @@ +latest(); + + // kalau ada input search + if ($request->has('search') && $request->search != '') { + $query->whereHas('santri', function ($q) use ($request) { + $q->where('nama', 'like', '%' . $request->search . '%'); + // ganti 'nama' sesuai kolom di tabel santris + }); + } + + $prestasis = $query->paginate(10)->withQueryString(); + + $view = auth()->user()->isGuru() ? 'guru.prestasis.index' : 'prestasis.index'; + return view($view, compact('prestasis')); + } + + + public function create() + { + $santris = Santri::all(); + $kelas = Kelas::all(); + $view = auth()->user()->isGuru() ? 'guru.prestasis.create' : 'prestasis.create'; + return view($view, compact('santris', 'kelas')); + } + + public function store(Request $request) + { + $request->validate([ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'jenis_prestasi' => 'required|string|max:255', + 'nama_prestasi' => 'required|string|max:255', + 'tingkat' => 'required|string|max:100', + 'peringkat' => 'required|string|max:100', + 'tanggal_prestasi' => 'required|date', + 'deskripsi' => 'nullable|string', + 'sertifikat' => 'nullable|file|mimes:jpg,jpeg,png,pdf|max:5120', + ]); + + $santri = Santri::findOrFail($request->santri_id); + + $sertifikat = null; + if ($request->hasFile('sertifikat')) { + $sertifikat = $request->file('sertifikat')->store('sertifikat', 'public'); + } + + Prestasi::create([ + 'user_id' => $santri->user_id, // otomatis dari santri + 'santri_id' => $request->santri_id, + 'kelas_id' => $request->kelas_id, + 'jenis_prestasi' => $request->jenis_prestasi, + 'nama_prestasi' => $request->nama_prestasi, + 'tingkat' => $request->tingkat, + 'peringkat' => $request->peringkat, + 'tanggal_prestasi' => $request->tanggal_prestasi, + 'deskripsi' => $request->deskripsi, + 'sertifikat' => $sertifikat, + ]); + + return redirect()->route('prestasis.index')->with('success', 'Prestasi berhasil ditambahkan.'); + } + + public function edit(Prestasi $prestasi) + { + $santris = Santri::all(); + $kelas = Kelas::all(); + return view('prestasis.edit', compact('prestasi', 'santris', 'kelas')); + } + + public function update(Request $request, Prestasi $prestasi) + { + $request->validate([ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'jenis_prestasi' => 'required|string|max:255', + 'nama_prestasi' => 'required|string|max:255', + 'tingkat' => 'required|string|max:100', + 'peringkat' => 'required|string|max:100', + 'tanggal_prestasi' => 'required|date', + 'deskripsi' => 'nullable|string', + 'sertifikat' => 'nullable|file|mimes:jpg,jpeg,png,pdf|max:5120', + ]); + + if ($request->hasFile('sertifikat')) { + if ($prestasi->sertifikat && Storage::disk('public')->exists($prestasi->sertifikat)) { + Storage::disk('public')->delete($prestasi->sertifikat); + } + + $prestasi->sertifikat = $request->file('sertifikat')->store('sertifikat', 'public'); + } + + $prestasi->update([ + 'santri_id' => $request->santri_id, + 'kelas_id' => $request->kelas_id, + 'jenis_prestasi' => $request->jenis_prestasi, + 'nama_prestasi' => $request->nama_prestasi, + 'tingkat' => $request->tingkat, + 'peringkat' => $request->peringkat, + 'tanggal_prestasi' => $request->tanggal_prestasi, + 'deskripsi' => $request->deskripsi, + 'sertifikat' => $prestasi->sertifikat, + ]); + + return redirect()->route('prestasis.index')->with('success', 'Prestasi berhasil diperbarui.'); + } + + public function destroy(Prestasi $prestasi) + { + if ($prestasi->sertifikat && Storage::disk('public')->exists($prestasi->sertifikat)) { + Storage::disk('public')->delete($prestasi->sertifikat); + } + + $prestasi->delete(); + + return redirect()->route('prestasis.index')->with('success', 'Prestasi berhasil dihapus.'); + } +} diff --git a/website/app/Http/Controllers/ProfileController.php b/website/app/Http/Controllers/ProfileController.php new file mode 100644 index 0000000..e541e48 --- /dev/null +++ b/website/app/Http/Controllers/ProfileController.php @@ -0,0 +1,55 @@ + $request->user(), + ]); + } + + /** + * Update the user's profile information. + */ + public function update(ProfileUpdateRequest $request): RedirectResponse + { + $request->user()->fill($request->validated()); + $request->user()->save(); + + return Redirect::route('profile.edit')->with('status', 'profile-updated'); + } + + /** + * Delete the user's account. + */ + public function destroy(Request $request): RedirectResponse + { + $request->validateWithBag('userDeletion', [ + 'password' => ['required', 'current_password'], + ]); + + $user = $request->user(); + + Auth::logout(); + + $user->delete(); + + $request->session()->invalidate(); + $request->session()->regenerateToken(); + + return Redirect::to('/'); + } +} diff --git a/website/app/Http/Controllers/SantriController.php b/website/app/Http/Controllers/SantriController.php new file mode 100644 index 0000000..1a410bf --- /dev/null +++ b/website/app/Http/Controllers/SantriController.php @@ -0,0 +1,144 @@ +input('search'); + $santris = Santri::query(); + + if ($search) { + $santris->where('nama', 'like', '%' . $search . '%'); + } + + $santris = $santris->paginate(10); + $view = auth()->user()->isGuru() ? 'guru.santris.index' : 'santris.index'; + return view($view, compact('santris', 'search')); + } + + /** + * Show the form for creating a new resource. + */ + public function create() + { + $kelas = Kelas::all(); + $nisBaru = Santri::generateNis(); + $view = auth()->user()->isGuru() ? 'guru.santris.create' : 'santris.create'; + return view($view, compact('kelas', 'nisBaru')); + } + + /** + * Store a newly created resource in storage. + */ + public function store(StoreSantriRequest $request) + { + $validated = $request->validated(); + + DB::transaction(function () use ($validated) { + $nisBaru = Santri::generateNis(); + + $user = User::create([ + 'name' => $validated['nama'], + 'username' => $nisBaru, + 'password' => bcrypt($nisBaru), + 'role' => 'santri', + 'status' => 'aktif', + ]); + + $data = [ + 'user_id' => $user->id, + 'nama' => $validated['nama'], + 'nis' => $nisBaru, + 'kelas_id' => $validated['kelas_id'], + 'alamat' => $validated['alamat'], + 'no_telp' => $validated['no_telp'], + 'tanggal_lahir' => $validated['tanggal_lahir'], + 'jenis_kelamin' => $validated['jenis_kelamin'], + ]; + + if (request()->hasFile('foto')) { + $data['foto'] = request()->file('foto')->store('santri', 'public'); + } + + Santri::create($data); + }); + + return redirect()->route('santris.index')->with('success', 'Santri dan akun pengguna berhasil ditambahkan'); + } + + /** + * Display the specified resource. + */ + public function show(Santri $santri) + { + $view = auth()->user()->isGuru() ? 'guru.santris.show' : 'santris.show'; + return view($view, compact('santri')); + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Santri $santri) + { + $kelas = Kelas::all(); + $view = auth()->user()->isGuru() ? 'guru.santris.edit' : 'santris.edit'; + return view($view, compact('santri', 'kelas')); + } + + /** + * Update the specified resource in storage. + */ + public function update(UpdateSantriRequest $request, Santri $santri) + { + $data = $request->validated(); + + if ($request->hasFile('foto')) { + if ($santri->foto && \Storage::disk('public')->exists($santri->foto)) { + \Storage::disk('public')->delete($santri->foto); + } + $data['foto'] = $request->file('foto')->store('santri', 'public'); + } + + $santri->update($data); + return redirect()->route('santris.index')->with('success', 'Santri berhasil diupdate'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Santri $santri) + { + $santri->delete(); + return redirect()->route('santris.index')->with('success', 'Santri berhasil dihapus'); + } + + public function importStore(Request $request) + { + $request->validate([ + 'file' => 'required|mimes:xlsx,csv,xls', + ]); + Excel::import(new SantrisImport, $request->file('file')); + return redirect()->route('santris.index')->with('success', 'Santri berhasil diimport.'); + } + + public function import() + { + return view('santris.import'); + } +} diff --git a/website/app/Http/Controllers/SantriImportController.php b/website/app/Http/Controllers/SantriImportController.php new file mode 100644 index 0000000..1db31ba --- /dev/null +++ b/website/app/Http/Controllers/SantriImportController.php @@ -0,0 +1,26 @@ +validate([ + 'file' => 'required|mimes:xlsx,csv,xls' + ]); + + Excel::import(new SantrisImport, $request->file('file')); + + return back()->with('success', 'Data santri berhasil diimport!'); + } +} diff --git a/website/app/Http/Controllers/SemesterController.php b/website/app/Http/Controllers/SemesterController.php new file mode 100644 index 0000000..26038eb --- /dev/null +++ b/website/app/Http/Controllers/SemesterController.php @@ -0,0 +1,85 @@ +is_active) { + Semester::where('is_active', true)->update(['is_active' => false]); + } + Semester::create($request->validated()); + return redirect()->route('semesters.index')->with('success', 'Semester berhasil ditambahkan'); + } + + /** + * Display the specified resource. + */ + public function show(Semester $semester) + { + // + } + + /** + * Show the form for editing the specified resource. + */ + public function edit(Semester $semester) + { + return view('semesters.edit', compact('semester')); + } + + /** + * Update the specified resource in storage. + */ + public function update(UpdateSemesterRequest $request, Semester $semester) + { + if ($request->is_active) { + Semester::where('is_active', true)->update(['is_active' => false]); + } + $semester->update($request->validated()); + return redirect()->route('semesters.index')->with('success', 'Semester berhasil diupdate'); + } + + /** + * Remove the specified resource from storage. + */ + public function destroy(Semester $semester) + { + $semester->delete(); + return redirect()->route('semesters.index')->with('success', 'Semester berhasil dihapus'); + } + + // Tambahkan method untuk mengaktifkan semester + public function activate(Semester $semester) + { + Semester::where('is_active', true)->update(['is_active' => false]); + $semester->update(['is_active' => true]); + return redirect()->route('semesters.index')->with('success', 'Semester diaktifkan'); + } +} diff --git a/website/app/Http/Controllers/UserController.php b/website/app/Http/Controllers/UserController.php new file mode 100644 index 0000000..2b29f30 --- /dev/null +++ b/website/app/Http/Controllers/UserController.php @@ -0,0 +1,78 @@ +validate([ + 'name' => 'required|string|max:255', + 'username' => 'required|string|max:255|unique:users', + 'password' => 'required|string|min:6', + 'role' => 'required|in:admin,guru,santri', + ]); + + User::create([ + 'name' => $request->name, + 'username' => $request->username, + 'password' => Hash::make($request->password), + 'role' => $request->role, + ]); + + return redirect()->route('users.index')->with('success', 'User berhasil ditambahkan!'); + } + + public function edit(User $user) + { + return view('users.edit', compact('user')); + } + + public function update(Request $request, User $user) + { + $request->validate([ + 'name' => 'required|string|max:255', + 'username' => ['required', 'string', 'max:255', Rule::unique('users')->ignore($user->id)], + 'password' => 'nullable|string|min:6', + 'role' => 'required|in:admin,guru,santri', + ]); + + $user->update([ + 'name' => $request->name, + 'username' => $request->username, + 'role' => $request->role, + ]); + + if ($request->filled('password')) { + $user->update(['password' => Hash::make($request->password)]); + } + + return redirect()->route('users.index')->with('success', 'User berhasil diperbarui!'); + } + + public function destroy(User $user) + { + if ($user->id === auth()->id()) { + return redirect()->route('users.index')->with('error', 'Tidak dapat menghapus akun sendiri!'); + } + + $user->delete(); + return redirect()->route('users.index')->with('success', 'User berhasil dihapus!'); + } +} \ No newline at end of file diff --git a/website/app/Http/Kernel.php b/website/app/Http/Kernel.php new file mode 100644 index 0000000..4777037 --- /dev/null +++ b/website/app/Http/Kernel.php @@ -0,0 +1,66 @@ + + */ + protected $middleware = [ + // \App\Http\Middleware\TrustHosts::class, + \App\Http\Middleware\TrustProxies::class, + \Illuminate\Http\Middleware\HandleCors::class, + \App\Http\Middleware\PreventRequestsDuringMaintenance::class, + \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class, + \App\Http\Middleware\TrimStrings::class, + \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, + ]; + + /** + * The application's route middleware groups. + * + * @var array> + */ + protected $middlewareGroups = [ + 'web' => [ + \App\Http\Middleware\EncryptCookies::class, + \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, + \Illuminate\Session\Middleware\StartSession::class, + // \Illuminate\Session\Middleware\AuthenticateSession::class, + \Illuminate\View\Middleware\ShareErrorsFromSession::class, + \App\Http\Middleware\VerifyCsrfToken::class, + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ], + + 'api' => [ + \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class, + 'throttle:api', + \Illuminate\Routing\Middleware\SubstituteBindings::class, + ], + ]; + + /** + * The application's route middleware. + * + * @var array + */ + protected $routeMiddleware = [ + 'auth' => \App\Http\Middleware\Authenticate::class, + 'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class, + 'auth.session' => \Illuminate\Session\Middleware\AuthenticateSession::class, + 'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class, + 'can' => \Illuminate\Auth\Middleware\Authorize::class, + 'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class, + 'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class, + 'precognitive' => \Illuminate\Foundation\Http\Middleware\HandlePrecognitiveRequests::class, + 'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class, + 'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class, + 'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class, + // Tambahkan middleware lain jika perlu + ]; +} \ No newline at end of file diff --git a/website/app/Http/Middleware/RoleMiddleware.php b/website/app/Http/Middleware/RoleMiddleware.php new file mode 100644 index 0000000..83ee91e --- /dev/null +++ b/website/app/Http/Middleware/RoleMiddleware.php @@ -0,0 +1,21 @@ +user()->role, $roles)) { + return response()->json([ + 'message' => 'Akses ditolak. Anda tidak memiliki izin.' + ], 403); + } + + return $next($request); + } +} diff --git a/website/app/Http/Requests/Auth/LoginRequest.php b/website/app/Http/Requests/Auth/LoginRequest.php new file mode 100644 index 0000000..eeb19f0 --- /dev/null +++ b/website/app/Http/Requests/Auth/LoginRequest.php @@ -0,0 +1,95 @@ +|string> + */ + public function rules(): array + { + return [ + 'username' => ['required', 'string'], + 'password' => ['required', 'string'], + 'role' => ['required', 'in:admin,guru,santri'], + ]; + } + + /** + * Attempt to authenticate the request's credentials. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function authenticate(): void + { + $this->ensureIsNotRateLimited(); + + if (! Auth::attempt($this->only('username', 'password'), $this->boolean('remember'))) { + RateLimiter::hit($this->throttleKey()); + + throw ValidationException::withMessages([ + 'username' => trans('auth.failed'), + ]); + } + + // Cek role user + $user = Auth::user(); + if ($user->role !== $this->input('role')) { + Auth::logout(); + throw ValidationException::withMessages([ + 'role' => __('auth.failed'), + ]); + } + + RateLimiter::clear($this->throttleKey()); + } + + /** + * Ensure the login request is not rate limited. + * + * @throws \Illuminate\Validation\ValidationException + */ + public function ensureIsNotRateLimited(): void + { + if (! RateLimiter::tooManyAttempts($this->throttleKey(), 5)) { + return; + } + + event(new Lockout($this)); + + $seconds = RateLimiter::availableIn($this->throttleKey()); + + throw ValidationException::withMessages([ + 'username' => trans('auth.throttle', [ + 'seconds' => $seconds, + 'minutes' => ceil($seconds / 60), + ]), + ]); + } + + /** + * Get the rate limiting throttle key for the request. + */ + public function throttleKey(): string + { + return Str::transliterate(Str::lower($this->string('username')).'|'.$this->ip()); + } +} diff --git a/website/app/Http/Requests/ProfileUpdateRequest.php b/website/app/Http/Requests/ProfileUpdateRequest.php new file mode 100644 index 0000000..a5ef577 --- /dev/null +++ b/website/app/Http/Requests/ProfileUpdateRequest.php @@ -0,0 +1,28 @@ +|string> + */ + public function rules(): array + { + return [ + 'name' => ['required', 'string', 'max:255'], + 'username' => [ + 'required', + 'string', + 'max:255', + Rule::unique(User::class)->ignore($this->user()->id), + ], + ]; + } +} diff --git a/website/app/Http/Requests/StoreAbsensiRequest.php b/website/app/Http/Requests/StoreAbsensiRequest.php new file mode 100644 index 0000000..c3f1990 --- /dev/null +++ b/website/app/Http/Requests/StoreAbsensiRequest.php @@ -0,0 +1,32 @@ +|string> + */ + public function rules(): array + { + return [ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'tanggal' => 'required|date', + 'status' => 'required|in:hadir,izin,sakit,alfa', + 'keterangan' => 'nullable|string', + ]; + } +} diff --git a/website/app/Http/Requests/StoreGuruRequest.php b/website/app/Http/Requests/StoreGuruRequest.php new file mode 100644 index 0000000..6ed3f9f --- /dev/null +++ b/website/app/Http/Requests/StoreGuruRequest.php @@ -0,0 +1,34 @@ +|string> + */ + public function rules(): array + { + return [ + 'nama' => 'required|string|max:255', + 'username' => 'required|string|max:255|unique:users,username', + 'password' => 'required|string|min:8|confirmed', + 'nip' => 'required|string|unique:gurus,nip', + 'alamat' => 'nullable|string', + 'tanggal_lahir' => 'nullable|date', + 'jenis_kelamin' => 'required|in:L,P', + ]; + } +} diff --git a/website/app/Http/Requests/StoreJadwalRequest.php b/website/app/Http/Requests/StoreJadwalRequest.php new file mode 100644 index 0000000..87fed94 --- /dev/null +++ b/website/app/Http/Requests/StoreJadwalRequest.php @@ -0,0 +1,31 @@ +|string> + */ + public function rules(): array + { + return [ + 'kelas_id' => 'required|exists:kelas,id', + 'hari' => 'required|string', + 'jam_pelajaran' => 'required|string', + 'mata_pelajaran_id' => 'required|exists:mata_pelajarans,id', + ]; + } +} diff --git a/website/app/Http/Requests/StoreKelasRequest.php b/website/app/Http/Requests/StoreKelasRequest.php new file mode 100644 index 0000000..4c7542b --- /dev/null +++ b/website/app/Http/Requests/StoreKelasRequest.php @@ -0,0 +1,29 @@ +|string> + */ + public function rules(): array + { + return [ + 'nama_kelas' => 'required|string|max:255', + 'wali_kelas_id' => 'nullable|exists:gurus,id', + ]; + } +} diff --git a/website/app/Http/Requests/StoreMataPelajaranRequest.php b/website/app/Http/Requests/StoreMataPelajaranRequest.php new file mode 100644 index 0000000..333de24 --- /dev/null +++ b/website/app/Http/Requests/StoreMataPelajaranRequest.php @@ -0,0 +1,29 @@ +|string> + */ + public function rules(): array + { + return [ + 'kode_mapel' => 'required|string|unique:mata_pelajarans,kode_mapel', + 'nama_mapel' => 'required|string|max:255', + ]; + } +} diff --git a/website/app/Http/Requests/StoreNilaiSantriRequest.php b/website/app/Http/Requests/StoreNilaiSantriRequest.php new file mode 100644 index 0000000..4252941 --- /dev/null +++ b/website/app/Http/Requests/StoreNilaiSantriRequest.php @@ -0,0 +1,33 @@ +|string> + */ + public function rules(): array + { + return [ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'mapel_id' => 'required|exists:mata_pelajarans,id', + 'tanggal' => 'required|date', + 'nilai' => 'required|numeric', + 'keterangan' => 'nullable|string', + ]; + } +} diff --git a/website/app/Http/Requests/StorePelanggaranRequest.php b/website/app/Http/Requests/StorePelanggaranRequest.php new file mode 100644 index 0000000..212e324 --- /dev/null +++ b/website/app/Http/Requests/StorePelanggaranRequest.php @@ -0,0 +1,32 @@ +|string> + */ + public function rules(): array + { + return [ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'jenis_pelanggaran' => 'required|string', + 'point_pelanggaran' => 'required|integer', + 'saran' => 'nullable|string', + ]; + } +} diff --git a/website/app/Http/Requests/StorePrestasiRequest.php b/website/app/Http/Requests/StorePrestasiRequest.php new file mode 100644 index 0000000..0cbb1f9 --- /dev/null +++ b/website/app/Http/Requests/StorePrestasiRequest.php @@ -0,0 +1,31 @@ +|string> + */ + public function rules(): array + { + return [ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'nama_perlombaan' => 'required|string', + 'keterangan' => 'nullable|string', + ]; + } +} diff --git a/website/app/Http/Requests/StoreSantriRequest.php b/website/app/Http/Requests/StoreSantriRequest.php new file mode 100644 index 0000000..0b9c5e8 --- /dev/null +++ b/website/app/Http/Requests/StoreSantriRequest.php @@ -0,0 +1,36 @@ +|string> + */ + public function rules(): array + { + return [ + 'nama' => 'required|string|max:255', + 'kelas_id' => 'required|exists:kelas,id', + 'alamat' => 'required|string', + 'tanggal_lahir' => 'required|date', + 'jenis_kelamin' => 'required|in:L,P', + 'tempat_lahir' => 'required|string', + 'no_telp' => 'nullable|string|max:20', // ⬅️ tambahkan ini + 'foto' => 'nullable|image|max:2048', + ]; + } + +} diff --git a/website/app/Http/Requests/StoreSemesterRequest.php b/website/app/Http/Requests/StoreSemesterRequest.php new file mode 100644 index 0000000..0302d18 --- /dev/null +++ b/website/app/Http/Requests/StoreSemesterRequest.php @@ -0,0 +1,30 @@ +|string> + */ + public function rules(): array + { + return [ + 'semester' => 'required|string|max:255', + 'tahun_ajaran' => 'required|string|max:255', + 'is_active' => 'nullable|boolean', + ]; + } +} diff --git a/website/app/Http/Requests/UpdateAbsensiRequest.php b/website/app/Http/Requests/UpdateAbsensiRequest.php new file mode 100644 index 0000000..097f63c --- /dev/null +++ b/website/app/Http/Requests/UpdateAbsensiRequest.php @@ -0,0 +1,32 @@ +|string> + */ + public function rules(): array + { + return [ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'tanggal' => 'required|date', + 'status' => 'required|in:hadir,izin,sakit,alfa', + 'keterangan' => 'nullable|string', + ]; + } +} diff --git a/website/app/Http/Requests/UpdateGuruRequest.php b/website/app/Http/Requests/UpdateGuruRequest.php new file mode 100644 index 0000000..1ee522d --- /dev/null +++ b/website/app/Http/Requests/UpdateGuruRequest.php @@ -0,0 +1,33 @@ +|string> + */ + public function rules(): array + { + return [ + 'nama' => 'required|string|max:255', + 'nip' => 'required|string|unique:gurus,nip,' . $this->route('guru')->id, + 'alamat' => 'nullable|string', + 'tanggal_lahir' => 'nullable|date', + 'jenis_kelamin' => 'required|in:L,P', + 'user_id' => 'nullable|integer|exists:users,id', + ]; + } +} diff --git a/website/app/Http/Requests/UpdateJadwalRequest.php b/website/app/Http/Requests/UpdateJadwalRequest.php new file mode 100644 index 0000000..6f8eb0d --- /dev/null +++ b/website/app/Http/Requests/UpdateJadwalRequest.php @@ -0,0 +1,31 @@ +|string> + */ + public function rules(): array + { + return [ + 'kelas_id' => 'required|exists:kelas,id', + 'hari' => 'required|string', + 'jam_pelajaran' => 'required|string', + 'mata_pelajaran_id' => 'required|exists:mata_pelajarans,id', + ]; + } +} diff --git a/website/app/Http/Requests/UpdateKelasRequest.php b/website/app/Http/Requests/UpdateKelasRequest.php new file mode 100644 index 0000000..0cddbf5 --- /dev/null +++ b/website/app/Http/Requests/UpdateKelasRequest.php @@ -0,0 +1,29 @@ +|string> + */ + public function rules(): array + { + return [ + 'nama_kelas' => 'required|string|max:255', + 'wali_kelas_id' => 'nullable|exists:gurus,id', + ]; + } +} diff --git a/website/app/Http/Requests/UpdateMataPelajaranRequest.php b/website/app/Http/Requests/UpdateMataPelajaranRequest.php new file mode 100644 index 0000000..d77f484 --- /dev/null +++ b/website/app/Http/Requests/UpdateMataPelajaranRequest.php @@ -0,0 +1,29 @@ +|string> + */ + public function rules(): array + { + return [ + 'kode_mapel' => 'required|string|unique:mata_pelajarans,kode_mapel,' . $this->route('mata_pelajaran')->id, + 'nama_mapel' => 'required|string|max:255', + ]; + } +} diff --git a/website/app/Http/Requests/UpdateNilaiSantriRequest.php b/website/app/Http/Requests/UpdateNilaiSantriRequest.php new file mode 100644 index 0000000..0a3092b --- /dev/null +++ b/website/app/Http/Requests/UpdateNilaiSantriRequest.php @@ -0,0 +1,33 @@ +|string> + */ + public function rules(): array + { + return [ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'mapel_id' => 'required|exists:mata_pelajarans,id', + 'tanggal' => 'required|date', + 'nilai' => 'required|numeric', + 'keterangan' => 'nullable|string', + ]; + } +} diff --git a/website/app/Http/Requests/UpdatePelanggaranRequest.php b/website/app/Http/Requests/UpdatePelanggaranRequest.php new file mode 100644 index 0000000..03ad690 --- /dev/null +++ b/website/app/Http/Requests/UpdatePelanggaranRequest.php @@ -0,0 +1,32 @@ +|string> + */ + public function rules(): array + { + return [ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'jenis_pelanggaran' => 'required|string', + 'point_pelanggaran' => 'required|integer', + 'saran' => 'nullable|string', + ]; + } +} diff --git a/website/app/Http/Requests/UpdatePrestasiRequest.php b/website/app/Http/Requests/UpdatePrestasiRequest.php new file mode 100644 index 0000000..afb3cc9 --- /dev/null +++ b/website/app/Http/Requests/UpdatePrestasiRequest.php @@ -0,0 +1,31 @@ +|string> + */ + public function rules(): array + { + return [ + 'santri_id' => 'required|exists:santris,id', + 'kelas_id' => 'required|exists:kelas,id', + 'nama_perlombaan' => 'required|string', + 'keterangan' => 'nullable|string', + ]; + } +} diff --git a/website/app/Http/Requests/UpdateSantriRequest.php b/website/app/Http/Requests/UpdateSantriRequest.php new file mode 100644 index 0000000..e213fe9 --- /dev/null +++ b/website/app/Http/Requests/UpdateSantriRequest.php @@ -0,0 +1,35 @@ +|string> + */ + public function rules(): array + { + return [ + 'nama' => 'required|string|max:255', + 'nis' => 'required|string|unique:santris,nis,' . $this->route('santri')->id, + 'kelas_id' => 'nullable|integer|exists:kelas,id', + 'alamat' => 'nullable|string', + 'tanggal_lahir' => 'nullable|date', + 'jenis_kelamin' => 'required|in:L,P', + 'user_id' => 'nullable|integer|exists:users,id', + 'foto' => 'nullable|image|max:2048', + ]; + } +} diff --git a/website/app/Http/Requests/UpdateSemesterRequest.php b/website/app/Http/Requests/UpdateSemesterRequest.php new file mode 100644 index 0000000..d0fea5e --- /dev/null +++ b/website/app/Http/Requests/UpdateSemesterRequest.php @@ -0,0 +1,30 @@ +|string> + */ + public function rules(): array + { + return [ + 'semester' => 'required|string|max:255', + 'tahun_ajaran' => 'required|string|max:255', + 'is_active' => 'nullable|boolean', + ]; + } +} diff --git a/website/app/Http/Resources/BeritaResource.php b/website/app/Http/Resources/BeritaResource.php new file mode 100644 index 0000000..9cef6b5 --- /dev/null +++ b/website/app/Http/Resources/BeritaResource.php @@ -0,0 +1,31 @@ + + */ + public function toArray($request) + { + return [ + 'id' => $this->id, + 'judul' => $this->judul, + 'kategori' => $this->kategori, + 'ringkasan' => $this->ringkasan, + 'isi' => $this->isi, + 'gambar' => $this->gambar, + 'gambar_url' => $this->gambar_url, + 'penulis' => $this->penulis, + 'status' => $this->status, + 'created_at' => $this->created_at, + 'updated_at' => $this->updated_at, + ]; + } +} \ No newline at end of file diff --git a/website/app/Imports/SantrisImport.php b/website/app/Imports/SantrisImport.php new file mode 100644 index 0000000..2ba37e3 --- /dev/null +++ b/website/app/Imports/SantrisImport.php @@ -0,0 +1,33 @@ + $row['nama'], + 'username' => $row['nis'], // atau kolom username dari excel + 'password' => Hash::make($row['nis']), // default password NIS + 'role' => 'santri', + 'status' => 'aktif', + ]); + + return new Santri([ + 'user_id' => $user->id, + 'nama' => $row['nama'], + 'nis' => $row['nis'], + 'kelas_id' => $row['kelas_id'], + 'alamat' => $row['alamat'], + 'tanggal_lahir' => $row['tanggal_lahir'], + 'jenis_kelamin' => $row['jenis_kelamin'], + ]); + } +} diff --git a/website/app/Models/Absensi.php b/website/app/Models/Absensi.php new file mode 100644 index 0000000..5d190eb --- /dev/null +++ b/website/app/Models/Absensi.php @@ -0,0 +1,33 @@ +belongsTo(\App\Models\Santri::class); + } + + public function kelas() + { + return $this->belongsTo(\App\Models\Kelas::class); + } + + public function guru() + { + return $this->belongsTo(\App\Models\Guru::class); + } +} diff --git a/website/app/Models/Alumni.php b/website/app/Models/Alumni.php new file mode 100644 index 0000000..c09c1a0 --- /dev/null +++ b/website/app/Models/Alumni.php @@ -0,0 +1,33 @@ +foto) { + return asset('storage/' . $this->foto); + } + return null; + } + + public function santri() + { + return $this->belongsTo(\App\Models\Santri::class); + } +} diff --git a/website/app/Models/Berita.php b/website/app/Models/Berita.php new file mode 100644 index 0000000..12323fc --- /dev/null +++ b/website/app/Models/Berita.php @@ -0,0 +1,58 @@ +belongsTo(\App\Models\User::class); + } + + /** + * Get the image URL attribute + */ + public function getGambarUrlAttribute() + { + if ($this->gambar) { + return asset('storage/' . $this->gambar); + } + return null; + } + + /** + * Scope for published berita + */ + public function scopePublished($query) + { + return $query->where('status', 'published'); + } + + /** + * Scope for draft berita + */ + public function scopeDraft($query) + { + return $query->where('status', 'draft'); + } +} diff --git a/website/app/Models/CatatanKesehatan.php b/website/app/Models/CatatanKesehatan.php new file mode 100644 index 0000000..d8b1d29 --- /dev/null +++ b/website/app/Models/CatatanKesehatan.php @@ -0,0 +1,27 @@ +belongsTo(\App\Models\Santri::class); + } + public function kelas() + { + return $this->belongsTo(\App\Models\Kelas::class); + } +} diff --git a/website/app/Models/FcmToken.php b/website/app/Models/FcmToken.php new file mode 100644 index 0000000..3ba414a --- /dev/null +++ b/website/app/Models/FcmToken.php @@ -0,0 +1,16 @@ +belongsTo(User::class); + } +} \ No newline at end of file diff --git a/website/app/Models/Guru.php b/website/app/Models/Guru.php new file mode 100644 index 0000000..60b7fb9 --- /dev/null +++ b/website/app/Models/Guru.php @@ -0,0 +1,58 @@ +foto) { + return asset('storage/' . $this->foto); + } + return null; + } + + // app/Models/Guru.php + public static function generateCodeGuru() + { + $lastGuru = self::orderBy('id', 'desc')->first(); + + if ($lastGuru) { + $lastKode = intval($lastGuru->code_guru); // ganti jadi code_guru + return str_pad($lastKode + 1, 4, '0', STR_PAD_LEFT); + } + + return '0001'; // mulai dari 0001 + } + + + public function user() + { + return $this->belongsTo(User::class); + } + + public function kelas() + { + return $this->hasMany(Kelas::class, 'wali_kelas_id'); + } +} diff --git a/website/app/Models/Jadwal.php b/website/app/Models/Jadwal.php new file mode 100644 index 0000000..4c2db1e --- /dev/null +++ b/website/app/Models/Jadwal.php @@ -0,0 +1,28 @@ +belongsTo(\App\Models\Kelas::class); + } + + public function mataPelajaran() + { + return $this->belongsTo(\App\Models\MataPelajaran::class); + } +} diff --git a/website/app/Models/Kelas.php b/website/app/Models/Kelas.php new file mode 100644 index 0000000..b80076b --- /dev/null +++ b/website/app/Models/Kelas.php @@ -0,0 +1,28 @@ +belongsTo(\App\Models\Guru::class, 'wali_kelas_id'); + } + + public function prestasis() + { + return $this->hasMany(Prestasi::class); + } +} diff --git a/website/app/Models/MataPelajaran.php b/website/app/Models/MataPelajaran.php new file mode 100644 index 0000000..25daecb --- /dev/null +++ b/website/app/Models/MataPelajaran.php @@ -0,0 +1,18 @@ +belongsTo(User::class, 'santri_id'); + } + public function kelas() + { + return $this->belongsTo(\App\Models\Kelas::class); + } + public function mapel() + { + return $this->belongsTo(\App\Models\MataPelajaran::class, 'mapel_id'); + } + public function mataPelajaran() + { + return $this->belongsTo(\App\Models\MataPelajaran::class, 'mapel_id'); + } + public function semester() + { + return $this->belongsTo(\App\Models\Semester::class, 'semester_id'); + } +} diff --git a/website/app/Models/Pelanggaran.php b/website/app/Models/Pelanggaran.php new file mode 100644 index 0000000..7673497 --- /dev/null +++ b/website/app/Models/Pelanggaran.php @@ -0,0 +1,36 @@ +belongsTo(User::class); + } + + public function santri() + { + return $this->belongsTo(Santri::class); + } + + public function kelas() + { + return $this->belongsTo(Kelas::class); + } +} diff --git a/website/app/Models/Pembayaran.php b/website/app/Models/Pembayaran.php new file mode 100644 index 0000000..5edbc8f --- /dev/null +++ b/website/app/Models/Pembayaran.php @@ -0,0 +1,37 @@ +bukti_pembayaran) { + return asset('storage/' . $this->bukti_pembayaran); + } + return null; + } + + public function santri() + { + return $this->belongsTo(\App\Models\Santri::class); + } + public function kelas() + { + return $this->belongsTo(\App\Models\Kelas::class); + } +} diff --git a/website/app/Models/Prestasi.php b/website/app/Models/Prestasi.php new file mode 100644 index 0000000..4adb191 --- /dev/null +++ b/website/app/Models/Prestasi.php @@ -0,0 +1,41 @@ +belongsTo(User::class); + } + + public function santri() + { + return $this->belongsTo(Santri::class); + } + + public function kelas() + { + return $this->belongsTo(Kelas::class); + } +} diff --git a/website/app/Models/Santri.php b/website/app/Models/Santri.php new file mode 100644 index 0000000..b241fdc --- /dev/null +++ b/website/app/Models/Santri.php @@ -0,0 +1,71 @@ +foto) { + return asset('storage/' . $this->foto); + } + return null; + } + + public static function generateNis() + { + $lastSantri = self::orderBy('id', 'desc')->first(); + + if ($lastSantri) { + $lastNis = intval($lastSantri->nis); + return str_pad($lastNis + 1, 6, '0', STR_PAD_LEFT); + } + + return '000001'; + } + + public function user() + { + return $this->belongsTo(User::class); + } + + public function kelas() + { + return $this->belongsTo(Kelas::class); + } + + public function prestasis() + { + return $this->hasMany(Prestasi::class); + } + + public function scopeActive($query) + { + return $query->where('status', 'aktif'); + } + +} diff --git a/website/app/Models/Semester.php b/website/app/Models/Semester.php new file mode 100644 index 0000000..456444d --- /dev/null +++ b/website/app/Models/Semester.php @@ -0,0 +1,20 @@ + */ + use HasApiTokens, HasFactory, Notifiable; + + /** + * The attributes that are mass assignable. + * + * @var list + */ + protected $fillable = [ + 'name', + 'username', + 'password', + 'role', + ]; + + /** + * The attributes that should be hidden for serialization. + * + * @var list + */ + protected $hidden = [ + 'password', + 'remember_token', + ]; + + /** + * Get the attributes that should be cast. + * + * @return array + */ + protected function casts(): array + { + return [ + 'email_verified_at' => 'datetime', + 'password' => 'hashed', + ]; + } + + /** + * Cek apakah user adalah admin + */ + public function isAdmin() + { + return $this->role === 'admin'; + } + + /** + * Cek apakah user adalah guru + */ + public function isGuru() + { + return $this->role === 'guru'; + } + + public function santri() + { + return $this->hasOne(Santri::class); + } + + public function guru() + { + return $this->hasOne(Guru::class); + } + + /** + * Route notifications for the mail channel. + * + * @param \Illuminate\Notifications\Notification $notification + * @return mixed + */ + public function routeNotificationForMail($notification) + { + // Jika ingin mengirim email, return null atau email default + return null; + } +} diff --git a/website/app/Notifications/NilaiBaruNotification.php b/website/app/Notifications/NilaiBaruNotification.php new file mode 100644 index 0000000..cc08b6e --- /dev/null +++ b/website/app/Notifications/NilaiBaruNotification.php @@ -0,0 +1,36 @@ +judul = $judul; + $this->pesan = $pesan; + } + + public function via($notifiable) + { + return [FcmChannel::class]; + } + + public function toFcm($notifiable) + { + return FcmMessage::create() + ->setData(['type' => 'nilai_baru']) + ->setNotification([ + 'title' => $this->judul, + 'body' => $this->pesan, + ]); + } +} \ No newline at end of file diff --git a/website/app/Providers/AppServiceProvider.php b/website/app/Providers/AppServiceProvider.php new file mode 100644 index 0000000..452e6b6 --- /dev/null +++ b/website/app/Providers/AppServiceProvider.php @@ -0,0 +1,24 @@ + + */ + protected $policies = [ + // 'App\Models\Model' => 'App\Policies\ModelPolicy', + ]; + + /** + * Register any authentication / authorization services. + */ + public function boot(): void + { + // + } +} diff --git a/website/app/Providers/EventServiceProvider.php b/website/app/Providers/EventServiceProvider.php new file mode 100644 index 0000000..eb9dec2 --- /dev/null +++ b/website/app/Providers/EventServiceProvider.php @@ -0,0 +1,25 @@ +> + */ + protected $listen = [ + // + ]; + + /** + * Register any events for your application. + */ + public function boot(): void + { + // + } +} diff --git a/website/app/Providers/RouteServiceProvider.php b/website/app/Providers/RouteServiceProvider.php new file mode 100644 index 0000000..1ef3cfa --- /dev/null +++ b/website/app/Providers/RouteServiceProvider.php @@ -0,0 +1,23 @@ +routes(function () { + Route::middleware('api') + ->prefix('api') + ->group(base_path('routes/api.php')); + + Route::middleware('web') + ->group(base_path('routes/web.php')); + }); + } +} diff --git a/website/app/View/Components/AppLayout.php b/website/app/View/Components/AppLayout.php new file mode 100644 index 0000000..de0d46f --- /dev/null +++ b/website/app/View/Components/AppLayout.php @@ -0,0 +1,17 @@ +handleCommand(new ArgvInput); + +exit($status); diff --git a/website/assets/404.png b/website/assets/404.png new file mode 100644 index 0000000..8ef7c63 Binary files /dev/null and b/website/assets/404.png differ diff --git a/website/assets/default_profile.png b/website/assets/default_profile.png new file mode 100644 index 0000000..9d60fde Binary files /dev/null and b/website/assets/default_profile.png differ diff --git a/website/assets/logo.png b/website/assets/logo.png new file mode 100644 index 0000000..45d6ac2 Binary files /dev/null and b/website/assets/logo.png differ diff --git a/website/bootstrap/app.php b/website/bootstrap/app.php new file mode 100644 index 0000000..c183276 --- /dev/null +++ b/website/bootstrap/app.php @@ -0,0 +1,18 @@ +withRouting( + web: __DIR__.'/../routes/web.php', + commands: __DIR__.'/../routes/console.php', + health: '/up', + ) + ->withMiddleware(function (Middleware $middleware): void { + // + }) + ->withExceptions(function (Exceptions $exceptions): void { + // + })->create(); diff --git a/website/bootstrap/cache/.gitignore b/website/bootstrap/cache/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/website/bootstrap/cache/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/website/bootstrap/providers.php b/website/bootstrap/providers.php new file mode 100644 index 0000000..f4ecddf --- /dev/null +++ b/website/bootstrap/providers.php @@ -0,0 +1,6 @@ +=5.0.0" + }, + "require-dev": { + "doctrine/dbal": "^4.0.0", + "nesbot/carbon": "^2.71.0 || ^3.0.0", + "phpunit/phpunit": "^10.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Carbon\\Doctrine\\": "src/Carbon/Doctrine/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "KyleKatarn", + "email": "kylekatarnls@gmail.com" + } + ], + "description": "Types to use Carbon in Doctrine", + "keywords": [ + "carbon", + "date", + "datetime", + "doctrine", + "time" + ], + "support": { + "issues": "https://github.com/CarbonPHP/carbon-doctrine-types/issues", + "source": "https://github.com/CarbonPHP/carbon-doctrine-types/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon", + "type": "open_collective" + }, + { + "url": "https://tidelift.com/funding/github/packagist/nesbot/carbon", + "type": "tidelift" + } + ], + "time": "2024-02-09T16:56:22+00:00" + }, + { + "name": "composer/pcre", + "version": "3.3.2", + "source": { + "type": "git", + "url": "https://github.com/composer/pcre.git", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/pcre/zipball/b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "reference": "b2bed4734f0cc156ee1fe9c0da2550420d99a21e", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<1.11.10" + }, + "require-dev": { + "phpstan/phpstan": "^1.12 || ^2", + "phpstan/phpstan-strict-rules": "^1 || ^2", + "phpunit/phpunit": "^8 || ^9" + }, + "type": "library", + "extra": { + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Pcre\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + } + ], + "description": "PCRE wrapping library that offers type-safe preg_* replacements.", + "keywords": [ + "PCRE", + "preg", + "regex", + "regular expression" + ], + "support": { + "issues": "https://github.com/composer/pcre/issues", + "source": "https://github.com/composer/pcre/tree/3.3.2" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-11-12T16:29:46+00:00" + }, + { + "name": "composer/semver", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-09-19T14:15:21+00:00" + }, + { + "name": "dflydev/dot-access-data", + "version": "v3.0.3", + "source": { + "type": "git", + "url": "https://github.com/dflydev/dflydev-dot-access-data.git", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dflydev/dflydev-dot-access-data/zipball/a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "reference": "a23a2bf4f31d3518f3ecb38660c95715dfead60f", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^0.12.42", + "phpunit/phpunit": "^7.5 || ^8.5 || ^9.3", + "scrutinizer/ocular": "1.6.0", + "squizlabs/php_codesniffer": "^3.5", + "vimeo/psalm": "^4.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Dflydev\\DotAccessData\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Dragonfly Development Inc.", + "email": "info@dflydev.com", + "homepage": "http://dflydev.com" + }, + { + "name": "Beau Simensen", + "email": "beau@dflydev.com", + "homepage": "http://beausimensen.com" + }, + { + "name": "Carlos Frutos", + "email": "carlos@kiwing.it", + "homepage": "https://github.com/cfrutos" + }, + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com" + } + ], + "description": "Given a deep data structure, access data by dot notation.", + "homepage": "https://github.com/dflydev/dflydev-dot-access-data", + "keywords": [ + "access", + "data", + "dot", + "notation" + ], + "support": { + "issues": "https://github.com/dflydev/dflydev-dot-access-data/issues", + "source": "https://github.com/dflydev/dflydev-dot-access-data/tree/v3.0.3" + }, + "time": "2024-07-08T12:26:09+00:00" + }, + { + "name": "doctrine/inflector", + "version": "2.0.10", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^11.0", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.0.10" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2024-02-18T20:23:39+00:00" + }, + { + "name": "doctrine/lexer", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/doctrine/lexer.git", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/lexer/zipball/31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "reference": "31ad66abc0fc9e1a1f2d9bc6a42668d2fbbcd6dd", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "doctrine/coding-standard": "^12", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^10.5", + "psalm/plugin-phpunit": "^0.18.3", + "vimeo/psalm": "^5.21" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Common\\Lexer\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Lexer parser library that can be used in Top-Down, Recursive Descent Parsers.", + "homepage": "https://www.doctrine-project.org/projects/lexer.html", + "keywords": [ + "annotations", + "docblock", + "lexer", + "parser", + "php" + ], + "support": { + "issues": "https://github.com/doctrine/lexer/issues", + "source": "https://github.com/doctrine/lexer/tree/3.0.1" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Flexer", + "type": "tidelift" + } + ], + "time": "2024-02-05T11:56:58+00:00" + }, + { + "name": "dragonmantank/cron-expression", + "version": "v3.4.0", + "source": { + "type": "git", + "url": "https://github.com/dragonmantank/cron-expression.git", + "reference": "8c784d071debd117328803d86b2097615b457500" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/dragonmantank/cron-expression/zipball/8c784d071debd117328803d86b2097615b457500", + "reference": "8c784d071debd117328803d86b2097615b457500", + "shasum": "" + }, + "require": { + "php": "^7.2|^8.0", + "webmozart/assert": "^1.0" + }, + "replace": { + "mtdowling/cron-expression": "^1.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.0", + "phpstan/phpstan": "^1.0", + "phpunit/phpunit": "^7.0|^8.0|^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Cron\\": "src/Cron/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Tankersley", + "email": "chris@ctankersley.com", + "homepage": "https://github.com/dragonmantank" + } + ], + "description": "CRON for PHP: Calculate the next or previous run date and determine if a CRON expression is due", + "keywords": [ + "cron", + "schedule" + ], + "support": { + "issues": "https://github.com/dragonmantank/cron-expression/issues", + "source": "https://github.com/dragonmantank/cron-expression/tree/v3.4.0" + }, + "funding": [ + { + "url": "https://github.com/dragonmantank", + "type": "github" + } + ], + "time": "2024-10-09T13:47:03+00:00" + }, + { + "name": "egulias/email-validator", + "version": "4.0.4", + "source": { + "type": "git", + "url": "https://github.com/egulias/EmailValidator.git", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/egulias/EmailValidator/zipball/d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "reference": "d42c8731f0624ad6bdc8d3e5e9a4524f68801cfa", + "shasum": "" + }, + "require": { + "doctrine/lexer": "^2.0 || ^3.0", + "php": ">=8.1", + "symfony/polyfill-intl-idn": "^1.26" + }, + "require-dev": { + "phpunit/phpunit": "^10.2", + "vimeo/psalm": "^5.12" + }, + "suggest": { + "ext-intl": "PHP Internationalization Libraries are required to use the SpoofChecking validation" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Egulias\\EmailValidator\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Eduardo Gulias Davis" + } + ], + "description": "A library for validating emails against several RFCs", + "homepage": "https://github.com/egulias/EmailValidator", + "keywords": [ + "email", + "emailvalidation", + "emailvalidator", + "validation", + "validator" + ], + "support": { + "issues": "https://github.com/egulias/EmailValidator/issues", + "source": "https://github.com/egulias/EmailValidator/tree/4.0.4" + }, + "funding": [ + { + "url": "https://github.com/egulias", + "type": "github" + } + ], + "time": "2025-03-06T22:45:56+00:00" + }, + { + "name": "ezyang/htmlpurifier", + "version": "v4.18.0", + "source": { + "type": "git", + "url": "https://github.com/ezyang/htmlpurifier.git", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ezyang/htmlpurifier/zipball/cb56001e54359df7ae76dc522d08845dc741621b", + "reference": "cb56001e54359df7ae76dc522d08845dc741621b", + "shasum": "" + }, + "require": { + "php": "~5.6.0 || ~7.0.0 || ~7.1.0 || ~7.2.0 || ~7.3.0 || ~7.4.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" + }, + "require-dev": { + "cerdic/css-tidy": "^1.7 || ^2.0", + "simpletest/simpletest": "dev-master" + }, + "suggest": { + "cerdic/css-tidy": "If you want to use the filter 'Filter.ExtractStyleBlocks'.", + "ext-bcmath": "Used for unit conversion and imagecrash protection", + "ext-iconv": "Converts text to and from non-UTF-8 encodings", + "ext-tidy": "Used for pretty-printing HTML" + }, + "type": "library", + "autoload": { + "files": [ + "library/HTMLPurifier.composer.php" + ], + "psr-0": { + "HTMLPurifier": "library/" + }, + "exclude-from-classmap": [ + "/library/HTMLPurifier/Language/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-2.1-or-later" + ], + "authors": [ + { + "name": "Edward Z. Yang", + "email": "admin@htmlpurifier.org", + "homepage": "http://ezyang.com" + } + ], + "description": "Standards compliant HTML filter written in PHP", + "homepage": "http://htmlpurifier.org/", + "keywords": [ + "html" + ], + "support": { + "issues": "https://github.com/ezyang/htmlpurifier/issues", + "source": "https://github.com/ezyang/htmlpurifier/tree/v4.18.0" + }, + "time": "2024-11-01T03:51:45+00:00" + }, + { + "name": "fig/http-message-util", + "version": "1.1.5", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message-util.git", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message-util/zipball/9d94dc0154230ac39e5bf89398b324a86f63f765", + "reference": "9d94dc0154230ac39e5bf89398b324a86f63f765", + "shasum": "" + }, + "require": { + "php": "^5.3 || ^7.0 || ^8.0" + }, + "suggest": { + "psr/http-message": "The package containing the PSR-7 interfaces" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Fig\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Utility classes and constants for use with PSR-7 (psr/http-message)", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "issues": "https://github.com/php-fig/http-message-util/issues", + "source": "https://github.com/php-fig/http-message-util/tree/1.1.5" + }, + "time": "2020-11-24T22:02:12+00:00" + }, + { + "name": "firebase/php-jwt", + "version": "v6.11.1", + "source": { + "type": "git", + "url": "https://github.com/firebase/php-jwt.git", + "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/firebase/php-jwt/zipball/d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", + "reference": "d1e91ecf8c598d073d0995afa8cd5c75c6e19e66", + "shasum": "" + }, + "require": { + "php": "^8.0" + }, + "require-dev": { + "guzzlehttp/guzzle": "^7.4", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.5", + "psr/cache": "^2.0||^3.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0" + }, + "suggest": { + "ext-sodium": "Support EdDSA (Ed25519) signatures", + "paragonie/sodium_compat": "Support EdDSA (Ed25519) signatures when libsodium is not present" + }, + "type": "library", + "autoload": { + "psr-4": { + "Firebase\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Neuman Vong", + "email": "neuman+pear@twilio.com", + "role": "Developer" + }, + { + "name": "Anant Narayanan", + "email": "anant@php.net", + "role": "Developer" + } + ], + "description": "A simple library to encode and decode JSON Web Tokens (JWT) in PHP. Should conform to the current spec.", + "homepage": "https://github.com/firebase/php-jwt", + "keywords": [ + "jwt", + "php" + ], + "support": { + "issues": "https://github.com/firebase/php-jwt/issues", + "source": "https://github.com/firebase/php-jwt/tree/v6.11.1" + }, + "time": "2025-04-09T20:32:01+00:00" + }, + { + "name": "fruitcake/php-cors", + "version": "v1.3.0", + "source": { + "type": "git", + "url": "https://github.com/fruitcake/php-cors.git", + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/fruitcake/php-cors/zipball/3d158f36e7875e2f040f37bc0573956240a5a38b", + "reference": "3d158f36e7875e2f040f37bc0573956240a5a38b", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0", + "symfony/http-foundation": "^4.4|^5.4|^6|^7" + }, + "require-dev": { + "phpstan/phpstan": "^1.4", + "phpunit/phpunit": "^9", + "squizlabs/php_codesniffer": "^3.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "Fruitcake\\Cors\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fruitcake", + "homepage": "https://fruitcake.nl" + }, + { + "name": "Barryvdh", + "email": "barryvdh@gmail.com" + } + ], + "description": "Cross-origin resource sharing library for the Symfony HttpFoundation", + "homepage": "https://github.com/fruitcake/php-cors", + "keywords": [ + "cors", + "laravel", + "symfony" + ], + "support": { + "issues": "https://github.com/fruitcake/php-cors/issues", + "source": "https://github.com/fruitcake/php-cors/tree/v1.3.0" + }, + "funding": [ + { + "url": "https://fruitcake.nl", + "type": "custom" + }, + { + "url": "https://github.com/barryvdh", + "type": "github" + } + ], + "time": "2023-10-12T05:21:21+00:00" + }, + { + "name": "google/auth", + "version": "v1.47.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-auth-library-php.git", + "reference": "d6389aae7c009daceaa8da9b7942d8df6969f6d9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-auth-library-php/zipball/d6389aae7c009daceaa8da9b7942d8df6969f6d9", + "reference": "d6389aae7c009daceaa8da9b7942d8df6969f6d9", + "shasum": "" + }, + "require": { + "firebase/php-jwt": "^6.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.4.5", + "php": "^8.0", + "psr/cache": "^2.0||^3.0", + "psr/http-message": "^1.1||^2.0", + "psr/log": "^3.0" + }, + "require-dev": { + "guzzlehttp/promises": "^2.0", + "kelvinmo/simplejwt": "0.7.1", + "phpseclib/phpseclib": "^3.0.35", + "phpspec/prophecy-phpunit": "^2.1", + "phpunit/phpunit": "^9.6", + "sebastian/comparator": ">=1.2.3", + "squizlabs/php_codesniffer": "^3.5", + "symfony/process": "^6.0||^7.0", + "webmozart/assert": "^1.11" + }, + "suggest": { + "phpseclib/phpseclib": "May be used in place of OpenSSL for signing strings or for token management. Please require version ^2." + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\Auth\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Auth Library for PHP", + "homepage": "https://github.com/google/google-auth-library-php", + "keywords": [ + "Authentication", + "google", + "oauth2" + ], + "support": { + "docs": "https://cloud.google.com/php/docs/reference/auth/latest", + "issues": "https://github.com/googleapis/google-auth-library-php/issues", + "source": "https://github.com/googleapis/google-auth-library-php/tree/v1.47.0" + }, + "time": "2025-04-15T21:47:20+00:00" + }, + { + "name": "google/cloud-core", + "version": "v1.63.0", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-cloud-php-core.git", + "reference": "14461f7b53b261caeed7174f9d704d10881b02c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-cloud-php-core/zipball/14461f7b53b261caeed7174f9d704d10881b02c2", + "reference": "14461f7b53b261caeed7174f9d704d10881b02c2", + "shasum": "" + }, + "require": { + "google/auth": "^1.34", + "google/gax": "^1.36.0", + "guzzlehttp/guzzle": "^6.5.8||^7.4.4", + "guzzlehttp/promises": "^1.4||^2.0", + "guzzlehttp/psr7": "^2.6", + "monolog/monolog": "^2.9||^3.0", + "php": "^8.0", + "psr/http-message": "^1.0||^2.0", + "rize/uri-template": "~0.3||~0.4" + }, + "require-dev": { + "erusev/parsedown": "^1.6", + "google/cloud-common-protos": "~0.5", + "opis/closure": "^3", + "phpdocumentor/reflection": "^5.3.3||^6.0", + "phpdocumentor/reflection-docblock": "^5.3", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.0", + "squizlabs/php_codesniffer": "2.*" + }, + "suggest": { + "opis/closure": "May be used to serialize closures to process jobs in the batch daemon. Please require version ^3.", + "symfony/lock": "Required for the Spanner cached based session pool. Please require the following commit: 3.3.x-dev#1ba6ac9" + }, + "bin": [ + "bin/google-cloud-batch" + ], + "type": "library", + "extra": { + "component": { + "id": "cloud-core", + "path": "Core", + "entry": "src/ServiceBuilder.php", + "target": "googleapis/google-cloud-php-core.git" + } + }, + "autoload": { + "psr-4": { + "Google\\Cloud\\Core\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google Cloud PHP shared dependency, providing functionality useful to all components.", + "support": { + "source": "https://github.com/googleapis/google-cloud-php-core/tree/v1.63.0" + }, + "time": "2025-06-13T20:36:13+00:00" + }, + { + "name": "google/cloud-storage", + "version": "v1.48.1", + "source": { + "type": "git", + "url": "https://github.com/googleapis/google-cloud-php-storage.git", + "reference": "509b095c3ea44db92c9e62a94b5773563c831821" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/google-cloud-php-storage/zipball/509b095c3ea44db92c9e62a94b5773563c831821", + "reference": "509b095c3ea44db92c9e62a94b5773563c831821", + "shasum": "" + }, + "require": { + "google/cloud-core": "^1.57", + "php": "^8.0", + "ramsey/uuid": "^4.2.3" + }, + "require-dev": { + "erusev/parsedown": "^1.6", + "google/cloud-pubsub": "^2.0", + "phpdocumentor/reflection": "^5.3.3||^6.0", + "phpdocumentor/reflection-docblock": "^5.3", + "phpseclib/phpseclib": "^2.0||^3.0", + "phpspec/prophecy-phpunit": "^2.0", + "phpunit/phpunit": "^9.0", + "squizlabs/php_codesniffer": "2.*" + }, + "suggest": { + "google/cloud-pubsub": "May be used to register a topic to receive bucket notifications.", + "phpseclib/phpseclib": "May be used in place of OpenSSL for creating signed Cloud Storage URLs. Please require version ^2." + }, + "type": "library", + "extra": { + "component": { + "id": "cloud-storage", + "path": "Storage", + "entry": "src/StorageClient.php", + "target": "googleapis/google-cloud-php-storage.git" + } + }, + "autoload": { + "psr-4": { + "Google\\Cloud\\Storage\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Cloud Storage Client for PHP", + "support": { + "source": "https://github.com/googleapis/google-cloud-php-storage/tree/v1.48.1" + }, + "time": "2025-05-20T19:49:54+00:00" + }, + { + "name": "google/common-protos", + "version": "4.12.1", + "source": { + "type": "git", + "url": "https://github.com/googleapis/common-protos-php.git", + "reference": "70c4eb1abab5484a23c17a43b0d455259f5d8c1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/common-protos-php/zipball/70c4eb1abab5484a23c17a43b0d455259f5d8c1b", + "reference": "70c4eb1abab5484a23c17a43b0d455259f5d8c1b", + "shasum": "" + }, + "require": { + "google/protobuf": "^v3.25.3||^4.26.1", + "php": "^8.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6" + }, + "type": "library", + "extra": { + "component": { + "id": "common-protos", + "path": "CommonProtos", + "entry": "README.md", + "target": "googleapis/common-protos-php.git" + } + }, + "autoload": { + "psr-4": { + "Google\\Api\\": "src/Api", + "Google\\Iam\\": "src/Iam", + "Google\\Rpc\\": "src/Rpc", + "Google\\Type\\": "src/Type", + "Google\\Cloud\\": "src/Cloud", + "GPBMetadata\\Google\\Api\\": "metadata/Api", + "GPBMetadata\\Google\\Iam\\": "metadata/Iam", + "GPBMetadata\\Google\\Rpc\\": "metadata/Rpc", + "GPBMetadata\\Google\\Type\\": "metadata/Type", + "GPBMetadata\\Google\\Cloud\\": "metadata/Cloud", + "GPBMetadata\\Google\\Logging\\": "metadata/Logging" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google API Common Protos for PHP", + "homepage": "https://github.com/googleapis/common-protos-php", + "keywords": [ + "google" + ], + "support": { + "source": "https://github.com/googleapis/common-protos-php/tree/v4.12.1" + }, + "time": "2025-05-20T19:49:54+00:00" + }, + { + "name": "google/gax", + "version": "v1.36.1", + "source": { + "type": "git", + "url": "https://github.com/googleapis/gax-php.git", + "reference": "afdac3bc38a3b17d70668115d7b1a97289ac4d72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/gax-php/zipball/afdac3bc38a3b17d70668115d7b1a97289ac4d72", + "reference": "afdac3bc38a3b17d70668115d7b1a97289ac4d72", + "shasum": "" + }, + "require": { + "google/auth": "^1.45", + "google/common-protos": "^4.4", + "google/grpc-gcp": "^0.4", + "google/longrunning": "~0.4", + "google/protobuf": "^v3.25.3||^4.26.1", + "grpc/grpc": "^1.13", + "guzzlehttp/promises": "^2.0", + "guzzlehttp/psr7": "^2.0", + "php": "^8.0", + "ramsey/uuid": "^4.0" + }, + "conflict": { + "ext-protobuf": "<3.7.0" + }, + "require-dev": { + "phpspec/prophecy-phpunit": "^2.1", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^9.6", + "squizlabs/php_codesniffer": "3.*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\ApiCore\\": "src", + "GPBMetadata\\ApiCore\\": "metadata/ApiCore" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "Google API Core for PHP", + "homepage": "https://github.com/googleapis/gax-php", + "keywords": [ + "google" + ], + "support": { + "issues": "https://github.com/googleapis/gax-php/issues", + "source": "https://github.com/googleapis/gax-php/tree/v1.36.1" + }, + "time": "2025-05-20T19:50:43+00:00" + }, + { + "name": "google/grpc-gcp", + "version": "v0.4.1", + "source": { + "type": "git", + "url": "https://github.com/GoogleCloudPlatform/grpc-gcp-php.git", + "reference": "e585b7721bbe806ef45b5c52ae43dfc2bff89968" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GoogleCloudPlatform/grpc-gcp-php/zipball/e585b7721bbe806ef45b5c52ae43dfc2bff89968", + "reference": "e585b7721bbe806ef45b5c52ae43dfc2bff89968", + "shasum": "" + }, + "require": { + "google/auth": "^1.3", + "google/protobuf": "^v3.25.3||^4.26.1", + "grpc/grpc": "^v1.13.0", + "php": "^8.0", + "psr/cache": "^1.0.1||^2.0.0||^3.0.0" + }, + "require-dev": { + "google/cloud-spanner": "^1.7", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Grpc\\Gcp\\": "src/" + }, + "classmap": [ + "src/generated/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "gRPC GCP library for channel management", + "support": { + "issues": "https://github.com/GoogleCloudPlatform/grpc-gcp-php/issues", + "source": "https://github.com/GoogleCloudPlatform/grpc-gcp-php/tree/v0.4.1" + }, + "time": "2025-02-19T21:53:22+00:00" + }, + { + "name": "google/longrunning", + "version": "0.4.7", + "source": { + "type": "git", + "url": "https://github.com/googleapis/php-longrunning.git", + "reference": "624cabb874c10e5ddc9034c999f724894b70a3d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/googleapis/php-longrunning/zipball/624cabb874c10e5ddc9034c999f724894b70a3d3", + "reference": "624cabb874c10e5ddc9034c999f724894b70a3d3", + "shasum": "" + }, + "require-dev": { + "google/gax": "^1.36.0", + "phpunit/phpunit": "^9.0" + }, + "type": "library", + "extra": { + "component": { + "id": "longrunning", + "path": "LongRunning", + "entry": null, + "target": "googleapis/php-longrunning" + } + }, + "autoload": { + "psr-4": { + "Google\\LongRunning\\": "src/LongRunning", + "Google\\ApiCore\\LongRunning\\": "src/ApiCore/LongRunning", + "GPBMetadata\\Google\\Longrunning\\": "metadata/Longrunning" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "Google LongRunning Client for PHP", + "support": { + "source": "https://github.com/googleapis/php-longrunning/tree/v0.4.7" + }, + "time": "2025-01-24T21:24:06+00:00" + }, + { + "name": "google/protobuf", + "version": "v4.31.1", + "source": { + "type": "git", + "url": "https://github.com/protocolbuffers/protobuf-php.git", + "reference": "2b028ce8876254e2acbeceea7d9b573faad41864" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/protocolbuffers/protobuf-php/zipball/2b028ce8876254e2acbeceea7d9b573faad41864", + "reference": "2b028ce8876254e2acbeceea7d9b573faad41864", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": ">=5.0.0" + }, + "suggest": { + "ext-bcmath": "Need to support JSON deserialization" + }, + "type": "library", + "autoload": { + "psr-4": { + "Google\\Protobuf\\": "src/Google/Protobuf", + "GPBMetadata\\Google\\Protobuf\\": "src/GPBMetadata/Google/Protobuf" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "proto library for PHP", + "homepage": "https://developers.google.com/protocol-buffers/", + "keywords": [ + "proto" + ], + "support": { + "source": "https://github.com/protocolbuffers/protobuf-php/tree/v4.31.1" + }, + "time": "2025-05-28T18:52:35+00:00" + }, + { + "name": "graham-campbell/result-type", + "version": "v1.1.3", + "source": { + "type": "git", + "url": "https://github.com/GrahamCampbell/Result-Type.git", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/GrahamCampbell/Result-Type/zipball/3ba905c11371512af9d9bdd27d99b782216b6945", + "reference": "3ba905c11371512af9d9bdd27d99b782216b6945", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "autoload": { + "psr-4": { + "GrahamCampbell\\ResultType\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "An Implementation Of The Result Type", + "keywords": [ + "Graham Campbell", + "GrahamCampbell", + "Result Type", + "Result-Type", + "result" + ], + "support": { + "issues": "https://github.com/GrahamCampbell/Result-Type/issues", + "source": "https://github.com/GrahamCampbell/Result-Type/tree/v1.1.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/graham-campbell/result-type", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:45:45+00:00" + }, + { + "name": "grpc/grpc", + "version": "1.57.0", + "source": { + "type": "git", + "url": "https://github.com/grpc/grpc-php.git", + "reference": "b610c42022ed3a22f831439cb93802f2a4502fdf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/grpc/grpc-php/zipball/b610c42022ed3a22f831439cb93802f2a4502fdf", + "reference": "b610c42022ed3a22f831439cb93802f2a4502fdf", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "google/auth": "^v1.3.0" + }, + "suggest": { + "ext-protobuf": "For better performance, install the protobuf C extension.", + "google/protobuf": "To get started using grpc quickly, install the native protobuf library." + }, + "type": "library", + "autoload": { + "psr-4": { + "Grpc\\": "src/lib/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "description": "gRPC library for PHP", + "homepage": "https://grpc.io", + "keywords": [ + "rpc" + ], + "support": { + "source": "https://github.com/grpc/grpc-php/tree/v1.57.0" + }, + "time": "2023-08-14T23:57:54+00:00" + }, + { + "name": "guzzlehttp/guzzle", + "version": "7.9.3", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "shasum": "" + }, + "require": { + "ext-json": "*", + "guzzlehttp/promises": "^1.5.3 || ^2.0.3", + "guzzlehttp/psr7": "^2.7.0", + "php": "^7.2.5 || ^8.0", + "psr/http-client": "^1.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "provide": { + "psr/http-client-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-curl": "*", + "guzzle/client-integration-tests": "3.0.2", + "php-http/message-factory": "^1.1", + "phpunit/phpunit": "^8.5.39 || ^9.6.20", + "psr/log": "^1.1 || ^2.0 || ^3.0" + }, + "suggest": { + "ext-curl": "Required for CURL handler support", + "ext-intl": "Required for Internationalized Domain Name (IDN) support", + "psr/log": "Required for using the Log middleware" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "files": [ + "src/functions_include.php" + ], + "psr-4": { + "GuzzleHttp\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Jeremy Lindblom", + "email": "jeremeamia@gmail.com", + "homepage": "https://github.com/jeremeamia" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle is a PHP HTTP client library", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "psr-18", + "psr-7", + "rest", + "web service" + ], + "support": { + "issues": "https://github.com/guzzle/guzzle/issues", + "source": "https://github.com/guzzle/guzzle/tree/7.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/guzzle", + "type": "tidelift" + } + ], + "time": "2025-03-27T13:37:11+00:00" + }, + { + "name": "guzzlehttp/promises", + "version": "2.2.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/promises.git", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", + "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Promise\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + } + ], + "description": "Guzzle promises library", + "keywords": [ + "promise" + ], + "support": { + "issues": "https://github.com/guzzle/promises/issues", + "source": "https://github.com/guzzle/promises/tree/2.2.0" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/promises", + "type": "tidelift" + } + ], + "time": "2025-03-27T13:27:01+00:00" + }, + { + "name": "guzzlehttp/psr7", + "version": "2.7.1", + "source": { + "type": "git", + "url": "https://github.com/guzzle/psr7.git", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "psr/http-factory": "^1.0", + "psr/http-message": "^1.1 || ^2.0", + "ralouphie/getallheaders": "^3.0" + }, + "provide": { + "psr/http-factory-implementation": "1.0", + "psr/http-message-implementation": "1.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "http-interop/http-factory-tests": "0.9.0", + "phpunit/phpunit": "^8.5.39 || ^9.6.20" + }, + "suggest": { + "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\Psr7\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://github.com/sagikazarmark" + }, + { + "name": "Tobias Schultze", + "email": "webmaster@tubo-world.de", + "homepage": "https://github.com/Tobion" + }, + { + "name": "Márk Sági-Kazár", + "email": "mark.sagikazar@gmail.com", + "homepage": "https://sagikazarmark.hu" + } + ], + "description": "PSR-7 message implementation that also provides common utility methods", + "keywords": [ + "http", + "message", + "psr-7", + "request", + "response", + "stream", + "uri", + "url" + ], + "support": { + "issues": "https://github.com/guzzle/psr7/issues", + "source": "https://github.com/guzzle/psr7/tree/2.7.1" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/psr7", + "type": "tidelift" + } + ], + "time": "2025-03-27T12:30:47+00:00" + }, + { + "name": "guzzlehttp/uri-template", + "version": "v1.0.4", + "source": { + "type": "git", + "url": "https://github.com/guzzle/uri-template.git", + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", + "reference": "30e286560c137526eccd4ce21b2de477ab0676d2", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "uri-template/tests": "1.0.0" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + } + }, + "autoload": { + "psr-4": { + "GuzzleHttp\\UriTemplate\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + }, + { + "name": "George Mponos", + "email": "gmponos@gmail.com", + "homepage": "https://github.com/gmponos" + }, + { + "name": "Tobias Nyholm", + "email": "tobias.nyholm@gmail.com", + "homepage": "https://github.com/Nyholm" + } + ], + "description": "A polyfill class for uri_template of PHP", + "keywords": [ + "guzzlehttp", + "uri-template" + ], + "support": { + "issues": "https://github.com/guzzle/uri-template/issues", + "source": "https://github.com/guzzle/uri-template/tree/v1.0.4" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://github.com/Nyholm", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/guzzlehttp/uri-template", + "type": "tidelift" + } + ], + "time": "2025-02-03T10:55:03+00:00" + }, + { + "name": "kreait/firebase-php", + "version": "7.19.0", + "source": { + "type": "git", + "url": "https://github.com/kreait/firebase-php.git", + "reference": "b06a2dd84eb5e2c4042773dce55b9291c0512d6b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kreait/firebase-php/zipball/b06a2dd84eb5e2c4042773dce55b9291c0512d6b", + "reference": "b06a2dd84eb5e2c4042773dce55b9291c0512d6b", + "shasum": "" + }, + "require": { + "beste/clock": "^3.0", + "beste/in-memory-cache": "^1.3.1", + "beste/json": "^1.5.1", + "ext-ctype": "*", + "ext-filter": "*", + "ext-json": "*", + "ext-mbstring": "*", + "fig/http-message-util": "^1.1.5", + "firebase/php-jwt": "^6.10.2", + "google/auth": "^v1.45", + "google/cloud-storage": "^1.45", + "guzzlehttp/guzzle": "^7.9.2", + "guzzlehttp/promises": "^2.0.4", + "guzzlehttp/psr7": "^2.7", + "kreait/firebase-tokens": "^5.2", + "lcobucci/jwt": "^4.3|^5.3", + "mtdowling/jmespath.php": "^2.8.0", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/cache": "^1.0.1|^2.0|^3.0", + "psr/clock": "^1.0", + "psr/http-client": "^1.0.3", + "psr/http-factory": "^1.1", + "psr/http-message": "^1.1 || ^2.0", + "psr/log": "^1.1|^2.0|^3.0.2" + }, + "require-dev": { + "google/cloud-firestore": "^1.50.0", + "php-cs-fixer/shim": "^3.75.0", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.17", + "phpstan/phpstan-deprecation-rules": "^2.0.3", + "phpstan/phpstan-phpunit": "^2.0.6", + "phpunit/phpunit": "^10.5.46", + "rector/rector": "^2.0.17", + "shipmonk/composer-dependency-analyser": "^1.8.3", + "symfony/var-dumper": "^6.4.15 || ^7.3.0", + "vlucas/phpdotenv": "^5.6.2" + }, + "suggest": { + "google/cloud-firestore": "^1.0 to use the Firestore component" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-7.x": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "Kreait\\Firebase\\": "src/Firebase" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérôme Gamez", + "homepage": "https://github.com/jeromegamez" + } + ], + "description": "Firebase Admin SDK", + "homepage": "https://github.com/kreait/firebase-php", + "keywords": [ + "api", + "database", + "firebase", + "google", + "sdk" + ], + "support": { + "docs": "https://firebase-php.readthedocs.io", + "issues": "https://github.com/kreait/firebase-php/issues", + "source": "https://github.com/kreait/firebase-php" + }, + "funding": [ + { + "url": "https://github.com/sponsors/jeromegamez", + "type": "github" + } + ], + "time": "2025-06-14T13:12:32+00:00" + }, + { + "name": "kreait/firebase-tokens", + "version": "5.2.1", + "source": { + "type": "git", + "url": "https://github.com/kreait/firebase-tokens-php.git", + "reference": "df6f9d153f3bbe671c3247576d2a45cbd0a79620" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kreait/firebase-tokens-php/zipball/df6f9d153f3bbe671c3247576d2a45cbd0a79620", + "reference": "df6f9d153f3bbe671c3247576d2a45cbd0a79620", + "shasum": "" + }, + "require": { + "beste/clock": "^3.0", + "ext-json": "*", + "ext-openssl": "*", + "fig/http-message-util": "^1.1.5", + "guzzlehttp/guzzle": "^7.8", + "lcobucci/jwt": "^5.2", + "php": "~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/cache": "^1.0|^2.0|^3.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.62.0", + "phpstan/extension-installer": "^1.4.1", + "phpstan/phpstan": "^1.11.10", + "phpstan/phpstan-phpunit": "^1.4.0", + "phpunit/phpunit": "^10.5.30", + "rector/rector": "^1.2.3", + "symfony/cache": "^6.4.3 || ^7.1.3", + "symfony/var-dumper": "^6.4.3 || ^7.1.3" + }, + "suggest": { + "psr/cache-implementation": "to cache fetched remote public keys" + }, + "type": "library", + "autoload": { + "psr-4": { + "Kreait\\Firebase\\JWT\\": "src/JWT" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérôme Gamez", + "homepage": "https://github.com/jeromegamez" + } + ], + "description": "A library to work with Firebase tokens", + "homepage": "https://github.com/kreait/firebase-token-php", + "keywords": [ + "Authentication", + "auth", + "firebase", + "google", + "token" + ], + "support": { + "issues": "https://github.com/kreait/firebase-tokens-php/issues", + "source": "https://github.com/kreait/firebase-tokens-php/tree/5.2.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/jeromegamez", + "type": "github" + } + ], + "time": "2024-12-20T11:29:43+00:00" + }, + { + "name": "kreait/laravel-firebase", + "version": "6.1.0", + "source": { + "type": "git", + "url": "https://github.com/kreait/laravel-firebase.git", + "reference": "9cbb24f17a42dbcb447468f0565e65d113e535aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/kreait/laravel-firebase/zipball/9cbb24f17a42dbcb447468f0565e65d113e535aa", + "reference": "9cbb24f17a42dbcb447468f0565e65d113e535aa", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^11.0 || ^12.0", + "illuminate/notifications": "^11.0 || ^12.0", + "illuminate/support": "^11.0 || ^12.0", + "kreait/firebase-php": "^7.19", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "symfony/cache": "^6.1.2 || ^7.0.3" + }, + "require-dev": { + "laravel/pint": "^1.22.1", + "orchestra/testbench": "^9.0 || ^10.4", + "phpunit/phpunit": "^11.5.23" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Firebase": "Kreait\\Laravel\\Firebase\\Facades\\Firebase" + }, + "providers": [ + "Kreait\\Laravel\\Firebase\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Kreait\\Laravel\\Firebase\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jérôme Gamez", + "email": "jerome@gamez.name" + } + ], + "description": "A Laravel package for the Firebase PHP Admin SDK", + "keywords": [ + "FCM", + "api", + "database", + "firebase", + "gcm", + "laravel", + "sdk" + ], + "support": { + "issues": "https://github.com/kreait/laravel-firebase/issues", + "source": "https://github.com/kreait/laravel-firebase/tree/6.1.0" + }, + "funding": [ + { + "url": "https://github.com/jeromegamez", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/kreait/laravel-firebase", + "type": "tidelift" + } + ], + "time": "2025-06-14T13:25:32+00:00" + }, + { + "name": "laravel-notification-channels/fcm", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/laravel-notification-channels/fcm.git", + "reference": "a4df1477c2be07b96fb42b0e35eaf14dcd00ec41" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel-notification-channels/fcm/zipball/a4df1477c2be07b96fb42b0e35eaf14dcd00ec41", + "reference": "a4df1477c2be07b96fb42b0e35eaf14dcd00ec41", + "shasum": "" + }, + "require": { + "guzzlehttp/guzzle": "^7.0", + "illuminate/notifications": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", + "kreait/laravel-firebase": "^6.0", + "php": "^8.2" + }, + "require-dev": { + "mockery/mockery": "^1.6.0", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "NotificationChannels\\Fcm\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Chris Bautista", + "email": "chris.bautista@coreproc.ph", + "homepage": "https://coreproc.com", + "role": "Developer" + } + ], + "description": "FCM (Firebase Cloud Messaging) Notifications Driver for Laravel", + "homepage": "https://github.com/laravel-notification-channels/fcm", + "support": { + "issues": "https://github.com/laravel-notification-channels/fcm/issues", + "source": "https://github.com/laravel-notification-channels/fcm/tree/5.1.0" + }, + "time": "2025-02-26T20:56:25+00:00" + }, + { + "name": "laravel/framework", + "version": "v12.19.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/framework.git", + "reference": "4e6ec689ef704bb4bd282f29d9dd658dfb4fb262" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/framework/zipball/4e6ec689ef704bb4bd282f29d9dd658dfb4fb262", + "reference": "4e6ec689ef704bb4bd282f29d9dd658dfb4fb262", + "shasum": "" + }, + "require": { + "brick/math": "^0.11|^0.12|^0.13", + "composer-runtime-api": "^2.2", + "doctrine/inflector": "^2.0.5", + "dragonmantank/cron-expression": "^3.4", + "egulias/email-validator": "^3.2.1|^4.0", + "ext-ctype": "*", + "ext-filter": "*", + "ext-hash": "*", + "ext-mbstring": "*", + "ext-openssl": "*", + "ext-session": "*", + "ext-tokenizer": "*", + "fruitcake/php-cors": "^1.3", + "guzzlehttp/guzzle": "^7.8.2", + "guzzlehttp/uri-template": "^1.0", + "laravel/prompts": "^0.3.0", + "laravel/serializable-closure": "^1.3|^2.0", + "league/commonmark": "^2.7", + "league/flysystem": "^3.25.1", + "league/flysystem-local": "^3.25.1", + "league/uri": "^7.5.1", + "monolog/monolog": "^3.0", + "nesbot/carbon": "^3.8.4", + "nunomaduro/termwind": "^2.0", + "php": "^8.2", + "psr/container": "^1.1.1|^2.0.1", + "psr/log": "^1.0|^2.0|^3.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "ramsey/uuid": "^4.7", + "symfony/console": "^7.2.0", + "symfony/error-handler": "^7.2.0", + "symfony/finder": "^7.2.0", + "symfony/http-foundation": "^7.2.0", + "symfony/http-kernel": "^7.2.0", + "symfony/mailer": "^7.2.0", + "symfony/mime": "^7.2.0", + "symfony/polyfill-php83": "^1.31", + "symfony/process": "^7.2.0", + "symfony/routing": "^7.2.0", + "symfony/uid": "^7.2.0", + "symfony/var-dumper": "^7.2.0", + "tijsverkoyen/css-to-inline-styles": "^2.2.5", + "vlucas/phpdotenv": "^5.6.1", + "voku/portable-ascii": "^2.0.2" + }, + "conflict": { + "tightenco/collect": "<5.5.33" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "psr/log-implementation": "1.0|2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0" + }, + "replace": { + "illuminate/auth": "self.version", + "illuminate/broadcasting": "self.version", + "illuminate/bus": "self.version", + "illuminate/cache": "self.version", + "illuminate/collections": "self.version", + "illuminate/concurrency": "self.version", + "illuminate/conditionable": "self.version", + "illuminate/config": "self.version", + "illuminate/console": "self.version", + "illuminate/container": "self.version", + "illuminate/contracts": "self.version", + "illuminate/cookie": "self.version", + "illuminate/database": "self.version", + "illuminate/encryption": "self.version", + "illuminate/events": "self.version", + "illuminate/filesystem": "self.version", + "illuminate/hashing": "self.version", + "illuminate/http": "self.version", + "illuminate/log": "self.version", + "illuminate/macroable": "self.version", + "illuminate/mail": "self.version", + "illuminate/notifications": "self.version", + "illuminate/pagination": "self.version", + "illuminate/pipeline": "self.version", + "illuminate/process": "self.version", + "illuminate/queue": "self.version", + "illuminate/redis": "self.version", + "illuminate/routing": "self.version", + "illuminate/session": "self.version", + "illuminate/support": "self.version", + "illuminate/testing": "self.version", + "illuminate/translation": "self.version", + "illuminate/validation": "self.version", + "illuminate/view": "self.version", + "spatie/once": "*" + }, + "require-dev": { + "ably/ably-php": "^1.0", + "aws/aws-sdk-php": "^3.322.9", + "ext-gmp": "*", + "fakerphp/faker": "^1.24", + "guzzlehttp/promises": "^2.0.3", + "guzzlehttp/psr7": "^2.4", + "laravel/pint": "^1.18", + "league/flysystem-aws-s3-v3": "^3.25.1", + "league/flysystem-ftp": "^3.25.1", + "league/flysystem-path-prefixing": "^3.25.1", + "league/flysystem-read-only": "^3.25.1", + "league/flysystem-sftp-v3": "^3.25.1", + "mockery/mockery": "^1.6.10", + "orchestra/testbench-core": "^10.0.0", + "pda/pheanstalk": "^5.0.6|^7.0.0", + "php-http/discovery": "^1.15", + "phpstan/phpstan": "^2.0", + "phpunit/phpunit": "^10.5.35|^11.5.3|^12.0.1", + "predis/predis": "^2.3|^3.0", + "resend/resend-php": "^0.10.0", + "symfony/cache": "^7.2.0", + "symfony/http-client": "^7.2.0", + "symfony/psr-http-message-bridge": "^7.2.0", + "symfony/translation": "^7.2.0" + }, + "suggest": { + "ably/ably-php": "Required to use the Ably broadcast driver (^1.0).", + "aws/aws-sdk-php": "Required to use the SQS queue driver, DynamoDb failed job storage, and SES mail driver (^3.322.9).", + "brianium/paratest": "Required to run tests in parallel (^7.0|^8.0).", + "ext-apcu": "Required to use the APC cache driver.", + "ext-fileinfo": "Required to use the Filesystem class.", + "ext-ftp": "Required to use the Flysystem FTP driver.", + "ext-gd": "Required to use Illuminate\\Http\\Testing\\FileFactory::image().", + "ext-memcached": "Required to use the memcache cache driver.", + "ext-pcntl": "Required to use all features of the queue worker and console signal trapping.", + "ext-pdo": "Required to use all database features.", + "ext-posix": "Required to use all features of the queue worker.", + "ext-redis": "Required to use the Redis cache and queue drivers (^4.0|^5.0|^6.0).", + "fakerphp/faker": "Required to use the eloquent factory builder (^1.9.1).", + "filp/whoops": "Required for friendly error pages in development (^2.14.3).", + "laravel/tinker": "Required to use the tinker console command (^2.0).", + "league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (^3.25.1).", + "league/flysystem-ftp": "Required to use the Flysystem FTP driver (^3.25.1).", + "league/flysystem-path-prefixing": "Required to use the scoped driver (^3.25.1).", + "league/flysystem-read-only": "Required to use read-only disks (^3.25.1)", + "league/flysystem-sftp-v3": "Required to use the Flysystem SFTP driver (^3.25.1).", + "mockery/mockery": "Required to use mocking (^1.6).", + "pda/pheanstalk": "Required to use the beanstalk queue driver (^5.0).", + "php-http/discovery": "Required to use PSR-7 bridging features (^1.15).", + "phpunit/phpunit": "Required to use assertions and run tests (^10.5.35|^11.5.3|^12.0.1).", + "predis/predis": "Required to use the predis connector (^2.3|^3.0).", + "psr/http-message": "Required to allow Storage::put to accept a StreamInterface (^1.0).", + "pusher/pusher-php-server": "Required to use the Pusher broadcast driver (^6.0|^7.0).", + "resend/resend-php": "Required to enable support for the Resend mail transport (^0.10.0).", + "symfony/cache": "Required to PSR-6 cache bridge (^7.2).", + "symfony/filesystem": "Required to enable support for relative symbolic links (^7.2).", + "symfony/http-client": "Required to enable support for the Symfony API mail transports (^7.2).", + "symfony/mailgun-mailer": "Required to enable support for the Mailgun mail transport (^7.2).", + "symfony/postmark-mailer": "Required to enable support for the Postmark mail transport (^7.2).", + "symfony/psr-http-message-bridge": "Required to use PSR-7 bridging features (^7.2)." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "12.x-dev" + } + }, + "autoload": { + "files": [ + "src/Illuminate/Collections/functions.php", + "src/Illuminate/Collections/helpers.php", + "src/Illuminate/Events/functions.php", + "src/Illuminate/Filesystem/functions.php", + "src/Illuminate/Foundation/helpers.php", + "src/Illuminate/Log/functions.php", + "src/Illuminate/Support/functions.php", + "src/Illuminate/Support/helpers.php" + ], + "psr-4": { + "Illuminate\\": "src/Illuminate/", + "Illuminate\\Support\\": [ + "src/Illuminate/Macroable/", + "src/Illuminate/Collections/", + "src/Illuminate/Conditionable/" + ] + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "The Laravel Framework.", + "homepage": "https://laravel.com", + "keywords": [ + "framework", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/framework/issues", + "source": "https://github.com/laravel/framework" + }, + "time": "2025-06-18T12:56:23+00:00" + }, + { + "name": "laravel/prompts", + "version": "v0.3.5", + "source": { + "type": "git", + "url": "https://github.com/laravel/prompts.git", + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/prompts/zipball/57b8f7efe40333cdb925700891c7d7465325d3b1", + "reference": "57b8f7efe40333cdb925700891c7d7465325d3b1", + "shasum": "" + }, + "require": { + "composer-runtime-api": "^2.2", + "ext-mbstring": "*", + "php": "^8.1", + "symfony/console": "^6.2|^7.0" + }, + "conflict": { + "illuminate/console": ">=10.17.0 <10.25.0", + "laravel/framework": ">=10.17.0 <10.25.0" + }, + "require-dev": { + "illuminate/collections": "^10.0|^11.0|^12.0", + "mockery/mockery": "^1.5", + "pestphp/pest": "^2.3|^3.4", + "phpstan/phpstan": "^1.11", + "phpstan/phpstan-mockery": "^1.1" + }, + "suggest": { + "ext-pcntl": "Required for the spinner to be animated." + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "0.3.x-dev" + } + }, + "autoload": { + "files": [ + "src/helpers.php" + ], + "psr-4": { + "Laravel\\Prompts\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Add beautiful and user-friendly forms to your command-line applications.", + "support": { + "issues": "https://github.com/laravel/prompts/issues", + "source": "https://github.com/laravel/prompts/tree/v0.3.5" + }, + "time": "2025-02-11T13:34:40+00:00" + }, + { + "name": "laravel/sanctum", + "version": "v4.1.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/sanctum.git", + "reference": "a360a6a1fd2400ead4eb9b6a9c1bb272939194f5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sanctum/zipball/a360a6a1fd2400ead4eb9b6a9c1bb272939194f5", + "reference": "a360a6a1fd2400ead4eb9b6a9c1bb272939194f5", + "shasum": "" + }, + "require": { + "ext-json": "*", + "illuminate/console": "^11.0|^12.0", + "illuminate/contracts": "^11.0|^12.0", + "illuminate/database": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", + "php": "^8.2", + "symfony/console": "^7.0" + }, + "require-dev": { + "mockery/mockery": "^1.6", + "orchestra/testbench": "^9.0|^10.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sanctum\\SanctumServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sanctum\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Laravel Sanctum provides a featherweight authentication system for SPAs and simple APIs.", + "keywords": [ + "auth", + "laravel", + "sanctum" + ], + "support": { + "issues": "https://github.com/laravel/sanctum/issues", + "source": "https://github.com/laravel/sanctum" + }, + "time": "2025-04-23T13:03:38+00:00" + }, + { + "name": "laravel/serializable-closure", + "version": "v2.0.4", + "source": { + "type": "git", + "url": "https://github.com/laravel/serializable-closure.git", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/serializable-closure/zipball/b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "reference": "b352cf0534aa1ae6b4d825d1e762e35d43f8a841", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "illuminate/support": "^10.0|^11.0|^12.0", + "nesbot/carbon": "^2.67|^3.0", + "pestphp/pest": "^2.36|^3.0", + "phpstan/phpstan": "^2.0", + "symfony/var-dumper": "^6.2.0|^7.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\SerializableClosure\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "nuno@laravel.com" + } + ], + "description": "Laravel Serializable Closure provides an easy and secure way to serialize closures in PHP.", + "keywords": [ + "closure", + "laravel", + "serializable" + ], + "support": { + "issues": "https://github.com/laravel/serializable-closure/issues", + "source": "https://github.com/laravel/serializable-closure" + }, + "time": "2025-03-19T13:51:03+00:00" + }, + { + "name": "laravel/tinker", + "version": "v2.10.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/tinker.git", + "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/tinker/zipball/22177cc71807d38f2810c6204d8f7183d88a57d3", + "reference": "22177cc71807d38f2810c6204d8f7183d88a57d3", + "shasum": "" + }, + "require": { + "illuminate/console": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/contracts": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "php": "^7.2.5|^8.0", + "psy/psysh": "^0.11.1|^0.12.0", + "symfony/var-dumper": "^4.3.4|^5.0|^6.0|^7.0" + }, + "require-dev": { + "mockery/mockery": "~1.3.3|^1.4.2", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^8.5.8|^9.3.3|^10.0" + }, + "suggest": { + "illuminate/database": "The Illuminate Database package (^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0)." + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Tinker\\TinkerServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Tinker\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Powerful REPL for the Laravel framework.", + "keywords": [ + "REPL", + "Tinker", + "laravel", + "psysh" + ], + "support": { + "issues": "https://github.com/laravel/tinker/issues", + "source": "https://github.com/laravel/tinker/tree/v2.10.1" + }, + "time": "2025-01-27T14:24:01+00:00" + }, + { + "name": "lcobucci/jwt", + "version": "5.5.0", + "source": { + "type": "git", + "url": "https://github.com/lcobucci/jwt.git", + "reference": "a835af59b030d3f2967725697cf88300f579088e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/lcobucci/jwt/zipball/a835af59b030d3f2967725697cf88300f579088e", + "reference": "a835af59b030d3f2967725697cf88300f579088e", + "shasum": "" + }, + "require": { + "ext-openssl": "*", + "ext-sodium": "*", + "php": "~8.2.0 || ~8.3.0 || ~8.4.0", + "psr/clock": "^1.0" + }, + "require-dev": { + "infection/infection": "^0.29", + "lcobucci/clock": "^3.2", + "lcobucci/coding-standard": "^11.0", + "phpbench/phpbench": "^1.2", + "phpstan/extension-installer": "^1.2", + "phpstan/phpstan": "^1.10.7", + "phpstan/phpstan-deprecation-rules": "^1.1.3", + "phpstan/phpstan-phpunit": "^1.3.10", + "phpstan/phpstan-strict-rules": "^1.5.0", + "phpunit/phpunit": "^11.1" + }, + "suggest": { + "lcobucci/clock": ">= 3.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Lcobucci\\JWT\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Luís Cobucci", + "email": "lcobucci@gmail.com", + "role": "Developer" + } + ], + "description": "A simple library to work with JSON Web Token and JSON Web Signature", + "keywords": [ + "JWS", + "jwt" + ], + "support": { + "issues": "https://github.com/lcobucci/jwt/issues", + "source": "https://github.com/lcobucci/jwt/tree/5.5.0" + }, + "funding": [ + { + "url": "https://github.com/lcobucci", + "type": "github" + }, + { + "url": "https://www.patreon.com/lcobucci", + "type": "patreon" + } + ], + "time": "2025-01-26T21:29:45+00:00" + }, + { + "name": "league/commonmark", + "version": "2.7.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/commonmark.git", + "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/commonmark/zipball/6fbb36d44824ed4091adbcf4c7d4a3923cdb3405", + "reference": "6fbb36d44824ed4091adbcf4c7d4a3923cdb3405", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "league/config": "^1.1.1", + "php": "^7.4 || ^8.0", + "psr/event-dispatcher": "^1.0", + "symfony/deprecation-contracts": "^2.1 || ^3.0", + "symfony/polyfill-php80": "^1.16" + }, + "require-dev": { + "cebe/markdown": "^1.0", + "commonmark/cmark": "0.31.1", + "commonmark/commonmark.js": "0.31.1", + "composer/package-versions-deprecated": "^1.8", + "embed/embed": "^4.4", + "erusev/parsedown": "^1.0", + "ext-json": "*", + "github/gfm": "0.29.0", + "michelf/php-markdown": "^1.4 || ^2.0", + "nyholm/psr7": "^1.5", + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.21 || ^10.5.9 || ^11.0.0", + "scrutinizer/ocular": "^1.8.1", + "symfony/finder": "^5.3 | ^6.0 | ^7.0", + "symfony/process": "^5.4 | ^6.0 | ^7.0", + "symfony/yaml": "^2.3 | ^3.0 | ^4.0 | ^5.0 | ^6.0 | ^7.0", + "unleashedtech/php-coding-standard": "^3.1.1", + "vimeo/psalm": "^4.24.0 || ^5.0.0" + }, + "suggest": { + "symfony/yaml": "v2.3+ required if using the Front Matter extension" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "2.8-dev" + } + }, + "autoload": { + "psr-4": { + "League\\CommonMark\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Highly-extensible PHP Markdown parser which fully supports the CommonMark spec and GitHub-Flavored Markdown (GFM)", + "homepage": "https://commonmark.thephpleague.com", + "keywords": [ + "commonmark", + "flavored", + "gfm", + "github", + "github-flavored", + "markdown", + "md", + "parser" + ], + "support": { + "docs": "https://commonmark.thephpleague.com/", + "forum": "https://github.com/thephpleague/commonmark/discussions", + "issues": "https://github.com/thephpleague/commonmark/issues", + "rss": "https://github.com/thephpleague/commonmark/releases.atom", + "source": "https://github.com/thephpleague/commonmark" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/commonmark", + "type": "tidelift" + } + ], + "time": "2025-05-05T12:20:28+00:00" + }, + { + "name": "league/config", + "version": "v1.2.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/config.git", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/config/zipball/754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "reference": "754b3604fb2984c71f4af4a9cbe7b57f346ec1f3", + "shasum": "" + }, + "require": { + "dflydev/dot-access-data": "^3.0.1", + "nette/schema": "^1.2", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.8.2", + "phpunit/phpunit": "^9.5.5", + "scrutinizer/ocular": "^1.8.1", + "unleashedtech/php-coding-standard": "^3.1", + "vimeo/psalm": "^4.7.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "1.2-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Config\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Colin O'Dell", + "email": "colinodell@gmail.com", + "homepage": "https://www.colinodell.com", + "role": "Lead Developer" + } + ], + "description": "Define configuration arrays with strict schemas and access values with dot notation", + "homepage": "https://config.thephpleague.com", + "keywords": [ + "array", + "config", + "configuration", + "dot", + "dot-access", + "nested", + "schema" + ], + "support": { + "docs": "https://config.thephpleague.com/", + "issues": "https://github.com/thephpleague/config/issues", + "rss": "https://github.com/thephpleague/config/releases.atom", + "source": "https://github.com/thephpleague/config" + }, + "funding": [ + { + "url": "https://www.colinodell.com/sponsor", + "type": "custom" + }, + { + "url": "https://www.paypal.me/colinpodell/10.00", + "type": "custom" + }, + { + "url": "https://github.com/colinodell", + "type": "github" + } + ], + "time": "2022-12-11T20:36:23+00:00" + }, + { + "name": "league/flysystem", + "version": "3.30.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem.git", + "reference": "2203e3151755d874bb2943649dae1eb8533ac93e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/2203e3151755d874bb2943649dae1eb8533ac93e", + "reference": "2203e3151755d874bb2943649dae1eb8533ac93e", + "shasum": "" + }, + "require": { + "league/flysystem-local": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "conflict": { + "async-aws/core": "<1.19.0", + "async-aws/s3": "<1.14.0", + "aws/aws-sdk-php": "3.209.31 || 3.210.0", + "guzzlehttp/guzzle": "<7.0", + "guzzlehttp/ringphp": "<1.1.1", + "phpseclib/phpseclib": "3.0.15", + "symfony/http-client": "<5.2" + }, + "require-dev": { + "async-aws/s3": "^1.5 || ^2.0", + "async-aws/simple-s3": "^1.1 || ^2.0", + "aws/aws-sdk-php": "^3.295.10", + "composer/semver": "^3.0", + "ext-fileinfo": "*", + "ext-ftp": "*", + "ext-mongodb": "^1.3|^2", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.5", + "google/cloud-storage": "^1.23", + "guzzlehttp/psr7": "^2.6", + "microsoft/azure-storage-blob": "^1.1", + "mongodb/mongodb": "^1.2|^2", + "phpseclib/phpseclib": "^3.0.36", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.5.11|^10.0", + "sabre/dav": "^4.6.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "File storage abstraction for PHP", + "keywords": [ + "WebDAV", + "aws", + "cloud", + "file", + "files", + "filesystem", + "filesystems", + "ftp", + "s3", + "sftp", + "storage" + ], + "support": { + "issues": "https://github.com/thephpleague/flysystem/issues", + "source": "https://github.com/thephpleague/flysystem/tree/3.30.0" + }, + "time": "2025-06-25T13:29:59+00:00" + }, + { + "name": "league/flysystem-local", + "version": "3.30.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/flysystem-local.git", + "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/flysystem-local/zipball/6691915f77c7fb69adfb87dcd550052dc184ee10", + "reference": "6691915f77c7fb69adfb87dcd550052dc184ee10", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "league/flysystem": "^3.0.0", + "league/mime-type-detection": "^1.0.0", + "php": "^8.0.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\Flysystem\\Local\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Local filesystem adapter for Flysystem.", + "keywords": [ + "Flysystem", + "file", + "files", + "filesystem", + "local" + ], + "support": { + "source": "https://github.com/thephpleague/flysystem-local/tree/3.30.0" + }, + "time": "2025-05-21T10:34:19+00:00" + }, + { + "name": "league/mime-type-detection", + "version": "1.16.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/mime-type-detection.git", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/2d6702ff215bf922936ccc1ad31007edc76451b9", + "reference": "2d6702ff215bf922936ccc1ad31007edc76451b9", + "shasum": "" + }, + "require": { + "ext-fileinfo": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.2", + "phpstan/phpstan": "^0.12.68", + "phpunit/phpunit": "^8.5.8 || ^9.3 || ^10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "League\\MimeTypeDetection\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Frank de Jonge", + "email": "info@frankdejonge.nl" + } + ], + "description": "Mime-type detection for Flysystem", + "support": { + "issues": "https://github.com/thephpleague/mime-type-detection/issues", + "source": "https://github.com/thephpleague/mime-type-detection/tree/1.16.0" + }, + "funding": [ + { + "url": "https://github.com/frankdejonge", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/league/flysystem", + "type": "tidelift" + } + ], + "time": "2024-09-21T08:32:55+00:00" + }, + { + "name": "league/uri", + "version": "7.5.1", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri.git", + "reference": "81fb5145d2644324614cc532b28efd0215bda430" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri/zipball/81fb5145d2644324614cc532b28efd0215bda430", + "reference": "81fb5145d2644324614cc532b28efd0215bda430", + "shasum": "" + }, + "require": { + "league/uri-interfaces": "^7.5", + "php": "^8.1" + }, + "conflict": { + "league/uri-schemes": "^1.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-fileinfo": "to create Data URI from file contennts", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "jeremykendall/php-domain-parser": "to resolve Public Suffix and Top Level Domain", + "league/uri-components": "Needed to easily manipulate URI objects components", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "URI manipulation library", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "middleware", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "uri-template", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri/tree/7.5.1" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:40:02+00:00" + }, + { + "name": "league/uri-interfaces", + "version": "7.5.0", + "source": { + "type": "git", + "url": "https://github.com/thephpleague/uri-interfaces.git", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/thephpleague/uri-interfaces/zipball/08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "reference": "08cfc6c4f3d811584fb09c37e2849e6a7f9b0742", + "shasum": "" + }, + "require": { + "ext-filter": "*", + "php": "^8.1", + "psr/http-factory": "^1", + "psr/http-message": "^1.1 || ^2.0" + }, + "suggest": { + "ext-bcmath": "to improve IPV4 host parsing", + "ext-gmp": "to improve IPV4 host parsing", + "ext-intl": "to handle IDN host with the best performance", + "php-64bit": "to improve IPV4 host parsing", + "symfony/polyfill-intl-idn": "to handle IDN host via the Symfony polyfill if ext-intl is not present" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "7.x-dev" + } + }, + "autoload": { + "psr-4": { + "League\\Uri\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ignace Nyamagana Butera", + "email": "nyamsprod@gmail.com", + "homepage": "https://nyamsprod.com" + } + ], + "description": "Common interfaces and classes for URI representation and interaction", + "homepage": "https://uri.thephpleague.com", + "keywords": [ + "data-uri", + "file-uri", + "ftp", + "hostname", + "http", + "https", + "parse_str", + "parse_url", + "psr-7", + "query-string", + "querystring", + "rfc3986", + "rfc3987", + "rfc6570", + "uri", + "url", + "ws" + ], + "support": { + "docs": "https://uri.thephpleague.com", + "forum": "https://thephpleague.slack.com", + "issues": "https://github.com/thephpleague/uri-src/issues", + "source": "https://github.com/thephpleague/uri-interfaces/tree/7.5.0" + }, + "funding": [ + { + "url": "https://github.com/sponsors/nyamsprod", + "type": "github" + } + ], + "time": "2024-12-08T08:18:47+00:00" + }, + { + "name": "maatwebsite/excel", + "version": "3.1.66", + "source": { + "type": "git", + "url": "https://github.com/SpartnerNL/Laravel-Excel.git", + "reference": "3b29c2426a46674f444890c45f742452a396aae8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SpartnerNL/Laravel-Excel/zipball/3b29c2426a46674f444890c45f742452a396aae8", + "reference": "3b29c2426a46674f444890c45f742452a396aae8", + "shasum": "" + }, + "require": { + "composer/semver": "^3.3", + "ext-json": "*", + "illuminate/support": "5.8.*||^6.0||^7.0||^8.0||^9.0||^10.0||^11.0||^12.0", + "php": "^7.0||^8.0", + "phpoffice/phpspreadsheet": "^1.29.12", + "psr/simple-cache": "^1.0||^2.0||^3.0" + }, + "require-dev": { + "laravel/scout": "^7.0||^8.0||^9.0||^10.0", + "orchestra/testbench": "^6.0||^7.0||^8.0||^9.0||^10.0", + "predis/predis": "^1.1" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "Excel": "Maatwebsite\\Excel\\Facades\\Excel" + }, + "providers": [ + "Maatwebsite\\Excel\\ExcelServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Maatwebsite\\Excel\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Patrick Brouwers", + "email": "patrick@spartner.nl" + } + ], + "description": "Supercharged Excel exports and imports in Laravel", + "keywords": [ + "PHPExcel", + "batch", + "csv", + "excel", + "export", + "import", + "laravel", + "php", + "phpspreadsheet" + ], + "support": { + "issues": "https://github.com/SpartnerNL/Laravel-Excel/issues", + "source": "https://github.com/SpartnerNL/Laravel-Excel/tree/3.1.66" + }, + "funding": [ + { + "url": "https://laravel-excel.com/commercial-support", + "type": "custom" + }, + { + "url": "https://github.com/patrickbrouwers", + "type": "github" + } + ], + "time": "2025-08-07T08:31:22+00:00" + }, + { + "name": "maennchen/zipstream-php", + "version": "3.2.0", + "source": { + "type": "git", + "url": "https://github.com/maennchen/ZipStream-PHP.git", + "reference": "9712d8fa4cdf9240380b01eb4be55ad8dcf71416" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/maennchen/ZipStream-PHP/zipball/9712d8fa4cdf9240380b01eb4be55ad8dcf71416", + "reference": "9712d8fa4cdf9240380b01eb4be55ad8dcf71416", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "ext-zlib": "*", + "php-64bit": "^8.3" + }, + "require-dev": { + "brianium/paratest": "^7.7", + "ext-zip": "*", + "friendsofphp/php-cs-fixer": "^3.16", + "guzzlehttp/guzzle": "^7.5", + "mikey179/vfsstream": "^1.6", + "php-coveralls/php-coveralls": "^2.5", + "phpunit/phpunit": "^12.0", + "vimeo/psalm": "^6.0" + }, + "suggest": { + "guzzlehttp/psr7": "^2.4", + "psr/http-message": "^2.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "ZipStream\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Paul Duncan", + "email": "pabs@pablotron.org" + }, + { + "name": "Jonatan Männchen", + "email": "jonatan@maennchen.ch" + }, + { + "name": "Jesse Donat", + "email": "donatj@gmail.com" + }, + { + "name": "András Kolesár", + "email": "kolesar@kolesar.hu" + } + ], + "description": "ZipStream is a library for dynamically streaming dynamic zip files from PHP without writing to the disk at all on the server.", + "keywords": [ + "stream", + "zip" + ], + "support": { + "issues": "https://github.com/maennchen/ZipStream-PHP/issues", + "source": "https://github.com/maennchen/ZipStream-PHP/tree/3.2.0" + }, + "funding": [ + { + "url": "https://github.com/maennchen", + "type": "github" + } + ], + "time": "2025-07-17T11:15:13+00:00" + }, + { + "name": "markbaker/complex", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPComplex.git", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPComplex/zipball/95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "reference": "95c56caa1cf5c766ad6d65b6344b807c1e8405b9", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Complex\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@lange.demon.co.uk" + } + ], + "description": "PHP Class for working with complex numbers", + "homepage": "https://github.com/MarkBaker/PHPComplex", + "keywords": [ + "complex", + "mathematics" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPComplex/issues", + "source": "https://github.com/MarkBaker/PHPComplex/tree/3.0.2" + }, + "time": "2022-12-06T16:21:08+00:00" + }, + { + "name": "markbaker/matrix", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/MarkBaker/PHPMatrix.git", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/MarkBaker/PHPMatrix/zipball/728434227fe21be27ff6d86621a1b13107a2562c", + "reference": "728434227fe21be27ff6d86621a1b13107a2562c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-master", + "phpcompatibility/php-compatibility": "^9.3", + "phpdocumentor/phpdocumentor": "2.*", + "phploc/phploc": "^4.0", + "phpmd/phpmd": "2.*", + "phpunit/phpunit": "^7.0 || ^8.0 || ^9.0", + "sebastian/phpcpd": "^4.0", + "squizlabs/php_codesniffer": "^3.7" + }, + "type": "library", + "autoload": { + "psr-4": { + "Matrix\\": "classes/src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Mark Baker", + "email": "mark@demon-angel.eu" + } + ], + "description": "PHP Class for working with matrices", + "homepage": "https://github.com/MarkBaker/PHPMatrix", + "keywords": [ + "mathematics", + "matrix", + "vector" + ], + "support": { + "issues": "https://github.com/MarkBaker/PHPMatrix/issues", + "source": "https://github.com/MarkBaker/PHPMatrix/tree/3.0.1" + }, + "time": "2022-12-02T22:17:43+00:00" + }, + { + "name": "monolog/monolog", + "version": "3.9.0", + "source": { + "type": "git", + "url": "https://github.com/Seldaek/monolog.git", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/Seldaek/monolog/zipball/10d85740180ecba7896c87e06a166e0c95a0e3b6", + "reference": "10d85740180ecba7896c87e06a166e0c95a0e3b6", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/log": "^2.0 || ^3.0" + }, + "provide": { + "psr/log-implementation": "3.0.0" + }, + "require-dev": { + "aws/aws-sdk-php": "^3.0", + "doctrine/couchdb": "~1.0@dev", + "elasticsearch/elasticsearch": "^7 || ^8", + "ext-json": "*", + "graylog2/gelf-php": "^1.4.2 || ^2.0", + "guzzlehttp/guzzle": "^7.4.5", + "guzzlehttp/psr7": "^2.2", + "mongodb/mongodb": "^1.8", + "php-amqplib/php-amqplib": "~2.4 || ^3", + "php-console/php-console": "^3.1.8", + "phpstan/phpstan": "^2", + "phpstan/phpstan-deprecation-rules": "^2", + "phpstan/phpstan-strict-rules": "^2", + "phpunit/phpunit": "^10.5.17 || ^11.0.7", + "predis/predis": "^1.1 || ^2", + "rollbar/rollbar": "^4.0", + "ruflin/elastica": "^7 || ^8", + "symfony/mailer": "^5.4 || ^6", + "symfony/mime": "^5.4 || ^6" + }, + "suggest": { + "aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB", + "doctrine/couchdb": "Allow sending log messages to a CouchDB server", + "elasticsearch/elasticsearch": "Allow sending log messages to an Elasticsearch server via official client", + "ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)", + "ext-curl": "Required to send log messages using the IFTTTHandler, the LogglyHandler, the SendGridHandler, the SlackWebhookHandler or the TelegramBotHandler", + "ext-mbstring": "Allow to work properly with unicode symbols", + "ext-mongodb": "Allow sending log messages to a MongoDB server (via driver)", + "ext-openssl": "Required to send log messages using SSL", + "ext-sockets": "Allow sending log messages to a Syslog server (via UDP driver)", + "graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server", + "mongodb/mongodb": "Allow sending log messages to a MongoDB server (via library)", + "php-amqplib/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib", + "rollbar/rollbar": "Allow sending log messages to Rollbar", + "ruflin/elastica": "Allow sending log messages to an Elastic Search server" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Monolog\\": "src/Monolog" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "https://seld.be" + } + ], + "description": "Sends your logs to files, sockets, inboxes, databases and various web services", + "homepage": "https://github.com/Seldaek/monolog", + "keywords": [ + "log", + "logging", + "psr-3" + ], + "support": { + "issues": "https://github.com/Seldaek/monolog/issues", + "source": "https://github.com/Seldaek/monolog/tree/3.9.0" + }, + "funding": [ + { + "url": "https://github.com/Seldaek", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/monolog/monolog", + "type": "tidelift" + } + ], + "time": "2025-03-24T10:02:05+00:00" + }, + { + "name": "mtdowling/jmespath.php", + "version": "2.8.0", + "source": { + "type": "git", + "url": "https://github.com/jmespath/jmespath.php.git", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/jmespath/jmespath.php/zipball/a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "reference": "a2a865e05d5f420b50cc2f85bb78d565db12a6bc", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0", + "symfony/polyfill-mbstring": "^1.17" + }, + "require-dev": { + "composer/xdebug-handler": "^3.0.3", + "phpunit/phpunit": "^8.5.33" + }, + "bin": [ + "bin/jp.php" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.8-dev" + } + }, + "autoload": { + "files": [ + "src/JmesPath.php" + ], + "psr-4": { + "JmesPath\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Declaratively specify how to extract elements from a JSON document", + "keywords": [ + "json", + "jsonpath" + ], + "support": { + "issues": "https://github.com/jmespath/jmespath.php/issues", + "source": "https://github.com/jmespath/jmespath.php/tree/2.8.0" + }, + "time": "2024-09-04T18:46:31+00:00" + }, + { + "name": "nesbot/carbon", + "version": "3.10.1", + "source": { + "type": "git", + "url": "https://github.com/CarbonPHP/carbon.git", + "reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/1fd1935b2d90aef2f093c5e35f7ae1257c448d00", + "reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00", + "shasum": "" + }, + "require": { + "carbonphp/carbon-doctrine-types": "<100.0", + "ext-json": "*", + "php": "^8.1", + "psr/clock": "^1.0", + "symfony/clock": "^6.3.12 || ^7.0", + "symfony/polyfill-mbstring": "^1.0", + "symfony/translation": "^4.4.18 || ^5.2.1 || ^6.0 || ^7.0" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "require-dev": { + "doctrine/dbal": "^3.6.3 || ^4.0", + "doctrine/orm": "^2.15.2 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.75.0", + "kylekatarnls/multi-tester": "^2.5.3", + "phpmd/phpmd": "^2.15.0", + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^2.1.17", + "phpunit/phpunit": "^10.5.46", + "squizlabs/php_codesniffer": "^3.13.0" + }, + "bin": [ + "bin/carbon" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Carbon\\Laravel\\ServiceProvider" + ] + }, + "phpstan": { + "includes": [ + "extension.neon" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev", + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Carbon\\": "src/Carbon/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brian Nesbitt", + "email": "brian@nesbot.com", + "homepage": "https://markido.com" + }, + { + "name": "kylekatarnls", + "homepage": "https://github.com/kylekatarnls" + } + ], + "description": "An API extension for DateTime that supports 281 different languages.", + "homepage": "https://carbon.nesbot.com", + "keywords": [ + "date", + "datetime", + "time" + ], + "support": { + "docs": "https://carbon.nesbot.com/docs", + "issues": "https://github.com/CarbonPHP/carbon/issues", + "source": "https://github.com/CarbonPHP/carbon" + }, + "funding": [ + { + "url": "https://github.com/sponsors/kylekatarnls", + "type": "github" + }, + { + "url": "https://opencollective.com/Carbon#sponsor", + "type": "opencollective" + }, + { + "url": "https://tidelift.com/subscription/pkg/packagist-nesbot-carbon?utm_source=packagist-nesbot-carbon&utm_medium=referral&utm_campaign=readme", + "type": "tidelift" + } + ], + "time": "2025-06-21T15:19:35+00:00" + }, + { + "name": "nette/schema", + "version": "v1.3.2", + "source": { + "type": "git", + "url": "https://github.com/nette/schema.git", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/schema/zipball/da801d52f0354f70a638673c4a0f04e16529431d", + "reference": "da801d52f0354f70a638673c4a0f04e16529431d", + "shasum": "" + }, + "require": { + "nette/utils": "^4.0", + "php": "8.1 - 8.4" + }, + "require-dev": { + "nette/tester": "^2.5.2", + "phpstan/phpstan-nette": "^1.0", + "tracy/tracy": "^2.8" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "📐 Nette Schema: validating data structures against a given Schema.", + "homepage": "https://nette.org", + "keywords": [ + "config", + "nette" + ], + "support": { + "issues": "https://github.com/nette/schema/issues", + "source": "https://github.com/nette/schema/tree/v1.3.2" + }, + "time": "2024-10-06T23:10:23+00:00" + }, + { + "name": "nette/utils", + "version": "v4.0.7", + "source": { + "type": "git", + "url": "https://github.com/nette/utils.git", + "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "shasum": "" + }, + "require": { + "php": "8.0 - 8.4" + }, + "conflict": { + "nette/finder": "<3", + "nette/schema": "<1.2.2" + }, + "require-dev": { + "jetbrains/phpstorm-attributes": "dev-master", + "nette/tester": "^2.5", + "phpstan/phpstan": "^1.0", + "tracy/tracy": "^2.9" + }, + "suggest": { + "ext-gd": "to use Image", + "ext-iconv": "to use Strings::webalize(), toAscii(), chr() and reverse()", + "ext-intl": "to use Strings::webalize(), toAscii(), normalize() and compare()", + "ext-json": "to use Nette\\Utils\\Json", + "ext-mbstring": "to use Strings::lower() etc...", + "ext-tokenizer": "to use Nette\\Utils\\Reflection::getUseStatements()" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause", + "GPL-2.0-only", + "GPL-3.0-only" + ], + "authors": [ + { + "name": "David Grudl", + "homepage": "https://davidgrudl.com" + }, + { + "name": "Nette Community", + "homepage": "https://nette.org/contributors" + } + ], + "description": "🛠 Nette Utils: lightweight utilities for string & array manipulation, image handling, safe JSON encoding/decoding, validation, slug or strong password generating etc.", + "homepage": "https://nette.org", + "keywords": [ + "array", + "core", + "datetime", + "images", + "json", + "nette", + "paginator", + "password", + "slugify", + "string", + "unicode", + "utf-8", + "utility", + "validation" + ], + "support": { + "issues": "https://github.com/nette/utils/issues", + "source": "https://github.com/nette/utils/tree/v4.0.7" + }, + "time": "2025-06-03T04:55:08+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.5.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/ae59794362fe85e051a58ad36b289443f57be7a9", + "reference": "ae59794362fe85e051a58ad36b289443f57be7a9", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.5.0" + }, + "time": "2025-05-31T08:24:38+00:00" + }, + { + "name": "nunomaduro/termwind", + "version": "v2.3.1", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/termwind.git", + "reference": "dfa08f390e509967a15c22493dc0bac5733d9123" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/termwind/zipball/dfa08f390e509967a15c22493dc0bac5733d9123", + "reference": "dfa08f390e509967a15c22493dc0bac5733d9123", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": "^8.2", + "symfony/console": "^7.2.6" + }, + "require-dev": { + "illuminate/console": "^11.44.7", + "laravel/pint": "^1.22.0", + "mockery/mockery": "^1.6.12", + "pestphp/pest": "^2.36.0 || ^3.8.2", + "phpstan/phpstan": "^1.12.25", + "phpstan/phpstan-strict-rules": "^1.6.2", + "symfony/var-dumper": "^7.2.6", + "thecodingmachine/phpstan-strict-rules": "^1.0.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Termwind\\Laravel\\TermwindServiceProvider" + ] + }, + "branch-alias": { + "dev-2.x": "2.x-dev" + } + }, + "autoload": { + "files": [ + "src/Functions.php" + ], + "psr-4": { + "Termwind\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Its like Tailwind CSS, but for the console.", + "keywords": [ + "cli", + "console", + "css", + "package", + "php", + "style" + ], + "support": { + "issues": "https://github.com/nunomaduro/termwind/issues", + "source": "https://github.com/nunomaduro/termwind/tree/v2.3.1" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://github.com/xiCO2k", + "type": "github" + } + ], + "time": "2025-05-08T08:14:37+00:00" + }, + { + "name": "phpoffice/phpspreadsheet", + "version": "1.30.0", + "source": { + "type": "git", + "url": "https://github.com/PHPOffice/PhpSpreadsheet.git", + "reference": "2f39286e0136673778b7a142b3f0d141e43d1714" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/PHPOffice/PhpSpreadsheet/zipball/2f39286e0136673778b7a142b3f0d141e43d1714", + "reference": "2f39286e0136673778b7a142b3f0d141e43d1714", + "shasum": "" + }, + "require": { + "composer/pcre": "^1||^2||^3", + "ext-ctype": "*", + "ext-dom": "*", + "ext-fileinfo": "*", + "ext-gd": "*", + "ext-iconv": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-simplexml": "*", + "ext-xml": "*", + "ext-xmlreader": "*", + "ext-xmlwriter": "*", + "ext-zip": "*", + "ext-zlib": "*", + "ezyang/htmlpurifier": "^4.15", + "maennchen/zipstream-php": "^2.1 || ^3.0", + "markbaker/complex": "^3.0", + "markbaker/matrix": "^3.0", + "php": "^7.4 || ^8.0", + "psr/http-client": "^1.0", + "psr/http-factory": "^1.0", + "psr/simple-cache": "^1.0 || ^2.0 || ^3.0" + }, + "require-dev": { + "dealerdirect/phpcodesniffer-composer-installer": "dev-main", + "dompdf/dompdf": "^1.0 || ^2.0 || ^3.0", + "friendsofphp/php-cs-fixer": "^3.2", + "mitoteam/jpgraph": "^10.3", + "mpdf/mpdf": "^8.1.1", + "phpcompatibility/php-compatibility": "^9.3", + "phpstan/phpstan": "^1.1", + "phpstan/phpstan-phpunit": "^1.0", + "phpunit/phpunit": "^8.5 || ^9.0", + "squizlabs/php_codesniffer": "^3.7", + "tecnickcom/tcpdf": "^6.5" + }, + "suggest": { + "dompdf/dompdf": "Option for rendering PDF with PDF Writer", + "ext-intl": "PHP Internationalization Functions", + "mitoteam/jpgraph": "Option for rendering charts, or including charts with PDF or HTML Writers", + "mpdf/mpdf": "Option for rendering PDF with PDF Writer", + "tecnickcom/tcpdf": "Option for rendering PDF with PDF Writer" + }, + "type": "library", + "autoload": { + "psr-4": { + "PhpOffice\\PhpSpreadsheet\\": "src/PhpSpreadsheet" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Maarten Balliauw", + "homepage": "https://blog.maartenballiauw.be" + }, + { + "name": "Mark Baker", + "homepage": "https://markbakeruk.net" + }, + { + "name": "Franck Lefevre", + "homepage": "https://rootslabs.net" + }, + { + "name": "Erik Tilt" + }, + { + "name": "Adrien Crivelli" + } + ], + "description": "PHPSpreadsheet - Read, Create and Write Spreadsheet documents in PHP - Spreadsheet engine", + "homepage": "https://github.com/PHPOffice/PhpSpreadsheet", + "keywords": [ + "OpenXML", + "excel", + "gnumeric", + "ods", + "php", + "spreadsheet", + "xls", + "xlsx" + ], + "support": { + "issues": "https://github.com/PHPOffice/PhpSpreadsheet/issues", + "source": "https://github.com/PHPOffice/PhpSpreadsheet/tree/1.30.0" + }, + "time": "2025-08-10T06:28:02+00:00" + }, + { + "name": "phpoption/phpoption", + "version": "1.9.3", + "source": { + "type": "git", + "url": "https://github.com/schmittjoh/php-option.git", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", + "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "shasum": "" + }, + "require": { + "php": "^7.2.5 || ^8.0" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "1.9-dev" + } + }, + "autoload": { + "psr-4": { + "PhpOption\\": "src/PhpOption/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "Apache-2.0" + ], + "authors": [ + { + "name": "Johannes M. Schmitt", + "email": "schmittjoh@gmail.com", + "homepage": "https://github.com/schmittjoh" + }, + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + } + ], + "description": "Option Type for PHP", + "keywords": [ + "language", + "option", + "php", + "type" + ], + "support": { + "issues": "https://github.com/schmittjoh/php-option/issues", + "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpoption/phpoption", + "type": "tidelift" + } + ], + "time": "2024-07-20T21:41:07+00:00" + }, + { + "name": "psr/cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/cache.git", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/cache/zipball/aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "reference": "aa5030cfa5405eccfdcb1083ce040c2cb8d253bf", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/clock", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/clock.git", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/clock/zipball/e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "reference": "e41a24703d4560fd0acb709162f73b8adfc3aa0d", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Psr\\Clock\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for reading the clock.", + "homepage": "https://github.com/php-fig/clock", + "keywords": [ + "clock", + "now", + "psr", + "psr-20", + "time" + ], + "support": { + "issues": "https://github.com/php-fig/clock/issues", + "source": "https://github.com/php-fig/clock/tree/1.0.0" + }, + "time": "2022-11-25T14:36:26+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/http-client", + "version": "1.0.3", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-client.git", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-client/zipball/bb5906edc1c324c9a05aa0873d40117941e5fa90", + "reference": "bb5906edc1c324c9a05aa0873d40117941e5fa90", + "shasum": "" + }, + "require": { + "php": "^7.0 || ^8.0", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Client\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP clients", + "homepage": "https://github.com/php-fig/http-client", + "keywords": [ + "http", + "http-client", + "psr", + "psr-18" + ], + "support": { + "source": "https://github.com/php-fig/http-client" + }, + "time": "2023-09-23T14:17:50+00:00" + }, + { + "name": "psr/http-factory", + "version": "1.1.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-factory.git", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-factory/zipball/2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "reference": "2b4765fddfe3b508ac62f829e852b1501d3f6e8a", + "shasum": "" + }, + "require": { + "php": ">=7.1", + "psr/http-message": "^1.0 || ^2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "PSR-17: Common interfaces for PSR-7 HTTP message factories", + "keywords": [ + "factory", + "http", + "message", + "psr", + "psr-17", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-factory" + }, + "time": "2024-04-15T12:06:14+00:00" + }, + { + "name": "psr/http-message", + "version": "2.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/http-message.git", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/http-message/zipball/402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "reference": "402d35bcb92c70c026d1a6a9883f06b2ead23d71", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Http\\Message\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for HTTP messages", + "homepage": "https://github.com/php-fig/http-message", + "keywords": [ + "http", + "http-message", + "psr", + "psr-7", + "request", + "response" + ], + "support": { + "source": "https://github.com/php-fig/http-message/tree/2.0" + }, + "time": "2023-04-04T09:54:51+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "psr/simple-cache", + "version": "3.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/simple-cache.git", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/simple-cache/zipball/764e0b3939f5ca87cb904f570ef9be2d78a07865", + "reference": "764e0b3939f5ca87cb904f570ef9be2d78a07865", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\SimpleCache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interfaces for simple caching", + "keywords": [ + "cache", + "caching", + "psr", + "psr-16", + "simple-cache" + ], + "support": { + "source": "https://github.com/php-fig/simple-cache/tree/3.0.0" + }, + "time": "2021-10-29T13:26:27+00:00" + }, + { + "name": "psy/psysh", + "version": "v0.12.9", + "source": { + "type": "git", + "url": "https://github.com/bobthecow/psysh.git", + "reference": "1b801844becfe648985372cb4b12ad6840245ace" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/1b801844becfe648985372cb4b12ad6840245ace", + "reference": "1b801844becfe648985372cb4b12ad6840245ace", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-tokenizer": "*", + "nikic/php-parser": "^5.0 || ^4.0", + "php": "^8.0 || ^7.4", + "symfony/console": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4", + "symfony/var-dumper": "^7.0 || ^6.0 || ^5.0 || ^4.0 || ^3.4" + }, + "conflict": { + "symfony/console": "4.4.37 || 5.3.14 || 5.3.15 || 5.4.3 || 5.4.4 || 6.0.3 || 6.0.4" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.2" + }, + "suggest": { + "ext-pcntl": "Enabling the PCNTL extension makes PsySH a lot happier :)", + "ext-pdo-sqlite": "The doc command requires SQLite to work.", + "ext-posix": "If you have PCNTL, you'll want the POSIX extension as well." + }, + "bin": [ + "bin/psysh" + ], + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": false, + "forward-command": false + }, + "branch-alias": { + "dev-main": "0.12.x-dev" + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Psy\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Justin Hileman", + "email": "justin@justinhileman.info", + "homepage": "http://justinhileman.com" + } + ], + "description": "An interactive shell for modern PHP.", + "homepage": "http://psysh.org", + "keywords": [ + "REPL", + "console", + "interactive", + "shell" + ], + "support": { + "issues": "https://github.com/bobthecow/psysh/issues", + "source": "https://github.com/bobthecow/psysh/tree/v0.12.9" + }, + "time": "2025-06-23T02:35:06+00:00" + }, + { + "name": "ralouphie/getallheaders", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/ralouphie/getallheaders.git", + "reference": "120b605dfeb996808c31b6477290a714d356e822" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ralouphie/getallheaders/zipball/120b605dfeb996808c31b6477290a714d356e822", + "reference": "120b605dfeb996808c31b6477290a714d356e822", + "shasum": "" + }, + "require": { + "php": ">=5.6" + }, + "require-dev": { + "php-coveralls/php-coveralls": "^2.1", + "phpunit/phpunit": "^5 || ^6.5" + }, + "type": "library", + "autoload": { + "files": [ + "src/getallheaders.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ralph Khattar", + "email": "ralph.khattar@gmail.com" + } + ], + "description": "A polyfill for getallheaders.", + "support": { + "issues": "https://github.com/ralouphie/getallheaders/issues", + "source": "https://github.com/ralouphie/getallheaders/tree/develop" + }, + "time": "2019-03-08T08:55:37+00:00" + }, + { + "name": "ramsey/collection", + "version": "2.1.1", + "source": { + "type": "git", + "url": "https://github.com/ramsey/collection.git", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/collection/zipball/344572933ad0181accbf4ba763e85a0306a8c5e2", + "reference": "344572933ad0181accbf4ba763e85a0306a8c5e2", + "shasum": "" + }, + "require": { + "php": "^8.1" + }, + "require-dev": { + "captainhook/plugin-composer": "^5.3", + "ergebnis/composer-normalize": "^2.45", + "fakerphp/faker": "^1.24", + "hamcrest/hamcrest-php": "^2.0", + "jangregor/phpstan-prophecy": "^2.1", + "mockery/mockery": "^1.6", + "php-parallel-lint/php-console-highlighter": "^1.0", + "php-parallel-lint/php-parallel-lint": "^1.4", + "phpspec/prophecy-phpunit": "^2.3", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^10.5", + "ramsey/coding-standard": "^2.3", + "ramsey/conventional-commits": "^1.6", + "roave/security-advisories": "dev-latest" + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + }, + "ramsey/conventional-commits": { + "configFile": "conventional-commits.json" + } + }, + "autoload": { + "psr-4": { + "Ramsey\\Collection\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ben Ramsey", + "email": "ben@benramsey.com", + "homepage": "https://benramsey.com" + } + ], + "description": "A PHP library for representing and manipulating collections.", + "keywords": [ + "array", + "collection", + "hash", + "map", + "queue", + "set" + ], + "support": { + "issues": "https://github.com/ramsey/collection/issues", + "source": "https://github.com/ramsey/collection/tree/2.1.1" + }, + "time": "2025-03-22T05:38:12+00:00" + }, + { + "name": "ramsey/uuid", + "version": "4.9.0", + "source": { + "type": "git", + "url": "https://github.com/ramsey/uuid.git", + "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/4e0e23cc785f0724a0e838279a9eb03f28b092a0", + "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0", + "shasum": "" + }, + "require": { + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13", + "php": "^8.0", + "ramsey/collection": "^1.2 || ^2.0" + }, + "replace": { + "rhumsaa/uuid": "self.version" + }, + "require-dev": { + "captainhook/captainhook": "^5.25", + "captainhook/plugin-composer": "^5.3", + "dealerdirect/phpcodesniffer-composer-installer": "^1.0", + "ergebnis/composer-normalize": "^2.47", + "mockery/mockery": "^1.6", + "paragonie/random-lib": "^2", + "php-mock/php-mock": "^2.6", + "php-mock/php-mock-mockery": "^1.5", + "php-parallel-lint/php-parallel-lint": "^1.4.0", + "phpbench/phpbench": "^1.2.14", + "phpstan/extension-installer": "^1.4", + "phpstan/phpstan": "^2.1", + "phpstan/phpstan-mockery": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^9.6", + "slevomat/coding-standard": "^8.18", + "squizlabs/php_codesniffer": "^3.13" + }, + "suggest": { + "ext-bcmath": "Enables faster math with arbitrary-precision integers using BCMath.", + "ext-gmp": "Enables faster math with arbitrary-precision integers using GMP.", + "ext-uuid": "Enables the use of PeclUuidTimeGenerator and PeclUuidRandomGenerator.", + "paragonie/random-lib": "Provides RandomLib for use with the RandomLibAdapter", + "ramsey/uuid-doctrine": "Allows the use of Ramsey\\Uuid\\Uuid as Doctrine field type." + }, + "type": "library", + "extra": { + "captainhook": { + "force-install": true + } + }, + "autoload": { + "files": [ + "src/functions.php" + ], + "psr-4": { + "Ramsey\\Uuid\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A PHP library for generating and working with universally unique identifiers (UUIDs).", + "keywords": [ + "guid", + "identifier", + "uuid" + ], + "support": { + "issues": "https://github.com/ramsey/uuid/issues", + "source": "https://github.com/ramsey/uuid/tree/4.9.0" + }, + "time": "2025-06-25T14:20:11+00:00" + }, + { + "name": "rize/uri-template", + "version": "0.4.0", + "source": { + "type": "git", + "url": "https://github.com/rize/UriTemplate.git", + "reference": "56f374a9a42c7c3998f8b55b6b21b224de90c58b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/rize/UriTemplate/zipball/56f374a9a42c7c3998f8b55b6b21b224de90c58b", + "reference": "56f374a9a42c7c3998f8b55b6b21b224de90c58b", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.63", + "phpstan/phpstan": "^1.12", + "phpunit/phpunit": "~10.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Rize\\": "src/Rize" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Marut K", + "homepage": "http://twitter.com/rezigned" + } + ], + "description": "PHP URI Template (RFC 6570) supports both expansion & extraction", + "keywords": [ + "RFC 6570", + "template", + "uri" + ], + "support": { + "issues": "https://github.com/rize/UriTemplate/issues", + "source": "https://github.com/rize/UriTemplate/tree/0.4.0" + }, + "funding": [ + { + "url": "https://www.paypal.me/rezigned", + "type": "custom" + }, + { + "url": "https://github.com/rezigned", + "type": "github" + }, + { + "url": "https://opencollective.com/rize-uri-template", + "type": "open_collective" + } + ], + "time": "2024-11-27T12:13:42+00:00" + }, + { + "name": "symfony/cache", + "version": "v7.3.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "a7c6caa9d6113cebfb3020b427bcb021ebfdfc9e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/a7c6caa9d6113cebfb3020b427bcb021ebfdfc9e", + "reference": "a7c6caa9d6113cebfb3020b427bcb021ebfdfc9e", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^3.6", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v7.3.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-06-27T19:55:54+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/5d68a57d66910405e5c0b63d6f0af941e66fc868", + "reference": "5d68a57d66910405e5c0b63d6f0af941e66fc868", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^3.0" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-13T15:25:07+00:00" + }, + { + "name": "symfony/clock", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/clock.git", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/clock/zipball/b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "reference": "b81435fbd6648ea425d1ee96a2d8e68f4ceacd24", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/clock": "^1.0", + "symfony/polyfill-php83": "^1.28" + }, + "provide": { + "psr/clock-implementation": "1.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/now.php" + ], + "psr-4": { + "Symfony\\Component\\Clock\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Decouples applications from the system clock", + "homepage": "https://symfony.com", + "keywords": [ + "clock", + "psr20", + "time" + ], + "support": { + "source": "https://github.com/symfony/clock/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/console", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/66c1440edf6f339fd82ed6c7caa76cb006211b44", + "reference": "66c1440edf6f339fd82ed6c7caa76cb006211b44", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^7.2" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-24T10:34:04+00:00" + }, + { + "name": "symfony/css-selector", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/css-selector.git", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/css-selector/zipball/601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "reference": "601a5ce9aaad7bf10797e3663faefce9e26c24e2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\CssSelector\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Jean-François Simon", + "email": "jeanfrancois.simon@sensiolabs.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Converts CSS selectors to XPath expressions", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/css-selector/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/63afe740e99a13ba87ec199bb07bbdee937a5b62", + "reference": "63afe740e99a13ba87ec199bb07bbdee937a5b62", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "cf68d225bc43629de4ff54778029aee6dc191b83" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/cf68d225bc43629de4ff54778029aee6dc191b83", + "reference": "cf68d225bc43629de4ff54778029aee6dc191b83", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^6.4|^7.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/webpack-encore-bundle": "^1.0|^2.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-29T07:19:49+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", + "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-22T09:11:45+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/59eb412e93815df44f05f342958efa9f46b1e586", + "reference": "59eb412e93815df44f05f342958efa9f46b1e586", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d", + "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-30T19:00:26+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "4236baf01609667d53b20371486228231eb135fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/4236baf01609667d53b20371486228231eb135fd", + "reference": "4236baf01609667d53b20371486228231eb135fd", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + }, + "require-dev": { + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4.12|^7.1.5", + "symfony/clock": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-12T14:48:23+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/ac7b8e163e8c83dce3abcc055a502d4486051a9f", + "reference": "ac7b8e163e8c83dce3abcc055a502d4486051a9f", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^7.3", + "symfony/http-foundation": "^7.3", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^7.1", + "symfony/routing": "^6.4|^7.0", + "symfony/serializer": "^7.1", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-29T07:47:32+00:00" + }, + { + "name": "symfony/mailer", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mailer.git", + "reference": "0f375bbbde96ae8c78e4aa3e63aabd486e33364c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mailer/zipball/0f375bbbde96ae8c78e4aa3e63aabd486e33364c", + "reference": "0f375bbbde96ae8c78e4aa3e63aabd486e33364c", + "shasum": "" + }, + "require": { + "egulias/email-validator": "^2.1.10|^3|^4", + "php": ">=8.2", + "psr/event-dispatcher": "^1", + "psr/log": "^1|^2|^3", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/mime": "^7.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/twig-bridge": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mailer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps sending emails", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/mailer/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-04T09:51:09+00:00" + }, + { + "name": "symfony/mime", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/mime.git", + "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/mime/zipball/0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", + "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-intl-idn": "^1.10", + "symfony/polyfill-mbstring": "^1.0" + }, + "conflict": { + "egulias/email-validator": "~3.0.0", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/mailer": "<6.4", + "symfony/serializer": "<6.4.3|>7.0,<7.0.3" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3.1|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Mime\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows manipulating MIME messages", + "homepage": "https://symfony.com", + "keywords": [ + "mime", + "mime-type" + ], + "support": { + "source": "https://github.com/symfony/mime/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-02-19T08:51:26+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-idn", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-idn.git", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-idn/zipball/9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "reference": "9614ac4d8061dc257ecc64cba1b140873dce8ad3", + "shasum": "" + }, + "require": { + "php": ">=7.2", + "symfony/polyfill-intl-normalizer": "^1.10" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Idn\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Laurent Bassin", + "email": "laurent@bassin.info" + }, + { + "name": "Trevor Rowbotham", + "email": "trevor.rowbotham@pm.me" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's idn_to_ascii and idn_to_utf8 functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "idn", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-10T14:38:51+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php80", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php80.git", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php80/zipball/0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "reference": "0cc9dd0f17f61d8131e7df6b84bd344899fe2608", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php80\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ion Bazan", + "email": "ion.bazan@gmail.com" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.0+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-02T08:10:11+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-uuid", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-uuid.git", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-uuid/zipball/21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "reference": "21533be36c24be3f4b1669c4725c7d1d2bab4ae2", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-uuid": "*" + }, + "suggest": { + "ext-uuid": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Uuid\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for uuid functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/process", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-17T09:11:12+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "8e213820c5fea844ecea29203d2a308019007c15" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/8e213820c5fea844ecea29203d2a308019007c15", + "reference": "8e213820c5fea844ecea29203d2a308019007c15", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-24T20:43:28+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "reference": "f021b05a130d35510bd6b25fe9053c2a8a15d5d4", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-25T09:37:31+00:00" + }, + { + "name": "symfony/string", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125", + "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-20T20:19:01+00:00" + }, + { + "name": "symfony/translation", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation.git", + "reference": "4aba29076a29a3aa667e09b791e5f868973a8667" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation/zipball/4aba29076a29a3aa667e09b791e5f868973a8667", + "reference": "4aba29076a29a3aa667e09b791e5f868973a8667", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0", + "symfony/translation-contracts": "^2.5|^3.0" + }, + "conflict": { + "nikic/php-parser": "<5.0", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/http-kernel": "<6.4", + "symfony/service-contracts": "<2.5", + "symfony/twig-bundle": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "symfony/translation-implementation": "2.3|3.0" + }, + "require-dev": { + "nikic/php-parser": "^5.0", + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "^1.21", + "symfony/routing": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to internationalize your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/translation/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-29T07:19:49+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.6.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "reference": "df210c7a2573f1913b2d17cc95f90f53a73d8f7d", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.6-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.6.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-27T08:32:26+00:00" + }, + { + "name": "symfony/uid", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/uid.git", + "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/uid/zipball/7beeb2b885cd584cd01e126c5777206ae4c3c6a3", + "reference": "7beeb2b885cd584cd01e126c5777206ae4c3c6a3", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-uuid": "^1.15" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Uid\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Grégoire Pineau", + "email": "lyrixx@lyrixx.info" + }, + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to generate and represent UIDs", + "homepage": "https://symfony.com", + "keywords": [ + "UID", + "ulid", + "uuid" + ], + "support": { + "source": "https://github.com/symfony/uid/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-24T14:28:13+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/548f6760c54197b1084e1e5c71f6d9d523f2f78e", + "reference": "548f6760c54197b1084e1e5c71f6d9d523f2f78e", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-27T18:39:23+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "c9a1168891b5aaadfd6332ef44393330b3498c4c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/c9a1168891b5aaadfd6332ef44393330b3498c4c", + "reference": "c9a1168891b5aaadfd6332ef44393330b3498c4c", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-15T09:04:05+00:00" + }, + { + "name": "tijsverkoyen/css-to-inline-styles", + "version": "v2.3.0", + "source": { + "type": "git", + "url": "https://github.com/tijsverkoyen/CssToInlineStyles.git", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tijsverkoyen/CssToInlineStyles/zipball/0d72ac1c00084279c1816675284073c5a337c20d", + "reference": "0d72ac1c00084279c1816675284073c5a337c20d", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "php": "^7.4 || ^8.0", + "symfony/css-selector": "^5.4 || ^6.0 || ^7.0" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpunit/phpunit": "^8.5.21 || ^9.5.10" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.x-dev" + } + }, + "autoload": { + "psr-4": { + "TijsVerkoyen\\CssToInlineStyles\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Tijs Verkoyen", + "email": "css_to_inline_styles@verkoyen.eu", + "role": "Developer" + } + ], + "description": "CssToInlineStyles is a class that enables you to convert HTML-pages/files into HTML-pages/files with inline styles. This is very useful when you're sending emails.", + "homepage": "https://github.com/tijsverkoyen/CssToInlineStyles", + "support": { + "issues": "https://github.com/tijsverkoyen/CssToInlineStyles/issues", + "source": "https://github.com/tijsverkoyen/CssToInlineStyles/tree/v2.3.0" + }, + "time": "2024-12-21T16:25:41+00:00" + }, + { + "name": "vlucas/phpdotenv", + "version": "v5.6.2", + "source": { + "type": "git", + "url": "https://github.com/vlucas/phpdotenv.git", + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/vlucas/phpdotenv/zipball/24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "reference": "24ac4c74f91ee2c193fa1aaa5c249cb0822809af", + "shasum": "" + }, + "require": { + "ext-pcre": "*", + "graham-campbell/result-type": "^1.1.3", + "php": "^7.2.5 || ^8.0", + "phpoption/phpoption": "^1.9.3", + "symfony/polyfill-ctype": "^1.24", + "symfony/polyfill-mbstring": "^1.24", + "symfony/polyfill-php80": "^1.24" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.8.2", + "ext-filter": "*", + "phpunit/phpunit": "^8.5.34 || ^9.6.13 || ^10.4.2" + }, + "suggest": { + "ext-filter": "Required to use the boolean validator." + }, + "type": "library", + "extra": { + "bamarni-bin": { + "bin-links": true, + "forward-command": false + }, + "branch-alias": { + "dev-master": "5.6-dev" + } + }, + "autoload": { + "psr-4": { + "Dotenv\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Graham Campbell", + "email": "hello@gjcampbell.co.uk", + "homepage": "https://github.com/GrahamCampbell" + }, + { + "name": "Vance Lucas", + "email": "vance@vancelucas.com", + "homepage": "https://github.com/vlucas" + } + ], + "description": "Loads environment variables from `.env` to `getenv()`, `$_ENV` and `$_SERVER` automagically.", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "issues": "https://github.com/vlucas/phpdotenv/issues", + "source": "https://github.com/vlucas/phpdotenv/tree/v5.6.2" + }, + "funding": [ + { + "url": "https://github.com/GrahamCampbell", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/vlucas/phpdotenv", + "type": "tidelift" + } + ], + "time": "2025-04-30T23:37:27+00:00" + }, + { + "name": "voku/portable-ascii", + "version": "2.0.3", + "source": { + "type": "git", + "url": "https://github.com/voku/portable-ascii.git", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/voku/portable-ascii/zipball/b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "reference": "b1d923f88091c6bf09699efcd7c8a1b1bfd7351d", + "shasum": "" + }, + "require": { + "php": ">=7.0.0" + }, + "require-dev": { + "phpunit/phpunit": "~6.0 || ~7.0 || ~9.0" + }, + "suggest": { + "ext-intl": "Use Intl for transliterator_transliterate() support" + }, + "type": "library", + "autoload": { + "psr-4": { + "voku\\": "src/voku/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Lars Moelleken", + "homepage": "https://www.moelleken.org/" + } + ], + "description": "Portable ASCII library - performance optimized (ascii) string functions for php.", + "homepage": "https://github.com/voku/portable-ascii", + "keywords": [ + "ascii", + "clean", + "php" + ], + "support": { + "issues": "https://github.com/voku/portable-ascii/issues", + "source": "https://github.com/voku/portable-ascii/tree/2.0.3" + }, + "funding": [ + { + "url": "https://www.paypal.me/moelleken", + "type": "custom" + }, + { + "url": "https://github.com/voku", + "type": "github" + }, + { + "url": "https://opencollective.com/portable-ascii", + "type": "open_collective" + }, + { + "url": "https://www.patreon.com/voku", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/voku/portable-ascii", + "type": "tidelift" + } + ], + "time": "2024-11-21T01:49:47+00:00" + }, + { + "name": "webmozart/assert", + "version": "1.11.0", + "source": { + "type": "git", + "url": "https://github.com/webmozarts/assert.git", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/webmozarts/assert/zipball/11cb2199493b2f8a3b53e7f19068fc6aac760991", + "reference": "11cb2199493b2f8a3b53e7f19068fc6aac760991", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "php": "^7.2 || ^8.0" + }, + "conflict": { + "phpstan/phpstan": "<0.12.20", + "vimeo/psalm": "<4.6.1 || 4.6.2" + }, + "require-dev": { + "phpunit/phpunit": "^8.5.13" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.10-dev" + } + }, + "autoload": { + "psr-4": { + "Webmozart\\Assert\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Assertions to validate method input/output with nice error messages.", + "keywords": [ + "assert", + "check", + "validate" + ], + "support": { + "issues": "https://github.com/webmozarts/assert/issues", + "source": "https://github.com/webmozarts/assert/tree/1.11.0" + }, + "time": "2022-06-03T18:03:27+00:00" + } + ], + "packages-dev": [ + { + "name": "fakerphp/faker", + "version": "v1.24.1", + "source": { + "type": "git", + "url": "https://github.com/FakerPHP/Faker.git", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/FakerPHP/Faker/zipball/e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "reference": "e0ee18eb1e6dc3cda3ce9fd97e5a0689a88a64b5", + "shasum": "" + }, + "require": { + "php": "^7.4 || ^8.0", + "psr/container": "^1.0 || ^2.0", + "symfony/deprecation-contracts": "^2.2 || ^3.0" + }, + "conflict": { + "fzaninotto/faker": "*" + }, + "require-dev": { + "bamarni/composer-bin-plugin": "^1.4.1", + "doctrine/persistence": "^1.3 || ^2.0", + "ext-intl": "*", + "phpunit/phpunit": "^9.5.26", + "symfony/phpunit-bridge": "^5.4.16" + }, + "suggest": { + "doctrine/orm": "Required to use Faker\\ORM\\Doctrine", + "ext-curl": "Required by Faker\\Provider\\Image to download images.", + "ext-dom": "Required by Faker\\Provider\\HtmlLorem for generating random HTML.", + "ext-iconv": "Required by Faker\\Provider\\ru_RU\\Text::realText() for generating real Russian text.", + "ext-mbstring": "Required for multibyte Unicode string functionality." + }, + "type": "library", + "autoload": { + "psr-4": { + "Faker\\": "src/Faker/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "François Zaninotto" + } + ], + "description": "Faker is a PHP library that generates fake data for you.", + "keywords": [ + "data", + "faker", + "fixtures" + ], + "support": { + "issues": "https://github.com/FakerPHP/Faker/issues", + "source": "https://github.com/FakerPHP/Faker/tree/v1.24.1" + }, + "time": "2024-11-21T13:46:39+00:00" + }, + { + "name": "filp/whoops", + "version": "2.18.3", + "source": { + "type": "git", + "url": "https://github.com/filp/whoops.git", + "reference": "59a123a3d459c5a23055802237cb317f609867e5" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", + "reference": "59a123a3d459c5a23055802237cb317f609867e5", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0", + "psr/log": "^1.0.1 || ^2.0 || ^3.0" + }, + "require-dev": { + "mockery/mockery": "^1.0", + "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.3", + "symfony/var-dumper": "^4.0 || ^5.0" + }, + "suggest": { + "symfony/var-dumper": "Pretty print complex values better with var-dumper available", + "whoops/soap": "Formats errors as SOAP responses" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.7-dev" + } + }, + "autoload": { + "psr-4": { + "Whoops\\": "src/Whoops/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Filipe Dobreira", + "homepage": "https://github.com/filp", + "role": "Developer" + } + ], + "description": "php error handling for cool kids", + "homepage": "https://filp.github.io/whoops/", + "keywords": [ + "error", + "exception", + "handling", + "library", + "throwable", + "whoops" + ], + "support": { + "issues": "https://github.com/filp/whoops/issues", + "source": "https://github.com/filp/whoops/tree/2.18.3" + }, + "funding": [ + { + "url": "https://github.com/denis-sokolov", + "type": "github" + } + ], + "time": "2025-06-16T00:02:10+00:00" + }, + { + "name": "hamcrest/hamcrest-php", + "version": "v2.1.1", + "source": { + "type": "git", + "url": "https://github.com/hamcrest/hamcrest-php.git", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/hamcrest/hamcrest-php/zipball/f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "reference": "f8b1c0173b22fa6ec77a81fe63e5b01eba7e6487", + "shasum": "" + }, + "require": { + "php": "^7.4|^8.0" + }, + "replace": { + "cordoval/hamcrest-php": "*", + "davedevelopment/hamcrest-php": "*", + "kodova/hamcrest-php": "*" + }, + "require-dev": { + "phpunit/php-file-iterator": "^1.4 || ^2.0 || ^3.0", + "phpunit/phpunit": "^4.8.36 || ^5.7 || ^6.5 || ^7.0 || ^8.0 || ^9.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.1-dev" + } + }, + "autoload": { + "classmap": [ + "hamcrest" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "description": "This is the PHP port of Hamcrest Matchers", + "keywords": [ + "test" + ], + "support": { + "issues": "https://github.com/hamcrest/hamcrest-php/issues", + "source": "https://github.com/hamcrest/hamcrest-php/tree/v2.1.1" + }, + "time": "2025-04-30T06:54:44+00:00" + }, + { + "name": "laravel/breeze", + "version": "v2.3.7", + "source": { + "type": "git", + "url": "https://github.com/laravel/breeze.git", + "reference": "73149b5d84be3881b2fdda94b2ad289e7905c1a4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/breeze/zipball/73149b5d84be3881b2fdda94b2ad289e7905c1a4", + "reference": "73149b5d84be3881b2fdda94b2ad289e7905c1a4", + "shasum": "" + }, + "require": { + "illuminate/console": "^11.0|^12.0", + "illuminate/filesystem": "^11.0|^12.0", + "illuminate/support": "^11.0|^12.0", + "illuminate/validation": "^11.0|^12.0", + "php": "^8.2.0", + "symfony/console": "^7.0" + }, + "require-dev": { + "laravel/framework": "^11.0|^12.0", + "orchestra/testbench-core": "^9.0|^10.0", + "phpstan/phpstan": "^2.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Breeze\\BreezeServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Breeze\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Minimal Laravel authentication scaffolding with Blade and Tailwind.", + "keywords": [ + "auth", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/breeze/issues", + "source": "https://github.com/laravel/breeze" + }, + "time": "2025-06-17T13:07:20+00:00" + }, + { + "name": "laravel/pail", + "version": "v1.2.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/pail.git", + "reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pail/zipball/8cc3d575c1f0e57eeb923f366a37528c50d2385a", + "reference": "8cc3d575c1f0e57eeb923f366a37528c50d2385a", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "illuminate/console": "^10.24|^11.0|^12.0", + "illuminate/contracts": "^10.24|^11.0|^12.0", + "illuminate/log": "^10.24|^11.0|^12.0", + "illuminate/process": "^10.24|^11.0|^12.0", + "illuminate/support": "^10.24|^11.0|^12.0", + "nunomaduro/termwind": "^1.15|^2.0", + "php": "^8.2", + "symfony/console": "^6.0|^7.0" + }, + "require-dev": { + "laravel/framework": "^10.24|^11.0|^12.0", + "laravel/pint": "^1.13", + "orchestra/testbench-core": "^8.13|^9.0|^10.0", + "pestphp/pest": "^2.20|^3.0", + "pestphp/pest-plugin-type-coverage": "^2.3|^3.0", + "phpstan/phpstan": "^1.12.27", + "symfony/var-dumper": "^6.3|^7.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Pail\\PailServiceProvider" + ] + }, + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Laravel\\Pail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Easily delve into your Laravel application's log files directly from the command line.", + "homepage": "https://github.com/laravel/pail", + "keywords": [ + "dev", + "laravel", + "logs", + "php", + "tail" + ], + "support": { + "issues": "https://github.com/laravel/pail/issues", + "source": "https://github.com/laravel/pail" + }, + "time": "2025-06-05T13:55:57+00:00" + }, + { + "name": "laravel/pint", + "version": "v1.22.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/pint.git", + "reference": "941d1927c5ca420c22710e98420287169c7bcaf7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/pint/zipball/941d1927c5ca420c22710e98420287169c7bcaf7", + "reference": "941d1927c5ca420c22710e98420287169c7bcaf7", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-mbstring": "*", + "ext-tokenizer": "*", + "ext-xml": "*", + "php": "^8.2.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^3.75.0", + "illuminate/view": "^11.44.7", + "larastan/larastan": "^3.4.0", + "laravel-zero/framework": "^11.36.1", + "mockery/mockery": "^1.6.12", + "nunomaduro/termwind": "^2.3.1", + "pestphp/pest": "^2.36.0" + }, + "bin": [ + "builds/pint" + ], + "type": "project", + "autoload": { + "psr-4": { + "App\\": "app/", + "Database\\Seeders\\": "database/seeders/", + "Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "An opinionated code formatter for PHP.", + "homepage": "https://laravel.com", + "keywords": [ + "format", + "formatter", + "lint", + "linter", + "php" + ], + "support": { + "issues": "https://github.com/laravel/pint/issues", + "source": "https://github.com/laravel/pint" + }, + "time": "2025-05-08T08:38:12+00:00" + }, + { + "name": "laravel/sail", + "version": "v1.43.1", + "source": { + "type": "git", + "url": "https://github.com/laravel/sail.git", + "reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/sail/zipball/3e7d899232a8c5e3ea4fc6dee7525ad583887e72", + "reference": "3e7d899232a8c5e3ea4fc6dee7525ad583887e72", + "shasum": "" + }, + "require": { + "illuminate/console": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/contracts": "^9.52.16|^10.0|^11.0|^12.0", + "illuminate/support": "^9.52.16|^10.0|^11.0|^12.0", + "php": "^8.0", + "symfony/console": "^6.0|^7.0", + "symfony/yaml": "^6.0|^7.0" + }, + "require-dev": { + "orchestra/testbench": "^7.0|^8.0|^9.0|^10.0", + "phpstan/phpstan": "^1.10" + }, + "bin": [ + "bin/sail" + ], + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Sail\\SailServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Sail\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + } + ], + "description": "Docker files for running a basic Laravel application.", + "keywords": [ + "docker", + "laravel" + ], + "support": { + "issues": "https://github.com/laravel/sail/issues", + "source": "https://github.com/laravel/sail" + }, + "time": "2025-05-19T13:19:21+00:00" + }, + { + "name": "mockery/mockery", + "version": "1.6.12", + "source": { + "type": "git", + "url": "https://github.com/mockery/mockery.git", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/mockery/mockery/zipball/1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "reference": "1f4efdd7d3beafe9807b08156dfcb176d18f1699", + "shasum": "" + }, + "require": { + "hamcrest/hamcrest-php": "^2.0.1", + "lib-pcre": ">=7.0", + "php": ">=7.3" + }, + "conflict": { + "phpunit/phpunit": "<8.0" + }, + "require-dev": { + "phpunit/phpunit": "^8.5 || ^9.6.17", + "symplify/easy-coding-standard": "^12.1.14" + }, + "type": "library", + "autoload": { + "files": [ + "library/helpers.php", + "library/Mockery.php" + ], + "psr-4": { + "Mockery\\": "library/Mockery" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Pádraic Brady", + "email": "padraic.brady@gmail.com", + "homepage": "https://github.com/padraic", + "role": "Author" + }, + { + "name": "Dave Marshall", + "email": "dave.marshall@atstsolutions.co.uk", + "homepage": "https://davedevelopment.co.uk", + "role": "Developer" + }, + { + "name": "Nathanael Esayeas", + "email": "nathanael.esayeas@protonmail.com", + "homepage": "https://github.com/ghostwriter", + "role": "Lead Developer" + } + ], + "description": "Mockery is a simple yet flexible PHP mock object framework", + "homepage": "https://github.com/mockery/mockery", + "keywords": [ + "BDD", + "TDD", + "library", + "mock", + "mock objects", + "mockery", + "stub", + "test", + "test double", + "testing" + ], + "support": { + "docs": "https://docs.mockery.io/", + "issues": "https://github.com/mockery/mockery/issues", + "rss": "https://github.com/mockery/mockery/releases.atom", + "security": "https://github.com/mockery/mockery/security/advisories", + "source": "https://github.com/mockery/mockery" + }, + "time": "2024-05-16T03:13:13+00:00" + }, + { + "name": "myclabs/deep-copy", + "version": "1.13.1", + "source": { + "type": "git", + "url": "https://github.com/myclabs/DeepCopy.git", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/1720ddd719e16cf0db4eb1c6eca108031636d46c", + "reference": "1720ddd719e16cf0db4eb1c6eca108031636d46c", + "shasum": "" + }, + "require": { + "php": "^7.1 || ^8.0" + }, + "conflict": { + "doctrine/collections": "<1.6.8", + "doctrine/common": "<2.13.3 || >=3 <3.2.2" + }, + "require-dev": { + "doctrine/collections": "^1.6.8", + "doctrine/common": "^2.13.3 || ^3.2.2", + "phpspec/prophecy": "^1.10", + "phpunit/phpunit": "^7.5.20 || ^8.5.23 || ^9.5.13" + }, + "type": "library", + "autoload": { + "files": [ + "src/DeepCopy/deep_copy.php" + ], + "psr-4": { + "DeepCopy\\": "src/DeepCopy/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "Create deep copies (clones) of your objects", + "keywords": [ + "clone", + "copy", + "duplicate", + "object", + "object graph" + ], + "support": { + "issues": "https://github.com/myclabs/DeepCopy/issues", + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.1" + }, + "funding": [ + { + "url": "https://tidelift.com/funding/github/packagist/myclabs/deep-copy", + "type": "tidelift" + } + ], + "time": "2025-04-29T12:36:36+00:00" + }, + { + "name": "nunomaduro/collision", + "version": "v8.8.2", + "source": { + "type": "git", + "url": "https://github.com/nunomaduro/collision.git", + "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nunomaduro/collision/zipball/60207965f9b7b7a4ce15a0f75d57f9dadb105bdb", + "reference": "60207965f9b7b7a4ce15a0f75d57f9dadb105bdb", + "shasum": "" + }, + "require": { + "filp/whoops": "^2.18.1", + "nunomaduro/termwind": "^2.3.1", + "php": "^8.2.0", + "symfony/console": "^7.3.0" + }, + "conflict": { + "laravel/framework": "<11.44.2 || >=13.0.0", + "phpunit/phpunit": "<11.5.15 || >=13.0.0" + }, + "require-dev": { + "brianium/paratest": "^7.8.3", + "larastan/larastan": "^3.4.2", + "laravel/framework": "^11.44.2 || ^12.18", + "laravel/pint": "^1.22.1", + "laravel/sail": "^1.43.1", + "laravel/sanctum": "^4.1.1", + "laravel/tinker": "^2.10.1", + "orchestra/testbench-core": "^9.12.0 || ^10.4", + "pestphp/pest": "^3.8.2", + "sebastian/environment": "^7.2.1 || ^8.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "NunoMaduro\\Collision\\Adapters\\Laravel\\CollisionServiceProvider" + ] + }, + "branch-alias": { + "dev-8.x": "8.x-dev" + } + }, + "autoload": { + "files": [ + "./src/Adapters/Phpunit/Autoload.php" + ], + "psr-4": { + "NunoMaduro\\Collision\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nuno Maduro", + "email": "enunomaduro@gmail.com" + } + ], + "description": "Cli error handling for console/command-line PHP applications.", + "keywords": [ + "artisan", + "cli", + "command-line", + "console", + "dev", + "error", + "handling", + "laravel", + "laravel-zero", + "php", + "symfony" + ], + "support": { + "issues": "https://github.com/nunomaduro/collision/issues", + "source": "https://github.com/nunomaduro/collision" + }, + "funding": [ + { + "url": "https://www.paypal.com/paypalme/enunomaduro", + "type": "custom" + }, + { + "url": "https://github.com/nunomaduro", + "type": "github" + }, + { + "url": "https://www.patreon.com/nunomaduro", + "type": "patreon" + } + ], + "time": "2025-06-25T02:12:12+00:00" + }, + { + "name": "phar-io/manifest", + "version": "2.0.4", + "source": { + "type": "git", + "url": "https://github.com/phar-io/manifest.git", + "reference": "54750ef60c58e43759730615a392c31c80e23176" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/manifest/zipball/54750ef60c58e43759730615a392c31c80e23176", + "reference": "54750ef60c58e43759730615a392c31c80e23176", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-phar": "*", + "ext-xmlwriter": "*", + "phar-io/version": "^3.0.1", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", + "support": { + "issues": "https://github.com/phar-io/manifest/issues", + "source": "https://github.com/phar-io/manifest/tree/2.0.4" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:33:53+00:00" + }, + { + "name": "phar-io/version", + "version": "3.2.1", + "source": { + "type": "git", + "url": "https://github.com/phar-io/version.git", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/phar-io/version/zipball/4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "reference": "4f7fd7836c6f332bb2933569e566a0d6c4cbed74", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + }, + { + "name": "Sebastian Heuer", + "email": "sebastian@phpeople.de", + "role": "Developer" + }, + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "Developer" + } + ], + "description": "Library for handling version information and constraints", + "support": { + "issues": "https://github.com/phar-io/version/issues", + "source": "https://github.com/phar-io/version/tree/3.2.1" + }, + "time": "2022-02-21T01:04:05+00:00" + }, + { + "name": "phpunit/php-code-coverage", + "version": "11.0.10", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-code-coverage.git", + "reference": "1a800a7446add2d79cc6b3c01c45381810367d76" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-code-coverage/zipball/1a800a7446add2d79cc6b3c01c45381810367d76", + "reference": "1a800a7446add2d79cc6b3c01c45381810367d76", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-libxml": "*", + "ext-xmlwriter": "*", + "nikic/php-parser": "^5.4.0", + "php": ">=8.2", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-text-template": "^4.0.1", + "sebastian/code-unit-reverse-lookup": "^4.0.1", + "sebastian/complexity": "^4.0.1", + "sebastian/environment": "^7.2.0", + "sebastian/lines-of-code": "^3.0.1", + "sebastian/version": "^5.0.2", + "theseer/tokenizer": "^1.2.3" + }, + "require-dev": { + "phpunit/phpunit": "^11.5.2" + }, + "suggest": { + "ext-pcov": "PHP extension that provides line coverage", + "ext-xdebug": "PHP extension that provides line coverage as well as branch and path coverage" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.0.x-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that provides collection, processing, and rendering functionality for PHP code coverage information.", + "homepage": "https://github.com/sebastianbergmann/php-code-coverage", + "keywords": [ + "coverage", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-code-coverage/issues", + "security": "https://github.com/sebastianbergmann/php-code-coverage/security/policy", + "source": "https://github.com/sebastianbergmann/php-code-coverage/tree/show" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/php-code-coverage", + "type": "tidelift" + } + ], + "time": "2025-06-18T08:56:18+00:00" + }, + { + "name": "phpunit/php-file-iterator", + "version": "5.1.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-file-iterator.git", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-file-iterator/zipball/118cfaaa8bc5aef3287bf315b6060b1174754af6", + "reference": "118cfaaa8bc5aef3287bf315b6060b1174754af6", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "FilterIterator implementation that filters files based on a list of suffixes.", + "homepage": "https://github.com/sebastianbergmann/php-file-iterator/", + "keywords": [ + "filesystem", + "iterator" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-file-iterator/issues", + "security": "https://github.com/sebastianbergmann/php-file-iterator/security/policy", + "source": "https://github.com/sebastianbergmann/php-file-iterator/tree/5.1.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-08-27T05:02:59+00:00" + }, + { + "name": "phpunit/php-invoker", + "version": "5.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-invoker.git", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-invoker/zipball/c1ca3814734c07492b3d4c5f794f4b0995333da2", + "reference": "c1ca3814734c07492b3d4c5f794f4b0995333da2", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "ext-pcntl": "*", + "phpunit/phpunit": "^11.0" + }, + "suggest": { + "ext-pcntl": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Invoke callables with a timeout", + "homepage": "https://github.com/sebastianbergmann/php-invoker/", + "keywords": [ + "process" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-invoker/issues", + "security": "https://github.com/sebastianbergmann/php-invoker/security/policy", + "source": "https://github.com/sebastianbergmann/php-invoker/tree/5.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:07:44+00:00" + }, + { + "name": "phpunit/php-text-template", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-text-template.git", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-text-template/zipball/3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "reference": "3e0404dc6b300e6bf56415467ebcb3fe4f33e964", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Simple template engine.", + "homepage": "https://github.com/sebastianbergmann/php-text-template/", + "keywords": [ + "template" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-text-template/issues", + "security": "https://github.com/sebastianbergmann/php-text-template/security/policy", + "source": "https://github.com/sebastianbergmann/php-text-template/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:08:43+00:00" + }, + { + "name": "phpunit/php-timer", + "version": "7.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/php-timer.git", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/php-timer/zipball/3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "reference": "3b415def83fbcb41f991d9ebf16ae4ad8b7837b3", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Utility class for timing", + "homepage": "https://github.com/sebastianbergmann/php-timer/", + "keywords": [ + "timer" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/php-timer/issues", + "security": "https://github.com/sebastianbergmann/php-timer/security/policy", + "source": "https://github.com/sebastianbergmann/php-timer/tree/7.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:09:35+00:00" + }, + { + "name": "phpunit/phpunit", + "version": "11.5.25", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/phpunit.git", + "reference": "864ab32b3ff52058f917c5b19b3cef821e4a4f1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/864ab32b3ff52058f917c5b19b3cef821e4a4f1b", + "reference": "864ab32b3ff52058f917c5b19b3cef821e4a4f1b", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-json": "*", + "ext-libxml": "*", + "ext-mbstring": "*", + "ext-xml": "*", + "ext-xmlwriter": "*", + "myclabs/deep-copy": "^1.13.1", + "phar-io/manifest": "^2.0.4", + "phar-io/version": "^3.2.1", + "php": ">=8.2", + "phpunit/php-code-coverage": "^11.0.10", + "phpunit/php-file-iterator": "^5.1.0", + "phpunit/php-invoker": "^5.0.1", + "phpunit/php-text-template": "^4.0.1", + "phpunit/php-timer": "^7.0.1", + "sebastian/cli-parser": "^3.0.2", + "sebastian/code-unit": "^3.0.3", + "sebastian/comparator": "^6.3.1", + "sebastian/diff": "^6.0.2", + "sebastian/environment": "^7.2.1", + "sebastian/exporter": "^6.3.0", + "sebastian/global-state": "^7.0.2", + "sebastian/object-enumerator": "^6.0.1", + "sebastian/type": "^5.1.2", + "sebastian/version": "^5.0.2", + "staabm/side-effects-detector": "^1.0.5" + }, + "suggest": { + "ext-soap": "To be able to generate mocks based on WSDL files" + }, + "bin": [ + "phpunit" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "11.5-dev" + } + }, + "autoload": { + "files": [ + "src/Framework/Assert/Functions.php" + ], + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "The PHP Unit Testing framework.", + "homepage": "https://phpunit.de/", + "keywords": [ + "phpunit", + "testing", + "xunit" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/phpunit/issues", + "security": "https://github.com/sebastianbergmann/phpunit/security/policy", + "source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.25" + }, + "funding": [ + { + "url": "https://phpunit.de/sponsors.html", + "type": "custom" + }, + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/phpunit/phpunit", + "type": "tidelift" + } + ], + "time": "2025-06-27T04:36:07+00:00" + }, + { + "name": "sebastian/cli-parser", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/cli-parser.git", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/cli-parser/zipball/15c5dd40dc4f38794d383bb95465193f5e0ae180", + "reference": "15c5dd40dc4f38794d383bb95465193f5e0ae180", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for parsing CLI options", + "homepage": "https://github.com/sebastianbergmann/cli-parser", + "support": { + "issues": "https://github.com/sebastianbergmann/cli-parser/issues", + "security": "https://github.com/sebastianbergmann/cli-parser/security/policy", + "source": "https://github.com/sebastianbergmann/cli-parser/tree/3.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:41:36+00:00" + }, + { + "name": "sebastian/code-unit", + "version": "3.0.3", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit.git", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit/zipball/54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "reference": "54391c61e4af8078e5b276ab082b6d3c54c9ad64", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the PHP code units", + "homepage": "https://github.com/sebastianbergmann/code-unit", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit/issues", + "security": "https://github.com/sebastianbergmann/code-unit/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit/tree/3.0.3" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-19T07:56:08+00:00" + }, + { + "name": "sebastian/code-unit-reverse-lookup", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/code-unit-reverse-lookup.git", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/code-unit-reverse-lookup/zipball/183a9b2632194febd219bb9246eee421dad8d45e", + "reference": "183a9b2632194febd219bb9246eee421dad8d45e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Looks up which function or method a line of code belongs to", + "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", + "support": { + "issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues", + "security": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/security/policy", + "source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:45:54+00:00" + }, + { + "name": "sebastian/comparator", + "version": "6.3.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/comparator.git", + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "reference": "24b8fbc2c8e201bb1308e7b05148d6ab393b6959", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/diff": "^6.0", + "sebastian/exporter": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.4" + }, + "suggest": { + "ext-bcmath": "For comparing BcMath\\Number objects" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.3-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@2bepublished.at" + } + ], + "description": "Provides the functionality to compare PHP values for equality", + "homepage": "https://github.com/sebastianbergmann/comparator", + "keywords": [ + "comparator", + "compare", + "equality" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/comparator/issues", + "security": "https://github.com/sebastianbergmann/comparator/security/policy", + "source": "https://github.com/sebastianbergmann/comparator/tree/6.3.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-07T06:57:01+00:00" + }, + { + "name": "sebastian/complexity", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/complexity.git", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/complexity/zipball/ee41d384ab1906c68852636b6de493846e13e5a0", + "reference": "ee41d384ab1906c68852636b6de493846e13e5a0", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for calculating the complexity of PHP code units", + "homepage": "https://github.com/sebastianbergmann/complexity", + "support": { + "issues": "https://github.com/sebastianbergmann/complexity/issues", + "security": "https://github.com/sebastianbergmann/complexity/security/policy", + "source": "https://github.com/sebastianbergmann/complexity/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:49:50+00:00" + }, + { + "name": "sebastian/diff", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/diff.git", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/diff/zipball/b4ccd857127db5d41a5b676f24b51371d76d8544", + "reference": "b4ccd857127db5d41a5b676f24b51371d76d8544", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0", + "symfony/process": "^4.2 || ^5" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Kore Nordmann", + "email": "mail@kore-nordmann.de" + } + ], + "description": "Diff implementation", + "homepage": "https://github.com/sebastianbergmann/diff", + "keywords": [ + "diff", + "udiff", + "unidiff", + "unified diff" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/diff/issues", + "security": "https://github.com/sebastianbergmann/diff/security/policy", + "source": "https://github.com/sebastianbergmann/diff/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:53:05+00:00" + }, + { + "name": "sebastian/environment", + "version": "7.2.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/environment.git", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/environment/zipball/a5c75038693ad2e8d4b6c15ba2403532647830c4", + "reference": "a5c75038693ad2e8d4b6c15ba2403532647830c4", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.2-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Provides functionality to handle HHVM/PHP environments", + "homepage": "https://github.com/sebastianbergmann/environment", + "keywords": [ + "Xdebug", + "environment", + "hhvm" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/environment/issues", + "security": "https://github.com/sebastianbergmann/environment/security/policy", + "source": "https://github.com/sebastianbergmann/environment/tree/7.2.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + }, + { + "url": "https://liberapay.com/sebastianbergmann", + "type": "liberapay" + }, + { + "url": "https://thanks.dev/u/gh/sebastianbergmann", + "type": "thanks_dev" + }, + { + "url": "https://tidelift.com/funding/github/packagist/sebastian/environment", + "type": "tidelift" + } + ], + "time": "2025-05-21T11:55:47+00:00" + }, + { + "name": "sebastian/exporter", + "version": "6.3.0", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/exporter.git", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/exporter/zipball/3473f61172093b2da7de1fb5782e1f24cc036dc3", + "reference": "3473f61172093b2da7de1fb5782e1f24cc036dc3", + "shasum": "" + }, + "require": { + "ext-mbstring": "*", + "php": ">=8.2", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Volker Dusch", + "email": "github@wallbash.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + }, + { + "name": "Bernhard Schussek", + "email": "bschussek@gmail.com" + } + ], + "description": "Provides the functionality to export PHP variables for visualization", + "homepage": "https://www.github.com/sebastianbergmann/exporter", + "keywords": [ + "export", + "exporter" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/exporter/issues", + "security": "https://github.com/sebastianbergmann/exporter/security/policy", + "source": "https://github.com/sebastianbergmann/exporter/tree/6.3.0" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-12-05T09:17:50+00:00" + }, + { + "name": "sebastian/global-state", + "version": "7.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/global-state.git", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/global-state/zipball/3be331570a721f9a4b5917f4209773de17f747d7", + "reference": "3be331570a721f9a4b5917f4209773de17f747d7", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "ext-dom": "*", + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "7.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Snapshotting of global state", + "homepage": "https://www.github.com/sebastianbergmann/global-state", + "keywords": [ + "global state" + ], + "support": { + "issues": "https://github.com/sebastianbergmann/global-state/issues", + "security": "https://github.com/sebastianbergmann/global-state/security/policy", + "source": "https://github.com/sebastianbergmann/global-state/tree/7.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:57:36+00:00" + }, + { + "name": "sebastian/lines-of-code", + "version": "3.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/lines-of-code.git", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/lines-of-code/zipball/d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "reference": "d36ad0d782e5756913e42ad87cb2890f4ffe467a", + "shasum": "" + }, + "require": { + "nikic/php-parser": "^5.0", + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library for counting the lines of code in PHP source code", + "homepage": "https://github.com/sebastianbergmann/lines-of-code", + "support": { + "issues": "https://github.com/sebastianbergmann/lines-of-code/issues", + "security": "https://github.com/sebastianbergmann/lines-of-code/security/policy", + "source": "https://github.com/sebastianbergmann/lines-of-code/tree/3.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T04:58:38+00:00" + }, + { + "name": "sebastian/object-enumerator", + "version": "6.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-enumerator.git", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-enumerator/zipball/f5b498e631a74204185071eb41f33f38d64608aa", + "reference": "f5b498e631a74204185071eb41f33f38d64608aa", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "sebastian/object-reflector": "^4.0", + "sebastian/recursion-context": "^6.0" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Traverses array structures and object graphs to enumerate all referenced objects", + "homepage": "https://github.com/sebastianbergmann/object-enumerator/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-enumerator/issues", + "security": "https://github.com/sebastianbergmann/object-enumerator/security/policy", + "source": "https://github.com/sebastianbergmann/object-enumerator/tree/6.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:00:13+00:00" + }, + { + "name": "sebastian/object-reflector", + "version": "4.0.1", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/object-reflector.git", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/object-reflector/zipball/6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "reference": "6e1a43b411b2ad34146dee7524cb13a068bb35f9", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "4.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + } + ], + "description": "Allows reflection of object attributes, including inherited and non-public ones", + "homepage": "https://github.com/sebastianbergmann/object-reflector/", + "support": { + "issues": "https://github.com/sebastianbergmann/object-reflector/issues", + "security": "https://github.com/sebastianbergmann/object-reflector/security/policy", + "source": "https://github.com/sebastianbergmann/object-reflector/tree/4.0.1" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:01:32+00:00" + }, + { + "name": "sebastian/recursion-context", + "version": "6.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/recursion-context.git", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/694d156164372abbd149a4b85ccda2e4670c0e16", + "reference": "694d156164372abbd149a4b85ccda2e4670c0e16", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "6.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de" + }, + { + "name": "Jeff Welch", + "email": "whatthejeff@gmail.com" + }, + { + "name": "Adam Harvey", + "email": "aharvey@php.net" + } + ], + "description": "Provides functionality to recursively process PHP variables", + "homepage": "https://github.com/sebastianbergmann/recursion-context", + "support": { + "issues": "https://github.com/sebastianbergmann/recursion-context/issues", + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/6.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-07-03T05:10:34+00:00" + }, + { + "name": "sebastian/type", + "version": "5.1.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/type.git", + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/type/zipball/a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "reference": "a8a7e30534b0eb0c77cd9d07e82de1a114389f5e", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "phpunit/phpunit": "^11.3" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.1-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Collection of value objects that represent the types of the PHP type system", + "homepage": "https://github.com/sebastianbergmann/type", + "support": { + "issues": "https://github.com/sebastianbergmann/type/issues", + "security": "https://github.com/sebastianbergmann/type/security/policy", + "source": "https://github.com/sebastianbergmann/type/tree/5.1.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2025-03-18T13:35:50+00:00" + }, + { + "name": "sebastian/version", + "version": "5.0.2", + "source": { + "type": "git", + "url": "https://github.com/sebastianbergmann/version.git", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/sebastianbergmann/version/zipball/c687e3387b99f5b03b6caa64c74b63e2936ff874", + "reference": "c687e3387b99f5b03b6caa64c74b63e2936ff874", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "5.0-dev" + } + }, + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Sebastian Bergmann", + "email": "sebastian@phpunit.de", + "role": "lead" + } + ], + "description": "Library that helps with managing the version number of Git-hosted PHP projects", + "homepage": "https://github.com/sebastianbergmann/version", + "support": { + "issues": "https://github.com/sebastianbergmann/version/issues", + "security": "https://github.com/sebastianbergmann/version/security/policy", + "source": "https://github.com/sebastianbergmann/version/tree/5.0.2" + }, + "funding": [ + { + "url": "https://github.com/sebastianbergmann", + "type": "github" + } + ], + "time": "2024-10-09T05:16:32+00:00" + }, + { + "name": "staabm/side-effects-detector", + "version": "1.0.5", + "source": { + "type": "git", + "url": "https://github.com/staabm/side-effects-detector.git", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/staabm/side-effects-detector/zipball/d8334211a140ce329c13726d4a715adbddd0a163", + "reference": "d8334211a140ce329c13726d4a715adbddd0a163", + "shasum": "" + }, + "require": { + "ext-tokenizer": "*", + "php": "^7.4 || ^8.0" + }, + "require-dev": { + "phpstan/extension-installer": "^1.4.3", + "phpstan/phpstan": "^1.12.6", + "phpunit/phpunit": "^9.6.21", + "symfony/var-dumper": "^5.4.43", + "tomasvotruba/type-coverage": "1.0.0", + "tomasvotruba/unused-public": "1.0.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "lib/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "description": "A static analysis tool to detect side effects in PHP code", + "keywords": [ + "static analysis" + ], + "support": { + "issues": "https://github.com/staabm/side-effects-detector/issues", + "source": "https://github.com/staabm/side-effects-detector/tree/1.0.5" + }, + "funding": [ + { + "url": "https://github.com/staabm", + "type": "github" + } + ], + "time": "2024-10-20T05:08:20+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.3.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "cea40a48279d58dc3efee8112634cb90141156c2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/cea40a48279d58dc3efee8112634cb90141156c2", + "reference": "cea40a48279d58dc3efee8112634cb90141156c2", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.3.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-04T10:10:33+00:00" + }, + { + "name": "theseer/tokenizer", + "version": "1.2.3", + "source": { + "type": "git", + "url": "https://github.com/theseer/tokenizer.git", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/theseer/tokenizer/zipball/737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "reference": "737eda637ed5e28c3413cb1ebe8bb52cbf1ca7a2", + "shasum": "" + }, + "require": { + "ext-dom": "*", + "ext-tokenizer": "*", + "ext-xmlwriter": "*", + "php": "^7.2 || ^8.0" + }, + "type": "library", + "autoload": { + "classmap": [ + "src/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Arne Blankerts", + "email": "arne@blankerts.de", + "role": "Developer" + } + ], + "description": "A small library for converting tokenized PHP source code into XML and potentially other formats", + "support": { + "issues": "https://github.com/theseer/tokenizer/issues", + "source": "https://github.com/theseer/tokenizer/tree/1.2.3" + }, + "funding": [ + { + "url": "https://github.com/theseer", + "type": "github" + } + ], + "time": "2024-03-03T12:36:25+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": "^8.2" + }, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/website/config/app.php b/website/config/app.php new file mode 100644 index 0000000..41fcbf2 --- /dev/null +++ b/website/config/app.php @@ -0,0 +1,208 @@ + env('APP_NAME', 'Laravel'), + + /* + |-------------------------------------------------------------------------- + | Application Environment + |-------------------------------------------------------------------------- + | + | This value determines the "environment" your application is currently + | running in. This may determine how you prefer to configure various + | services the application utilizes. Set this in your ".env" file. + | + */ + + 'env' => env('APP_ENV', 'production'), + + /* + |-------------------------------------------------------------------------- + | Application Debug Mode + |-------------------------------------------------------------------------- + | + | When your application is in debug mode, detailed error messages with + | stack traces will be shown on every error that occurs within your + | application. If disabled, a simple generic error page is shown. + | + */ + + 'debug' => (bool) env('APP_DEBUG', false), + + /* + |-------------------------------------------------------------------------- + | Application URL + |-------------------------------------------------------------------------- + | + | This URL is used by the console to properly generate URLs when using + | the Artisan command line tool. You should set this to the root of + | the application so that it's available within Artisan commands. + | + */ + + 'url' => env('APP_URL', 'http://localhost'), + + /* + |-------------------------------------------------------------------------- + | Application Timezone + |-------------------------------------------------------------------------- + | + | Here you may specify the default timezone for your application, which + | will be used by the PHP date and date-time functions. The timezone + | is set to "UTC" by default as it is suitable for most use cases. + | + */ + + 'timezone' => 'UTC', + + /* + |-------------------------------------------------------------------------- + | Application Locale Configuration + |-------------------------------------------------------------------------- + | + | The application locale determines the default locale that will be used + | by Laravel's translation / localization methods. This option can be + | set to any locale for which you plan to have translation strings. + | + */ + + 'locale' => env('APP_LOCALE', 'en'), + + 'fallback_locale' => env('APP_FALLBACK_LOCALE', 'en'), + + 'faker_locale' => env('APP_FAKER_LOCALE', 'en_US'), + + /* + |-------------------------------------------------------------------------- + | Encryption Key + |-------------------------------------------------------------------------- + | + | This key is utilized by Laravel's encryption services and should be set + | to a random, 32 character string to ensure that all encrypted values + | are secure. You should do this prior to deploying the application. + | + */ + + 'cipher' => 'AES-256-CBC', + + 'key' => env('APP_KEY'), + + 'previous_keys' => [ + ...array_filter( + explode(',', env('APP_PREVIOUS_KEYS', '')) + ), + ], + + /* + |-------------------------------------------------------------------------- + | Maintenance Mode Driver + |-------------------------------------------------------------------------- + | + | These configuration options determine the driver used to determine and + | manage Laravel's "maintenance mode" status. The "cache" driver will + | allow maintenance mode to be controlled across multiple machines. + | + | Supported drivers: "file", "cache" + | + */ + + 'maintenance' => [ + 'driver' => env('APP_MAINTENANCE_DRIVER', 'file'), + 'store' => env('APP_MAINTENANCE_STORE', 'database'), + ], + + 'providers' => [ + + /* + * Laravel Framework Service Providers... + */ + Illuminate\Auth\AuthServiceProvider::class, + Illuminate\Broadcasting\BroadcastServiceProvider::class, + Illuminate\Bus\BusServiceProvider::class, + Illuminate\Cache\CacheServiceProvider::class, + Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class, + Illuminate\Cookie\CookieServiceProvider::class, + Illuminate\Database\DatabaseServiceProvider::class, + Illuminate\Encryption\EncryptionServiceProvider::class, + Illuminate\Filesystem\FilesystemServiceProvider::class, + Illuminate\Foundation\Providers\FoundationServiceProvider::class, + Illuminate\Hashing\HashServiceProvider::class, + Illuminate\Mail\MailServiceProvider::class, + Illuminate\Notifications\NotificationServiceProvider::class, + Illuminate\Pagination\PaginationServiceProvider::class, + Illuminate\Pipeline\PipelineServiceProvider::class, + Illuminate\Queue\QueueServiceProvider::class, + Illuminate\Redis\RedisServiceProvider::class, + Illuminate\Auth\Passwords\PasswordResetServiceProvider::class, + Illuminate\Session\SessionServiceProvider::class, + Illuminate\Translation\TranslationServiceProvider::class, + Illuminate\Validation\ValidationServiceProvider::class, + Illuminate\View\ViewServiceProvider::class, + + /* + * Package Service Providers... + */ + Laravel\Sanctum\SanctumServiceProvider::class, + Maatwebsite\Excel\ExcelServiceProvider::class, + /* + * Application Service Providers... + */ + App\Providers\AppServiceProvider::class, + App\Providers\AuthServiceProvider::class, + // App\Providers\BroadcastServiceProvider::class, + App\Providers\EventServiceProvider::class, + App\Providers\RouteServiceProvider::class, + ], + + + 'aliases' => [ + 'App' => Illuminate\Support\Facades\App::class, + 'Arr' => Illuminate\Support\Arr::class, + 'Artisan' => Illuminate\Support\Facades\Artisan::class, + 'Auth' => Illuminate\Support\Facades\Auth::class, + 'Blade' => Illuminate\Support\Facades\Blade::class, + 'Broadcast' => Illuminate\Support\Facades\Broadcast::class, + 'Bus' => Illuminate\Support\Facades\Bus::class, + 'Cache' => Illuminate\Support\Facades\Cache::class, + 'Config' => Illuminate\Support\Facades\Config::class, + 'Cookie' => Illuminate\Support\Facades\Cookie::class, + 'Crypt' => Illuminate\Support\Facades\Crypt::class, + 'DB' => Illuminate\Support\Facades\DB::class, + 'Eloquent' => Illuminate\Database\Eloquent\Model::class, + 'Event' => Illuminate\Support\Facades\Event::class, + 'File' => Illuminate\Support\Facades\File::class, + 'Gate' => Illuminate\Support\Facades\Gate::class, + 'Hash' => Illuminate\Support\Facades\Hash::class, + 'Http' => Illuminate\Support\Facades\Http::class, + 'Lang' => Illuminate\Support\Facades\Lang::class, + 'Log' => Illuminate\Support\Facades\Log::class, + 'Mail' => Illuminate\Support\Facades\Mail::class, + 'Notification' => Illuminate\Support\Facades\Notification::class, + 'Password' => Illuminate\Support\Facades\Password::class, + 'Queue' => Illuminate\Support\Facades\Queue::class, + 'Redirect' => Illuminate\Support\Facades\Redirect::class, + 'Request' => Illuminate\Support\Facades\Request::class, + 'Response' => Illuminate\Support\Facades\Response::class, + 'Route' => Illuminate\Support\Facades\Route::class, + 'Schema' => Illuminate\Support\Facades\Schema::class, + 'Session' => Illuminate\Support\Facades\Session::class, + 'Storage' => Illuminate\Support\Facades\Storage::class, + 'Str' => Illuminate\Support\Str::class, + 'URL' => Illuminate\Support\Facades\URL::class, + 'Validator' => Illuminate\Support\Facades\Validator::class, + 'View' => Illuminate\Support\Facades\View::class, + 'Excel' => Maatwebsite\Excel\Facades\Excel::class, + ], +]; diff --git a/website/config/auth.php b/website/config/auth.php new file mode 100644 index 0000000..a1559b9 --- /dev/null +++ b/website/config/auth.php @@ -0,0 +1,121 @@ + [ + 'guard' => env('AUTH_GUARD', 'web'), + 'passwords' => env('AUTH_PASSWORD_BROKER', 'users'), + ], + + /* + |-------------------------------------------------------------------------- + | Authentication Guards + |-------------------------------------------------------------------------- + | + | Next, you may define every authentication guard for your application. + | Of course, a great default configuration has been defined for you + | which utilizes session storage plus the Eloquent user provider. + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | Supported: "session" + | + */ + + 'guards' => [ + 'web' => [ + 'driver' => 'session', + 'provider' => 'users', + ], + + 'sanctum' => [ + 'driver' => 'sanctum', + 'provider' => 'users', + ], +], + + + /* + |-------------------------------------------------------------------------- + | User Providers + |-------------------------------------------------------------------------- + | + | All authentication guards have a user provider, which defines how the + | users are actually retrieved out of your database or other storage + | system used by the application. Typically, Eloquent is utilized. + | + | If you have multiple user tables or models you may configure multiple + | providers to represent the model / table. These providers may then + | be assigned to any extra authentication guards you have defined. + | + | Supported: "database", "eloquent" + | + */ + + 'providers' => [ + 'users' => [ + 'driver' => 'eloquent', + 'model' => env('AUTH_MODEL', App\Models\User::class), + ], + + // 'users' => [ + // 'driver' => 'database', + // 'table' => 'users', + // ], + ], + + /* + |-------------------------------------------------------------------------- + | Resetting Passwords + |-------------------------------------------------------------------------- + | + | These configuration options specify the behavior of Laravel's password + | reset functionality, including the table utilized for token storage + | and the user provider that is invoked to actually retrieve users. + | + | The expiry time is the number of minutes that each reset token will be + | considered valid. This security feature keeps tokens short-lived so + | they have less time to be guessed. You may change this as needed. + | + | The throttle setting is the number of seconds a user must wait before + | generating more password reset tokens. This prevents the user from + | quickly generating a very large amount of password reset tokens. + | + */ + + 'passwords' => [ + 'users' => [ + 'provider' => 'users', + 'table' => env('AUTH_PASSWORD_RESET_TOKEN_TABLE', 'password_reset_tokens'), + 'expire' => 60, + 'throttle' => 60, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Password Confirmation Timeout + |-------------------------------------------------------------------------- + | + | Here you may define the number of seconds before a password confirmation + | window expires and users are asked to re-enter their password via the + | confirmation screen. By default, the timeout lasts for three hours. + | + */ + + 'password_timeout' => env('AUTH_PASSWORD_TIMEOUT', 10800), + +]; diff --git a/website/config/cache.php b/website/config/cache.php new file mode 100644 index 0000000..925f7d2 --- /dev/null +++ b/website/config/cache.php @@ -0,0 +1,108 @@ + env('CACHE_STORE', 'database'), + + /* + |-------------------------------------------------------------------------- + | Cache Stores + |-------------------------------------------------------------------------- + | + | Here you may define all of the cache "stores" for your application as + | well as their drivers. You may even define multiple stores for the + | same cache driver to group types of items stored in your caches. + | + | Supported drivers: "array", "database", "file", "memcached", + | "redis", "dynamodb", "octane", "null" + | + */ + + 'stores' => [ + + 'array' => [ + 'driver' => 'array', + 'serialize' => false, + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_CACHE_CONNECTION'), + 'table' => env('DB_CACHE_TABLE', 'cache'), + 'lock_connection' => env('DB_CACHE_LOCK_CONNECTION'), + 'lock_table' => env('DB_CACHE_LOCK_TABLE'), + ], + + 'file' => [ + 'driver' => 'file', + 'path' => storage_path('framework/cache/data'), + 'lock_path' => storage_path('framework/cache/data'), + ], + + 'memcached' => [ + 'driver' => 'memcached', + 'persistent_id' => env('MEMCACHED_PERSISTENT_ID'), + 'sasl' => [ + env('MEMCACHED_USERNAME'), + env('MEMCACHED_PASSWORD'), + ], + 'options' => [ + // Memcached::OPT_CONNECT_TIMEOUT => 2000, + ], + 'servers' => [ + [ + 'host' => env('MEMCACHED_HOST', '127.0.0.1'), + 'port' => env('MEMCACHED_PORT', 11211), + 'weight' => 100, + ], + ], + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_CACHE_CONNECTION', 'cache'), + 'lock_connection' => env('REDIS_CACHE_LOCK_CONNECTION', 'default'), + ], + + 'dynamodb' => [ + 'driver' => 'dynamodb', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'table' => env('DYNAMODB_CACHE_TABLE', 'cache'), + 'endpoint' => env('DYNAMODB_ENDPOINT'), + ], + + 'octane' => [ + 'driver' => 'octane', + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Cache Key Prefix + |-------------------------------------------------------------------------- + | + | When utilizing the APC, database, memcached, Redis, and DynamoDB cache + | stores, there might be other applications using the same cache. For + | that reason, you may prefix every cache key to avoid collisions. + | + */ + + 'prefix' => env('CACHE_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_cache_'), + +]; diff --git a/website/config/cors.php b/website/config/cors.php new file mode 100644 index 0000000..6999142 --- /dev/null +++ b/website/config/cors.php @@ -0,0 +1,22 @@ + ['api/*', 'storage/*'], + + 'allowed_methods' => ['*'], + + 'allowed_origins' => ['*'], // ⚠️ Gunakan ['http://localhost:xxxxx'] di production + + 'allowed_origins_patterns' => [], + + 'allowed_headers' => ['*'], + + 'exposed_headers' => [], + + 'max_age' => 0, + + 'supports_credentials' => true + , + +]; diff --git a/website/config/database.php b/website/config/database.php new file mode 100644 index 0000000..8910562 --- /dev/null +++ b/website/config/database.php @@ -0,0 +1,174 @@ + env('DB_CONNECTION', 'sqlite'), + + /* + |-------------------------------------------------------------------------- + | Database Connections + |-------------------------------------------------------------------------- + | + | Below are all of the database connections defined for your application. + | An example configuration is provided for each database system which + | is supported by Laravel. You're free to add / remove connections. + | + */ + + 'connections' => [ + + 'sqlite' => [ + 'driver' => 'sqlite', + 'url' => env('DB_URL'), + 'database' => env('DB_DATABASE', database_path('database.sqlite')), + 'prefix' => '', + 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), + 'busy_timeout' => null, + 'journal_mode' => null, + 'synchronous' => null, + ], + + 'mysql' => [ + 'driver' => 'mysql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'mariadb' => [ + 'driver' => 'mariadb', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '3306'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'unix_socket' => env('DB_SOCKET', ''), + 'charset' => env('DB_CHARSET', 'utf8mb4'), + 'collation' => env('DB_COLLATION', 'utf8mb4_unicode_ci'), + 'prefix' => '', + 'prefix_indexes' => true, + 'strict' => true, + 'engine' => null, + 'options' => extension_loaded('pdo_mysql') ? array_filter([ + PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), + ]) : [], + ], + + 'pgsql' => [ + 'driver' => 'pgsql', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', '127.0.0.1'), + 'port' => env('DB_PORT', '5432'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + 'search_path' => 'public', + 'sslmode' => 'prefer', + ], + + 'sqlsrv' => [ + 'driver' => 'sqlsrv', + 'url' => env('DB_URL'), + 'host' => env('DB_HOST', 'localhost'), + 'port' => env('DB_PORT', '1433'), + 'database' => env('DB_DATABASE', 'laravel'), + 'username' => env('DB_USERNAME', 'root'), + 'password' => env('DB_PASSWORD', ''), + 'charset' => env('DB_CHARSET', 'utf8'), + 'prefix' => '', + 'prefix_indexes' => true, + // 'encrypt' => env('DB_ENCRYPT', 'yes'), + // 'trust_server_certificate' => env('DB_TRUST_SERVER_CERTIFICATE', 'false'), + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Migration Repository Table + |-------------------------------------------------------------------------- + | + | This table keeps track of all the migrations that have already run for + | your application. Using this information, we can determine which of + | the migrations on disk haven't actually been run on the database. + | + */ + + 'migrations' => [ + 'table' => 'migrations', + 'update_date_on_publish' => true, + ], + + /* + |-------------------------------------------------------------------------- + | Redis Databases + |-------------------------------------------------------------------------- + | + | Redis is an open source, fast, and advanced key-value store that also + | provides a richer body of commands than a typical key-value system + | such as Memcached. You may define your connection settings here. + | + */ + + 'redis' => [ + + 'client' => env('REDIS_CLIENT', 'phpredis'), + + 'options' => [ + 'cluster' => env('REDIS_CLUSTER', 'redis'), + 'prefix' => env('REDIS_PREFIX', Str::slug(env('APP_NAME', 'laravel'), '_').'_database_'), + 'persistent' => env('REDIS_PERSISTENT', false), + ], + + 'default' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_DB', '0'), + ], + + 'cache' => [ + 'url' => env('REDIS_URL'), + 'host' => env('REDIS_HOST', '127.0.0.1'), + 'username' => env('REDIS_USERNAME'), + 'password' => env('REDIS_PASSWORD'), + 'port' => env('REDIS_PORT', '6379'), + 'database' => env('REDIS_CACHE_DB', '1'), + ], + + ], + +]; diff --git a/website/config/fcm.php b/website/config/fcm.php new file mode 100644 index 0000000..36eb802 --- /dev/null +++ b/website/config/fcm.php @@ -0,0 +1,10 @@ + [ + 'file' => env('FCM_CREDENTIALS', storage_path('app/firebase/service-account.json')), + ], + 'default' => [ + 'sender_id' => env('FCM_SENDER_ID'), + 'server_key' => env('FCM_SERVER_KEY'), + ], +]; \ No newline at end of file diff --git a/website/config/filesystems.php b/website/config/filesystems.php new file mode 100644 index 0000000..3d671bd --- /dev/null +++ b/website/config/filesystems.php @@ -0,0 +1,80 @@ + env('FILESYSTEM_DISK', 'local'), + + /* + |-------------------------------------------------------------------------- + | Filesystem Disks + |-------------------------------------------------------------------------- + | + | Below you may configure as many filesystem disks as necessary, and you + | may even configure multiple disks for the same driver. Examples for + | most supported storage drivers are configured here for reference. + | + | Supported drivers: "local", "ftp", "sftp", "s3" + | + */ + + 'disks' => [ + + 'local' => [ + 'driver' => 'local', + 'root' => storage_path('app/private'), + 'serve' => true, + 'throw' => false, + 'report' => false, + ], + + 'public' => [ + 'driver' => 'local', + 'root' => storage_path('app/public'), + 'url' => env('APP_URL').'/storage', + 'visibility' => 'public', + 'throw' => false, + 'report' => false, + ], + + 's3' => [ + 'driver' => 's3', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION'), + 'bucket' => env('AWS_BUCKET'), + 'url' => env('AWS_URL'), + 'endpoint' => env('AWS_ENDPOINT'), + 'use_path_style_endpoint' => env('AWS_USE_PATH_STYLE_ENDPOINT', false), + 'throw' => false, + 'report' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Symbolic Links + |-------------------------------------------------------------------------- + | + | Here you may configure the symbolic links that will be created when the + | `storage:link` Artisan command is executed. The array keys should be + | the locations of the links and the values should be their targets. + | + */ + + 'links' => [ + public_path('storage') => storage_path('app/public'), + ], + +]; diff --git a/website/config/logging.php b/website/config/logging.php new file mode 100644 index 0000000..1345f6f --- /dev/null +++ b/website/config/logging.php @@ -0,0 +1,132 @@ + env('LOG_CHANNEL', 'stack'), + + /* + |-------------------------------------------------------------------------- + | Deprecations Log Channel + |-------------------------------------------------------------------------- + | + | This option controls the log channel that should be used to log warnings + | regarding deprecated PHP and library features. This allows you to get + | your application ready for upcoming major versions of dependencies. + | + */ + + 'deprecations' => [ + 'channel' => env('LOG_DEPRECATIONS_CHANNEL', 'null'), + 'trace' => env('LOG_DEPRECATIONS_TRACE', false), + ], + + /* + |-------------------------------------------------------------------------- + | Log Channels + |-------------------------------------------------------------------------- + | + | Here you may configure the log channels for your application. Laravel + | utilizes the Monolog PHP logging library, which includes a variety + | of powerful log handlers and formatters that you're free to use. + | + | Available drivers: "single", "daily", "slack", "syslog", + | "errorlog", "monolog", "custom", "stack" + | + */ + + 'channels' => [ + + 'stack' => [ + 'driver' => 'stack', + 'channels' => explode(',', env('LOG_STACK', 'single')), + 'ignore_exceptions' => false, + ], + + 'single' => [ + 'driver' => 'single', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'daily' => [ + 'driver' => 'daily', + 'path' => storage_path('logs/laravel.log'), + 'level' => env('LOG_LEVEL', 'debug'), + 'days' => env('LOG_DAILY_DAYS', 14), + 'replace_placeholders' => true, + ], + + 'slack' => [ + 'driver' => 'slack', + 'url' => env('LOG_SLACK_WEBHOOK_URL'), + 'username' => env('LOG_SLACK_USERNAME', 'Laravel Log'), + 'emoji' => env('LOG_SLACK_EMOJI', ':boom:'), + 'level' => env('LOG_LEVEL', 'critical'), + 'replace_placeholders' => true, + ], + + 'papertrail' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => env('LOG_PAPERTRAIL_HANDLER', SyslogUdpHandler::class), + 'handler_with' => [ + 'host' => env('PAPERTRAIL_URL'), + 'port' => env('PAPERTRAIL_PORT'), + 'connectionString' => 'tls://'.env('PAPERTRAIL_URL').':'.env('PAPERTRAIL_PORT'), + ], + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'stderr' => [ + 'driver' => 'monolog', + 'level' => env('LOG_LEVEL', 'debug'), + 'handler' => StreamHandler::class, + 'handler_with' => [ + 'stream' => 'php://stderr', + ], + 'formatter' => env('LOG_STDERR_FORMATTER'), + 'processors' => [PsrLogMessageProcessor::class], + ], + + 'syslog' => [ + 'driver' => 'syslog', + 'level' => env('LOG_LEVEL', 'debug'), + 'facility' => env('LOG_SYSLOG_FACILITY', LOG_USER), + 'replace_placeholders' => true, + ], + + 'errorlog' => [ + 'driver' => 'errorlog', + 'level' => env('LOG_LEVEL', 'debug'), + 'replace_placeholders' => true, + ], + + 'null' => [ + 'driver' => 'monolog', + 'handler' => NullHandler::class, + ], + + 'emergency' => [ + 'path' => storage_path('logs/laravel.log'), + ], + + ], + +]; diff --git a/website/config/mail.php b/website/config/mail.php new file mode 100644 index 0000000..0034532 --- /dev/null +++ b/website/config/mail.php @@ -0,0 +1,118 @@ + env('MAIL_MAILER', 'log'), + + /* + |-------------------------------------------------------------------------- + | Mailer Configurations + |-------------------------------------------------------------------------- + | + | Here you may configure all of the mailers used by your application plus + | their respective settings. Several examples have been configured for + | you and you are free to add your own as your application requires. + | + | Laravel supports a variety of mail "transport" drivers that can be used + | when delivering an email. You may specify which one you're using for + | your mailers below. You may also add additional mailers if needed. + | + | Supported: "smtp", "sendmail", "mailgun", "ses", "ses-v2", + | "postmark", "resend", "log", "array", + | "failover", "roundrobin" + | + */ + + 'mailers' => [ + + 'smtp' => [ + 'transport' => 'smtp', + 'scheme' => env('MAIL_SCHEME'), + 'url' => env('MAIL_URL'), + 'host' => env('MAIL_HOST', '127.0.0.1'), + 'port' => env('MAIL_PORT', 2525), + 'username' => env('MAIL_USERNAME'), + 'password' => env('MAIL_PASSWORD'), + 'timeout' => null, + 'local_domain' => env('MAIL_EHLO_DOMAIN', parse_url(env('APP_URL', 'http://localhost'), PHP_URL_HOST)), + ], + + 'ses' => [ + 'transport' => 'ses', + ], + + 'postmark' => [ + 'transport' => 'postmark', + // 'message_stream_id' => env('POSTMARK_MESSAGE_STREAM_ID'), + // 'client' => [ + // 'timeout' => 5, + // ], + ], + + 'resend' => [ + 'transport' => 'resend', + ], + + 'sendmail' => [ + 'transport' => 'sendmail', + 'path' => env('MAIL_SENDMAIL_PATH', '/usr/sbin/sendmail -bs -i'), + ], + + 'log' => [ + 'transport' => 'log', + 'channel' => env('MAIL_LOG_CHANNEL'), + ], + + 'array' => [ + 'transport' => 'array', + ], + + 'failover' => [ + 'transport' => 'failover', + 'mailers' => [ + 'smtp', + 'log', + ], + 'retry_after' => 60, + ], + + 'roundrobin' => [ + 'transport' => 'roundrobin', + 'mailers' => [ + 'ses', + 'postmark', + ], + 'retry_after' => 60, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Global "From" Address + |-------------------------------------------------------------------------- + | + | You may wish for all emails sent by your application to be sent from + | the same address. Here you may specify a name and address that is + | used globally for all emails that are sent by your application. + | + */ + + 'from' => [ + 'address' => env('MAIL_FROM_ADDRESS', 'hello@example.com'), + 'name' => env('MAIL_FROM_NAME', 'Example'), + ], + +]; diff --git a/website/config/queue.php b/website/config/queue.php new file mode 100644 index 0000000..116bd8d --- /dev/null +++ b/website/config/queue.php @@ -0,0 +1,112 @@ + env('QUEUE_CONNECTION', 'database'), + + /* + |-------------------------------------------------------------------------- + | Queue Connections + |-------------------------------------------------------------------------- + | + | Here you may configure the connection options for every queue backend + | used by your application. An example configuration is provided for + | each backend supported by Laravel. You're also free to add more. + | + | Drivers: "sync", "database", "beanstalkd", "sqs", "redis", "null" + | + */ + + 'connections' => [ + + 'sync' => [ + 'driver' => 'sync', + ], + + 'database' => [ + 'driver' => 'database', + 'connection' => env('DB_QUEUE_CONNECTION'), + 'table' => env('DB_QUEUE_TABLE', 'jobs'), + 'queue' => env('DB_QUEUE', 'default'), + 'retry_after' => (int) env('DB_QUEUE_RETRY_AFTER', 90), + 'after_commit' => false, + ], + + 'beanstalkd' => [ + 'driver' => 'beanstalkd', + 'host' => env('BEANSTALKD_QUEUE_HOST', 'localhost'), + 'queue' => env('BEANSTALKD_QUEUE', 'default'), + 'retry_after' => (int) env('BEANSTALKD_QUEUE_RETRY_AFTER', 90), + 'block_for' => 0, + 'after_commit' => false, + ], + + 'sqs' => [ + 'driver' => 'sqs', + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'prefix' => env('SQS_PREFIX', 'https://sqs.us-east-1.amazonaws.com/your-account-id'), + 'queue' => env('SQS_QUEUE', 'default'), + 'suffix' => env('SQS_SUFFIX'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + 'after_commit' => false, + ], + + 'redis' => [ + 'driver' => 'redis', + 'connection' => env('REDIS_QUEUE_CONNECTION', 'default'), + 'queue' => env('REDIS_QUEUE', 'default'), + 'retry_after' => (int) env('REDIS_QUEUE_RETRY_AFTER', 90), + 'block_for' => null, + 'after_commit' => false, + ], + + ], + + /* + |-------------------------------------------------------------------------- + | Job Batching + |-------------------------------------------------------------------------- + | + | The following options configure the database and table that store job + | batching information. These options can be updated to any database + | connection and table which has been defined by your application. + | + */ + + 'batching' => [ + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'job_batches', + ], + + /* + |-------------------------------------------------------------------------- + | Failed Queue Jobs + |-------------------------------------------------------------------------- + | + | These options configure the behavior of failed queue job logging so you + | can control how and where failed jobs are stored. Laravel ships with + | support for storing failed jobs in a simple file or in a database. + | + | Supported drivers: "database-uuids", "dynamodb", "file", "null" + | + */ + + 'failed' => [ + 'driver' => env('QUEUE_FAILED_DRIVER', 'database-uuids'), + 'database' => env('DB_CONNECTION', 'sqlite'), + 'table' => 'failed_jobs', + ], + +]; diff --git a/website/config/sanctum.php b/website/config/sanctum.php new file mode 100644 index 0000000..44527d6 --- /dev/null +++ b/website/config/sanctum.php @@ -0,0 +1,84 @@ + explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf( + '%s%s', + 'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1', + Sanctum::currentApplicationUrlWithPort(), + // Sanctum::currentRequestHost(), + ))), + + /* + |-------------------------------------------------------------------------- + | Sanctum Guards + |-------------------------------------------------------------------------- + | + | This array contains the authentication guards that will be checked when + | Sanctum is trying to authenticate a request. If none of these guards + | are able to authenticate the request, Sanctum will use the bearer + | token that's present on an incoming request for authentication. + | + */ + + 'guard' => ['web'], + + /* + |-------------------------------------------------------------------------- + | Expiration Minutes + |-------------------------------------------------------------------------- + | + | This value controls the number of minutes until an issued token will be + | considered expired. This will override any values set in the token's + | "expires_at" attribute, but first-party sessions are not affected. + | + */ + + 'expiration' => null, + + /* + |-------------------------------------------------------------------------- + | Token Prefix + |-------------------------------------------------------------------------- + | + | Sanctum can prefix new tokens in order to take advantage of numerous + | security scanning initiatives maintained by open source platforms + | that notify developers if they commit tokens into repositories. + | + | See: https://docs.github.com/en/code-security/secret-scanning/about-secret-scanning + | + */ + + 'token_prefix' => env('SANCTUM_TOKEN_PREFIX', ''), + + /* + |-------------------------------------------------------------------------- + | Sanctum Middleware + |-------------------------------------------------------------------------- + | + | When authenticating your first-party SPA with Sanctum you may need to + | customize some of the middleware Sanctum uses while processing the + | request. You may change the middleware listed below as required. + | + */ + + 'middleware' => [ + 'authenticate_session' => Laravel\Sanctum\Http\Middleware\AuthenticateSession::class, + 'encrypt_cookies' => Illuminate\Cookie\Middleware\EncryptCookies::class, + 'validate_csrf_token' => Illuminate\Foundation\Http\Middleware\ValidateCsrfToken::class, + ], + +]; diff --git a/website/config/services.php b/website/config/services.php new file mode 100644 index 0000000..6182e4b --- /dev/null +++ b/website/config/services.php @@ -0,0 +1,38 @@ + [ + 'token' => env('POSTMARK_TOKEN'), + ], + + 'resend' => [ + 'key' => env('RESEND_KEY'), + ], + + 'ses' => [ + 'key' => env('AWS_ACCESS_KEY_ID'), + 'secret' => env('AWS_SECRET_ACCESS_KEY'), + 'region' => env('AWS_DEFAULT_REGION', 'us-east-1'), + ], + + 'slack' => [ + 'notifications' => [ + 'bot_user_oauth_token' => env('SLACK_BOT_USER_OAUTH_TOKEN'), + 'channel' => env('SLACK_BOT_USER_DEFAULT_CHANNEL'), + ], + ], + +]; diff --git a/website/config/session.php b/website/config/session.php new file mode 100644 index 0000000..b5fa531 --- /dev/null +++ b/website/config/session.php @@ -0,0 +1,217 @@ + env('SESSION_DRIVER', 'database'), + + /* + |-------------------------------------------------------------------------- + | Session Lifetime + |-------------------------------------------------------------------------- + | + | Here you may specify the number of minutes that you wish the session + | to be allowed to remain idle before it expires. If you want them + | to expire immediately when the browser is closed then you may + | indicate that via the expire_on_close configuration option. + | + */ + + 'lifetime' => (int) env('SESSION_LIFETIME', 120), + + 'expire_on_close' => env('SESSION_EXPIRE_ON_CLOSE', false), + + /* + |-------------------------------------------------------------------------- + | Session Encryption + |-------------------------------------------------------------------------- + | + | This option allows you to easily specify that all of your session data + | should be encrypted before it's stored. All encryption is performed + | automatically by Laravel and you may use the session like normal. + | + */ + + 'encrypt' => env('SESSION_ENCRYPT', false), + + /* + |-------------------------------------------------------------------------- + | Session File Location + |-------------------------------------------------------------------------- + | + | When utilizing the "file" session driver, the session files are placed + | on disk. The default storage location is defined here; however, you + | are free to provide another location where they should be stored. + | + */ + + 'files' => storage_path('framework/sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Database Connection + |-------------------------------------------------------------------------- + | + | When using the "database" or "redis" session drivers, you may specify a + | connection that should be used to manage these sessions. This should + | correspond to a connection in your database configuration options. + | + */ + + 'connection' => env('SESSION_CONNECTION'), + + /* + |-------------------------------------------------------------------------- + | Session Database Table + |-------------------------------------------------------------------------- + | + | When using the "database" session driver, you may specify the table to + | be used to store sessions. Of course, a sensible default is defined + | for you; however, you're welcome to change this to another table. + | + */ + + 'table' => env('SESSION_TABLE', 'sessions'), + + /* + |-------------------------------------------------------------------------- + | Session Cache Store + |-------------------------------------------------------------------------- + | + | When using one of the framework's cache driven session backends, you may + | define the cache store which should be used to store the session data + | between requests. This must match one of your defined cache stores. + | + | Affects: "dynamodb", "memcached", "redis" + | + */ + + 'store' => env('SESSION_STORE'), + + /* + |-------------------------------------------------------------------------- + | Session Sweeping Lottery + |-------------------------------------------------------------------------- + | + | Some session drivers must manually sweep their storage location to get + | rid of old sessions from storage. Here are the chances that it will + | happen on a given request. By default, the odds are 2 out of 100. + | + */ + + 'lottery' => [2, 100], + + /* + |-------------------------------------------------------------------------- + | Session Cookie Name + |-------------------------------------------------------------------------- + | + | Here you may change the name of the session cookie that is created by + | the framework. Typically, you should not need to change this value + | since doing so does not grant a meaningful security improvement. + | + */ + + 'cookie' => env( + 'SESSION_COOKIE', + Str::slug(env('APP_NAME', 'laravel'), '_').'_session' + ), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Path + |-------------------------------------------------------------------------- + | + | The session cookie path determines the path for which the cookie will + | be regarded as available. Typically, this will be the root path of + | your application, but you're free to change this when necessary. + | + */ + + 'path' => env('SESSION_PATH', '/'), + + /* + |-------------------------------------------------------------------------- + | Session Cookie Domain + |-------------------------------------------------------------------------- + | + | This value determines the domain and subdomains the session cookie is + | available to. By default, the cookie will be available to the root + | domain and all subdomains. Typically, this shouldn't be changed. + | + */ + + 'domain' => env('SESSION_DOMAIN'), + + /* + |-------------------------------------------------------------------------- + | HTTPS Only Cookies + |-------------------------------------------------------------------------- + | + | By setting this option to true, session cookies will only be sent back + | to the server if the browser has a HTTPS connection. This will keep + | the cookie from being sent to you when it can't be done securely. + | + */ + + 'secure' => env('SESSION_SECURE_COOKIE'), + + /* + |-------------------------------------------------------------------------- + | HTTP Access Only + |-------------------------------------------------------------------------- + | + | Setting this value to true will prevent JavaScript from accessing the + | value of the cookie and the cookie will only be accessible through + | the HTTP protocol. It's unlikely you should disable this option. + | + */ + + 'http_only' => env('SESSION_HTTP_ONLY', true), + + /* + |-------------------------------------------------------------------------- + | Same-Site Cookies + |-------------------------------------------------------------------------- + | + | This option determines how your cookies behave when cross-site requests + | take place, and can be used to mitigate CSRF attacks. By default, we + | will set this value to "lax" to permit secure cross-site requests. + | + | See: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie#samesitesamesite-value + | + | Supported: "lax", "strict", "none", null + | + */ + + 'same_site' => env('SESSION_SAME_SITE', 'lax'), + + /* + |-------------------------------------------------------------------------- + | Partitioned Cookies + |-------------------------------------------------------------------------- + | + | Setting this value to true will tie the cookie to the top-level site for + | a cross-site context. Partitioned cookies are accepted by the browser + | when flagged "secure" and the Same-Site attribute is set to "none". + | + */ + + 'partitioned' => env('SESSION_PARTITIONED_COOKIE', false), + +]; diff --git a/website/convert_remaining.ps1 b/website/convert_remaining.ps1 new file mode 100644 index 0000000..e73c858 --- /dev/null +++ b/website/convert_remaining.ps1 @@ -0,0 +1,81 @@ +# Script untuk mengkonversi direktori yang tersisa +$viewsPath = "resources/views" + +# Daftar direktori yang tersisa +$directories = @( + "semesters", + "jadwals", + "prestasis", + "pelanggarans", + "catatan_kesehatans", + "pembayarans" +) + +foreach ($dir in $directories) { + $fullPath = Join-Path $viewsPath $dir + if (Test-Path $fullPath) { + Write-Host "Processing directory: $dir" + + # Proses semua file .blade.php dalam direktori + $files = Get-ChildItem -Path $fullPath -Filter "*.blade.php" + + foreach ($file in $files) { + Write-Host " Converting: $($file.Name)" + + $content = Get-Content $file.FullName -Raw + + # Skip jika sudah menggunakan x-app-layout + if ($content -match '') { + Write-Host " Skipped (already converted): $($file.Name)" + continue + } + + # Konversi @extends('layouts.app') ke + $content = $content -replace '@extends\(''layouts\.app''\)', '' + + # Hapus @section('content') + $content = $content -replace '@section\(''content''\)', '' + + # Ganti @endsection dengan + $content = $content -replace '@endsection', '' + + # Tambah header slot setelah + $title = "" + if ($file.Name -match 'index\.blade\.php') { + $title = "Daftar " + ($dir -replace '_', ' ' -replace 's$', '') + } elseif ($file.Name -match 'create\.blade\.php') { + $title = "Tambah " + ($dir -replace '_', ' ' -replace 's$', '') + } elseif ($file.Name -match 'edit\.blade\.php') { + $title = "Edit " + ($dir -replace '_', ' ' -replace 's$', '') + } elseif ($file.Name -match 'show\.blade\.php') { + $title = "Detail " + ($dir -replace '_', ' ' -replace 's$', '') + } else { + $title = "Manage " + ($dir -replace '_', ' ' -replace 's$', '') + } + + # Tambah header slot + $headerSlot = "`n `n

`n {{ __('$title') }}`n

`n
`n`n
`n
`n
`n
" + + $content = $content -replace '', "$headerSlot" + + # Tutup div wrapper + $content = $content -replace '', "`n
`n
`n
`n
`n
" + + # Update styling untuk container dan card + $content = $content -replace '
', '' + $content = $content -replace '
', '' + $content = $content -replace '
\s*
\s*', '' + + # Update button styling + $content = $content -replace 'class="btn-primary mb-3 inline-block"', 'class="btn-primary"' + + # Update alert styling + $content = $content -replace 'class="alert-success"', 'class="alert-success mb-4"' + + # Simpan file + Set-Content -Path $file.FullName -Value $content -Encoding UTF8 + } + } +} + +Write-Host "Conversion completed!" \ No newline at end of file diff --git a/website/convert_views.ps1 b/website/convert_views.ps1 new file mode 100644 index 0000000..391a551 --- /dev/null +++ b/website/convert_views.ps1 @@ -0,0 +1,87 @@ +# Script untuk mengkonversi semua view dari @extends ke x-app-layout +$viewsPath = "resources/views" + +# Daftar direktori yang perlu dikonversi +$directories = @( + "kelas", + "semesters", + "mata_pelajarans", + "jadwals", + "absensis", + "nilai_santris", + "prestasis", + "pelanggarans", + "catatan_kesehatans", + "beritas", + "pembayarans", + "alumnis" +) + +foreach ($dir in $directories) { + $fullPath = Join-Path $viewsPath $dir + if (Test-Path $fullPath) { + Write-Host "Processing directory: $dir" + + # Proses semua file .blade.php dalam direktori + $files = Get-ChildItem -Path $fullPath -Filter "*.blade.php" + + foreach ($file in $files) { + Write-Host " Converting: $($file.Name)" + + $content = Get-Content $file.FullName -Raw + + # Skip jika sudah menggunakan x-app-layout + if ($content -match '') { + Write-Host " Skipped (already converted): $($file.Name)" + continue + } + + # Konversi @extends('layouts.app') ke + $content = $content -replace '@extends\(''layouts\.app''\)', '' + + # Hapus @section('content') + $content = $content -replace '@section\(''content''\)', '' + + # Ganti @endsection dengan + $content = $content -replace '@endsection', '' + + # Tambah header slot setelah + $title = "" + if ($file.Name -match 'index\.blade\.php') { + $title = "Daftar " + ($dir -replace '_', ' ' -replace 's$', '') + } elseif ($file.Name -match 'create\.blade\.php') { + $title = "Tambah " + ($dir -replace '_', ' ' -replace 's$', '') + } elseif ($file.Name -match 'edit\.blade\.php') { + $title = "Edit " + ($dir -replace '_', ' ' -replace 's$', '') + } elseif ($file.Name -match 'show\.blade\.php') { + $title = "Detail " + ($dir -replace '_', ' ' -replace 's$', '') + } else { + $title = "Manage " + ($dir -replace '_', ' ' -replace 's$', '') + } + + # Tambah header slot + $headerSlot = "`n `n

`n {{ __('$title') }}`n

`n
`n`n
`n
`n
`n
" + + $content = $content -replace '', "$headerSlot" + + # Tutup div wrapper + $content = $content -replace '', "`n
`n
`n
`n
`n
" + + # Update styling untuk container dan card + $content = $content -replace '
', '' + $content = $content -replace '
', '' + $content = $content -replace '
\s*
\s*', '' + + # Update button styling + $content = $content -replace 'class="btn-primary mb-3 inline-block"', 'class="btn-primary"' + + # Update alert styling + $content = $content -replace 'class="alert-success"', 'class="alert-success mb-4"' + + # Simpan file + Set-Content -Path $file.FullName -Value $content -Encoding UTF8 + } + } +} + +Write-Host "Conversion completed!" \ No newline at end of file diff --git a/website/database/.gitignore b/website/database/.gitignore new file mode 100644 index 0000000..9b19b93 --- /dev/null +++ b/website/database/.gitignore @@ -0,0 +1 @@ +*.sqlite* diff --git a/website/database/factories/AlumniFactory.php b/website/database/factories/AlumniFactory.php new file mode 100644 index 0000000..d54414d --- /dev/null +++ b/website/database/factories/AlumniFactory.php @@ -0,0 +1,28 @@ + + */ +class AlumniFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'nama_santri' => $santri?->nama ?? $this->faker->name(), + 'tahun_lulus' => $this->faker->year(), + 'aktivitas_setelah_lulus' => $this->faker->randomElement(['Kuliah','Kerja','Wirausaha','Lainnya']), + 'kontak' => $this->faker->optional()->phoneNumber(), + 'keterangan' => $this->faker->optional()->sentence(), + ]; + } +} diff --git a/website/database/factories/BeritaFactory.php b/website/database/factories/BeritaFactory.php new file mode 100644 index 0000000..cd6b279 --- /dev/null +++ b/website/database/factories/BeritaFactory.php @@ -0,0 +1,53 @@ + + */ +class BeritaFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + $kategoris = ['Akademik', 'Non-Akademik', 'Kegiatan Sekolah', 'Pengumuman', 'Prestasi']; + $statuses = ['draft', 'published']; + + return [ + 'judul' => fake()->sentence(6), + 'kategori' => fake()->randomElement($kategoris), + 'ringkasan' => fake()->paragraph(2), + 'isi' => fake()->paragraphs(5, true), + 'gambar' => null, // Set to null for now, can be updated later + 'penulis' => fake()->name(), + 'status' => fake()->randomElement($statuses), + ]; + } + + /** + * Indicate that the berita is published. + */ + public function published(): static + { + return $this->state(fn (array $attributes) => [ + 'status' => 'published', + ]); + } + + /** + * Indicate that the berita is draft. + */ + public function draft(): static + { + return $this->state(fn (array $attributes) => [ + 'status' => 'draft', + ]); + } +} \ No newline at end of file diff --git a/website/database/factories/KelasFactory.php b/website/database/factories/KelasFactory.php new file mode 100644 index 0000000..260b465 --- /dev/null +++ b/website/database/factories/KelasFactory.php @@ -0,0 +1,25 @@ + + */ +class KelasFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'nama_kelas' => $this->faker->unique()->bothify('Kelas-?#'), + 'guru_id' => Guru::inRandomOrder()->first()?->id ?? 1, + ]; + } +} diff --git a/website/database/factories/MataPelajaranFactory.php b/website/database/factories/MataPelajaranFactory.php new file mode 100644 index 0000000..abbddc6 --- /dev/null +++ b/website/database/factories/MataPelajaranFactory.php @@ -0,0 +1,24 @@ + + */ +class MataPelajaranFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'kode_mapel' => 'MP-' . uniqid(), + 'nama_mapel' => $this->faker->word(), + ]; + } +} diff --git a/website/database/factories/SemesterFactory.php b/website/database/factories/SemesterFactory.php new file mode 100644 index 0000000..8dbbd76 --- /dev/null +++ b/website/database/factories/SemesterFactory.php @@ -0,0 +1,25 @@ + + */ +class SemesterFactory extends Factory +{ + /** + * Define the model's default state. + * + * @return array + */ + public function definition(): array + { + return [ + 'semester' => $this->faker->randomElement(['Ganjil', 'Genap']), + 'tahun_ajaran' => $this->faker->year() . '/' . ($this->faker->year() + 1), + 'is_active' => $this->faker->boolean(), + ]; + } +} diff --git a/website/database/migrations/0001_01_01_000000_create_users_table.php b/website/database/migrations/0001_01_01_000000_create_users_table.php new file mode 100644 index 0000000..0d24532 --- /dev/null +++ b/website/database/migrations/0001_01_01_000000_create_users_table.php @@ -0,0 +1,49 @@ +id(); + $table->string('name'); + $table->string('username')->unique(); + $table->string('password'); + $table->enum('role', ['admin', 'guru', 'santri'])->default('santri'); + $table->rememberToken(); + $table->timestamps(); + }); + + Schema::create('password_reset_tokens', function (Blueprint $table) { + $table->string('username')->primary(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + + Schema::create('sessions', function (Blueprint $table) { + $table->string('id')->primary(); + $table->foreignId('user_id')->nullable()->index(); + $table->string('ip_address', 45)->nullable(); + $table->text('user_agent')->nullable(); + $table->longText('payload'); + $table->integer('last_activity')->index(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('users'); + Schema::dropIfExists('password_reset_tokens'); + Schema::dropIfExists('sessions'); + } +}; diff --git a/website/database/migrations/0001_01_01_000001_create_cache_table.php b/website/database/migrations/0001_01_01_000001_create_cache_table.php new file mode 100644 index 0000000..b9c106b --- /dev/null +++ b/website/database/migrations/0001_01_01_000001_create_cache_table.php @@ -0,0 +1,35 @@ +string('key')->primary(); + $table->mediumText('value'); + $table->integer('expiration'); + }); + + Schema::create('cache_locks', function (Blueprint $table) { + $table->string('key')->primary(); + $table->string('owner'); + $table->integer('expiration'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('cache'); + Schema::dropIfExists('cache_locks'); + } +}; diff --git a/website/database/migrations/0001_01_01_000002_create_jobs_table.php b/website/database/migrations/0001_01_01_000002_create_jobs_table.php new file mode 100644 index 0000000..425e705 --- /dev/null +++ b/website/database/migrations/0001_01_01_000002_create_jobs_table.php @@ -0,0 +1,57 @@ +id(); + $table->string('queue')->index(); + $table->longText('payload'); + $table->unsignedTinyInteger('attempts'); + $table->unsignedInteger('reserved_at')->nullable(); + $table->unsignedInteger('available_at'); + $table->unsignedInteger('created_at'); + }); + + Schema::create('job_batches', function (Blueprint $table) { + $table->string('id')->primary(); + $table->string('name'); + $table->integer('total_jobs'); + $table->integer('pending_jobs'); + $table->integer('failed_jobs'); + $table->longText('failed_job_ids'); + $table->mediumText('options')->nullable(); + $table->integer('cancelled_at')->nullable(); + $table->integer('created_at'); + $table->integer('finished_at')->nullable(); + }); + + Schema::create('failed_jobs', function (Blueprint $table) { + $table->id(); + $table->string('uuid')->unique(); + $table->text('connection'); + $table->text('queue'); + $table->longText('payload'); + $table->longText('exception'); + $table->timestamp('failed_at')->useCurrent(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jobs'); + Schema::dropIfExists('job_batches'); + Schema::dropIfExists('failed_jobs'); + } +}; diff --git a/website/database/migrations/2024_01_01_000000_create_beritas_table.php b/website/database/migrations/2024_01_01_000000_create_beritas_table.php new file mode 100644 index 0000000..c4b9b21 --- /dev/null +++ b/website/database/migrations/2024_01_01_000000_create_beritas_table.php @@ -0,0 +1,34 @@ +id(); + $table->string('judul'); + $table->string('kategori'); + $table->text('ringkasan'); + $table->longText('isi'); + $table->string('gambar')->nullable(); // path gambar + $table->string('penulis'); + $table->enum('status', ['draft', 'published'])->default('draft'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('beritas'); + } +}; \ No newline at end of file diff --git a/website/database/migrations/2025_06_20_032936_create_santris_table.php b/website/database/migrations/2025_06_20_032936_create_santris_table.php new file mode 100644 index 0000000..646f4aa --- /dev/null +++ b/website/database/migrations/2025_06_20_032936_create_santris_table.php @@ -0,0 +1,39 @@ +id(); + $table->string('nama'); + $table->string('nis')->unique(); + $table->unsignedBigInteger('kelas_id')->nullable(); + $table->string('alamat')->nullable(); + $table->string('foto')->nullable(); + $table->string('no_telp')->nullable(); + $table->date('tanggal_lahir')->nullable(); + $table->enum('jenis_kelamin', ['L', 'P']); + $table->enum('status', ['aktif', 'tidak_aktif'])->default('aktif'); + $table->unsignedBigInteger('user_id')->nullable(); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('santris'); + } +}; diff --git a/website/database/migrations/2025_06_20_032941_create_gurus_table.php b/website/database/migrations/2025_06_20_032941_create_gurus_table.php new file mode 100644 index 0000000..babe3e2 --- /dev/null +++ b/website/database/migrations/2025_06_20_032941_create_gurus_table.php @@ -0,0 +1,35 @@ +id(); + $table->string('nama'); + $table->string('code_guru')->unique(); + $table->string('alamat')->nullable(); + $table->date('tanggal_lahir')->nullable(); + $table->enum('jenis_kelamin', ['L', 'P']); + $table->unsignedBigInteger('user_id')->nullable(); + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('gurus'); + } +}; diff --git a/website/database/migrations/2025_06_20_041154_create_kelas_table.php b/website/database/migrations/2025_06_20_041154_create_kelas_table.php new file mode 100644 index 0000000..468b1f0 --- /dev/null +++ b/website/database/migrations/2025_06_20_041154_create_kelas_table.php @@ -0,0 +1,34 @@ +id(); + $table->string('nama_kelas'); + $table->unsignedBigInteger('guru_id')->nullable(); + $table->timestamps(); + }); + + // Tambahkan foreign key constraint untuk kelas_id di tabel santris + Schema::table('santris', function (Blueprint $table) { + $table->foreign('kelas_id')->references('id')->on('kelas')->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('kelas'); + } +}; diff --git a/website/database/migrations/2025_06_20_041512_create_semesters_table.php b/website/database/migrations/2025_06_20_041512_create_semesters_table.php new file mode 100644 index 0000000..d200703 --- /dev/null +++ b/website/database/migrations/2025_06_20_041512_create_semesters_table.php @@ -0,0 +1,30 @@ +id(); + $table->string('semester'); + $table->string('tahun_ajaran'); + $table->boolean('is_active')->default(false); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('semesters'); + } +}; diff --git a/website/database/migrations/2025_06_20_042615_create_mata_pelajarans_table.php b/website/database/migrations/2025_06_20_042615_create_mata_pelajarans_table.php new file mode 100644 index 0000000..80a4a9b --- /dev/null +++ b/website/database/migrations/2025_06_20_042615_create_mata_pelajarans_table.php @@ -0,0 +1,29 @@ +id(); + $table->string('kode_mapel')->unique(); + $table->string('nama_mapel'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('mata_pelajarans'); + } +}; diff --git a/website/database/migrations/2025_06_20_043914_create_jadwals_table.php b/website/database/migrations/2025_06_20_043914_create_jadwals_table.php new file mode 100644 index 0000000..4c75a17 --- /dev/null +++ b/website/database/migrations/2025_06_20_043914_create_jadwals_table.php @@ -0,0 +1,31 @@ +id(); + $table->unsignedBigInteger('kelas_id'); + $table->string('hari'); + $table->string('jam_pelajaran'); + $table->unsignedBigInteger('mata_pelajaran_id'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('jadwals'); + } +}; diff --git a/website/database/migrations/2025_06_20_045401_create_absensis_table.php b/website/database/migrations/2025_06_20_045401_create_absensis_table.php new file mode 100644 index 0000000..5baafc3 --- /dev/null +++ b/website/database/migrations/2025_06_20_045401_create_absensis_table.php @@ -0,0 +1,32 @@ +id(); + $table->unsignedBigInteger('santri_id'); + $table->unsignedBigInteger('kelas_id'); + $table->date('tanggal'); + $table->enum('status', ['hadir', 'izin', 'sakit', 'alfa']); + $table->string('keterangan')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('absensis'); + } +}; diff --git a/website/database/migrations/2025_06_20_050939_create_nilai_santris_table.php b/website/database/migrations/2025_06_20_050939_create_nilai_santris_table.php new file mode 100644 index 0000000..8aa95cf --- /dev/null +++ b/website/database/migrations/2025_06_20_050939_create_nilai_santris_table.php @@ -0,0 +1,34 @@ +id(); + $table->unsignedBigInteger('santri_id'); // Definisikan kolom santri_id terlebih dahulu + $table->foreign('santri_id')->references('id')->on('santris')->onDelete('cascade'); + $table->unsignedBigInteger('kelas_id'); + $table->unsignedBigInteger('mapel_id'); + $table->date('tanggal'); + $table->float('nilai')->default(0); + $table->string('keterangan')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('nilai_santris'); + } +}; diff --git a/website/database/migrations/2025_06_20_060234_create_prestasis_table.php b/website/database/migrations/2025_06_20_060234_create_prestasis_table.php new file mode 100644 index 0000000..bfd5a69 --- /dev/null +++ b/website/database/migrations/2025_06_20_060234_create_prestasis_table.php @@ -0,0 +1,38 @@ +id(); + + $table->unsignedBigInteger('user_id'); + $table->unsignedBigInteger('santri_id'); + $table->unsignedBigInteger('kelas_id'); + + $table->string('jenis_prestasi'); + $table->string('nama_prestasi'); + $table->string('tingkat'); + $table->string('peringkat'); + $table->date('tanggal_prestasi'); + $table->text('deskripsi')->nullable(); + $table->string('sertifikat')->nullable(); + + $table->timestamps(); + + // Foreign keys + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('santri_id')->references('id')->on('santris')->onDelete('cascade'); + $table->foreign('kelas_id')->references('id')->on('kelas')->onDelete('cascade'); + }); + } + + public function down(): void + { + Schema::dropIfExists('prestasis'); + } +}; diff --git a/website/database/migrations/2025_06_20_062028_create_pelanggarans_table.php b/website/database/migrations/2025_06_20_062028_create_pelanggarans_table.php new file mode 100644 index 0000000..27a7577 --- /dev/null +++ b/website/database/migrations/2025_06_20_062028_create_pelanggarans_table.php @@ -0,0 +1,36 @@ +id(); + $table->unsignedBigInteger('user_id'); // penginput (guru/pengurus) + $table->unsignedBigInteger('santri_id'); + $table->unsignedBigInteger('kelas_id'); + $table->string('jenis_pelanggaran'); + $table->enum('hukuman', ['Teguran Lisan', 'Teguran Tertulis', 'Skorsing', 'Lainnya']); + $table->string('keterangan_hukuman')->nullable(); + $table->enum('hukuman_selesai', ['belum', 'selesai'])->default('belum'); // untuk menandai selesai/tidaknya hukuman + $table->timestamps(); + + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('santri_id')->references('id')->on('santris')->onDelete('cascade'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('pelanggarans'); + } +}; diff --git a/website/database/migrations/2025_06_20_062730_create_catatan_kesehatans_table.php b/website/database/migrations/2025_06_20_062730_create_catatan_kesehatans_table.php new file mode 100644 index 0000000..4fb967a --- /dev/null +++ b/website/database/migrations/2025_06_20_062730_create_catatan_kesehatans_table.php @@ -0,0 +1,32 @@ +id(); + $table->unsignedBigInteger('santri_id'); + $table->unsignedBigInteger('kelas_id'); + $table->string('keluhan'); + $table->string('diagnosis'); + $table->string('saran')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('catatan_kesehatans'); + } +}; diff --git a/website/database/migrations/2025_06_20_063744_create_pembayarans_table.php b/website/database/migrations/2025_06_20_063744_create_pembayarans_table.php new file mode 100644 index 0000000..6fdfbad --- /dev/null +++ b/website/database/migrations/2025_06_20_063744_create_pembayarans_table.php @@ -0,0 +1,34 @@ +id(); + $table->unsignedBigInteger('santri_id'); + $table->unsignedBigInteger('kelas_id'); + $table->date('tanggal'); + $table->string('jenis_pembayaran'); + $table->integer('jumlah'); + $table->string('keterangan')->nullable(); + $table->enum('status', ['menunggu', 'diterima', 'ditolak'])->default('menunggu'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('pembayarans'); + } +}; diff --git a/website/database/migrations/2025_06_20_064136_create_alumnis_table.php b/website/database/migrations/2025_06_20_064136_create_alumnis_table.php new file mode 100644 index 0000000..a408992 --- /dev/null +++ b/website/database/migrations/2025_06_20_064136_create_alumnis_table.php @@ -0,0 +1,32 @@ +id(); + $table->string('nama_santri'); + $table->year('tahun_lulus'); + $table->string('aktivitas_setelah_lulus'); + $table->string('kontak')->nullable(); + $table->string('keterangan')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('alumnis'); + } +}; diff --git a/website/database/migrations/2025_06_22_224515_add_wali_kelas_id_to_kelas_table.php b/website/database/migrations/2025_06_22_224515_add_wali_kelas_id_to_kelas_table.php new file mode 100644 index 0000000..47a3a51 --- /dev/null +++ b/website/database/migrations/2025_06_22_224515_add_wali_kelas_id_to_kelas_table.php @@ -0,0 +1,30 @@ +unsignedBigInteger('wali_kelas_id')->nullable()->after('nama_kelas'); + $table->foreign('wali_kelas_id')->references('id')->on('gurus')->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('kelas', function (Blueprint $table) { + $table->dropForeign(['wali_kelas_id']); + $table->dropColumn('wali_kelas_id'); + }); + } +}; diff --git a/website/database/migrations/2025_06_24_050301_add_bukti_to_pembayarans_table.php b/website/database/migrations/2025_06_24_050301_add_bukti_to_pembayarans_table.php new file mode 100644 index 0000000..f1c7e50 --- /dev/null +++ b/website/database/migrations/2025_06_24_050301_add_bukti_to_pembayarans_table.php @@ -0,0 +1,28 @@ +string('bukti')->nullable()->after('status'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('pembayarans', function (Blueprint $table) { + $table->dropColumn('bukti'); + }); + } +}; diff --git a/website/database/migrations/2025_06_24_999999_add_foto_to_gurus_table.php b/website/database/migrations/2025_06_24_999999_add_foto_to_gurus_table.php new file mode 100644 index 0000000..d109c1f --- /dev/null +++ b/website/database/migrations/2025_06_24_999999_add_foto_to_gurus_table.php @@ -0,0 +1,22 @@ +string('foto')->nullable(); + }); + } + + public function down() + { + Schema::table('gurus', function (Blueprint $table) { + $table->dropColumn('foto'); + }); + } +}; \ No newline at end of file diff --git a/website/database/migrations/2025_06_25_010542_add_semester_id_and_jenis_nilai_to_nilai_santris_table.php b/website/database/migrations/2025_06_25_010542_add_semester_id_and_jenis_nilai_to_nilai_santris_table.php new file mode 100644 index 0000000..c75a63b --- /dev/null +++ b/website/database/migrations/2025_06_25_010542_add_semester_id_and_jenis_nilai_to_nilai_santris_table.php @@ -0,0 +1,31 @@ +unsignedBigInteger('semester_id')->nullable()->after('mapel_id'); + $table->string('jenis_nilai')->nullable()->after('tanggal'); + $table->foreign('semester_id')->references('id')->on('semesters')->onDelete('set null'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('nilai_santris', function (Blueprint $table) { + $table->dropForeign(['semester_id']); + $table->dropColumn(['semester_id', 'jenis_nilai']); + }); + } +}; diff --git a/website/database/migrations/2025_06_25_204259_create_personal_access_tokens_table.php b/website/database/migrations/2025_06_25_204259_create_personal_access_tokens_table.php new file mode 100644 index 0000000..e828ad8 --- /dev/null +++ b/website/database/migrations/2025_06_25_204259_create_personal_access_tokens_table.php @@ -0,0 +1,33 @@ +id(); + $table->morphs('tokenable'); + $table->string('name'); + $table->string('token', 64)->unique(); + $table->text('abilities')->nullable(); + $table->timestamp('last_used_at')->nullable(); + $table->timestamp('expires_at')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::dropIfExists('personal_access_tokens'); + } +}; diff --git a/website/database/migrations/2025_06_29_031214_rename_bukti_to_bukti_pembayaran_in_pembayarans_table.php b/website/database/migrations/2025_06_29_031214_rename_bukti_to_bukti_pembayaran_in_pembayarans_table.php new file mode 100644 index 0000000..8cbdbc2 --- /dev/null +++ b/website/database/migrations/2025_06_29_031214_rename_bukti_to_bukti_pembayaran_in_pembayarans_table.php @@ -0,0 +1,28 @@ +renameColumn('bukti', 'bukti_pembayaran'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('pembayarans', function (Blueprint $table) { + $table->renameColumn('bukti_pembayaran', 'bukti'); + }); + } +}; diff --git a/website/database/migrations/2025_07_01_000000_create_fcm_tokens_table.php b/website/database/migrations/2025_07_01_000000_create_fcm_tokens_table.php new file mode 100644 index 0000000..3ba80c7 --- /dev/null +++ b/website/database/migrations/2025_07_01_000000_create_fcm_tokens_table.php @@ -0,0 +1,21 @@ +id(); + $table->unsignedBigInteger('user_id'); + $table->string('token')->unique(); + $table->timestamps(); + $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade'); + }); + } + public function down() + { + Schema::dropIfExists('fcm_tokens'); + } +}; \ No newline at end of file diff --git a/website/database/migrations/2025_07_02_130527_add_foto_to_santris_table.php b/website/database/migrations/2025_07_02_130527_add_foto_to_santris_table.php new file mode 100644 index 0000000..04c8cb2 --- /dev/null +++ b/website/database/migrations/2025_07_02_130527_add_foto_to_santris_table.php @@ -0,0 +1,28 @@ +string('tempat_lahir')->nullable()->after('alamat'); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('santris', function (Blueprint $table) { + // + }); + } +}; diff --git a/website/database/migrations/2025_08_06_114414_create_password_resets_table.php b/website/database/migrations/2025_08_06_114414_create_password_resets_table.php new file mode 100644 index 0000000..03353de --- /dev/null +++ b/website/database/migrations/2025_08_06_114414_create_password_resets_table.php @@ -0,0 +1,22 @@ +id(); + $table->string('username')->index(); + $table->string('token'); + $table->timestamp('created_at')->nullable(); + }); + } + + public function down(): void + { + Schema::dropIfExists('password_resets'); + } +}; diff --git a/website/database/seeders/AdminSeeder.php b/website/database/seeders/AdminSeeder.php new file mode 100644 index 0000000..c1bd3ec --- /dev/null +++ b/website/database/seeders/AdminSeeder.php @@ -0,0 +1,20 @@ + 'Admin', + 'username' => 'admin', + 'password' => bcrypt('admin123'), + 'role' => 'admin', + ]); + } +} \ No newline at end of file diff --git a/website/database/seeders/AlumniSeeder.php b/website/database/seeders/AlumniSeeder.php new file mode 100644 index 0000000..e7abcc0 --- /dev/null +++ b/website/database/seeders/AlumniSeeder.php @@ -0,0 +1,17 @@ +create(); + Semester::factory(2)->create(); + MataPelajaran::factory(10)->create(); + + // Seed basic users (admin, guru, santri) + $this->call([ + UserSeeder::class, + ]); + + // Seed dependent data + Alumni::factory(10)->create(); + Berita::factory(15)->create(); + + // Seeder relasi berat di akhir + } +} diff --git a/website/database/seeders/GuruSeeder.php b/website/database/seeders/GuruSeeder.php new file mode 100644 index 0000000..be3409b --- /dev/null +++ b/website/database/seeders/GuruSeeder.php @@ -0,0 +1,18 @@ +count(10)->create(); + } +} diff --git a/website/database/seeders/PelanggaranSeeder.php b/website/database/seeders/PelanggaranSeeder.php new file mode 100644 index 0000000..981cb4d --- /dev/null +++ b/website/database/seeders/PelanggaranSeeder.php @@ -0,0 +1,17 @@ +role) { + // Implementasi penugasan role kepada user + } + } + } +} diff --git a/website/database/seeders/RoleSeeder.php b/website/database/seeders/RoleSeeder.php new file mode 100644 index 0000000..f92e85b --- /dev/null +++ b/website/database/seeders/RoleSeeder.php @@ -0,0 +1,14 @@ + 'Admin', + 'username' => 'admin', + 'password' => Hash::make('admin123'), + 'role' => 'admin', + ]); + } +} \ No newline at end of file diff --git a/website/devtools_options.yaml b/website/devtools_options.yaml new file mode 100644 index 0000000..fa0b357 --- /dev/null +++ b/website/devtools_options.yaml @@ -0,0 +1,3 @@ +description: This file stores settings for Dart & Flutter DevTools. +documentation: https://docs.flutter.dev/tools/devtools/extensions#configure-extension-enablement-states +extensions: diff --git a/website/fix_remaining.ps1 b/website/fix_remaining.ps1 new file mode 100644 index 0000000..0519ecb --- /dev/null +++ b/website/fix_remaining.ps1 @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/website/ios/.gitignore b/website/ios/.gitignore new file mode 100644 index 0000000..7a7f987 --- /dev/null +++ b/website/ios/.gitignore @@ -0,0 +1,34 @@ +**/dgph +*.mode1v3 +*.mode2v3 +*.moved-aside +*.pbxuser +*.perspectivev3 +**/*sync/ +.sconsign.dblite +.tags* +**/.vagrant/ +**/DerivedData/ +Icon? +**/Pods/ +**/.symlinks/ +profile +xcuserdata +**/.generated/ +Flutter/App.framework +Flutter/Flutter.framework +Flutter/Flutter.podspec +Flutter/Generated.xcconfig +Flutter/ephemeral/ +Flutter/app.flx +Flutter/app.zip +Flutter/flutter_assets/ +Flutter/flutter_export_environment.sh +ServiceDefinitions.json +Runner/GeneratedPluginRegistrant.* + +# Exceptions to above rules. +!default.mode1v3 +!default.mode2v3 +!default.pbxuser +!default.perspectivev3 diff --git a/website/ios/Flutter/AppFrameworkInfo.plist b/website/ios/Flutter/AppFrameworkInfo.plist new file mode 100644 index 0000000..7c56964 --- /dev/null +++ b/website/ios/Flutter/AppFrameworkInfo.plist @@ -0,0 +1,26 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + App + CFBundleIdentifier + io.flutter.flutter.app + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + App + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1.0 + MinimumOSVersion + 12.0 + + diff --git a/website/ios/Flutter/Debug.xcconfig b/website/ios/Flutter/Debug.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/website/ios/Flutter/Debug.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/website/ios/Flutter/Release.xcconfig b/website/ios/Flutter/Release.xcconfig new file mode 100644 index 0000000..592ceee --- /dev/null +++ b/website/ios/Flutter/Release.xcconfig @@ -0,0 +1 @@ +#include "Generated.xcconfig" diff --git a/website/ios/Runner.xcodeproj/project.pbxproj b/website/ios/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..eab3ce3 --- /dev/null +++ b/website/ios/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,616 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXBuildFile section */ + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; }; + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C807B294A618700263BE5 /* RunnerTests.swift */; }; + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; }; + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 74858FAE1ED2DC5600515810 /* AppDelegate.swift */; }; + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FD1CF9000F007C117D /* Assets.xcassets */; }; + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C8085294A63A400263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 97C146E61CF9000F007C117D /* Project object */; + proxyType = 1; + remoteGlobalIDString = 97C146ED1CF9000F007C117D; + remoteInfo = Runner; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 9705A1C41CF9048500538489 /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; + 331C807B294A618700263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 331C8081294A63A400263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = ""; }; + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Runner-Bridging-Header.h"; sourceTree = ""; }; + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; + 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; + 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 97C146FB1CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 97C146FD1CF9000F007C117D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 97C147001CF9000F007C117D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 97C147021CF9000F007C117D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 97C146EB1CF9000F007C117D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C8082294A63A400263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C807B294A618700263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 9740EEB11CF90186004384FC /* Flutter */ = { + isa = PBXGroup; + children = ( + 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 9740EEB31CF90195004384FC /* Generated.xcconfig */, + ); + name = Flutter; + sourceTree = ""; + }; + 97C146E51CF9000F007C117D = { + isa = PBXGroup; + children = ( + 9740EEB11CF90186004384FC /* Flutter */, + 97C146F01CF9000F007C117D /* Runner */, + 97C146EF1CF9000F007C117D /* Products */, + 331C8082294A63A400263BE5 /* RunnerTests */, + ); + sourceTree = ""; + }; + 97C146EF1CF9000F007C117D /* Products */ = { + isa = PBXGroup; + children = ( + 97C146EE1CF9000F007C117D /* Runner.app */, + 331C8081294A63A400263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 97C146F01CF9000F007C117D /* Runner */ = { + isa = PBXGroup; + children = ( + 97C146FA1CF9000F007C117D /* Main.storyboard */, + 97C146FD1CF9000F007C117D /* Assets.xcassets */, + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */, + 97C147021CF9000F007C117D /* Info.plist */, + 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, + 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, + 74858FAE1ED2DC5600515810 /* AppDelegate.swift */, + 74858FAD1ED2DC5600515810 /* Runner-Bridging-Header.h */, + ); + path = Runner; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C8080294A63A400263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C807D294A63A400263BE5 /* Sources */, + 331C807F294A63A400263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C8086294A63A400263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C8081294A63A400263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 97C146ED1CF9000F007C117D /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 9740EEB61CF901F6004384FC /* Run Script */, + 97C146EA1CF9000F007C117D /* Sources */, + 97C146EB1CF9000F007C117D /* Frameworks */, + 97C146EC1CF9000F007C117D /* Resources */, + 9705A1C41CF9048500538489 /* Embed Frameworks */, + 3B06AD1E1E4923F5004D2608 /* Thin Binary */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Runner; + productName = Runner; + productReference = 97C146EE1CF9000F007C117D /* Runner.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 97C146E61CF9000F007C117D /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C8080294A63A400263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 97C146ED1CF9000F007C117D; + }; + 97C146ED1CF9000F007C117D = { + CreatedOnToolsVersion = 7.3.1; + LastSwiftMigration = 1100; + }; + }; + }; + buildConfigurationList = 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 97C146E51CF9000F007C117D; + productRefGroup = 97C146EF1CF9000F007C117D /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 97C146ED1CF9000F007C117D /* Runner */, + 331C8080294A63A400263BE5 /* RunnerTests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C807F294A63A400263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EC1CF9000F007C117D /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, + 97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */, + 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3B06AD1E1E4923F5004D2608 /* Thin Binary */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + "${TARGET_BUILD_DIR}/${INFOPLIST_PATH}", + ); + name = "Thin Binary"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" embed_and_thin"; + }; + 9740EEB61CF901F6004384FC /* Run Script */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputPaths = ( + ); + name = "Run Script"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "/bin/sh \"$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh\" build"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C807D294A63A400263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C808B294A63AB00263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 97C146EA1CF9000F007C117D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 74858FAF1ED2DC5600515810 /* AppDelegate.swift in Sources */, + 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C8086294A63A400263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 97C146ED1CF9000F007C117D /* Runner */; + targetProxy = 331C8085294A63A400263BE5 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 97C146FA1CF9000F007C117D /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C146FB1CF9000F007C117D /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 97C146FF1CF9000F007C117D /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 97C147001CF9000F007C117D /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 249021D3217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Profile; + }; + 249021D4217E4FDB00AE95B9 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Profile; + }; + 331C8088294A63A400263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Debug; + }; + 331C8089294A63A400263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Release; + }; + 331C808A294A63A400263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Runner.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/Runner"; + }; + name = Profile; + }; + 97C147031CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 97C147041CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 12.0; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SUPPORTED_PLATFORMS = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 97C147061CF9000F007C117D /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Debug; + }; + 97C147071CF9000F007C117D /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CURRENT_PROJECT_VERSION = "$(FLUTTER_BUILD_NUMBER)"; + ENABLE_BITCODE = NO; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + ); + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OBJC_BRIDGING_HEADER = "Runner/Runner-Bridging-Header.h"; + SWIFT_VERSION = 5.0; + VERSIONING_SYSTEM = "apple-generic"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C8087294A63A400263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C8088294A63A400263BE5 /* Debug */, + 331C8089294A63A400263BE5 /* Release */, + 331C808A294A63A400263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C146E91CF9000F007C117D /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147031CF9000F007C117D /* Debug */, + 97C147041CF9000F007C117D /* Release */, + 249021D3217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 97C147051CF9000F007C117D /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 97C147061CF9000F007C117D /* Debug */, + 97C147071CF9000F007C117D /* Release */, + 249021D4217E4FDB00AE95B9 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 97C146E61CF9000F007C117D /* Project object */; +} diff --git a/website/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/website/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/website/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/website/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/website/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/website/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/website/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/website/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/website/ios/Runner.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/website/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/website/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..e3773d4 --- /dev/null +++ b/website/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/ios/Runner.xcworkspace/contents.xcworkspacedata b/website/ios/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/website/ios/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/website/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/website/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/website/ios/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/website/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings b/website/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..f9b0d7c --- /dev/null +++ b/website/ios/Runner.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings @@ -0,0 +1,8 @@ + + + + + PreviewsEnabled + + + diff --git a/website/ios/Runner/AppDelegate.swift b/website/ios/Runner/AppDelegate.swift new file mode 100644 index 0000000..6266644 --- /dev/null +++ b/website/ios/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Flutter +import UIKit + +@main +@objc class AppDelegate: FlutterAppDelegate { + override func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + GeneratedPluginRegistrant.register(with: self) + return super.application(application, didFinishLaunchingWithOptions: launchOptions) + } +} diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..d36b1fa --- /dev/null +++ b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,122 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "1024x1024", + "idiom" : "ios-marketing", + "filename" : "Icon-App-1024x1024@1x.png", + "scale" : "1x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png new file mode 100644 index 0000000..dc9ada4 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png new file mode 100644 index 0000000..7353c41 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png new file mode 100644 index 0000000..6ed2d93 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png new file mode 100644 index 0000000..4cd7b00 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png new file mode 100644 index 0000000..fe73094 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png new file mode 100644 index 0000000..321773c Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png new file mode 100644 index 0000000..797d452 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png new file mode 100644 index 0000000..502f463 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png new file mode 100644 index 0000000..0ec3034 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png new file mode 100644 index 0000000..e9f5fea Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png new file mode 100644 index 0000000..84ac32a Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png new file mode 100644 index 0000000..8953cba Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png differ diff --git a/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png new file mode 100644 index 0000000..0467bf1 Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png differ diff --git a/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json new file mode 100644 index 0000000..0bedcf2 --- /dev/null +++ b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "LaunchImage.png", + "scale" : "1x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@2x.png", + "scale" : "2x" + }, + { + "idiom" : "universal", + "filename" : "LaunchImage@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png differ diff --git a/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png differ diff --git a/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png new file mode 100644 index 0000000..9da19ea Binary files /dev/null and b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png differ diff --git a/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md new file mode 100644 index 0000000..89c2725 --- /dev/null +++ b/website/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md @@ -0,0 +1,5 @@ +# Launch Screen Assets + +You can customize the launch screen with your own desired assets by replacing the image files in this directory. + +You can also do it by opening your Flutter project's Xcode project with `open ios/Runner.xcworkspace`, selecting `Runner/Assets.xcassets` in the Project Navigator and dropping in the desired images. \ No newline at end of file diff --git a/website/ios/Runner/Base.lproj/LaunchScreen.storyboard b/website/ios/Runner/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..f2e259c --- /dev/null +++ b/website/ios/Runner/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,37 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/ios/Runner/Base.lproj/Main.storyboard b/website/ios/Runner/Base.lproj/Main.storyboard new file mode 100644 index 0000000..f3c2851 --- /dev/null +++ b/website/ios/Runner/Base.lproj/Main.storyboard @@ -0,0 +1,26 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/ios/Runner/Info.plist b/website/ios/Runner/Info.plist new file mode 100644 index 0000000..b5d0bdc --- /dev/null +++ b/website/ios/Runner/Info.plist @@ -0,0 +1,49 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleDisplayName + Monitoring + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + monitoring + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleSignature + ???? + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + CADisableMinimumFrameDurationOnPhone + + UIApplicationSupportsIndirectInputEvents + + + diff --git a/website/ios/Runner/Runner-Bridging-Header.h b/website/ios/Runner/Runner-Bridging-Header.h new file mode 100644 index 0000000..308a2a5 --- /dev/null +++ b/website/ios/Runner/Runner-Bridging-Header.h @@ -0,0 +1 @@ +#import "GeneratedPluginRegistrant.h" diff --git a/website/ios/RunnerTests/RunnerTests.swift b/website/ios/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..86a7c3b --- /dev/null +++ b/website/ios/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Flutter +import UIKit +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/website/lib/config.dart b/website/lib/config.dart new file mode 100644 index 0000000..a7fb541 --- /dev/null +++ b/website/lib/config.dart @@ -0,0 +1,5 @@ +// String baseUrl = 'http://10.10.9.217:8000/api'; +// String baseUrl = 'http://192.168.43.24:8000/api'; +// String baseUrl = 'http://10.75.50.24:8000/api'; +// String baseUrl = 'http://10.0.2.2:8000/api'; +String baseUrl = 'http://10.75.50.24:8000/api'; diff --git a/website/lib/features/berita_detail_screen.dart b/website/lib/features/berita_detail_screen.dart new file mode 100644 index 0000000..613744d --- /dev/null +++ b/website/lib/features/berita_detail_screen.dart @@ -0,0 +1 @@ +// TODO Implement this library. diff --git a/website/lib/main.dart b/website/lib/main.dart new file mode 100644 index 0000000..1df0377 --- /dev/null +++ b/website/lib/main.dart @@ -0,0 +1,35 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:monitoring/screens/home_screen.dart'; +import 'package:monitoring/screens/splash_screen.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +final GlobalKey navigatorKey = GlobalKey(); + +void main() => runApp(const MonitoringSantriApp()); + +class MonitoringSantriApp extends StatelessWidget { + const MonitoringSantriApp({super.key}); + + void _handleLogin(String token, Map user) async { + final prefs = await SharedPreferences.getInstance(); + await prefs.setString('token', token); + await prefs.setString('user', jsonEncode(user)); + + navigatorKey.currentState!.pushAndRemoveUntil( + MaterialPageRoute(builder: (_) => HomeScreen(token: token, user: user)), + (route) => false, + ); + } + + @override + Widget build(BuildContext context) { + return MaterialApp( + title: 'Santri Login App', + theme: ThemeData(primarySwatch: Colors.indigo), + debugShowCheckedModeBanner: false, + navigatorKey: navigatorKey, + home: SplashScreen(onLoginSuccess: _handleLogin), + ); + } +} diff --git a/website/lib/models/berita_model.dart b/website/lib/models/berita_model.dart new file mode 100644 index 0000000..c5434b2 --- /dev/null +++ b/website/lib/models/berita_model.dart @@ -0,0 +1,28 @@ +class BeritaModel { + final int id; + final String judul; + final String? ringkasan; + final String? gambarUrl; + final String? kategori; + final String? penulis; + + BeritaModel({ + required this.id, + required this.judul, + this.ringkasan, + this.gambarUrl, + this.kategori, + this.penulis, + }); + + factory BeritaModel.fromJson(Map json) { + return BeritaModel( + id: json['id'], + judul: json['judul'], + ringkasan: json['ringkasan'], + gambarUrl: json['gambar_url'], + kategori: json['kategori'], + penulis: json['penulis'], + ); + } +} diff --git a/website/lib/screens/feature_grid.dart b/website/lib/screens/feature_grid.dart new file mode 100644 index 0000000..3fda93e --- /dev/null +++ b/website/lib/screens/feature_grid.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; + +import 'features/absensi_screen.dart'; +import 'features/nilai_screen.dart'; +import 'features/kesehatan_screen.dart'; +import 'features/prestasi_screen.dart'; +import 'features/pelanggaran_screen.dart'; +import 'features/berita_screen.dart'; +import 'features/alumni_screen.dart'; +import 'features/pembayaran_screen.dart'; + +class FeatureGrid extends StatelessWidget { + final String token; + + const FeatureGrid({super.key, required this.token}); + + final List<_FeatureItem> _items = const [ + _FeatureItem('Absensi', Icons.how_to_reg), + _FeatureItem('Nilai', Icons.grade), + _FeatureItem('Kesehatan', Icons.local_hospital), + _FeatureItem('Prestasi', Icons.emoji_events), + _FeatureItem('Pelanggaran', Icons.report), + _FeatureItem('Berita', Icons.article), + _FeatureItem('Alumni', Icons.people), + _FeatureItem('Pembayaran', Icons.attach_money), + ]; + + @override + Widget build(BuildContext context) { + return GridView.builder( + itemCount: _items.length, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + itemBuilder: (context, index) { + final item = _items[index]; + + return GestureDetector( + onTap: () { + Widget? destination; + + switch (item.label) { + case 'Absensi': + destination = AbsensiScreen(token: token); + break; + case 'Nilai': + destination = NilaiScreen(token: token); + break; + case 'Kesehatan': + destination = KesehatanScreen(token: token); + break; + case 'Prestasi': + destination = PrestasiScreen(token: token); + break; + case 'Pelanggaran': + destination = PelanggaranScreen(token: token); + break; + case 'Berita': + destination = BeritaScreen(token: token); + break; + case 'Alumni': + destination = AlumniScreen(token: token); + break; + case 'Pembayaran': + destination = PembayaranScreen(token: token); + break; + } + + if (destination != null) { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => destination!), + ); + } + }, + child: Container( + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFF43A047), Color(0xFFFFEB3B)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.08), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(item.icon, size: 32, color: Colors.white), + const SizedBox(height: 8), + Text( + item.label, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + }, + ); + } +} + +class _FeatureItem { + final String label; + final IconData icon; + + const _FeatureItem(this.label, this.icon); +} diff --git a/website/lib/screens/features/absensi_screen.dart b/website/lib/screens/features/absensi_screen.dart new file mode 100644 index 0000000..cce25bc --- /dev/null +++ b/website/lib/screens/features/absensi_screen.dart @@ -0,0 +1,167 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; + +class AbsensiScreen extends StatefulWidget { + final String token; + const AbsensiScreen({super.key, required this.token}); + + @override + State createState() => _AbsensiScreenState(); +} + +class _AbsensiScreenState extends State { + List data = []; + List filteredData = []; + bool loading = true; + + int selectedMonth = DateTime.now().month; + + final List months = [ + 'Januari', + 'Februari', + 'Maret', + 'April', + 'Mei', + 'Juni', + 'Juli', + 'Agustus', + 'September', + 'Oktober', + 'November', + 'Desember', + ]; + + @override + void initState() { + super.initState(); + fetchAbsensi(); + } + + Future fetchAbsensi() async { + final url = Uri.parse('$baseUrl/absensi'); + + try { + final response = await http.get( + url, + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final resData = json.decode(response.body); + setState(() { + data = resData['data']; + loading = false; + applyMonthFilter(); + }); + } else { + setState(() => loading = false); + } + } catch (e) { + setState(() => loading = false); + } + } + + void applyMonthFilter() { + setState(() { + filteredData = + data.where((item) { + final date = DateTime.tryParse(item['tanggal'] ?? ''); + return date != null && date.month == selectedMonth; + }).toList(); + }); + } + + Color getStatusColor(String status) { + switch (status.toLowerCase()) { + case 'hadir': + return Colors.green; + case 'sakit': + return Colors.orange; + case 'izin': + return Colors.blue; + default: + return Colors.grey; + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Absensi'), + actions: [ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: DropdownButtonHideUnderline( + child: DropdownButton( + value: selectedMonth, + items: List.generate(12, (index) { + final monthName = months[index]; + return DropdownMenuItem( + value: index + 1, + child: Text(monthName), + ); + }), + onChanged: (value) { + if (value != null) { + setState(() { + selectedMonth = value; + applyMonthFilter(); + }); + } + }, + ), + ), + ), + ], + ), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : filteredData.isEmpty + ? const Center(child: Text('Tidak ada data absensi bulan ini.')) + : ListView.builder( + itemCount: filteredData.length, + itemBuilder: (context, index) { + final item = filteredData[index]; + final tanggal = item['tanggal'] ?? '-'; + final status = item['status'] ?? '-'; + final keterangan = item['keterangan'] ?? ''; + + return ListTile( + leading: const Icon( + Icons.calendar_today, + color: Colors.green, + ), + title: Text(tanggal), + subtitle: keterangan.isNotEmpty ? Text(keterangan) : null, + trailing: Container( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 6, + ), + decoration: BoxDecoration( + color: getStatusColor(status).withOpacity(0.1), + border: Border.all(color: getStatusColor(status)), + borderRadius: BorderRadius.circular(20), + ), + child: Text( + status.toUpperCase(), + style: TextStyle( + color: getStatusColor(status), + fontWeight: FontWeight.bold, + fontSize: 12, + ), + ), + ), + ); + }, + ), + ); + } +} diff --git a/website/lib/screens/features/alumni_screen.dart b/website/lib/screens/features/alumni_screen.dart new file mode 100644 index 0000000..3789a9a --- /dev/null +++ b/website/lib/screens/features/alumni_screen.dart @@ -0,0 +1,203 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; +import 'package:url_launcher/url_launcher.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; +import 'dart:convert'; + +class AlumniScreen extends StatefulWidget { + final String token; + const AlumniScreen({super.key, required this.token}); + + @override + State createState() => _AlumniScreenState(); +} + +class _AlumniScreenState extends State { + List data = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchAlumni(); + } + + Future fetchAlumni() async { + final url = '$baseUrl/alumni'; + + try { + final response = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final jsonData = json.decode(response.body); + debugPrint('Data diterima: ${json.encode(jsonData)}'); + + if (jsonData != null && + jsonData['data'] != null && + jsonData['data'] is List) { + setState(() { + data = jsonData['data']; + loading = false; + }); + } else { + debugPrint('Format JSON tidak sesuai: $jsonData'); + setState(() => loading = false); + } + } else { + debugPrint('Gagal ambil alumni: ${response.body}'); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Gagal mengambil alumni: $e'); + setState(() => loading = false); + } + } + + Future _launchWhatsApp(String number) async { + final uri = Uri.parse("https://wa.me/$number"); + if (await canLaunchUrl(uri)) { + await launchUrl(uri, mode: LaunchMode.externalApplication); + } else { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Gagal membuka WhatsApp'))); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Data Alumni')), + body: loading + ? const Center(child: CircularProgressIndicator()) + : data.isEmpty + ? const Center(child: Text('Tidak ada data alumni.')) + : ListView.builder( + padding: const EdgeInsets.all(12), + itemCount: data.length, + itemBuilder: (context, index) { + final alumni = data[index]; + return Card( + elevation: 3, + margin: const EdgeInsets.only(bottom: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon( + Icons.person, + color: Colors.green, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + alumni['nama'] ?? '-', + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + ), + Chip( + label: Text( + 'Angkatan ${alumni['angkatan'] ?? 'Tidak Diketahui'}', + style: const TextStyle(fontSize: 12), + ), + backgroundColor: Colors.green.shade50, + labelStyle: const TextStyle( + color: Colors.green, + ), + ), + ], + ), + const SizedBox(height: 12), + Row( + children: [ + const Icon( + Icons.work_outline, + size: 20, + color: Colors.black54, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + alumni['aktivitas_setelah_lulus'] ?? '-', + style: const TextStyle(fontSize: 14), + ), + ), + ], + ), + const SizedBox(height: 6), + Row( + children: [ + const Icon( + Icons.phone_android, + size: 20, + color: Colors.black54, + ), + const SizedBox(width: 8), + Text( + alumni['kontak'] ?? '-', + style: const TextStyle(fontSize: 14), + ), + if ((alumni['kontak'] ?? '') + .toString() + .isNotEmpty) + IconButton( + icon: const FaIcon( + FontAwesomeIcons.whatsapp, + color: Colors.green, + ), + tooltip: 'Hubungi di WhatsApp', + onPressed: () { + _launchWhatsApp( + alumni['kontak'].toString(), + ); + }, + ), + ], + ), + if (alumni['keterangan'] != null && + alumni['keterangan'].toString().isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 8), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon( + Icons.info_outline, + size: 20, + color: Colors.black54, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + alumni['keterangan'], + style: const TextStyle(fontSize: 14), + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + ), + ); + } +} diff --git a/website/lib/screens/features/berita_detail_screen.dart b/website/lib/screens/features/berita_detail_screen.dart new file mode 100644 index 0000000..48fd627 --- /dev/null +++ b/website/lib/screens/features/berita_detail_screen.dart @@ -0,0 +1,90 @@ +import 'package:flutter/material.dart'; +import 'package:monitoring/models/berita_model.dart'; + +class BeritaDetailScreen extends StatelessWidget { + final BeritaModel berita; + + const BeritaDetailScreen({super.key, required this.berita}); + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: const Color(0xFFF8F9FA), + appBar: AppBar( + title: const Text('Detail Berita'), + + backgroundColor: Color(0xFF43A047), + foregroundColor: Colors.white, + elevation: 0, + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + // Gambar + ClipRRect( + borderRadius: BorderRadius.circular(12), + child: + berita.gambarUrl != null + ? Image.network( + berita.gambarUrl!, + width: double.infinity, + height: 200, + fit: BoxFit.cover, + errorBuilder: + (_, __, ___) => Image.asset( + 'assets/404.png', + width: double.infinity, + height: 200, + fit: BoxFit.cover, + ), + ) + : Image.asset( + 'assets/404.png', + width: double.infinity, + height: 200, + fit: BoxFit.cover, + ), + ), + const SizedBox(height: 16), + + // Judul + Text( + berita.judul, + style: const TextStyle( + fontSize: 24, + fontWeight: FontWeight.bold, + color: Colors.black87, + ), + ), + const SizedBox(height: 8), + + // Kategori dan Penulis + Row( + children: [ + Chip( + label: Text(berita.kategori ?? 'Umum'), + backgroundColor: Colors.pink.shade100, + ), + const SizedBox(width: 8), + Text( + 'Oleh ${berita.penulis ?? '-'}', + style: const TextStyle(fontSize: 14, color: Colors.grey), + ), + ], + ), + const SizedBox(height: 16), + + // Ringkasan atau isi + Text( + berita.ringkasan ?? 'Tidak ada isi berita.', + textAlign: TextAlign.justify, + style: const TextStyle(fontSize: 16, height: 1.5), + ), + ], + ), + ), + ); + } +} diff --git a/website/lib/screens/features/berita_detail_screen_gak_dipakek.dart b/website/lib/screens/features/berita_detail_screen_gak_dipakek.dart new file mode 100644 index 0000000..9595d0e --- /dev/null +++ b/website/lib/screens/features/berita_detail_screen_gak_dipakek.dart @@ -0,0 +1,450 @@ +// Lengkap: CRUD layanan Flutter (Tanpa Edit) +import 'dart:convert'; +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; + +class Service { + final int id; + final String name; + final int price; + final String? imageUrl; + + Service({ + required this.id, + required this.name, + required this.price, + this.imageUrl, + }); + + factory Service.fromJson(Map json) { + return Service( + id: json['id'], + name: json['name'], + price: json['price'], + imageUrl: json['image'], + ); + } +} + +class DataLayananPage extends StatefulWidget { + final String token; + + const DataLayananPage({super.key, required this.token}); + + @override + State createState() => _DataLayananPageState(); +} + +class _DataLayananPageState extends State { + List categories = []; + Map> servicesByCategory = {}; + int? selectedCategoryId; + bool loadingCategories = true; + bool loadingServices = false; + + String? imagePath; + + @override + void initState() { + super.initState(); + fetchCategories(); + } + + Future fetchCategories() async { + setState(() => loadingCategories = true); + try { + final response = await http.get( + Uri.parse('$baseUrl/categories'), + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + setState(() { + categories = data is List ? data : data['categories']; + if (categories.isNotEmpty) { + selectedCategoryId = categories[0]['id']; + fetchServicesByCategory(selectedCategoryId!); + } + }); + } + } catch (e) { + print(e); + } finally { + setState(() => loadingCategories = false); + } + } + + Future fetchServicesByCategory(int categoryId) async { + setState(() => loadingServices = true); + try { + final response = await http.get( + Uri.parse('$baseUrl/api/services?category_id=$categoryId'), + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + final List services = + (data as List).map((item) => Service.fromJson(item)).toList(); + + setState(() { + servicesByCategory[categoryId] = services; + }); + } + } catch (e) { + print(e); + } finally { + setState(() => loadingServices = false); + } + } + + Future addService({ + required String name, + required String price, + required String description, + required int categoryId, + required File? imageFile, + }) async { + final url = Uri.parse('$baseUrl/api/services'); + final request = + http.MultipartRequest('POST', url) + ..headers.addAll({ + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }) + ..fields['name'] = name + ..fields['category_id'] = categoryId.toString() + ..fields['price'] = price + ..fields['description'] = description; + + if (imageFile != null) { + request.files.add( + await http.MultipartFile.fromPath('image', imageFile.path), + ); + } + + final response = await request.send(); + + if (response.statusCode == 201) { + print("Layanan berhasil ditambahkan."); + await fetchServicesByCategory(categoryId); + } else { + final respStr = await response.stream.bytesToString(); + print("Gagal tambah layanan: $respStr"); + } + } + + Future deleteService(int id, int categoryId) async { + final url = Uri.parse('$baseUrl/services/$id'); + + final response = await http.delete( + url, + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ); + + if (response.statusCode == 200) { + print("Layanan berhasil dihapus."); + await fetchServicesByCategory(categoryId); + } else { + print("Gagal hapus layanan: ${response.body}"); + } + } + + void showAddServiceDialog() { + final nameController = TextEditingController(); + final priceController = TextEditingController(); + final descriptionController = TextEditingController(); + + int? selectedDialogCategoryId = selectedCategoryId; + String? previewImagePath; + + imagePath = null; + + showDialog( + context: context, + builder: + (context) => StatefulBuilder( + builder: (context, setStateDialog) { + return AlertDialog( + title: const Text('Tambah Layanan'), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + DropdownButtonFormField( + value: selectedDialogCategoryId, + items: + categories.map>((category) { + return DropdownMenuItem( + value: category['id'], + child: Text(category['name']), + ); + }).toList(), + onChanged: + (value) => setStateDialog( + () => selectedDialogCategoryId = value, + ), + decoration: const InputDecoration( + labelText: 'Kategori', + ), + ), + TextField( + controller: nameController, + decoration: const InputDecoration( + labelText: 'Nama Layanan', + ), + ), + TextField( + controller: priceController, + keyboardType: TextInputType.number, + decoration: const InputDecoration(labelText: 'Harga'), + ), + TextField( + controller: descriptionController, + decoration: const InputDecoration( + labelText: 'Deskripsi', + ), + ), + ElevatedButton( + onPressed: () async { + final picker = ImagePicker(); + final pickedFile = await picker.pickImage( + source: ImageSource.gallery, + ); + if (pickedFile != null) { + setStateDialog(() { + previewImagePath = pickedFile.path; + imagePath = pickedFile.path; + }); + } + }, + child: const Text('Pilih Gambar'), + ), + if (previewImagePath != null) + Image.file(File(previewImagePath!), height: 100), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('Batal'), + ), + ElevatedButton( + onPressed: () async { + if (nameController.text.isEmpty || + priceController.text.isEmpty || + descriptionController.text.isEmpty || + selectedDialogCategoryId == null) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Semua field harus diisi'), + ), + ); + return; + } + await addService( + name: nameController.text, + price: priceController.text, + description: descriptionController.text, + categoryId: selectedDialogCategoryId!, + imageFile: imagePath != null ? File(imagePath!) : null, + ); + Navigator.pop(context); + }, + child: const Text('Simpan'), + ), + ], + ); + }, + ), + ); + } + + void selectCategory(int categoryId) async { + if (selectedCategoryId == categoryId) return; + setState(() => selectedCategoryId = categoryId); + await fetchServicesByCategory(categoryId); + } + + @override + Widget build(BuildContext context) { + final primaryColor = const Color(0xFFF06292); + final backgroundColor = const Color(0xFFFFF6F9); + + final services = + selectedCategoryId != null + ? (servicesByCategory[selectedCategoryId!] ?? []) + : []; + + return Scaffold( + backgroundColor: backgroundColor, + appBar: AppBar( + title: const Text('Data Layanan'), + backgroundColor: primaryColor, + ), + floatingActionButton: FloatingActionButton( + backgroundColor: primaryColor, + onPressed: showAddServiceDialog, + child: const Icon(Icons.add), + ), + body: Column( + children: [ + SizedBox( + height: 60, + child: + loadingCategories + ? const Center(child: CircularProgressIndicator()) + : ListView.builder( + scrollDirection: Axis.horizontal, + itemCount: categories.length, + itemBuilder: (context, index) { + final category = categories[index]; + final isSelected = category['id'] == selectedCategoryId; + + return GestureDetector( + onTap: () => selectCategory(category['id']), + child: Container( + margin: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 10, + ), + padding: const EdgeInsets.symmetric(horizontal: 20), + decoration: BoxDecoration( + color: + isSelected + ? primaryColor + : Colors.pink.shade100, + borderRadius: BorderRadius.circular(20), + ), + child: Center( + child: Text( + category['name'], + style: TextStyle( + color: + isSelected ? Colors.white : Colors.black, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + ); + }, + ), + ), + const Divider(), + Expanded( + child: + loadingServices + ? const Center(child: CircularProgressIndicator()) + : services.isEmpty + ? const Center(child: Text('Belum ada layanan.')) + : ListView.builder( + itemCount: services.length, + itemBuilder: (context, index) { + final service = services[index]; + return Card( + margin: const EdgeInsets.symmetric( + horizontal: 10, + vertical: 8, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(15), + ), + elevation: 4, + child: ListTile( + contentPadding: const EdgeInsets.all(10), + leading: + service.imageUrl != null && + service.imageUrl!.isNotEmpty + ? ClipRRect( + borderRadius: BorderRadius.circular(10), + child: Image.network( + service.imageUrl!, + width: 60, + height: 60, + fit: BoxFit.cover, + errorBuilder: + (context, error, stackTrace) => + const Icon( + Icons.broken_image, + size: 60, + ), + ), + ) + : const Icon( + Icons.image, + size: 60, + color: Colors.grey, + ), + title: Text( + service.name, + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + subtitle: Text("Rp ${service.price}"), + trailing: IconButton( + icon: const Icon(Icons.delete, color: Colors.red), + onPressed: () async { + final confirm = await showDialog( + context: context, + builder: + (context) => AlertDialog( + title: const Text('Hapus Layanan'), + content: const Text( + 'Apakah Anda yakin ingin menghapus layanan ini?', + ), + actions: [ + TextButton( + onPressed: + () => Navigator.pop( + context, + false, + ), + child: const Text('Batal'), + ), + ElevatedButton( + onPressed: + () => Navigator.pop( + context, + true, + ), + child: const Text('Hapus'), + ), + ], + ), + ); + + if (confirm == true) { + await deleteService( + service.id, + selectedCategoryId!, + ); + } + }, + ), + ), + ); + }, + ), + ), + ], + ), + ); + } +} diff --git a/website/lib/screens/features/berita_screen.dart b/website/lib/screens/features/berita_screen.dart new file mode 100644 index 0000000..c966008 --- /dev/null +++ b/website/lib/screens/features/berita_screen.dart @@ -0,0 +1,143 @@ +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:monitoring/config.dart'; +import 'package:monitoring/models/berita_model.dart'; +import 'package:monitoring/screens/features/berita_detail_screen.dart'; + +class BeritaScreen extends StatefulWidget { + final String token; + const BeritaScreen({super.key, required this.token}); + + @override + State createState() => _BeritaScreenState(); +} + +class _BeritaScreenState extends State { + List beritaList = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchBerita(); + } + + Future fetchBerita() async { + try { + final dio = Dio( + BaseOptions( + baseUrl: '$baseUrl', + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ), + ); + + final res = await dio.get('/berita'); + final List raw = res.data['data']; + setState(() { + beritaList = raw.map((e) => BeritaModel.fromJson(e)).toList(); + loading = false; + }); + } catch (e) { + debugPrint('Gagal: $e'); + setState(() => loading = false); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Berita'), + backgroundColor: Color(0xFF43A047), + foregroundColor: Colors.white, + ), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : ListView.builder( + itemCount: beritaList.length, + padding: const EdgeInsets.all(12), + itemBuilder: (context, index) { + final berita = beritaList[index]; + return Card( + margin: const EdgeInsets.only(bottom: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + elevation: 2, + child: Column( + children: [ + if (berita.gambarUrl != null) + ClipRRect( + borderRadius: const BorderRadius.vertical( + top: Radius.circular(12), + ), + child: Image.network( + berita.gambarUrl!, + height: 160, + width: double.infinity, + fit: BoxFit.cover, + errorBuilder: + (_, __, ___) => Image.asset('assets/404.png'), + ), + ), + Padding( + padding: const EdgeInsets.all(12), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + berita.judul, + style: const TextStyle( + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 6), + Text( + berita.ringkasan ?? '-', + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 8), + Text( + 'Kategori: ${berita.kategori ?? '-'} - oleh ${berita.penulis ?? '-'}', + style: const TextStyle( + fontSize: 12, + color: Colors.grey, + ), + ), + Align( + alignment: Alignment.centerRight, + child: GestureDetector( + onTap: () { + Navigator.push( + context, + MaterialPageRoute( + builder: + (context) => BeritaDetailScreen( + berita: berita, + ), + ), + ); + }, + child: Text( + 'Selengkapnya...', + style: TextStyle(color: Colors.blue), + ), + ), + ), + ], + ), + ), + ], + ), + ); + }, + ), + ); + } +} diff --git a/website/lib/screens/features/change_password_screen.dart b/website/lib/screens/features/change_password_screen.dart new file mode 100644 index 0000000..e70007a --- /dev/null +++ b/website/lib/screens/features/change_password_screen.dart @@ -0,0 +1,206 @@ +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:monitoring/config.dart'; + +class ChangePasswordScreen extends StatefulWidget { + final String token; + const ChangePasswordScreen({super.key, required this.token}); + + @override + State createState() => _ChangePasswordScreenState(); +} + +class _ChangePasswordScreenState extends State { + final _formKey = GlobalKey(); + final _oldPassController = TextEditingController(); + final _newPassController = TextEditingController(); + final _confirmPassController = TextEditingController(); + + bool _loading = false; + bool _obscureOld = true; + bool _obscureNew = true; + bool _obscureConfirm = true; + + Future _submit() async { + if (!_formKey.currentState!.validate()) return; + + setState(() => _loading = true); + + try { + final dio = Dio( + BaseOptions( + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ), + ); + + final response = await dio.post( + '$baseUrl/password', + data: { + 'old_password': _oldPassController.text.trim(), + 'new_password': _newPassController.text.trim(), + 'confirm_password': _confirmPassController.text.trim(), + }, + ); + + if (context.mounted) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(response.data['message'] ?? 'Berhasil')), + ); + Navigator.pop(context); + } + } on DioException catch (e) { + final msg = + e.response?.data['message'] ?? + e.response?.data.toString() ?? + 'Gagal mengganti password'; + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg))); + } catch (_) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar( + content: Text('Terjadi kesalahan saat mengganti password'), + ), + ); + } finally { + setState(() => _loading = false); + } + } + + @override + void dispose() { + _oldPassController.dispose(); + _newPassController.dispose(); + _confirmPassController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + const fieldPadding = EdgeInsets.symmetric(vertical: 8); + + return Scaffold( + appBar: AppBar(title: const Text('Ganti Password')), + body: SingleChildScrollView( + padding: const EdgeInsets.all(20), + child: Form( + key: _formKey, + child: Column( + children: [ + const Text( + 'Untuk alasan keamanan, gunakan password baru yang kuat dan mudah diingat.', + style: TextStyle(fontSize: 14, color: Colors.black87), + ), + const SizedBox(height: 16), + + /// Old password + Padding( + padding: fieldPadding, + child: TextFormField( + controller: _oldPassController, + obscureText: _obscureOld, + decoration: InputDecoration( + labelText: 'Password Saat Ini', + border: const OutlineInputBorder(), + suffixIcon: IconButton( + icon: Icon( + _obscureOld ? Icons.visibility_off : Icons.visibility, + ), + onPressed: + () => setState(() => _obscureOld = !_obscureOld), + ), + ), + validator: + (val) => + val == null || val.isEmpty ? 'Wajib diisi' : null, + ), + ), + + /// New password + Padding( + padding: fieldPadding, + child: TextFormField( + controller: _newPassController, + obscureText: _obscureNew, + decoration: InputDecoration( + labelText: 'Password Baru', + border: const OutlineInputBorder(), + suffixIcon: IconButton( + icon: Icon( + _obscureNew ? Icons.visibility_off : Icons.visibility, + ), + onPressed: + () => setState(() => _obscureNew = !_obscureNew), + ), + ), + validator: (val) { + if (val == null || val.isEmpty) return 'Wajib diisi'; + if (val.length < 6) return 'Minimal 6 karakter'; + return null; + }, + ), + ), + + /// Confirm password + Padding( + padding: fieldPadding, + child: TextFormField( + controller: _confirmPassController, + obscureText: _obscureConfirm, + decoration: InputDecoration( + labelText: 'Konfirmasi Password Baru', + border: const OutlineInputBorder(), + suffixIcon: IconButton( + icon: Icon( + _obscureConfirm + ? Icons.visibility_off + : Icons.visibility, + ), + onPressed: + () => setState( + () => _obscureConfirm = !_obscureConfirm, + ), + ), + ), + validator: + (val) => + val != _newPassController.text + ? 'Password tidak cocok' + : null, + ), + ), + + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: _loading ? null : _submit, + icon: const Icon(Icons.lock_open), + label: + _loading + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : const Text('Simpan Password'), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 14), + backgroundColor: Colors.green, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/website/lib/screens/features/edit_profile_screen.dart b/website/lib/screens/features/edit_profile_screen.dart new file mode 100644 index 0000000..1bfd3ba --- /dev/null +++ b/website/lib/screens/features/edit_profile_screen.dart @@ -0,0 +1,261 @@ +import 'dart:io'; +import 'package:dio/dio.dart'; +import 'package:flutter/material.dart'; +import 'package:image_picker/image_picker.dart'; +import 'package:http_parser/http_parser.dart'; +import 'package:monitoring/config.dart'; + +class EditProfileScreen extends StatefulWidget { + final String token; + + const EditProfileScreen({super.key, required this.token}); + + @override + State createState() => _EditProfileScreenState(); +} + +class _EditProfileScreenState extends State { + final _formKey = GlobalKey(); + bool _loading = true; + bool _saving = false; + + final _nameController = TextEditingController(); + final _alamatController = TextEditingController(); + final _tempatLahirController = TextEditingController(); + final _tanggalLahirController = TextEditingController(); + + String? _jenisKelamin; + String? _fotoUrl; + File? _selectedImage; + + @override + void initState() { + super.initState(); + fetchProfile(); + } + + Future fetchProfile() async { + try { + final dio = Dio( + BaseOptions( + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + }, + ), + ); + + final response = await dio.get('$baseUrl/santri/me'); + final data = response.data; + + final user = data['user']; + final santri = data['santri']; + + setState(() { + _nameController.text = user['name'] ?? ''; + _alamatController.text = santri['alamat'] ?? ''; + _tempatLahirController.text = santri['tempat_lahir'] ?? ''; + _tanggalLahirController.text = santri['tanggal_lahir'] ?? ''; + _jenisKelamin = santri['jenis_kelamin']; + _fotoUrl = santri['foto_url']; + _loading = false; + }); + } catch (e) { + debugPrint('Gagal ambil profil: $e'); + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Gagal mengambil profil'))); + Navigator.pop(context); + } + } + + Future pickImage() async { + final picked = await ImagePicker().pickImage(source: ImageSource.gallery); + if (picked != null) { + setState(() { + _selectedImage = File(picked.path); + }); + } + } + + Future saveProfile() async { + if (!_formKey.currentState!.validate()) return; + + setState(() => _saving = true); + + try { + final dio = Dio( + BaseOptions( + headers: { + 'Authorization': 'Bearer ${widget.token}', + 'Accept': 'application/json', + 'Content-Type': 'multipart/form-data', + }, + ), + ); + + final formData = FormData.fromMap({ + 'name': _nameController.text.trim(), + 'alamat': _alamatController.text.trim(), + 'tempat_lahir': _tempatLahirController.text.trim(), + 'tanggal_lahir': _tanggalLahirController.text.trim(), + 'jenis_kelamin': _jenisKelamin, + if (_selectedImage != null) + 'foto': await MultipartFile.fromFile( + _selectedImage!.path, + filename: _selectedImage!.path.split('/').last, + contentType: MediaType('image', 'jpeg'), + ), + }); + + final response = await dio.post('$baseUrl/santri/me', data: formData); + + final message = response.data['message'] ?? 'Profil berhasil diperbarui'; + + if (context.mounted) { + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text(message))); + Navigator.pop(context, true); // Kembali & beri sinyal refresh + } + } on DioException catch (e) { + final msg = + e.response?.data['message'] ?? + e.response?.data.toString() ?? + 'Gagal memperbarui profil'; + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(msg))); + } finally { + setState(() => _saving = false); + } + } + + @override + void dispose() { + _nameController.dispose(); + _alamatController.dispose(); + _tempatLahirController.dispose(); + _tanggalLahirController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + const fieldSpace = SizedBox(height: 16); + + return Scaffold( + appBar: AppBar(title: const Text('Edit Profil')), + body: + _loading + ? const Center(child: CircularProgressIndicator()) + : SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Form( + key: _formKey, + child: Column( + children: [ + if (_fotoUrl != null && _selectedImage == null) + CircleAvatar( + backgroundImage: NetworkImage(_fotoUrl!), + radius: 45, + ), + if (_selectedImage != null) + CircleAvatar( + backgroundImage: FileImage(_selectedImage!), + radius: 45, + ), + TextButton.icon( + onPressed: pickImage, + icon: const Icon(Icons.photo), + label: const Text('Ubah Foto'), + ), + fieldSpace, + + TextFormField( + controller: _nameController, + decoration: const InputDecoration( + labelText: 'Nama Lengkap', + border: OutlineInputBorder(), + ), + validator: (val) => val!.isEmpty ? 'Wajib diisi' : null, + ), + fieldSpace, + + TextFormField( + controller: _alamatController, + decoration: const InputDecoration( + labelText: 'Alamat', + border: OutlineInputBorder(), + ), + ), + fieldSpace, + + TextFormField( + controller: _tempatLahirController, + decoration: const InputDecoration( + labelText: 'Tempat Lahir', + border: OutlineInputBorder(), + ), + ), + fieldSpace, + + TextFormField( + controller: _tanggalLahirController, + decoration: const InputDecoration( + labelText: 'Tanggal Lahir', + hintText: 'YYYY-MM-DD', + border: OutlineInputBorder(), + ), + ), + fieldSpace, + + DropdownButtonFormField( + value: _jenisKelamin, + decoration: const InputDecoration( + labelText: 'Jenis Kelamin', + border: OutlineInputBorder(), + ), + items: const [ + DropdownMenuItem( + value: 'L', + child: Text('Laki-laki'), + ), + DropdownMenuItem( + value: 'P', + child: Text('Perempuan'), + ), + ], + onChanged: (val) => setState(() => _jenisKelamin = val), + ), + + const SizedBox(height: 28), + SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: _saving ? null : saveProfile, + icon: const Icon(Icons.save), + label: + _saving + ? const SizedBox( + width: 20, + height: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + ), + ) + : const Text('Simpan Perubahan'), + style: ElevatedButton.styleFrom( + padding: const EdgeInsets.symmetric(vertical: 16), + backgroundColor: Colors.green, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/website/lib/screens/features/kesehatan_screen.dart b/website/lib/screens/features/kesehatan_screen.dart new file mode 100644 index 0000000..a4869a5 --- /dev/null +++ b/website/lib/screens/features/kesehatan_screen.dart @@ -0,0 +1,139 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; + +import 'package:monitoring/config.dart'; + +class KesehatanScreen extends StatefulWidget { + final String token; + const KesehatanScreen({super.key, required this.token}); + + @override + State createState() => _KesehatanScreenState(); +} + +class _KesehatanScreenState extends State { + List data = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchKesehatan(); + } + + Future fetchKesehatan() async { + final url = '$baseUrl/kesehatan'; + + try { + final response = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final res = json.decode(response.body); + setState(() { + data = res['data'] ?? []; + loading = false; + }); + } else { + debugPrint('Gagal ambil data kesehatan: ${response.statusCode}'); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Gagal ambil kesehatan: $e'); + setState(() => loading = false); + } + } + + Widget _buildCard(Map item) { + return Card( + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + elevation: 3, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon(Icons.local_hospital, color: Colors.green), + const SizedBox(width: 8), + Expanded( + child: Text( + item['keluhan'] ?? '-', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 12), + _infoRow('Diagnosis', item['diagnosis']), + _infoRow('Saran', item['saran']), + _infoRow('Kelas', item['kelas_nama']), + _infoRow('Tanggal', _formatDate(item['created_at'])), + ], + ), + ), + ); + } + + Widget _infoRow(String label, String? value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 90, + child: Text( + '$label:', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Expanded( + child: Text( + value ?? '-', + style: const TextStyle(color: Colors.black87), + ), + ), + ], + ), + ); + } + + String _formatDate(String? datetime) { + if (datetime == null) return '-'; + final date = DateTime.tryParse(datetime); + if (date == null) return '-'; + return '${date.day.toString().padLeft(2, '0')}-${date.month.toString().padLeft(2, '0')}-${date.year}'; + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Catatan Kesehatan')), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : data.isEmpty + ? const Center(child: Text('Tidak ada catatan kesehatan.')) + : RefreshIndicator( + onRefresh: fetchKesehatan, + child: ListView.builder( + physics: const AlwaysScrollableScrollPhysics(), + itemCount: data.length, + itemBuilder: (context, index) => _buildCard(data[index]), + ), + ), + ); + } +} diff --git a/website/lib/screens/features/nilai_screen.dart b/website/lib/screens/features/nilai_screen.dart new file mode 100644 index 0000000..6b12046 --- /dev/null +++ b/website/lib/screens/features/nilai_screen.dart @@ -0,0 +1,147 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; +import 'package:intl/intl.dart'; +import 'package:monitoring/config.dart'; + +class NilaiScreen extends StatefulWidget { + final String token; + const NilaiScreen({super.key, required this.token}); + + @override + State createState() => _NilaiScreenState(); +} + +class _NilaiScreenState extends State { + List data = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchNilai(); + } + + Future fetchNilai() async { + final url = '$baseUrl/nilai'; + + try { + final response = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final res = json.decode(response.body); + setState(() { + data = res['data'] ?? []; + loading = false; + }); + } else { + debugPrint( + 'Gagal ambil nilai: ${response.statusCode} - ${response.body}', + ); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Error nilai: $e'); + setState(() => loading = false); + } + } + + String formatTanggal(String? tanggal) { + if (tanggal == null) return '-'; + try { + final date = DateTime.parse(tanggal); + return DateFormat('dd MMM yyyy', 'id_ID').format(date); + } catch (e) { + return tanggal; + } + } + + Widget _buildCard(Map item) { + return Card( + elevation: 3, + margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + item['mapel'] ?? '-', + style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), + ), + const SizedBox(height: 4), + Row( + children: [ + Chip( + label: Text(item['jenis_nilai'] ?? '-'), + backgroundColor: Colors.indigo.shade50, + labelStyle: const TextStyle(color: Colors.indigo), + ), + const SizedBox(width: 8), + Text( + 'Nilai: ${item['nilai']}', + style: const TextStyle(fontSize: 14), + ), + ], + ), + const SizedBox(height: 8), + _infoRow( + Icons.calendar_today, + 'Tanggal', + formatTanggal(item['tanggal']), + ), + _infoRow(Icons.school, 'Semester', item['semester']), + if ((item['keterangan'] ?? '').toString().isNotEmpty) + _infoRow(Icons.info_outline, 'Catatan', item['keterangan']), + ], + ), + ), + ); + } + + Widget _infoRow(IconData icon, String label, String? value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 2), + child: Row( + children: [ + Icon(icon, size: 18, color: Colors.grey.shade600), + const SizedBox(width: 8), + Text('$label: ', style: const TextStyle(fontWeight: FontWeight.bold)), + Expanded( + child: Text( + value ?? '-', + style: const TextStyle(color: Colors.black87), + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Nilai Akademik')), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : data.isEmpty + ? const Center(child: Text('Belum ada data nilai.')) + : RefreshIndicator( + onRefresh: fetchNilai, + child: ListView.builder( + physics: const AlwaysScrollableScrollPhysics(), + itemCount: data.length, + itemBuilder: (context, i) => _buildCard(data[i]), + ), + ), + ); + } +} diff --git a/website/lib/screens/features/pelanggaran_screen.dart b/website/lib/screens/features/pelanggaran_screen.dart new file mode 100644 index 0000000..eb2d6d1 --- /dev/null +++ b/website/lib/screens/features/pelanggaran_screen.dart @@ -0,0 +1,90 @@ +// lib/screens/features/pelanggaran_screen.dart +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; + +class PelanggaranScreen extends StatefulWidget { + final String token; + + const PelanggaranScreen({super.key, required this.token}); + + @override + State createState() => _PelanggaranScreenState(); +} + +class _PelanggaranScreenState extends State { + List _pelanggaranList = []; + bool _loading = true; + + @override + void initState() { + super.initState(); + fetchPelanggaran(); + } + + Future fetchPelanggaran() async { + try { + final response = await http.get( + Uri.parse("http://10.75.50.24:8000/api/pelanggaran"), + headers: { + "Authorization": "Bearer ${widget.token}", + "Accept": "application/json", + }, + ); + + final data = jsonDecode(response.body); + if (data["success"] == true) { + setState(() { + _pelanggaranList = data["data"]; + _loading = false; + }); + } else { + throw Exception("Gagal mengambil data"); + } + } catch (e) { + setState(() { + _loading = false; + }); + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text("Error: $e")), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text("Data Pelanggaran"), + backgroundColor: const Color(0xFF43A047), + ), + body: _loading + ? const Center(child: CircularProgressIndicator()) + : _pelanggaranList.isEmpty + ? const Center(child: Text("Tidak ada data pelanggaran.")) + : ListView.builder( + itemCount: _pelanggaranList.length, + itemBuilder: (context, index) { + final item = _pelanggaranList[index]; + return Card( + margin: + const EdgeInsets.symmetric(horizontal: 12, vertical: 6), + child: ListTile( + // title: Text(item["nama_santri"] ?? "-"), + subtitle: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text("Kelas: ${item["nama_kelas"] ?? '-'}"), + Text("Jenis: ${item["jenis_pelanggaran"] ?? '-'}"), + Text("Hukuman: ${item["hukuman"] ?? '-'}"), + Text("Guru Penegur: ${item["nama_penginput"] ?? '-'}"), + ], + ), + // trailing: const Icon(Icons.arrow_forward_ios, size: 16), + ), + ); + }, + ), + ); + } +} \ No newline at end of file diff --git a/website/lib/screens/features/pembayaran_screen.dart b/website/lib/screens/features/pembayaran_screen.dart new file mode 100644 index 0000000..a5747ae --- /dev/null +++ b/website/lib/screens/features/pembayaran_screen.dart @@ -0,0 +1,246 @@ +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:monitoring/config.dart'; +// import halaman tambah pembayaran jika ada +import 'tambah_pembayaran_screen.dart'; + +class Pembayaran { + final int id; + final int santriId; + final int? kelasId; + final String tanggal; + final int jumlah; + final String jenis; + final String? keterangan; + final String? bukti; + final String status; + final String? santriName; + + Pembayaran({ + required this.id, + required this.santriId, + this.kelasId, + required this.tanggal, + required this.jumlah, + required this.jenis, + this.keterangan, + this.bukti, + required this.status, + this.santriName, + }); + + factory Pembayaran.fromJson(Map json) { + return Pembayaran( + id: json['id'], + santriId: json['santri_id'], + kelasId: json['kelas_id'], + tanggal: json['tanggal'], + jumlah: json['jumlah'], + jenis: json['jenis_pembayaran'], + keterangan: json['keterangan'], + bukti: json['bukti_pembayaran'], + status: json['status'], + santriName: json['santri_name'], + ); + } +} + +class PembayaranScreen extends StatefulWidget { + final String token; + const PembayaranScreen({super.key, required this.token}); + + @override + State createState() => _PembayaranScreenState(); +} + +class _PembayaranScreenState extends State { + List pembayaranList = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchPembayaran(); + } + + Future fetchPembayaran() async { + try { + final dio = Dio( + BaseOptions( + baseUrl: '$baseUrl', + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ), + ); + + final response = await dio.get('/pembayaran'); + final data = response.data as List; + + setState(() { + pembayaranList = data.map((e) => Pembayaran.fromJson(e)).toList(); + loading = false; + }); + } catch (e) { + debugPrint('Error fetch pembayaran: $e'); + setState(() => loading = false); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Data Pembayaran')), + floatingActionButton: FloatingActionButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => TambahPembayaranScreen(token: widget.token), + ), + ).then((_) => fetchPembayaran()); // refresh setelah kembali + }, + backgroundColor: Colors.teal, + child: const Icon(Icons.add), + ), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : pembayaranList.isEmpty + ? const Center(child: Text('Belum ada data pembayaran')) + : ListView.builder( + padding: const EdgeInsets.all(12), + itemCount: pembayaranList.length, + itemBuilder: (context, index) { + final bayar = pembayaranList[index]; + + return Card( + elevation: 2, + margin: const EdgeInsets.only(bottom: 12), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + bayar.jenis, + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + const SizedBox(height: 4), + Text('Tanggal: ${bayar.tanggal}'), + Text('Jumlah: Rp${bayar.jumlah}'), + if (bayar.keterangan != null) + Text('Keterangan: ${bayar.keterangan}'), + Text('Status: ${bayar.status}'), + if (bayar.bukti != null) + Padding( + padding: const EdgeInsets.only(top: 8), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Bukti Pembayaran:', + style: TextStyle( + fontWeight: FontWeight.bold, + ), + ), + const SizedBox(height: 8), + if (bayar.bukti != null) + SizedBox( + width: double.infinity, + child: ElevatedButton.icon( + onPressed: () { + showDialog( + context: context, + builder: + (_) => AlertDialog( + title: const Text( + 'Bukti Pembayaran', + ), + content: ClipRRect( + borderRadius: + BorderRadius.circular( + 8, + ), + child: Image.network( + bayar.bukti!, + fit: BoxFit.cover, + errorBuilder: + ( + context, + error, + stackTrace, + ) => const Text( + 'Gagal memuat gambar', + style: TextStyle( + color: Colors.red, + ), + ), + loadingBuilder: ( + context, + child, + loadingProgress, + ) { + if (loadingProgress == + null) + return child; + return const SizedBox( + height: 100, + child: Center( + child: + CircularProgressIndicator(), + ), + ); + }, + ), + ), + actions: [ + TextButton( + onPressed: + () => Navigator.pop( + context, + ), + child: const Text( + 'Tutup', + ), + ), + ], + ), + ); + }, + icon: const Icon( + Icons.image, + color: Colors.white, + ), + label: const Text( + 'Lihat Bukti Pembayaran', + ), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.teal, + foregroundColor: Colors.white, + padding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 10, + ), + ), + ), + ), + ], + ), + ), + ], + ), + ), + ); + }, + ), + ); + } +} diff --git a/website/lib/screens/features/prestasi_screen.dart b/website/lib/screens/features/prestasi_screen.dart new file mode 100644 index 0000000..0c0bb19 --- /dev/null +++ b/website/lib/screens/features/prestasi_screen.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'dart:convert'; + +import 'package:monitoring/config.dart'; + +class PrestasiScreen extends StatefulWidget { + final String token; + const PrestasiScreen({super.key, required this.token}); + + @override + State createState() => _PrestasiScreenState(); +} + +class _PrestasiScreenState extends State { + List data = []; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchPrestasi(); + } + + Future fetchPrestasi() async { + final url = '${baseUrl}/prestasi'; // Ganti jika pakai emulator + + try { + final response = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (response.statusCode == 200) { + final res = json.decode(response.body); + setState(() { + data = res['data'] ?? []; + loading = false; + }); + } else { + debugPrint( + 'Gagal ambil prestasi: ${response.statusCode} - ${response.body}', + ); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Error prestasi: $e'); + setState(() => loading = false); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Riwayat Prestasi')), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : data.isEmpty + ? const Center(child: Text('Belum ada data prestasi.')) + : ListView.builder( + itemCount: data.length, + padding: const EdgeInsets.all(12), + itemBuilder: (context, index) { + final item = data[index]; + return Card( + margin: const EdgeInsets.only(bottom: 12), + elevation: 3, + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(12), + ), + child: Padding( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + children: [ + const Icon( + Icons.emoji_events, + color: Colors.amber, + size: 28, + ), + const SizedBox(width: 8), + Expanded( + child: Text( + item['nama_prestasi'] ?? '-', + style: const TextStyle( + fontSize: 16, + fontWeight: FontWeight.bold, + ), + ), + ), + ], + ), + const SizedBox(height: 8), + Text('Jenis: ${item['jenis_prestasi'] ?? '-'}'), + Text('Tingkat: ${item['tingkat'] ?? '-'}'), + Text('Peringkat: ${item['peringkat'] ?? '-'}'), + Text('Tanggal: ${item['tanggal_prestasi'] ?? '-'}'), + if (item['deskripsi'] != null && + item['deskripsi'].toString().isNotEmpty) + Padding( + padding: const EdgeInsets.only(top: 6), + child: Text( + item['deskripsi'], + style: const TextStyle(color: Colors.black54), + ), + ), + const Divider(height: 20), + Text('Santri: ${item['santri']?['nama'] ?? '-'}'), + Text('Kelas: ${item['kelas']?['nama_kelas'] ?? '-'}'), + ], + ), + ), + ); + }, + ), + ); + } +} diff --git a/website/lib/screens/features/profile_screen.dart b/website/lib/screens/features/profile_screen.dart new file mode 100644 index 0000000..5987c9c --- /dev/null +++ b/website/lib/screens/features/profile_screen.dart @@ -0,0 +1,187 @@ +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; +import 'dart:convert'; + +import 'edit_profile_screen.dart'; +import 'change_password_screen.dart'; + +class ProfileScreen extends StatefulWidget { + final String token; + const ProfileScreen({super.key, required this.token}); + + @override + State createState() => _ProfileScreenState(); +} + +class _ProfileScreenState extends State { + Map? userData; + Map? santriData; + String? fotoUrl; + bool loading = true; + + @override + void initState() { + super.initState(); + fetchProfile(); + } + + Future fetchProfile() async { + final url = '$baseUrl/santri/me'; + try { + final res = await http.get( + Uri.parse(url), + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ); + + if (res.statusCode == 200) { + final jsonRes = json.decode(res.body); + setState(() { + userData = jsonRes['user']; + santriData = jsonRes['santri']; + fotoUrl = santriData?['foto_url']; + loading = false; + }); + } else { + debugPrint('Gagal ambil profil: ${res.body}'); + setState(() => loading = false); + } + } catch (e) { + debugPrint('Error profile: $e'); + setState(() => loading = false); + } + } + + void _logout() { + Navigator.pushNamedAndRemoveUntil(context, '/login', (_) => false); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: const Text('Profil'), + actions: [ + IconButton( + onPressed: _logout, + icon: const Icon(Icons.logout), + tooltip: 'Logout', + ), + ], + ), + body: + loading + ? const Center(child: CircularProgressIndicator()) + : userData == null || santriData == null + ? const Center(child: Text('Data tidak ditemukan')) + : SingleChildScrollView( + padding: const EdgeInsets.all(16), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: CircleAvatar( + radius: 50, + backgroundImage: + fotoUrl != null + ? NetworkImage(fotoUrl!) + : const AssetImage('assets/default_profile.png') + as ImageProvider, + backgroundColor: Colors.grey[300], + ), + ), + const SizedBox(height: 20), + Center( + child: Text( + userData!['name'] ?? '-', + style: const TextStyle( + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ), + const SizedBox(height: 16), + // _buildInfoTile('Username', userData!['username']), + // _buildInfoTile('Email', userData!['email']), + // _buildInfoTile('Role', userData!['role']), + const Divider(), + _buildInfoTile('NIS', santriData!['nis']), + _buildInfoTile('Alamat', santriData!['alamat']), + _buildInfoTile('Tempat Lahir', santriData!['tempat_lahir']), + _buildInfoTile( + 'Tanggal Lahir', + santriData!['tanggal_lahir'], + ), + _buildInfoTile( + 'Jenis Kelamin', + santriData!['jenis_kelamin'] == 'L' + ? 'Laki-laki' + : 'Perempuan', + ), + const SizedBox(height: 24), + + // ✅ PERBAIKAN NAVIGASI EDIT + ElevatedButton.icon( + onPressed: () async { + final result = await Navigator.push( + context, + MaterialPageRoute( + builder: + (_) => EditProfileScreen(token: widget.token), + ), + ); + if (result == true) { + fetchProfile(); // Refresh profil setelah edit + } + }, + icon: const Icon(Icons.edit), + label: const Text('Edit Profil'), + ), + + const SizedBox(height: 12), + + ElevatedButton.icon( + style: ElevatedButton.styleFrom( + backgroundColor: Colors.orange, + ), + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: + (_) => + ChangePasswordScreen(token: widget.token), + ), + ); + }, + icon: const Icon(Icons.lock), + label: const Text('Ganti Password'), + ), + ], + ), + ), + ); + } + + Widget _buildInfoTile(String label, String? value) { + return Padding( + padding: const EdgeInsets.symmetric(vertical: 4), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + SizedBox( + width: 120, + child: Text( + '$label:', + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ), + Expanded(child: Text(value ?? '-')), + ], + ), + ); + } +} diff --git a/website/lib/screens/features/tambah_pembayaran_screen.dart b/website/lib/screens/features/tambah_pembayaran_screen.dart new file mode 100644 index 0000000..93044aa --- /dev/null +++ b/website/lib/screens/features/tambah_pembayaran_screen.dart @@ -0,0 +1,211 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:file_picker/file_picker.dart'; +import 'package:monitoring/config.dart'; + +class TambahPembayaranScreen extends StatefulWidget { + final String token; + const TambahPembayaranScreen({super.key, required this.token}); + + @override + State createState() => _TambahPembayaranScreenState(); +} + +class _TambahPembayaranScreenState extends State { + final formKey = GlobalKey(); + String jenis = 'SPP'; + String tanggal = ''; + int jumlah = 0; + String keterangan = ''; + File? bukti; + bool isLoading = false; + + Future submit() async { + if (!formKey.currentState!.validate()) return; + + if (bukti == null) { + ScaffoldMessenger.of( + context, + ).showSnackBar(const SnackBar(content: Text('Bukti belum dipilih'))); + return; + } + setState(() => isLoading = true); + + final dio = Dio( + BaseOptions( + baseUrl: '$baseUrl', + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ), + ); + + final formData = FormData.fromMap({ + 'tanggal': tanggal, + 'jenis_pembayaran': jenis, + 'jumlah': jumlah, + 'keterangan': keterangan, + 'bukti_pembayaran': await MultipartFile.fromFile(bukti!.path), + }); + + try { + final response = await dio.post('/pembayaran', data: formData); + if (response.statusCode == 201) { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Pembayaran berhasil dikirim')), + ); + Navigator.pop(context); + } else { + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Gagal mengirim pembayaran')), + ); + } + } catch (e) { + debugPrint('Gagal kirim pembayaran: $e'); + ScaffoldMessenger.of( + context, + ).showSnackBar(SnackBar(content: Text('Terjadi kesalahan: $e'))); + } finally { + setState(() => isLoading = false); // selesai loading + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Tambah Pembayaran')), + body: Padding( + padding: const EdgeInsets.all(16), + child: Form( + key: formKey, + child: ListView( + children: [ + DropdownButtonFormField( + value: jenis, + items: const [ + DropdownMenuItem(value: 'SPP', child: Text('SPP')), + DropdownMenuItem( + value: 'Uang Makan', + child: Text('Uang Makan'), + ), + DropdownMenuItem( + value: 'Uang Asrama', + child: Text('Uang Asrama'), + ), + DropdownMenuItem( + value: 'Uang Kegiatan', + child: Text('Uang Kegiatan'), + ), + DropdownMenuItem( + value: 'Uang Seragam', + child: Text('Uang Seragam'), + ), + DropdownMenuItem(value: 'Lainnya', child: Text('Lainnya')), + ], + onChanged: (val) => setState(() => jenis = val!), + decoration: const InputDecoration( + labelText: 'Jenis Pembayaran', + ), + ), + const SizedBox(height: 12), + TextFormField( + decoration: const InputDecoration(labelText: 'Jumlah'), + keyboardType: TextInputType.number, + onChanged: (val) => jumlah = int.tryParse(val) ?? 0, + validator: + (val) => + val == null || val.isEmpty + ? 'Jumlah wajib diisi' + : null, + ), + const SizedBox(height: 12), + TextFormField( + decoration: const InputDecoration(labelText: 'Tanggal'), + controller: TextEditingController(text: tanggal), + readOnly: true, + onTap: () async { + final picked = await showDatePicker( + context: context, + initialDate: DateTime.now(), + firstDate: DateTime(2022), + lastDate: DateTime(2030), + ); + if (picked != null) { + setState(() { + tanggal = picked.toIso8601String().split('T')[0]; + }); + } + }, + validator: + (val) => + val == null || val.isEmpty + ? 'Tanggal wajib diisi' + : null, + ), + const SizedBox(height: 12), + TextFormField( + decoration: const InputDecoration(labelText: 'Keterangan'), + maxLines: 2, + onChanged: (val) => keterangan = val, + ), + const SizedBox(height: 12), + ElevatedButton.icon( + onPressed: () async { + final picked = await FilePicker.platform.pickFiles( + type: FileType.image, + ); + if (picked != null && picked.files.first.path != null) { + setState(() { + bukti = File(picked.files.first.path!); + }); + } + }, + icon: const Icon(Icons.attach_file), + label: const Text('Pilih Bukti Pembayaran'), + ), + if (bukti != null) ...[ + const SizedBox(height: 10), + const Text( + 'Preview Bukti:', + style: TextStyle(fontWeight: FontWeight.bold), + ), + const SizedBox(height: 8), + ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Image.file( + bukti!, + height: 200, + width: double.infinity, + fit: BoxFit.cover, + ), + ), + ], + const SizedBox(height: 24), + ElevatedButton.icon( + onPressed: isLoading ? null : submit, + icon: + isLoading + ? const SizedBox( + height: 20, + width: 20, + child: CircularProgressIndicator( + strokeWidth: 2, + color: Colors.white, + ), + ) + : const Icon(Icons.save), + label: Text(isLoading ? 'Proses...' : 'Kirim Pembayaran'), + style: ElevatedButton.styleFrom( + backgroundColor: Colors.teal, + padding: const EdgeInsets.symmetric(vertical: 14), + ), + ), + ], + ), + ), + ), + ); + } +} diff --git a/website/lib/screens/forgot_password_screen.dart b/website/lib/screens/forgot_password_screen.dart new file mode 100644 index 0000000..5b9b825 --- /dev/null +++ b/website/lib/screens/forgot_password_screen.dart @@ -0,0 +1,111 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import '../config.dart'; // baseUrl disimpan di file ini + +class ForgotPasswordScreen extends StatefulWidget { + const ForgotPasswordScreen({Key? key}) : super(key: key); + + @override + State createState() => _ForgotPasswordScreenState(); +} + +class _ForgotPasswordScreenState extends State { + final _formKey = GlobalKey(); + final _nisController = TextEditingController(); + final _newPassController = TextEditingController(); + final _confirmPassController = TextEditingController(); + + bool _loading = false; + + Future _resetPassword() async { + if (!_formKey.currentState!.validate()) return; + + setState(() => _loading = true); + + final response = await http.post( + Uri.parse('$baseUrl/forgot-password/reset'), + headers: {'Accept': 'application/json'}, + body: { + 'nis': _nisController.text, + 'new_password': _newPassController.text, + 'confirm_password': _confirmPassController.text, + }, + ); + + final data = jsonDecode(response.body); + setState(() => _loading = false); + + if (response.statusCode == 200) { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(data['message'])), + ); + Navigator.pop(context); // kembali ke halaman login + } else { + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(data['message'] ?? 'Gagal mereset password')), + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text("Reset Password")), + body: Padding( + padding: const EdgeInsets.all(20), + child: Form( + key: _formKey, + child: Column( + children: [ + TextFormField( + controller: _nisController, + decoration: const InputDecoration( + labelText: "NIS", + border: OutlineInputBorder(), + ), + validator: (val) => + val == null || val.isEmpty ? 'NIS wajib diisi' : null, + ), + const SizedBox(height: 16), + TextFormField( + controller: _newPassController, + obscureText: true, + decoration: const InputDecoration( + labelText: "Password Baru", + border: OutlineInputBorder(), + ), + validator: (val) => + val == null || val.length < 6 ? 'Minimal 6 karakter' : null, + ), + const SizedBox(height: 16), + TextFormField( + controller: _confirmPassController, + obscureText: true, + decoration: const InputDecoration( + labelText: "Konfirmasi Password", + border: OutlineInputBorder(), + ), + validator: (val) => + val != _newPassController.text ? 'Tidak cocok' : null, + ), + const SizedBox(height: 24), + SizedBox( + width: double.infinity, + child: ElevatedButton( + onPressed: _loading ? null : _resetPassword, + child: _loading + ? const CircularProgressIndicator( + color: Colors.white, + strokeWidth: 2, + ) + : const Text("Reset Password"), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/website/lib/screens/home_screen.dart b/website/lib/screens/home_screen.dart new file mode 100644 index 0000000..d05dcd2 --- /dev/null +++ b/website/lib/screens/home_screen.dart @@ -0,0 +1,148 @@ +import 'package:flutter/material.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +import '../main.dart'; +import '../widgets/feature_grid.dart'; +import 'features/profile_screen.dart'; +import 'splash_screen.dart'; // ✅ Tambahkan ini + +class HomeScreen extends StatefulWidget { + final String token; + final Map user; + + const HomeScreen({super.key, required this.token, required this.user}); + + @override + State createState() => _HomeScreenState(); +} + +class _HomeScreenState extends State { + void logout() async { + final prefs = await SharedPreferences.getInstance(); + await prefs.remove('token'); + await prefs.remove('user'); + + if (!mounted) return; // ✅ Hindari error context async + + Navigator.pushAndRemoveUntil( + context, + MaterialPageRoute( + builder: + (_) => SplashScreen( + onLoginSuccess: (token, user) { + Navigator.pushReplacement( + navigatorKey.currentContext!, + MaterialPageRoute( + builder: (_) => HomeScreen(token: token, user: user), + ), + ); + }, + ), + ), + (route) => false, + ); + } + + Widget buildBanner(String name) { + return Container( + margin: const EdgeInsets.symmetric(horizontal: 16), + padding: const EdgeInsets.all(16), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(20), + gradient: const LinearGradient( + colors: [Color(0xFFA5D6A7), Color(0xFF66BB6A)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Text( + 'Monas SMA Bina Insan Mandiri', + style: TextStyle(color: Colors.white70, fontSize: 12), + ), + const SizedBox(height: 4), + Text( + 'Selamat Datang, $name', + style: const TextStyle( + color: Colors.white, + fontSize: 20, + fontWeight: FontWeight.bold, + ), + ), + ], + ), + ); + } + + @override + Widget build(BuildContext context) { + final name = widget.user['name'] ?? 'Santri'; + + return Scaffold( + drawer: Drawer( + child: ListView( + padding: EdgeInsets.zero, + children: [ + DrawerHeader( + decoration: const BoxDecoration(color: Color(0xFF43A047)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const Icon( + Icons.account_circle, + size: 64, + color: Colors.white, + ), + const SizedBox(height: 8), + Text( + name, + style: const TextStyle(color: Colors.white, fontSize: 18), + ), + const Text('Santri', style: TextStyle(color: Colors.white70)), + ], + ), + ), + ListTile( + leading: const Icon(Icons.person), + title: const Text('Profil'), + onTap: () { + Navigator.pop(context); + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => ProfileScreen(token: widget.token), + ), + ); + }, + ), + ListTile( + leading: const Icon(Icons.logout), + title: const Text('Logout'), + onTap: () { + Navigator.pop(context); + logout(); + }, + ), + ], + ), + ), + appBar: AppBar(backgroundColor: const Color(0xFF43A047), elevation: 0), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + const SizedBox(height: 12), + buildBanner(name), + const SizedBox(height: 20), + Expanded( + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 16), + child: FeatureGrid(token: widget.token), + ), + ), + ], + ), + ); + } +} diff --git a/website/lib/screens/login_screen.dart b/website/lib/screens/login_screen.dart new file mode 100644 index 0000000..4359eee --- /dev/null +++ b/website/lib/screens/login_screen.dart @@ -0,0 +1,152 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import 'package:monitoring/config.dart'; +import 'forgot_password_screen.dart'; + +class LoginScreen extends StatefulWidget { + final Function(String token, Map user) onLoginSuccess; + + const LoginScreen({super.key, required this.onLoginSuccess}); + + @override + State createState() => _LoginScreenState(); +} + +class _LoginScreenState extends State { + final TextEditingController _usernameController = TextEditingController(); + final TextEditingController _passwordController = TextEditingController(); + bool _isLoading = false; + String _error = ''; + + Future login() async { + setState(() { + _isLoading = true; + _error = ''; + }); + + final url = Uri.parse('$baseUrl/login'); + final response = await http.post( + url, + headers: {'Accept': 'application/json'}, + body: { + 'username': _usernameController.text.trim(), + 'password': _passwordController.text.trim(), + }, + ); + + setState(() { + _isLoading = false; + }); + + if (response.statusCode == 200) { + final data = json.decode(response.body); + final token = data['access_token']; + final user = Map.from(data['user']); + + widget.onLoginSuccess(token, user); + } else { + final data = json.decode(response.body); + setState(() { + _error = data['message'] ?? 'Login gagal'; + }); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + body: Container( + decoration: const BoxDecoration( + gradient: LinearGradient( + colors: [Color(0xFF43A047), Color(0xFFFFF176)], // Hijau ke kuning + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + ), + padding: const EdgeInsets.all(16.0), + child: Center( + child: SingleChildScrollView( + child: Card( + elevation: 12, + shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(16)), + child: Padding( + padding: const EdgeInsets.all(24.0), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text( + 'Login Santri', + style: TextStyle( + fontSize: 28, + fontWeight: FontWeight.bold, + color: Color(0xFF388E3C), // Hijau Tua + ), + ), + const SizedBox(height: 24), + if (_error.isNotEmpty) + Text( + _error, + style: const TextStyle(color: Colors.red), + ), + TextField( + controller: _usernameController, + decoration: const InputDecoration( + labelText: 'Username', + prefixIcon: Icon(Icons.person), + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 16), + TextField( + controller: _passwordController, + obscureText: true, + decoration: const InputDecoration( + labelText: 'Password', + prefixIcon: Icon(Icons.lock), + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 24), + _isLoading + ? const CircularProgressIndicator() + : SizedBox( + width: double.infinity, + child: ElevatedButton( + style: ElevatedButton.styleFrom( + backgroundColor: const Color(0xFF8BC34A), // Hijau Muda + padding: const EdgeInsets.symmetric(vertical: 16), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8), + ), + ), + onPressed: login, + child: const Text( + 'Login', + style: TextStyle(fontSize: 16, color: Colors.white), + ), + ), + ), + const SizedBox(height: 16), + TextButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => const ForgotPasswordScreen()), + ); + }, + child: const Text( + 'Lupa Password?', + style: TextStyle(color: Color(0xFF388E3C)), + ), + ), + ], + ), + ), + ), + ), + ), + ), + ); + } +} diff --git a/website/lib/screens/reset_password_screen.dart b/website/lib/screens/reset_password_screen.dart new file mode 100644 index 0000000..b46fa39 --- /dev/null +++ b/website/lib/screens/reset_password_screen.dart @@ -0,0 +1,121 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:http/http.dart' as http; +import '../config.dart'; + +class ResetPasswordScreen extends StatefulWidget { + final int userId; + + const ResetPasswordScreen({Key? key, required this.userId}) : super(key: key); + + @override + State createState() => _ResetPasswordScreenState(); +} + +class _ResetPasswordScreenState extends State { + final TextEditingController _passwordController = TextEditingController(); + final TextEditingController _confirmController = TextEditingController(); + bool _isLoading = false; + + Future _resetPassword() async { + final password = _passwordController.text.trim(); + final confirmPassword = _confirmController.text.trim(); + + if (password.isEmpty || confirmPassword.isEmpty) { + _showMessage('Semua kolom harus diisi.'); + return; + } + + if (password != confirmPassword) { + _showMessage('Password tidak sama.'); + return; + } + + setState(() => _isLoading = true); + + try { + final response = await http.post( + Uri.parse('$baseUrl/forgot-password/reset'), + body: { + 'user_id': widget.userId.toString(), + 'password': password, + 'password_confirmation': confirmPassword, + }, + ); + + final data = jsonDecode(response.body); + + if (response.statusCode == 200) { + _showMessage(data['message'] ?? 'Password berhasil diubah'); + Navigator.popUntil(context, (route) => route.isFirst); // Kembali ke login + } else { + _showMessage(data['message'] ?? 'Gagal reset password.'); + } + } catch (e) { + _showMessage('Gagal menghubungi server.'); + } finally { + setState(() => _isLoading = false); + } + } + + void _showMessage(String message) { + showDialog( + context: context, + builder: (_) => AlertDialog( + title: const Text('Informasi'), + content: Text(message), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: const Text('OK'), + ), + ], + ), + ); + } + + @override + void dispose() { + _passwordController.dispose(); + _confirmController.dispose(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(title: const Text('Reset Password Baru')), + body: Padding( + padding: const EdgeInsets.all(20.0), + child: Column( + children: [ + TextField( + controller: _passwordController, + obscureText: true, + decoration: const InputDecoration( + labelText: 'Password Baru', + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 16), + TextField( + controller: _confirmController, + obscureText: true, + decoration: const InputDecoration( + labelText: 'Konfirmasi Password', + border: OutlineInputBorder(), + ), + ), + const SizedBox(height: 24), + _isLoading + ? const CircularProgressIndicator() + : ElevatedButton( + onPressed: _resetPassword, + child: const Text('Reset Password'), + ), + ], + ), + ), + ); + } +} diff --git a/website/lib/screens/splash_screen.dart b/website/lib/screens/splash_screen.dart new file mode 100644 index 0000000..410e657 --- /dev/null +++ b/website/lib/screens/splash_screen.dart @@ -0,0 +1,60 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:monitoring/screens/login_screen.dart'; +import 'package:shared_preferences/shared_preferences.dart'; + +class SplashScreen extends StatefulWidget { + final Function(String token, Map user) onLoginSuccess; + + const SplashScreen({super.key, required this.onLoginSuccess}); + + @override + State createState() => _SplashScreenState(); +} + +class _SplashScreenState extends State { + bool isLoading = true; + + @override + void initState() { + super.initState(); + checkLoginStatus(); + } + + Future checkLoginStatus() async { + final prefs = await SharedPreferences.getInstance(); + final token = prefs.getString('token'); + final userJson = prefs.getString('user'); + + if (token != null && userJson != null) { + final user = jsonDecode(userJson); + widget.onLoginSuccess(token, Map.from(user)); + } else { + setState(() => isLoading = false); + } + } + + @override + Widget build(BuildContext context) { + if (isLoading) { + return const Scaffold(body: Center(child: CircularProgressIndicator())); + } + + return Scaffold( + appBar: AppBar(title: const Text('Santri App')), + body: Center( + child: ElevatedButton( + onPressed: () { + Navigator.push( + context, + MaterialPageRoute( + builder: (_) => LoginScreen(onLoginSuccess: widget.onLoginSuccess), + ), + ); + }, + child: const Text('Login as Santri'), + ), + ), + ); + } +} diff --git a/website/lib/widgets/berita_carousel.dart b/website/lib/widgets/berita_carousel.dart new file mode 100644 index 0000000..0976420 --- /dev/null +++ b/website/lib/widgets/berita_carousel.dart @@ -0,0 +1,113 @@ +import 'package:flutter/material.dart'; +import 'package:dio/dio.dart'; +import 'package:monitoring/config.dart'; + +class Berita { + final int id; + final String judul; + final String? gambarUrl; + + Berita({required this.id, required this.judul, this.gambarUrl}); + + factory Berita.fromJson(Map json) { + return Berita( + id: json['id'], + judul: json['judul'] ?? '', + gambarUrl: json['gambar_url'], + ); + } +} + +class BeritaCarousel extends StatefulWidget { + const BeritaCarousel({ + super.key, + required this.token, + required bool isCircleStyle, + }); + final String token; + + @override + State createState() => _BeritaCarouselState(); +} + +class _BeritaCarouselState extends State { + List _beritaList = []; + bool _loading = true; + + @override + void initState() { + super.initState(); + fetchBerita(); + } + + Future fetchBerita() async { + try { + final dio = Dio( + BaseOptions( + baseUrl: '$baseUrl', + headers: { + 'Accept': 'application/json', + 'Authorization': 'Bearer ${widget.token}', + }, + ), + ); + + final response = await dio.get('/berita/published'); + final List raw = response.data['data']; + setState(() { + _beritaList = raw.map((e) => Berita.fromJson(e)).toList(); + _loading = false; + }); + } catch (e) { + debugPrint('Gagal ambil berita: $e'); + setState(() => _loading = false); + } + } + + @override + Widget build(BuildContext context) { + if (_loading) return const Center(child: CircularProgressIndicator()); + if (_beritaList.isEmpty) return const Text('Tidak ada berita.'); + + return SizedBox( + height: 160, + child: PageView.builder( + itemCount: _beritaList.length, + controller: PageController(viewportFraction: 0.85), + itemBuilder: (context, index) { + final berita = _beritaList[index]; + return Container( + margin: const EdgeInsets.symmetric(horizontal: 8), + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(12), + image: DecorationImage( + image: + berita.gambarUrl != null + ? NetworkImage(berita.gambarUrl!) + : const AssetImage('assets/404.png') as ImageProvider, + fit: BoxFit.cover, + ), + ), + child: Container( + alignment: Alignment.bottomLeft, + padding: const EdgeInsets.all(12), + decoration: BoxDecoration( + color: Colors.black54, + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(12), + bottomRight: Radius.circular(12), + ), + ), + child: Text( + berita.judul, + style: const TextStyle(color: Colors.white, fontSize: 14), + maxLines: 2, + overflow: TextOverflow.ellipsis, + ), + ), + ); + }, + ), + ); + } +} diff --git a/website/lib/widgets/feature_grid.dart b/website/lib/widgets/feature_grid.dart new file mode 100644 index 0000000..ac305c3 --- /dev/null +++ b/website/lib/widgets/feature_grid.dart @@ -0,0 +1,122 @@ +import 'package:flutter/material.dart'; + +import '../screens/features/absensi_screen.dart'; +import '../screens/features/nilai_screen.dart'; +import '../screens/features/kesehatan_screen.dart'; +import '../screens/features/prestasi_screen.dart'; +import '../screens/features/pelanggaran_screen.dart'; +import '../screens/features/berita_screen.dart'; +import '../screens/features/alumni_screen.dart'; +import '../screens/features/pembayaran_screen.dart'; + +class FeatureGrid extends StatelessWidget { + final String token; + + const FeatureGrid({super.key, required this.token}); + + final List<_FeatureItem> _items = const [ + _FeatureItem('Absensi', Icons.how_to_reg), + _FeatureItem('Nilai', Icons.grade), + _FeatureItem('Kesehatan', Icons.local_hospital), + _FeatureItem('Prestasi', Icons.emoji_events), + _FeatureItem('Pelanggaran', Icons.report), + _FeatureItem('Berita', Icons.article), + _FeatureItem('Alumni', Icons.people), + _FeatureItem('Pembayaran', Icons.attach_money), + ]; + + @override + Widget build(BuildContext context) { + return GridView.builder( + itemCount: _items.length, + gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( + crossAxisCount: 4, + crossAxisSpacing: 12, + mainAxisSpacing: 12, + ), + itemBuilder: (context, index) { + final item = _items[index]; + + return GestureDetector( + onTap: () { + Widget? destination; + + switch (item.label) { + case 'Absensi': + destination = AbsensiScreen(token: token); + break; + case 'Nilai': + destination = NilaiScreen(token: token); + break; + case 'Kesehatan': + destination = KesehatanScreen(token: token); + break; + case 'Prestasi': + destination = PrestasiScreen(token: token); + break; + case 'Pelanggaran': + destination = PelanggaranScreen(token: token); + break; + case 'Berita': + destination = BeritaScreen(token: token); + break; + case 'Alumni': + destination = AlumniScreen(token: token); + break; + case 'Pembayaran': + destination = PembayaranScreen(token: token); + break; + } + + if (destination != null) { + Navigator.push( + context, + MaterialPageRoute(builder: (_) => destination!), + ); + } + }, + child: Container( + decoration: BoxDecoration( + gradient: const LinearGradient( + colors: [Color(0xFF43A047), Color(0xFFFFEB3B)], + begin: Alignment.topLeft, + end: Alignment.bottomRight, + ), + borderRadius: BorderRadius.circular(16), + boxShadow: [ + BoxShadow( + color: Colors.black.withOpacity(0.08), + blurRadius: 8, + offset: const Offset(0, 4), + ), + ], + ), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Icon(item.icon, size: 32, color: Colors.white), + const SizedBox(height: 8), + Text( + item.label, + style: const TextStyle( + fontSize: 12, + fontWeight: FontWeight.bold, + color: Colors.white, + ), + textAlign: TextAlign.center, + ), + ], + ), + ), + ); + }, + ); + } +} + +class _FeatureItem { + final String label; + final IconData icon; + + const _FeatureItem(this.label, this.icon); +} diff --git a/website/linux/.gitignore b/website/linux/.gitignore new file mode 100644 index 0000000..d3896c9 --- /dev/null +++ b/website/linux/.gitignore @@ -0,0 +1 @@ +flutter/ephemeral diff --git a/website/linux/CMakeLists.txt b/website/linux/CMakeLists.txt new file mode 100644 index 0000000..240bad4 --- /dev/null +++ b/website/linux/CMakeLists.txt @@ -0,0 +1,128 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "monitoring") +# The unique GTK application identifier for this application. See: +# https://wiki.gnome.org/HowDoI/ChooseApplicationID +set(APPLICATION_ID "com.example.monitoring") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(SET CMP0063 NEW) + +# Load bundled libraries from the lib/ directory relative to the binary. +set(CMAKE_INSTALL_RPATH "$ORIGIN/lib") + +# Root filesystem for cross-building. +if(FLUTTER_TARGET_PLATFORM_SYSROOT) + set(CMAKE_SYSROOT ${FLUTTER_TARGET_PLATFORM_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH ${CMAKE_SYSROOT}) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + set(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) +endif() + +# Define build configuration options. +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") +endif() + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_14) + target_compile_options(${TARGET} PRIVATE -Wall -Werror) + target_compile_options(${TARGET} PRIVATE "$<$>:-O3>") + target_compile_definitions(${TARGET} PRIVATE "$<$>:NDEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) + +# Only the install-generated bundle's copy of the executable will launch +# correctly, since the resources must in the right relative locations. To avoid +# people trying to run the unbundled copy, put it in a subdirectory instead of +# the default top-level location. +set_target_properties(${BINARY_NAME} + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/intermediates_do_not_run" +) + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# By default, "installing" just makes a relocatable bundle in the build +# directory. +set(BUILD_BUNDLE_DIR "${PROJECT_BINARY_DIR}/bundle") +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +# Start with a clean build bundle directory every time. +install(CODE " + file(REMOVE_RECURSE \"${BUILD_BUNDLE_DIR}/\") + " COMPONENT Runtime) + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}/lib") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +foreach(bundled_library ${PLUGIN_BUNDLED_LIBRARIES}) + install(FILES "${bundled_library}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endforeach(bundled_library) + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/linux/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") + install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() diff --git a/website/linux/flutter/CMakeLists.txt b/website/linux/flutter/CMakeLists.txt new file mode 100644 index 0000000..d5bd016 --- /dev/null +++ b/website/linux/flutter/CMakeLists.txt @@ -0,0 +1,88 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.10) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. + +# Serves the same purpose as list(TRANSFORM ... PREPEND ...), +# which isn't available in 3.10. +function(list_prepend LIST_NAME PREFIX) + set(NEW_LIST "") + foreach(element ${${LIST_NAME}}) + list(APPEND NEW_LIST "${PREFIX}${element}") + endforeach(element) + set(${LIST_NAME} "${NEW_LIST}" PARENT_SCOPE) +endfunction() + +# === Flutter Library === +# System-level dependencies. +find_package(PkgConfig REQUIRED) +pkg_check_modules(GTK REQUIRED IMPORTED_TARGET gtk+-3.0) +pkg_check_modules(GLIB REQUIRED IMPORTED_TARGET glib-2.0) +pkg_check_modules(GIO REQUIRED IMPORTED_TARGET gio-2.0) + +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/libflutter_linux_gtk.so") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/lib/libapp.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "fl_basic_message_channel.h" + "fl_binary_codec.h" + "fl_binary_messenger.h" + "fl_dart_project.h" + "fl_engine.h" + "fl_json_message_codec.h" + "fl_json_method_codec.h" + "fl_message_codec.h" + "fl_method_call.h" + "fl_method_channel.h" + "fl_method_codec.h" + "fl_method_response.h" + "fl_plugin_registrar.h" + "fl_plugin_registry.h" + "fl_standard_message_codec.h" + "fl_standard_method_codec.h" + "fl_string_codec.h" + "fl_value.h" + "fl_view.h" + "flutter_linux.h" +) +list_prepend(FLUTTER_LIBRARY_HEADERS "${EPHEMERAL_DIR}/flutter_linux/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}") +target_link_libraries(flutter INTERFACE + PkgConfig::GTK + PkgConfig::GLIB + PkgConfig::GIO +) +add_dependencies(flutter flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CMAKE_CURRENT_BINARY_DIR}/_phony_ + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.sh" + ${FLUTTER_TARGET_PLATFORM} ${CMAKE_BUILD_TYPE} + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} +) diff --git a/website/linux/flutter/generated_plugin_registrant.cc b/website/linux/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..3ccd551 --- /dev/null +++ b/website/linux/flutter/generated_plugin_registrant.cc @@ -0,0 +1,23 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include + +void fl_register_plugins(FlPluginRegistry* registry) { + g_autoptr(FlPluginRegistrar) file_selector_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FileSelectorPlugin"); + file_selector_plugin_register_with_registrar(file_selector_linux_registrar); + g_autoptr(FlPluginRegistrar) flutter_secure_storage_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "FlutterSecureStorageLinuxPlugin"); + flutter_secure_storage_linux_plugin_register_with_registrar(flutter_secure_storage_linux_registrar); + g_autoptr(FlPluginRegistrar) url_launcher_linux_registrar = + fl_plugin_registry_get_registrar_for_plugin(registry, "UrlLauncherPlugin"); + url_launcher_plugin_register_with_registrar(url_launcher_linux_registrar); +} diff --git a/website/linux/flutter/generated_plugin_registrant.h b/website/linux/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..e0f0a47 --- /dev/null +++ b/website/linux/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void fl_register_plugins(FlPluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/website/linux/flutter/generated_plugins.cmake b/website/linux/flutter/generated_plugins.cmake new file mode 100644 index 0000000..9ce94c4 --- /dev/null +++ b/website/linux/flutter/generated_plugins.cmake @@ -0,0 +1,26 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_linux + flutter_secure_storage_linux + url_launcher_linux +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/linux plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/linux plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/website/linux/runner/CMakeLists.txt b/website/linux/runner/CMakeLists.txt new file mode 100644 index 0000000..e97dabc --- /dev/null +++ b/website/linux/runner/CMakeLists.txt @@ -0,0 +1,26 @@ +cmake_minimum_required(VERSION 3.13) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} + "main.cc" + "my_application.cc" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the application ID. +add_definitions(-DAPPLICATION_ID="${APPLICATION_ID}") + +# Add dependency libraries. Add any application-specific dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter) +target_link_libraries(${BINARY_NAME} PRIVATE PkgConfig::GTK) + +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") diff --git a/website/linux/runner/main.cc b/website/linux/runner/main.cc new file mode 100644 index 0000000..e7c5c54 --- /dev/null +++ b/website/linux/runner/main.cc @@ -0,0 +1,6 @@ +#include "my_application.h" + +int main(int argc, char** argv) { + g_autoptr(MyApplication) app = my_application_new(); + return g_application_run(G_APPLICATION(app), argc, argv); +} diff --git a/website/linux/runner/my_application.cc b/website/linux/runner/my_application.cc new file mode 100644 index 0000000..952dbf0 --- /dev/null +++ b/website/linux/runner/my_application.cc @@ -0,0 +1,130 @@ +#include "my_application.h" + +#include +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "flutter/generated_plugin_registrant.h" + +struct _MyApplication { + GtkApplication parent_instance; + char** dart_entrypoint_arguments; +}; + +G_DEFINE_TYPE(MyApplication, my_application, GTK_TYPE_APPLICATION) + +// Implements GApplication::activate. +static void my_application_activate(GApplication* application) { + MyApplication* self = MY_APPLICATION(application); + GtkWindow* window = + GTK_WINDOW(gtk_application_window_new(GTK_APPLICATION(application))); + + // Use a header bar when running in GNOME as this is the common style used + // by applications and is the setup most users will be using (e.g. Ubuntu + // desktop). + // If running on X and not using GNOME then just use a traditional title bar + // in case the window manager does more exotic layout, e.g. tiling. + // If running on Wayland assume the header bar will work (may need changing + // if future cases occur). + gboolean use_header_bar = TRUE; +#ifdef GDK_WINDOWING_X11 + GdkScreen* screen = gtk_window_get_screen(window); + if (GDK_IS_X11_SCREEN(screen)) { + const gchar* wm_name = gdk_x11_screen_get_window_manager_name(screen); + if (g_strcmp0(wm_name, "GNOME Shell") != 0) { + use_header_bar = FALSE; + } + } +#endif + if (use_header_bar) { + GtkHeaderBar* header_bar = GTK_HEADER_BAR(gtk_header_bar_new()); + gtk_widget_show(GTK_WIDGET(header_bar)); + gtk_header_bar_set_title(header_bar, "monitoring"); + gtk_header_bar_set_show_close_button(header_bar, TRUE); + gtk_window_set_titlebar(window, GTK_WIDGET(header_bar)); + } else { + gtk_window_set_title(window, "monitoring"); + } + + gtk_window_set_default_size(window, 1280, 720); + gtk_widget_show(GTK_WIDGET(window)); + + g_autoptr(FlDartProject) project = fl_dart_project_new(); + fl_dart_project_set_dart_entrypoint_arguments(project, self->dart_entrypoint_arguments); + + FlView* view = fl_view_new(project); + gtk_widget_show(GTK_WIDGET(view)); + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(view)); + + fl_register_plugins(FL_PLUGIN_REGISTRY(view)); + + gtk_widget_grab_focus(GTK_WIDGET(view)); +} + +// Implements GApplication::local_command_line. +static gboolean my_application_local_command_line(GApplication* application, gchar*** arguments, int* exit_status) { + MyApplication* self = MY_APPLICATION(application); + // Strip out the first argument as it is the binary name. + self->dart_entrypoint_arguments = g_strdupv(*arguments + 1); + + g_autoptr(GError) error = nullptr; + if (!g_application_register(application, nullptr, &error)) { + g_warning("Failed to register: %s", error->message); + *exit_status = 1; + return TRUE; + } + + g_application_activate(application); + *exit_status = 0; + + return TRUE; +} + +// Implements GApplication::startup. +static void my_application_startup(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application startup. + + G_APPLICATION_CLASS(my_application_parent_class)->startup(application); +} + +// Implements GApplication::shutdown. +static void my_application_shutdown(GApplication* application) { + //MyApplication* self = MY_APPLICATION(object); + + // Perform any actions required at application shutdown. + + G_APPLICATION_CLASS(my_application_parent_class)->shutdown(application); +} + +// Implements GObject::dispose. +static void my_application_dispose(GObject* object) { + MyApplication* self = MY_APPLICATION(object); + g_clear_pointer(&self->dart_entrypoint_arguments, g_strfreev); + G_OBJECT_CLASS(my_application_parent_class)->dispose(object); +} + +static void my_application_class_init(MyApplicationClass* klass) { + G_APPLICATION_CLASS(klass)->activate = my_application_activate; + G_APPLICATION_CLASS(klass)->local_command_line = my_application_local_command_line; + G_APPLICATION_CLASS(klass)->startup = my_application_startup; + G_APPLICATION_CLASS(klass)->shutdown = my_application_shutdown; + G_OBJECT_CLASS(klass)->dispose = my_application_dispose; +} + +static void my_application_init(MyApplication* self) {} + +MyApplication* my_application_new() { + // Set the program name to the application ID, which helps various systems + // like GTK and desktop environments map this running application to its + // corresponding .desktop file. This ensures better integration by allowing + // the application to be recognized beyond its binary name. + g_set_prgname(APPLICATION_ID); + + return MY_APPLICATION(g_object_new(my_application_get_type(), + "application-id", APPLICATION_ID, + "flags", G_APPLICATION_NON_UNIQUE, + nullptr)); +} diff --git a/website/linux/runner/my_application.h b/website/linux/runner/my_application.h new file mode 100644 index 0000000..72271d5 --- /dev/null +++ b/website/linux/runner/my_application.h @@ -0,0 +1,18 @@ +#ifndef FLUTTER_MY_APPLICATION_H_ +#define FLUTTER_MY_APPLICATION_H_ + +#include + +G_DECLARE_FINAL_TYPE(MyApplication, my_application, MY, APPLICATION, + GtkApplication) + +/** + * my_application_new: + * + * Creates a new Flutter-based application. + * + * Returns: a new #MyApplication. + */ +MyApplication* my_application_new(); + +#endif // FLUTTER_MY_APPLICATION_H_ diff --git a/website/local.properties b/website/local.properties new file mode 100644 index 0000000..1ef74e3 --- /dev/null +++ b/website/local.properties @@ -0,0 +1,8 @@ +## This file must *NOT* be checked into Version Control Systems, +# as it contains information specific to your local configuration. +# +# Location of the SDK. This is only used by Gradle. +# For customization when using a Version Control System, please read the +# header note. +#Wed Jul 16 13:13:55 WIB 2025 +sdk.dir=C\:\\Users\\ASUS\\AppData\\Local\\Android diff --git a/website/macos/.gitignore b/website/macos/.gitignore new file mode 100644 index 0000000..746adbb --- /dev/null +++ b/website/macos/.gitignore @@ -0,0 +1,7 @@ +# Flutter-related +**/Flutter/ephemeral/ +**/Pods/ + +# Xcode-related +**/dgph +**/xcuserdata/ diff --git a/website/macos/Flutter/Flutter-Debug.xcconfig b/website/macos/Flutter/Flutter-Debug.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/website/macos/Flutter/Flutter-Debug.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/website/macos/Flutter/Flutter-Release.xcconfig b/website/macos/Flutter/Flutter-Release.xcconfig new file mode 100644 index 0000000..c2efd0b --- /dev/null +++ b/website/macos/Flutter/Flutter-Release.xcconfig @@ -0,0 +1 @@ +#include "ephemeral/Flutter-Generated.xcconfig" diff --git a/website/macos/Flutter/GeneratedPluginRegistrant.swift b/website/macos/Flutter/GeneratedPluginRegistrant.swift new file mode 100644 index 0000000..6d6171a --- /dev/null +++ b/website/macos/Flutter/GeneratedPluginRegistrant.swift @@ -0,0 +1,22 @@ +// +// Generated file. Do not edit. +// + +import FlutterMacOS +import Foundation + +import file_picker +import file_selector_macos +import flutter_secure_storage_macos +import path_provider_foundation +import shared_preferences_foundation +import url_launcher_macos + +func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { + FilePickerPlugin.register(with: registry.registrar(forPlugin: "FilePickerPlugin")) + FileSelectorPlugin.register(with: registry.registrar(forPlugin: "FileSelectorPlugin")) + FlutterSecureStoragePlugin.register(with: registry.registrar(forPlugin: "FlutterSecureStoragePlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) + SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) + UrlLauncherPlugin.register(with: registry.registrar(forPlugin: "UrlLauncherPlugin")) +} diff --git a/website/macos/Runner.xcodeproj/project.pbxproj b/website/macos/Runner.xcodeproj/project.pbxproj new file mode 100644 index 0000000..702cea6 --- /dev/null +++ b/website/macos/Runner.xcodeproj/project.pbxproj @@ -0,0 +1,705 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 54; + objects = { + +/* Begin PBXAggregateTarget section */ + 33CC111A2044C6BA0003C045 /* Flutter Assemble */ = { + isa = PBXAggregateTarget; + buildConfigurationList = 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */; + buildPhases = ( + 33CC111E2044C6BF0003C045 /* ShellScript */, + ); + dependencies = ( + ); + name = "Flutter Assemble"; + productName = FLX; + }; +/* End PBXAggregateTarget section */ + +/* Begin PBXBuildFile section */ + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 331C80D7294CF71000263BE5 /* RunnerTests.swift */; }; + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */ = {isa = PBXBuildFile; fileRef = 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */; }; + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC10F02044A3C60003C045 /* AppDelegate.swift */; }; + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F22044A3C60003C045 /* Assets.xcassets */; }; + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 33CC10F42044A3C60003C045 /* MainMenu.xib */; }; + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC10EC2044A3C60003C045; + remoteInfo = Runner; + }; + 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 33CC10E52044A3C60003C045 /* Project object */; + proxyType = 1; + remoteGlobalIDString = 33CC111A2044C6BA0003C045; + remoteInfo = FLX; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 33CC110E2044A8840003C045 /* Bundle Framework */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + ); + name = "Bundle Framework"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = RunnerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; + 331C80D7294CF71000263BE5 /* RunnerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RunnerTests.swift; sourceTree = ""; }; + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Warnings.xcconfig; sourceTree = ""; }; + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GeneratedPluginRegistrant.swift; sourceTree = ""; }; + 33CC10ED2044A3C60003C045 /* monitoring.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "monitoring.app"; sourceTree = BUILT_PRODUCTS_DIR; }; + 33CC10F02044A3C60003C045 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 33CC10F22044A3C60003C045 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = Runner/Assets.xcassets; sourceTree = ""; }; + 33CC10F52044A3C60003C045 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = ""; }; + 33CC10F72044A3C60003C045 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = Runner/Info.plist; sourceTree = ""; }; + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainFlutterWindow.swift; sourceTree = ""; }; + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Debug.xcconfig"; sourceTree = ""; }; + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = "Flutter-Release.xcconfig"; sourceTree = ""; }; + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "Flutter-Generated.xcconfig"; path = "ephemeral/Flutter-Generated.xcconfig"; sourceTree = ""; }; + 33E51913231747F40026EE4D /* DebugProfile.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = DebugProfile.entitlements; sourceTree = ""; }; + 33E51914231749380026EE4D /* Release.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = Release.entitlements; sourceTree = ""; }; + 33E5194F232828860026EE4D /* AppInfo.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = AppInfo.xcconfig; sourceTree = ""; }; + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Release.xcconfig; sourceTree = ""; }; + 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Debug.xcconfig; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 331C80D2294CF70F00263BE5 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EA2044A3C60003C045 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 331C80D6294CF71000263BE5 /* RunnerTests */ = { + isa = PBXGroup; + children = ( + 331C80D7294CF71000263BE5 /* RunnerTests.swift */, + ); + path = RunnerTests; + sourceTree = ""; + }; + 33BA886A226E78AF003329D5 /* Configs */ = { + isa = PBXGroup; + children = ( + 33E5194F232828860026EE4D /* AppInfo.xcconfig */, + 9740EEB21CF90195004384FC /* Debug.xcconfig */, + 7AFA3C8E1D35360C0083082E /* Release.xcconfig */, + 333000ED22D3DE5D00554162 /* Warnings.xcconfig */, + ); + path = Configs; + sourceTree = ""; + }; + 33CC10E42044A3C60003C045 = { + isa = PBXGroup; + children = ( + 33FAB671232836740065AC1E /* Runner */, + 33CEB47122A05771004F2AC0 /* Flutter */, + 331C80D6294CF71000263BE5 /* RunnerTests */, + 33CC10EE2044A3C60003C045 /* Products */, + D73912EC22F37F3D000D13A0 /* Frameworks */, + ); + sourceTree = ""; + }; + 33CC10EE2044A3C60003C045 /* Products */ = { + isa = PBXGroup; + children = ( + 33CC10ED2044A3C60003C045 /* monitoring.app */, + 331C80D5294CF71000263BE5 /* RunnerTests.xctest */, + ); + name = Products; + sourceTree = ""; + }; + 33CC11242044D66E0003C045 /* Resources */ = { + isa = PBXGroup; + children = ( + 33CC10F22044A3C60003C045 /* Assets.xcassets */, + 33CC10F42044A3C60003C045 /* MainMenu.xib */, + 33CC10F72044A3C60003C045 /* Info.plist */, + ); + name = Resources; + path = ..; + sourceTree = ""; + }; + 33CEB47122A05771004F2AC0 /* Flutter */ = { + isa = PBXGroup; + children = ( + 335BBD1A22A9A15E00E9071D /* GeneratedPluginRegistrant.swift */, + 33CEB47222A05771004F2AC0 /* Flutter-Debug.xcconfig */, + 33CEB47422A05771004F2AC0 /* Flutter-Release.xcconfig */, + 33CEB47722A0578A004F2AC0 /* Flutter-Generated.xcconfig */, + ); + path = Flutter; + sourceTree = ""; + }; + 33FAB671232836740065AC1E /* Runner */ = { + isa = PBXGroup; + children = ( + 33CC10F02044A3C60003C045 /* AppDelegate.swift */, + 33CC11122044BFA00003C045 /* MainFlutterWindow.swift */, + 33E51913231747F40026EE4D /* DebugProfile.entitlements */, + 33E51914231749380026EE4D /* Release.entitlements */, + 33CC11242044D66E0003C045 /* Resources */, + 33BA886A226E78AF003329D5 /* Configs */, + ); + path = Runner; + sourceTree = ""; + }; + D73912EC22F37F3D000D13A0 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXNativeTarget section */ + 331C80D4294CF70F00263BE5 /* RunnerTests */ = { + isa = PBXNativeTarget; + buildConfigurationList = 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */; + buildPhases = ( + 331C80D1294CF70F00263BE5 /* Sources */, + 331C80D2294CF70F00263BE5 /* Frameworks */, + 331C80D3294CF70F00263BE5 /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + 331C80DA294CF71000263BE5 /* PBXTargetDependency */, + ); + name = RunnerTests; + productName = RunnerTests; + productReference = 331C80D5294CF71000263BE5 /* RunnerTests.xctest */; + productType = "com.apple.product-type.bundle.unit-test"; + }; + 33CC10EC2044A3C60003C045 /* Runner */ = { + isa = PBXNativeTarget; + buildConfigurationList = 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */; + buildPhases = ( + 33CC10E92044A3C60003C045 /* Sources */, + 33CC10EA2044A3C60003C045 /* Frameworks */, + 33CC10EB2044A3C60003C045 /* Resources */, + 33CC110E2044A8840003C045 /* Bundle Framework */, + 3399D490228B24CF009A79C7 /* ShellScript */, + ); + buildRules = ( + ); + dependencies = ( + 33CC11202044C79F0003C045 /* PBXTargetDependency */, + ); + name = Runner; + productName = Runner; + productReference = 33CC10ED2044A3C60003C045 /* monitoring.app */; + productType = "com.apple.product-type.application"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 33CC10E52044A3C60003C045 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = YES; + LastSwiftUpdateCheck = 0920; + LastUpgradeCheck = 1510; + ORGANIZATIONNAME = ""; + TargetAttributes = { + 331C80D4294CF70F00263BE5 = { + CreatedOnToolsVersion = 14.0; + TestTargetID = 33CC10EC2044A3C60003C045; + }; + 33CC10EC2044A3C60003C045 = { + CreatedOnToolsVersion = 9.2; + LastSwiftMigration = 1100; + ProvisioningStyle = Automatic; + SystemCapabilities = { + com.apple.Sandbox = { + enabled = 1; + }; + }; + }; + 33CC111A2044C6BA0003C045 = { + CreatedOnToolsVersion = 9.2; + ProvisioningStyle = Manual; + }; + }; + }; + buildConfigurationList = 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */; + compatibilityVersion = "Xcode 9.3"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 33CC10E42044A3C60003C045; + productRefGroup = 33CC10EE2044A3C60003C045 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 33CC10EC2044A3C60003C045 /* Runner */, + 331C80D4294CF70F00263BE5 /* RunnerTests */, + 33CC111A2044C6BA0003C045 /* Flutter Assemble */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 331C80D3294CF70F00263BE5 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10EB2044A3C60003C045 /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC10F32044A3C60003C045 /* Assets.xcassets in Resources */, + 33CC10F62044A3C60003C045 /* MainMenu.xib in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXShellScriptBuildPhase section */ + 3399D490228B24CF009A79C7 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "echo \"$PRODUCT_NAME.app\" > \"$PROJECT_DIR\"/Flutter/ephemeral/.app_filename && \"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh embed\n"; + }; + 33CC111E2044C6BF0003C045 /* ShellScript */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + Flutter/ephemeral/FlutterInputs.xcfilelist, + ); + inputPaths = ( + Flutter/ephemeral/tripwire, + ); + outputFileListPaths = ( + Flutter/ephemeral/FlutterOutputs.xcfilelist, + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"$FLUTTER_ROOT\"/packages/flutter_tools/bin/macos_assemble.sh && touch Flutter/ephemeral/tripwire"; + }; +/* End PBXShellScriptBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 331C80D1294CF70F00263BE5 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 331C80D8294CF71000263BE5 /* RunnerTests.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 33CC10E92044A3C60003C045 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 33CC11132044BFA00003C045 /* MainFlutterWindow.swift in Sources */, + 33CC10F12044A3C60003C045 /* AppDelegate.swift in Sources */, + 335BBD1B22A9A15E00E9071D /* GeneratedPluginRegistrant.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 331C80DA294CF71000263BE5 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC10EC2044A3C60003C045 /* Runner */; + targetProxy = 331C80D9294CF71000263BE5 /* PBXContainerItemProxy */; + }; + 33CC11202044C79F0003C045 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 33CC111A2044C6BA0003C045 /* Flutter Assemble */; + targetProxy = 33CC111F2044C79F0003C045 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 33CC10F42044A3C60003C045 /* MainMenu.xib */ = { + isa = PBXVariantGroup; + children = ( + 33CC10F52044A3C60003C045 /* Base */, + ); + name = MainMenu.xib; + path = Runner; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 331C80DB294CF71000263BE5 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/monitoring.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/monitoring"; + }; + name = Debug; + }; + 331C80DC294CF71000263BE5 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/monitoring.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/monitoring"; + }; + name = Release; + }; + 331C80DD294CF71000263BE5 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + BUNDLE_LOADER = "$(TEST_HOST)"; + CURRENT_PROJECT_VERSION = 1; + GENERATE_INFOPLIST_FILE = YES; + MARKETING_VERSION = 1.0; + PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring.RunnerTests; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + TEST_HOST = "$(BUILT_PRODUCTS_DIR)/monitoring.app/$(BUNDLE_EXECUTABLE_FOLDER_PATH)/monitoring"; + }; + name = Profile; + }; + 338D0CE9231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Profile; + }; + 338D0CEA231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Profile; + }; + 338D0CEB231458BD00FA5F75 /* Profile */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Profile; + }; + 33CC10F92044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 9740EEB21CF90195004384FC /* Debug.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = macosx; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + }; + name = Debug; + }; + 33CC10FA2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 7AFA3C8E1D35360C0083082E /* Release.xcconfig */; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CODE_SIGN_IDENTITY = "-"; + COPY_PHASE_STRIP = NO; + DEAD_CODE_STRIPPING = YES; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + MACOSX_DEPLOYMENT_TARGET = 10.14; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = macosx; + SWIFT_COMPILATION_MODE = wholemodule; + SWIFT_OPTIMIZATION_LEVEL = "-O"; + }; + name = Release; + }; + 33CC10FC2044A3C60003C045 /* Debug */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/DebugProfile.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 33CC10FD2044A3C60003C045 /* Release */ = { + isa = XCBuildConfiguration; + baseConfigurationReference = 33E5194F232828860026EE4D /* AppInfo.xcconfig */; + buildSettings = { + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + CLANG_ENABLE_MODULES = YES; + CODE_SIGN_ENTITLEMENTS = Runner/Release.entitlements; + CODE_SIGN_STYLE = Automatic; + COMBINE_HIDPI_IMAGES = YES; + INFOPLIST_FILE = Runner/Info.plist; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/../Frameworks", + ); + PROVISIONING_PROFILE_SPECIFIER = ""; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; + 33CC111C2044C6BA0003C045 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Manual; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + 33CC111D2044C6BA0003C045 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 331C80DE294CF71000263BE5 /* Build configuration list for PBXNativeTarget "RunnerTests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 331C80DB294CF71000263BE5 /* Debug */, + 331C80DC294CF71000263BE5 /* Release */, + 331C80DD294CF71000263BE5 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10E82044A3C60003C045 /* Build configuration list for PBXProject "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10F92044A3C60003C045 /* Debug */, + 33CC10FA2044A3C60003C045 /* Release */, + 338D0CE9231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC10FB2044A3C60003C045 /* Build configuration list for PBXNativeTarget "Runner" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC10FC2044A3C60003C045 /* Debug */, + 33CC10FD2044A3C60003C045 /* Release */, + 338D0CEA231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 33CC111B2044C6BA0003C045 /* Build configuration list for PBXAggregateTarget "Flutter Assemble" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 33CC111C2044C6BA0003C045 /* Debug */, + 33CC111D2044C6BA0003C045 /* Release */, + 338D0CEB231458BD00FA5F75 /* Profile */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 33CC10E52044A3C60003C045 /* Project object */; +} diff --git a/website/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/website/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/website/macos/Runner.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/website/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/website/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme new file mode 100644 index 0000000..3dd6171 --- /dev/null +++ b/website/macos/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/macos/Runner.xcworkspace/contents.xcworkspacedata b/website/macos/Runner.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..1d526a1 --- /dev/null +++ b/website/macos/Runner.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/website/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/website/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/website/macos/Runner.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/website/macos/Runner/AppDelegate.swift b/website/macos/Runner/AppDelegate.swift new file mode 100644 index 0000000..b3c1761 --- /dev/null +++ b/website/macos/Runner/AppDelegate.swift @@ -0,0 +1,13 @@ +import Cocoa +import FlutterMacOS + +@main +class AppDelegate: FlutterAppDelegate { + override func applicationShouldTerminateAfterLastWindowClosed(_ sender: NSApplication) -> Bool { + return true + } + + override func applicationSupportsSecureRestorableState(_ app: NSApplication) -> Bool { + return true + } +} diff --git a/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..a2ec33f --- /dev/null +++ b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images" : [ + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_16.png", + "scale" : "1x" + }, + { + "size" : "16x16", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "2x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_32.png", + "scale" : "1x" + }, + { + "size" : "32x32", + "idiom" : "mac", + "filename" : "app_icon_64.png", + "scale" : "2x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_128.png", + "scale" : "1x" + }, + { + "size" : "128x128", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "2x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_256.png", + "scale" : "1x" + }, + { + "size" : "256x256", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "2x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_512.png", + "scale" : "1x" + }, + { + "size" : "512x512", + "idiom" : "mac", + "filename" : "app_icon_1024.png", + "scale" : "2x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} diff --git a/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png new file mode 100644 index 0000000..82b6f9d Binary files /dev/null and b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_1024.png differ diff --git a/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png new file mode 100644 index 0000000..13b35eb Binary files /dev/null and b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_128.png differ diff --git a/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png new file mode 100644 index 0000000..0a3f5fa Binary files /dev/null and b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_16.png differ diff --git a/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png new file mode 100644 index 0000000..bdb5722 Binary files /dev/null and b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_256.png differ diff --git a/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png new file mode 100644 index 0000000..f083318 Binary files /dev/null and b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_32.png differ diff --git a/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png new file mode 100644 index 0000000..326c0e7 Binary files /dev/null and b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_512.png differ diff --git a/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png new file mode 100644 index 0000000..2f1632c Binary files /dev/null and b/website/macos/Runner/Assets.xcassets/AppIcon.appiconset/app_icon_64.png differ diff --git a/website/macos/Runner/Base.lproj/MainMenu.xib b/website/macos/Runner/Base.lproj/MainMenu.xib new file mode 100644 index 0000000..80e867a --- /dev/null +++ b/website/macos/Runner/Base.lproj/MainMenu.xib @@ -0,0 +1,343 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/macos/Runner/Configs/AppInfo.xcconfig b/website/macos/Runner/Configs/AppInfo.xcconfig new file mode 100644 index 0000000..d24cd00 --- /dev/null +++ b/website/macos/Runner/Configs/AppInfo.xcconfig @@ -0,0 +1,14 @@ +// Application-level settings for the Runner target. +// +// This may be replaced with something auto-generated from metadata (e.g., pubspec.yaml) in the +// future. If not, the values below would default to using the project name when this becomes a +// 'flutter create' template. + +// The application's name. By default this is also the title of the Flutter window. +PRODUCT_NAME = monitoring + +// The application's bundle identifier +PRODUCT_BUNDLE_IDENTIFIER = com.example.monitoring + +// The copyright displayed in application information +PRODUCT_COPYRIGHT = Copyright © 2025 com.example. All rights reserved. diff --git a/website/macos/Runner/Configs/Debug.xcconfig b/website/macos/Runner/Configs/Debug.xcconfig new file mode 100644 index 0000000..36b0fd9 --- /dev/null +++ b/website/macos/Runner/Configs/Debug.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Debug.xcconfig" +#include "Warnings.xcconfig" diff --git a/website/macos/Runner/Configs/Release.xcconfig b/website/macos/Runner/Configs/Release.xcconfig new file mode 100644 index 0000000..dff4f49 --- /dev/null +++ b/website/macos/Runner/Configs/Release.xcconfig @@ -0,0 +1,2 @@ +#include "../../Flutter/Flutter-Release.xcconfig" +#include "Warnings.xcconfig" diff --git a/website/macos/Runner/Configs/Warnings.xcconfig b/website/macos/Runner/Configs/Warnings.xcconfig new file mode 100644 index 0000000..42bcbf4 --- /dev/null +++ b/website/macos/Runner/Configs/Warnings.xcconfig @@ -0,0 +1,13 @@ +WARNING_CFLAGS = -Wall -Wconditional-uninitialized -Wnullable-to-nonnull-conversion -Wmissing-method-return-type -Woverlength-strings +GCC_WARN_UNDECLARED_SELECTOR = YES +CLANG_UNDEFINED_BEHAVIOR_SANITIZER_NULLABILITY = YES +CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE +CLANG_WARN__DUPLICATE_METHOD_MATCH = YES +CLANG_WARN_PRAGMA_PACK = YES +CLANG_WARN_STRICT_PROTOTYPES = YES +CLANG_WARN_COMMA = YES +GCC_WARN_STRICT_SELECTOR_MATCH = YES +CLANG_WARN_OBJC_REPEATED_USE_OF_WEAK = YES +CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES +GCC_WARN_SHADOW = YES +CLANG_WARN_UNREACHABLE_CODE = YES diff --git a/website/macos/Runner/DebugProfile.entitlements b/website/macos/Runner/DebugProfile.entitlements new file mode 100644 index 0000000..dddb8a3 --- /dev/null +++ b/website/macos/Runner/DebugProfile.entitlements @@ -0,0 +1,12 @@ + + + + + com.apple.security.app-sandbox + + com.apple.security.cs.allow-jit + + com.apple.security.network.server + + + diff --git a/website/macos/Runner/Info.plist b/website/macos/Runner/Info.plist new file mode 100644 index 0000000..4789daa --- /dev/null +++ b/website/macos/Runner/Info.plist @@ -0,0 +1,32 @@ + + + + + CFBundleDevelopmentRegion + $(DEVELOPMENT_LANGUAGE) + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIconFile + + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + $(FLUTTER_BUILD_NAME) + CFBundleVersion + $(FLUTTER_BUILD_NUMBER) + LSMinimumSystemVersion + $(MACOSX_DEPLOYMENT_TARGET) + NSHumanReadableCopyright + $(PRODUCT_COPYRIGHT) + NSMainNibFile + MainMenu + NSPrincipalClass + NSApplication + + diff --git a/website/macos/Runner/MainFlutterWindow.swift b/website/macos/Runner/MainFlutterWindow.swift new file mode 100644 index 0000000..3cc05eb --- /dev/null +++ b/website/macos/Runner/MainFlutterWindow.swift @@ -0,0 +1,15 @@ +import Cocoa +import FlutterMacOS + +class MainFlutterWindow: NSWindow { + override func awakeFromNib() { + let flutterViewController = FlutterViewController() + let windowFrame = self.frame + self.contentViewController = flutterViewController + self.setFrame(windowFrame, display: true) + + RegisterGeneratedPlugins(registry: flutterViewController) + + super.awakeFromNib() + } +} diff --git a/website/macos/Runner/Release.entitlements b/website/macos/Runner/Release.entitlements new file mode 100644 index 0000000..852fa1a --- /dev/null +++ b/website/macos/Runner/Release.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/website/macos/RunnerTests/RunnerTests.swift b/website/macos/RunnerTests/RunnerTests.swift new file mode 100644 index 0000000..61f3bd1 --- /dev/null +++ b/website/macos/RunnerTests/RunnerTests.swift @@ -0,0 +1,12 @@ +import Cocoa +import FlutterMacOS +import XCTest + +class RunnerTests: XCTestCase { + + func testExample() { + // If you add code to the Runner application, consider adding tests here. + // See https://developer.apple.com/documentation/xctest for more information about using XCTest. + } + +} diff --git a/website/monitoring_santri b/website/monitoring_santri new file mode 100644 index 0000000..83876df Binary files /dev/null and b/website/monitoring_santri differ diff --git a/website/package-lock.json b/website/package-lock.json new file mode 100644 index 0000000..38a9c31 --- /dev/null +++ b/website/package-lock.json @@ -0,0 +1,4609 @@ +{ + "name": "website", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "website", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "ansi-regex": "^6.1.0", + "ansi-styles": "^4.3.0", + "any-promise": "^1.3.0", + "anymatch": "^3.1.3", + "arg": "^5.0.2", + "asynckit": "^0.4.0", + "balanced-match": "^1.0.2", + "binary-extensions": "^2.3.0", + "brace-expansion": "^2.0.2", + "braces": "^3.0.3", + "browserslist": "^4.25.0", + "call-bind-apply-helpers": "^1.0.2", + "camelcase-css": "^2.0.1", + "caniuse-lite": "^1.0.30001724", + "chalk": "^4.1.2", + "chokidar": "^3.6.0", + "chownr": "^3.0.0", + "cliui": "^8.0.1", + "color-convert": "^2.0.1", + "color-name": "^1.1.4", + "combined-stream": "^1.0.8", + "commander": "^4.1.1", + "cross-spawn": "^7.0.6", + "cssesc": "^3.0.0", + "delayed-stream": "^1.0.0", + "detect-libc": "^2.0.4", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "dunder-proto": "^1.0.1", + "eastasianwidth": "^0.2.0", + "electron-to-chromium": "^1.5.171", + "emoji-regex": "^9.2.2", + "enhanced-resolve": "^5.18.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "esbuild": "^0.25.5", + "escalade": "^3.2.0", + "express": "^5.1.0", + "fast-glob": "^3.3.3", + "fastq": "^1.19.1", + "fill-range": "^7.1.1", + "follow-redirects": "^1.15.9", + "foreground-child": "^3.3.1", + "form-data": "^4.0.3", + "fraction.js": "^4.3.7", + "function-bind": "^1.1.2", + "get-caller-file": "^2.0.5", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "glob": "^10.4.5", + "glob-parent": "^6.0.2", + "gopd": "^1.2.0", + "graceful-fs": "^4.2.11", + "has-flag": "^4.0.0", + "has-symbols": "^1.1.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2", + "is-binary-path": "^2.1.0", + "is-core-module": "^2.16.1", + "is-extglob": "^2.1.1", + "is-fullwidth-code-point": "^3.0.0", + "is-glob": "^4.0.3", + "is-number": "^7.0.0", + "isexe": "^2.0.0", + "jackspeak": "^3.4.3", + "jiti": "^2.4.2", + "lightningcss": "^1.30.1", + "lightningcss-win32-x64-msvc": "^1.30.1", + "lilconfig": "^3.1.3", + "lines-and-columns": "^1.2.4", + "lodash": "^4.17.21", + "lru-cache": "^10.4.3", + "magic-string": "^0.30.17", + "math-intrinsics": "^1.1.0", + "merge2": "^1.4.1", + "micromatch": "^4.0.8", + "mime-db": "^1.52.0", + "mime-types": "^2.1.35", + "mini-svg-data-uri": "^1.4.4", + "minimatch": "^9.0.5", + "minipass": "^7.1.2", + "minizlib": "^3.0.2", + "mkdirp": "^3.0.1", + "mz": "^2.7.0", + "nanoid": "^3.3.11", + "node-releases": "^2.0.19", + "normalize-path": "^3.0.0", + "normalize-range": "^0.1.2", + "object-assign": "^4.1.1", + "object-hash": "^3.0.0", + "package-json-from-dist": "^1.0.1", + "path-key": "^3.1.1", + "path-parse": "^1.0.7", + "path-scurry": "^1.11.1", + "picocolors": "^1.1.1", + "picomatch": "^2.3.1", + "pify": "^2.3.0", + "pirates": "^4.0.7", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "postcss-value-parser": "^4.2.0", + "proxy-from-env": "^1.1.0", + "queue-microtask": "^1.2.3", + "read-cache": "^1.0.0", + "readdirp": "^3.6.0", + "require-directory": "^2.1.1", + "resolve": "^1.22.10", + "reusify": "^1.1.0", + "rollup": "^4.44.0", + "run-parallel": "^1.2.0", + "rxjs": "^7.8.2", + "shebang-command": "^2.0.0", + "shebang-regex": "^3.0.0", + "shell-quote": "^1.8.3", + "signal-exit": "^4.1.0", + "source-map-js": "^1.2.1", + "string-width": "^5.1.2", + "string-width-cjs": "^4.2.3", + "strip-ansi": "^7.1.0", + "strip-ansi-cjs": "^6.0.1", + "sucrase": "^3.35.0", + "supports-color": "^8.1.1", + "supports-preserve-symlinks-flag": "^1.0.0", + "tapable": "^2.2.2", + "tar": "^7.4.3", + "thenify": "^3.3.1", + "thenify-all": "^1.6.0", + "tinyglobby": "^0.2.14", + "to-regex-range": "^5.0.1", + "tree-kill": "^1.2.2", + "ts-interface-checker": "^0.1.13", + "tslib": "^2.8.1", + "update-browserslist-db": "^1.1.3", + "util-deprecate": "^1.0.2", + "vite-plugin-full-reload": "^1.2.0", + "which": "^2.0.2", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "^7.0.0", + "y18n": "^5.0.8", + "yallist": "^5.0.0", + "yaml": "^2.8.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "devDependencies": { + "@tailwindcss/forms": "^0.5.2", + "@tailwindcss/vite": "^4.0.0", + "alpinejs": "^3.4.2", + "autoprefixer": "^10.4.2", + "axios": "^1.8.2", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^1.2.0", + "postcss": "^8.4.31", + "tailwindcss": "^3.1.0", + "vite": "^6.2.4" + } + }, + "node_modules/@alloc/quick-lru": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", + "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz", + "integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz", + "integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz", + "integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz", + "integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz", + "integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz", + "integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz", + "integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz", + "integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz", + "integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz", + "integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz", + "integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz", + "integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz", + "integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz", + "integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz", + "integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz", + "integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz", + "integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz", + "integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz", + "integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz", + "integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz", + "integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz", + "integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz", + "integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz", + "integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz", + "integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.44.0.tgz", + "integrity": "sha512-xEiEE5oDW6tK4jXCAyliuntGR+amEMO7HLtdSshVuhFnKTYoeYMyXQK7pLouAJJj5KHdwdn87bfHAR2nSdNAUA==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.44.0.tgz", + "integrity": "sha512-uNSk/TgvMbskcHxXYHzqwiyBlJ/lGcv8DaUfcnNwict8ba9GTTNxfn3/FAoFZYgkaXXAdrAA+SLyKplyi349Jw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.44.0.tgz", + "integrity": "sha512-VGF3wy0Eq1gcEIkSCr8Ke03CWT+Pm2yveKLaDvq51pPpZza3JX/ClxXOCmTYYq3us5MvEuNRTaeyFThCKRQhOA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.44.0.tgz", + "integrity": "sha512-fBkyrDhwquRvrTxSGH/qqt3/T0w5Rg0L7ZIDypvBPc1/gzjJle6acCpZ36blwuwcKD/u6oCE/sRWlUAcxLWQbQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.44.0.tgz", + "integrity": "sha512-u5AZzdQJYJXByB8giQ+r4VyfZP+walV+xHWdaFx/1VxsOn6eWJhK2Vl2eElvDJFKQBo/hcYIBg/jaKS8ZmKeNQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.44.0.tgz", + "integrity": "sha512-qC0kS48c/s3EtdArkimctY7h3nHicQeEUdjJzYVJYR3ct3kWSafmn6jkNCA8InbUdge6PVx6keqjk5lVGJf99g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.44.0.tgz", + "integrity": "sha512-x+e/Z9H0RAWckn4V2OZZl6EmV0L2diuX3QB0uM1r6BvhUIv6xBPL5mrAX2E3e8N8rEHVPwFfz/ETUbV4oW9+lQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.44.0.tgz", + "integrity": "sha512-1exwiBFf4PU/8HvI8s80icyCcnAIB86MCBdst51fwFmH5dyeoWVPVgmQPcKrMtBQ0W5pAs7jBCWuRXgEpRzSCg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.44.0.tgz", + "integrity": "sha512-ZTR2mxBHb4tK4wGf9b8SYg0Y6KQPjGpR4UWwTFdnmjB4qRtoATZ5dWn3KsDwGa5Z2ZBOE7K52L36J9LueKBdOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.44.0.tgz", + "integrity": "sha512-GFWfAhVhWGd4r6UxmnKRTBwP1qmModHtd5gkraeW2G490BpFOZkFtem8yuX2NyafIP/mGpRJgTJ2PwohQkUY/Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.44.0.tgz", + "integrity": "sha512-xw+FTGcov/ejdusVOqKgMGW3c4+AgqrfvzWEVXcNP6zq2ue+lsYUgJ+5Rtn/OTJf7e2CbgTFvzLW2j0YAtj0Gg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.44.0.tgz", + "integrity": "sha512-bKGibTr9IdF0zr21kMvkZT4K6NV+jjRnBoVMt2uNMG0BYWm3qOVmYnXKzx7UhwrviKnmK46IKMByMgvpdQlyJQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.44.0.tgz", + "integrity": "sha512-vV3cL48U5kDaKZtXrti12YRa7TyxgKAIDoYdqSIOMOFBXqFj2XbChHAtXquEn2+n78ciFgr4KIqEbydEGPxXgA==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.44.0.tgz", + "integrity": "sha512-TDKO8KlHJuvTEdfw5YYFBjhFts2TR0VpZsnLLSYmB7AaohJhM8ctDSdDnUGq77hUh4m/djRafw+9zQpkOanE2Q==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.44.0.tgz", + "integrity": "sha512-8541GEyktXaw4lvnGp9m84KENcxInhAt6vPWJ9RodsB/iGjHoMB2Pp5MVBCiKIRxrxzJhGCxmNzdu+oDQ7kwRA==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.44.0.tgz", + "integrity": "sha512-iUVJc3c0o8l9Sa/qlDL2Z9UP92UZZW1+EmQ4xfjTc1akr0iUFZNfxrXJ/R1T90h/ILm9iXEY6+iPrmYB3pXKjw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.44.0.tgz", + "integrity": "sha512-PQUobbhLTQT5yz/SPg116VJBgz+XOtXt8D1ck+sfJJhuEsMj2jSej5yTdp8CvWBSceu+WW+ibVL6dm0ptG5fcA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.44.0.tgz", + "integrity": "sha512-M0CpcHf8TWn+4oTxJfh7LQuTuaYeXGbk0eageVjQCKzYLsajWS/lFC94qlRqOlyC2KvRT90ZrfXULYmukeIy7w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.44.0.tgz", + "integrity": "sha512-3XJ0NQtMAXTWFW8FqZKcw3gOQwBtVWP/u8TpHP3CRPXD7Pd6s8lLdH3sHWh8vqKCyyiI8xW5ltJScQmBU9j7WA==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.44.0.tgz", + "integrity": "sha512-Q2Mgwt+D8hd5FIPUuPDsvPR7Bguza6yTkJxspDGkZj7tBRn2y4KSWYuIXpftFSjBra76TbKerCV7rgFPQrn+wQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@tailwindcss/forms": { + "version": "0.5.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/forms/-/forms-0.5.10.tgz", + "integrity": "sha512-utI1ONF6uf/pPNO68kmN1b8rEwNXv3czukalo8VtJH8ksIkZXr3Q3VYudZLkCsDd4Wku120uF02hYK25XGPorw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mini-svg-data-uri": "^1.2.3" + }, + "peerDependencies": { + "tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20 || >= 4.0.0-beta.1" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.10.tgz", + "integrity": "sha512-2ACf1znY5fpRBwRhMgj9ZXvb2XZW8qs+oTfotJ2C5xR0/WNL7UHZ7zXl6s+rUqedL1mNi+0O+WQr5awGowS3PQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.30.1", + "magic-string": "^0.30.17", + "source-map-js": "^1.2.1", + "tailwindcss": "4.1.10" + } + }, + "node_modules/@tailwindcss/node/node_modules/tailwindcss": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.10.tgz", + "integrity": "sha512-P3nr6WkvKV/ONsTzj6Gb57sWPMX29EPNPopo7+FcpkQaNsrNpZ1pv8QmrYI2RqEKD7mlGqLnGovlcYnBK0IqUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.10.tgz", + "integrity": "sha512-v0C43s7Pjw+B9w21htrQwuFObSkio2aV/qPx/mhrRldbqxbWJK6KizM+q7BF1/1CmuLqZqX3CeYF7s7P9fbA8Q==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "detect-libc": "^2.0.4", + "tar": "^7.4.3" + }, + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.10", + "@tailwindcss/oxide-darwin-arm64": "4.1.10", + "@tailwindcss/oxide-darwin-x64": "4.1.10", + "@tailwindcss/oxide-freebsd-x64": "4.1.10", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.10", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.10", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.10", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.10", + "@tailwindcss/oxide-linux-x64-musl": "4.1.10", + "@tailwindcss/oxide-wasm32-wasi": "4.1.10", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.10", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.10" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.10.tgz", + "integrity": "sha512-VGLazCoRQ7rtsCzThaI1UyDu/XRYVyH4/EWiaSX6tFglE+xZB5cvtC5Omt0OQ+FfiIVP98su16jDVHDEIuH4iQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.10.tgz", + "integrity": "sha512-ZIFqvR1irX2yNjWJzKCqTCcHZbgkSkSkZKbRM3BPzhDL/18idA8uWCoopYA2CSDdSGFlDAxYdU2yBHwAwx8euQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.10.tgz", + "integrity": "sha512-eCA4zbIhWUFDXoamNztmS0MjXHSEJYlvATzWnRiTqJkcUteSjO94PoRHJy1Xbwp9bptjeIxxBHh+zBWFhttbrQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.10.tgz", + "integrity": "sha512-8/392Xu12R0cc93DpiJvNpJ4wYVSiciUlkiOHOSOQNH3adq9Gi/dtySK7dVQjXIOzlpSHjeCL89RUUI8/GTI6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.10.tgz", + "integrity": "sha512-t9rhmLT6EqeuPT+MXhWhlRYIMSfh5LZ6kBrC4FS6/+M1yXwfCtp24UumgCWOAJVyjQwG+lYva6wWZxrfvB+NhQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.10.tgz", + "integrity": "sha512-3oWrlNlxLRxXejQ8zImzrVLuZ/9Z2SeKoLhtCu0hpo38hTO2iL86eFOu4sVR8cZc6n3z7eRXXqtHJECa6mFOvA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.10.tgz", + "integrity": "sha512-saScU0cmWvg/Ez4gUmQWr9pvY9Kssxt+Xenfx1LG7LmqjcrvBnw4r9VjkFcqmbBb7GCBwYNcZi9X3/oMda9sqQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.10.tgz", + "integrity": "sha512-/G3ao/ybV9YEEgAXeEg28dyH6gs1QG8tvdN9c2MNZdUXYBaIY/Gx0N6RlJzfLy/7Nkdok4kaxKPHKJUlAaoTdA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.10.tgz", + "integrity": "sha512-LNr7X8fTiKGRtQGOerSayc2pWJp/9ptRYAa4G+U+cjw9kJZvkopav1AQc5HHD+U364f71tZv6XamaHKgrIoVzA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.1.10.tgz", + "integrity": "sha512-d6ekQpopFQJAcIK2i7ZzWOYGZ+A6NzzvQ3ozBvWFdeyqfOZdYHU66g5yr+/HC4ipP1ZgWsqa80+ISNILk+ae/Q==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.4.3", + "@emnapi/runtime": "^1.4.3", + "@emnapi/wasi-threads": "^1.0.2", + "@napi-rs/wasm-runtime": "^0.2.10", + "@tybys/wasm-util": "^0.9.0", + "tslib": "^2.8.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.10.tgz", + "integrity": "sha512-i1Iwg9gRbwNVOCYmnigWCCgow8nDWSFmeTUU5nbNx3rqbe4p0kRbEqLwLJbYZKmSSp23g4N6rCDmm7OuPBXhDA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.10.tgz", + "integrity": "sha512-sGiJTjcBSfGq2DVRtaSljq5ZgZS2SDHSIfhOylkBvHVjwOsodBhnb3HdmiKkVuUGKD0I7G63abMOVaskj1KpOA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.10.tgz", + "integrity": "sha512-QWnD5HDY2IADv+vYR82lOhqOlS1jSCUUAmfem52cXAhRTKxpDh3ARX8TTXJTCCO7Rv7cD2Nlekabv02bwP3a2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.10", + "@tailwindcss/oxide": "4.1.10", + "tailwindcss": "4.1.10" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6" + } + }, + "node_modules/@tailwindcss/vite/node_modules/tailwindcss": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.10.tgz", + "integrity": "sha512-P3nr6WkvKV/ONsTzj6Gb57sWPMX29EPNPopo7+FcpkQaNsrNpZ1pv8QmrYI2RqEKD7mlGqLnGovlcYnBK0IqUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "license": "MIT" + }, + "node_modules/@vue/reactivity": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.1.5.tgz", + "integrity": "sha512-1tdfLmNjWG6t/CsPldh+foumYFo3cpyCHgBYQ34ylaMsJ+SNHQ1kApMIa8jN+i593zQuaw3AdWH0nJTARzCFhg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/shared": "3.1.5" + } + }, + "node_modules/@vue/shared": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.1.5.tgz", + "integrity": "sha512-oJ4F3TnvpXaQwZJNF3ZK+kLPHKarDmJjJ6jyzVNDKH9md1dptjC7lWR//jrGuLdek/U6iltWxqAnYOu8gCiOvA==", + "dev": true, + "license": "MIT" + }, + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", + "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/accepts/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/alpinejs": { + "version": "3.14.9", + "resolved": "https://registry.npmjs.org/alpinejs/-/alpinejs-3.14.9.tgz", + "integrity": "sha512-gqSOhTEyryU9FhviNqiHBHzgjkvtukq9tevew29fTj+ofZtfsYriw4zPirHHOAy9bw8QoL3WGhyk7QqCh5AYlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vue/reactivity": "~3.1.1" + } + }, + "node_modules/ansi-regex": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/autoprefixer": { + "version": "10.4.21", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.21.tgz", + "integrity": "sha512-O+A6LWV5LDHSJD3LjHYoNi4VLsj/Whi7k6zG12xTYaU4cQ8oxQGckXNX8cRHK5yOZ/ppVHe0ZBXGzSV9jXdVbQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "browserslist": "^4.24.4", + "caniuse-lite": "^1.0.30001702", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.1.1", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/axios": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.10.0.tgz", + "integrity": "sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/body-parser": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", + "integrity": "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==", + "license": "MIT", + "dependencies": { + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.0", + "http-errors": "^2.0.0", + "iconv-lite": "^0.6.3", + "on-finished": "^2.4.1", + "qs": "^6.14.0", + "raw-body": "^3.0.0", + "type-is": "^2.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/brace-expansion": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.25.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.25.0.tgz", + "integrity": "sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "caniuse-lite": "^1.0.30001718", + "electron-to-chromium": "^1.5.160", + "node-releases": "^2.0.19", + "update-browserslist-db": "^1.1.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase-css": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", + "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001724", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001724.tgz", + "integrity": "sha512-WqJo7p0TbHDOythNTqYujmaJTvtYRZrjpP8TCvH6Vb9CYJerJNKamKzIWOM4BkQatWj9H2lYulpdAQNBe7QhNA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/cliui/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cliui/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", + "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/concurrently": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.1.2.tgz", + "integrity": "sha512-H9MWcoPsYddwbOGM6difjVwVZHl63nwMEwDJG/L7VGtuaJhb12h2caPG2tVPWs7emuYix252iGfqOyrz1GczTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.2", + "lodash": "^4.17.21", + "rxjs": "^7.8.1", + "shell-quote": "^1.8.1", + "supports-color": "^8.1.1", + "tree-kill": "^1.2.2", + "yargs": "^17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/content-disposition": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.0.0.tgz", + "integrity": "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.2.tgz", + "integrity": "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==", + "license": "MIT", + "engines": { + "node": ">=6.6.0" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/debug": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.1.tgz", + "integrity": "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/detect-libc": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", + "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/didyoumean": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", + "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", + "license": "Apache-2.0" + }, + "node_modules/dlv": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", + "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", + "license": "MIT" + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", + "license": "MIT" + }, + "node_modules/electron-to-chromium": { + "version": "1.5.171", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.171.tgz", + "integrity": "sha512-scWpzXEJEMrGJa4Y6m/tVotb0WuvNmasv3wWVzUAeCgKU0ToFOhUW6Z+xWnRQANMYGxN4ngJXIThgBJOqzVPCQ==", + "license": "ISC" + }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/encodeurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.25.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz", + "integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==", + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.5", + "@esbuild/android-arm": "0.25.5", + "@esbuild/android-arm64": "0.25.5", + "@esbuild/android-x64": "0.25.5", + "@esbuild/darwin-arm64": "0.25.5", + "@esbuild/darwin-x64": "0.25.5", + "@esbuild/freebsd-arm64": "0.25.5", + "@esbuild/freebsd-x64": "0.25.5", + "@esbuild/linux-arm": "0.25.5", + "@esbuild/linux-arm64": "0.25.5", + "@esbuild/linux-ia32": "0.25.5", + "@esbuild/linux-loong64": "0.25.5", + "@esbuild/linux-mips64el": "0.25.5", + "@esbuild/linux-ppc64": "0.25.5", + "@esbuild/linux-riscv64": "0.25.5", + "@esbuild/linux-s390x": "0.25.5", + "@esbuild/linux-x64": "0.25.5", + "@esbuild/netbsd-arm64": "0.25.5", + "@esbuild/netbsd-x64": "0.25.5", + "@esbuild/openbsd-arm64": "0.25.5", + "@esbuild/openbsd-x64": "0.25.5", + "@esbuild/sunos-x64": "0.25.5", + "@esbuild/win32-arm64": "0.25.5", + "@esbuild/win32-ia32": "0.25.5", + "@esbuild/win32-x64": "0.25.5" + } + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", + "license": "MIT" + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/express/-/express-5.1.0.tgz", + "integrity": "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==", + "license": "MIT", + "dependencies": { + "accepts": "^2.0.0", + "body-parser": "^2.2.0", + "content-disposition": "^1.0.0", + "content-type": "^1.0.5", + "cookie": "^0.7.1", + "cookie-signature": "^1.2.1", + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "finalhandler": "^2.1.0", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "merge-descriptors": "^2.0.0", + "mime-types": "^3.0.0", + "on-finished": "^2.4.1", + "once": "^1.4.0", + "parseurl": "^1.3.3", + "proxy-addr": "^2.0.7", + "qs": "^6.14.0", + "range-parser": "^1.2.1", + "router": "^2.2.0", + "send": "^1.1.0", + "serve-static": "^2.2.0", + "statuses": "^2.0.1", + "type-is": "^2.0.1", + "vary": "^1.1.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/express/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", + "integrity": "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/form-data": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.3.tgz", + "integrity": "sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "license": "MIT", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob": { + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^3.1.2", + "minimatch": "^9.0.4", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^1.11.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "license": "MIT", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "license": "MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", + "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", + "license": "MIT", + "dependencies": { + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jackspeak": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", + "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/laravel-vite-plugin": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/laravel-vite-plugin/-/laravel-vite-plugin-1.3.0.tgz", + "integrity": "sha512-P5qyG56YbYxM8OuYmK2OkhcKe0AksNVJUjq9LUZ5tOekU9fBn9LujYyctI4t9XoLjuMvHJXXpCoPntY1oKltuA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "vite-plugin-full-reload": "^1.1.0" + }, + "bin": { + "clean-orphaned-assets": "bin/clean.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0" + } + }, + "node_modules/lightningcss": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", + "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.30.1", + "lightningcss-darwin-x64": "1.30.1", + "lightningcss-freebsd-x64": "1.30.1", + "lightningcss-linux-arm-gnueabihf": "1.30.1", + "lightningcss-linux-arm64-gnu": "1.30.1", + "lightningcss-linux-arm64-musl": "1.30.1", + "lightningcss-linux-x64-gnu": "1.30.1", + "lightningcss-linux-x64-musl": "1.30.1", + "lightningcss-win32-arm64-msvc": "1.30.1", + "lightningcss-win32-x64-msvc": "1.30.1" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.30.1.tgz", + "integrity": "sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.30.1.tgz", + "integrity": "sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.30.1.tgz", + "integrity": "sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.30.1.tgz", + "integrity": "sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.30.1.tgz", + "integrity": "sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.30.1.tgz", + "integrity": "sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.30.1.tgz", + "integrity": "sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.30.1.tgz", + "integrity": "sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.30.1.tgz", + "integrity": "sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.30.1.tgz", + "integrity": "sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", + "license": "MIT", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "license": "MIT" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "license": "ISC" + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mini-svg-data-uri": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/mini-svg-data-uri/-/mini-svg-data-uri-1.4.4.tgz", + "integrity": "sha512-r9deDe9p5FJUPZAk3A59wGH7Ii9YrjjWw0jmw/liSbHl2CHiyXj6FcDXDu2K3TjVAXqiJdaw3xxwlZZr9E6nHg==", + "license": "MIT", + "bin": { + "mini-svg-data-uri": "cli.js" + } + }, + "node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minizlib": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", + "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/mkdirp": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", + "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", + "license": "MIT", + "bin": { + "mkdirp": "dist/cjs/src/bin.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/negotiator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-1.0.0.tgz", + "integrity": "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-releases": { + "version": "2.0.19", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz", + "integrity": "sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==", + "license": "MIT" + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-hash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", + "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "license": "MIT", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/package-json-from-dist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", + "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", + "license": "BlueOak-1.0.0" + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "license": "MIT" + }, + "node_modules/path-scurry": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", + "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^10.2.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.18" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-to-regexp": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pirates": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", + "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss": { + "version": "8.5.6", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", + "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-import": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", + "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", + "license": "MIT", + "dependencies": { + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" + } + }, + "node_modules/postcss-js": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz", + "integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==", + "license": "MIT", + "dependencies": { + "camelcase-css": "^2.0.1" + }, + "engines": { + "node": "^12 || ^14 || >= 16" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" + } + }, + "node_modules/postcss-load-config": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-4.0.2.tgz", + "integrity": "sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "lilconfig": "^3.0.0", + "yaml": "^2.3.4" + }, + "engines": { + "node": ">= 14" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-nested": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", + "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "postcss-selector-parser": "^6.1.1" + }, + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.2.14" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", + "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "license": "MIT" + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "license": "MIT", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "license": "BSD-3-Clause", + "dependencies": { + "side-channel": "^1.1.0" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.0.tgz", + "integrity": "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==", + "license": "MIT", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.6.3", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-cache": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", + "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", + "license": "MIT", + "dependencies": { + "pify": "^2.3.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.10", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", + "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "license": "MIT", + "dependencies": { + "is-core-module": "^2.16.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.44.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.44.0.tgz", + "integrity": "sha512-qHcdEzLCiktQIfwBq420pn2dP+30uzqYxv9ETm91wdt2R9AFcWfjNAmje4NWlnCIQ5RMTzVf0ZyisOKqHR6RwA==", + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.44.0", + "@rollup/rollup-android-arm64": "4.44.0", + "@rollup/rollup-darwin-arm64": "4.44.0", + "@rollup/rollup-darwin-x64": "4.44.0", + "@rollup/rollup-freebsd-arm64": "4.44.0", + "@rollup/rollup-freebsd-x64": "4.44.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.44.0", + "@rollup/rollup-linux-arm-musleabihf": "4.44.0", + "@rollup/rollup-linux-arm64-gnu": "4.44.0", + "@rollup/rollup-linux-arm64-musl": "4.44.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.44.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-gnu": "4.44.0", + "@rollup/rollup-linux-riscv64-musl": "4.44.0", + "@rollup/rollup-linux-s390x-gnu": "4.44.0", + "@rollup/rollup-linux-x64-gnu": "4.44.0", + "@rollup/rollup-linux-x64-musl": "4.44.0", + "@rollup/rollup-win32-arm64-msvc": "4.44.0", + "@rollup/rollup-win32-ia32-msvc": "4.44.0", + "@rollup/rollup-win32-x64-msvc": "4.44.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/router": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", + "integrity": "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==", + "license": "MIT", + "dependencies": { + "debug": "^4.4.0", + "depd": "^2.0.0", + "is-promise": "^4.0.0", + "parseurl": "^1.3.3", + "path-to-regexp": "^8.0.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" + }, + "node_modules/send": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.0.tgz", + "integrity": "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==", + "license": "MIT", + "dependencies": { + "debug": "^4.3.5", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.0", + "mime-types": "^3.0.1", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/send/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/send/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-static": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.0.tgz", + "integrity": "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==", + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", + "license": "ISC" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/string-width-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase": { + "version": "3.35.0", + "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", + "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "^10.3.10", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tailwindcss": { + "version": "3.4.17", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.17.tgz", + "integrity": "sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.6.0", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.21.6", + "lilconfig": "^3.1.3", + "micromatch": "^4.0.8", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.1.1", + "postcss": "^8.4.47", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "resolve": "^1.22.8", + "sucrase": "^3.35.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/jiti": { + "version": "1.21.7", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", + "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/tapable": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", + "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", + "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", + "license": "ISC", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.0.1", + "mkdirp": "^3.0.1", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/thenify": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", + "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", + "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==", + "license": "MIT", + "dependencies": { + "fdir": "^6.4.4", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", + "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", + "license": "Apache-2.0" + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/type-is": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", + "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "license": "MIT", + "dependencies": { + "content-type": "^1.0.5", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/type-is/node_modules/mime-types": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.1.tgz", + "integrity": "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==", + "license": "MIT", + "dependencies": { + "mime-db": "^1.54.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.3.tgz", + "integrity": "sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vite": { + "version": "6.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.5.tgz", + "integrity": "sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "fdir": "^6.4.4", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.13" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-plugin-full-reload": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/vite-plugin-full-reload/-/vite-plugin-full-reload-1.2.0.tgz", + "integrity": "sha512-kz18NW79x0IHbxRSHm0jttP4zoO9P9gXh+n6UTwlNKnviTTEpOlum6oS9SmecrTtSr+muHEn5TUuC75UovQzcA==", + "license": "MIT", + "dependencies": { + "picocolors": "^1.0.0", + "picomatch": "^2.3.1" + } + }, + "node_modules/vite/node_modules/fdir": { + "version": "6.4.6", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz", + "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/wrap-ansi-cjs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/yaml": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.0.tgz", + "integrity": "sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/yargs/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + } + } +} diff --git a/website/package.json b/website/package.json new file mode 100644 index 0000000..7f3b050 --- /dev/null +++ b/website/package.json @@ -0,0 +1,181 @@ +{ + "$schema": "https://json.schemastore.org/package.json", + "private": true, + "type": "module", + "scripts": { + "build": "vite build", + "dev": "vite" + }, + "devDependencies": { + "@tailwindcss/forms": "^0.5.2", + "@tailwindcss/vite": "^4.0.0", + "alpinejs": "^3.4.2", + "autoprefixer": "^10.4.2", + "axios": "^1.8.2", + "concurrently": "^9.0.1", + "laravel-vite-plugin": "^1.2.0", + "postcss": "^8.4.31", + "tailwindcss": "^3.1.0", + "vite": "^6.2.4" + }, + "name": "website", + "version": "1.0.0", + "description": "

\"Laravel

", + "main": "postcss.config.js", + "directories": { + "test": "tests" + }, + "dependencies": { + "ansi-regex": "^6.1.0", + "ansi-styles": "^4.3.0", + "any-promise": "^1.3.0", + "anymatch": "^3.1.3", + "arg": "^5.0.2", + "asynckit": "^0.4.0", + "balanced-match": "^1.0.2", + "binary-extensions": "^2.3.0", + "brace-expansion": "^2.0.2", + "braces": "^3.0.3", + "browserslist": "^4.25.0", + "call-bind-apply-helpers": "^1.0.2", + "camelcase-css": "^2.0.1", + "caniuse-lite": "^1.0.30001724", + "chalk": "^4.1.2", + "chokidar": "^3.6.0", + "chownr": "^3.0.0", + "cliui": "^8.0.1", + "color-convert": "^2.0.1", + "color-name": "^1.1.4", + "combined-stream": "^1.0.8", + "commander": "^4.1.1", + "cross-spawn": "^7.0.6", + "cssesc": "^3.0.0", + "delayed-stream": "^1.0.0", + "detect-libc": "^2.0.4", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "dunder-proto": "^1.0.1", + "eastasianwidth": "^0.2.0", + "electron-to-chromium": "^1.5.171", + "emoji-regex": "^9.2.2", + "enhanced-resolve": "^5.18.1", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "es-set-tostringtag": "^2.1.0", + "esbuild": "^0.25.5", + "escalade": "^3.2.0", + "express": "^5.1.0", + "fast-glob": "^3.3.3", + "fastq": "^1.19.1", + "fill-range": "^7.1.1", + "follow-redirects": "^1.15.9", + "foreground-child": "^3.3.1", + "form-data": "^4.0.3", + "fraction.js": "^4.3.7", + "function-bind": "^1.1.2", + "get-caller-file": "^2.0.5", + "get-intrinsic": "^1.3.0", + "get-proto": "^1.0.1", + "glob": "^10.4.5", + "glob-parent": "^6.0.2", + "gopd": "^1.2.0", + "graceful-fs": "^4.2.11", + "has-flag": "^4.0.0", + "has-symbols": "^1.1.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2", + "is-binary-path": "^2.1.0", + "is-core-module": "^2.16.1", + "is-extglob": "^2.1.1", + "is-fullwidth-code-point": "^3.0.0", + "is-glob": "^4.0.3", + "is-number": "^7.0.0", + "isexe": "^2.0.0", + "jackspeak": "^3.4.3", + "jiti": "^2.4.2", + "lightningcss": "^1.30.1", + "lightningcss-win32-x64-msvc": "^1.30.1", + "lilconfig": "^3.1.3", + "lines-and-columns": "^1.2.4", + "lodash": "^4.17.21", + "lru-cache": "^10.4.3", + "magic-string": "^0.30.17", + "math-intrinsics": "^1.1.0", + "merge2": "^1.4.1", + "micromatch": "^4.0.8", + "mime-db": "^1.52.0", + "mime-types": "^2.1.35", + "mini-svg-data-uri": "^1.4.4", + "minimatch": "^9.0.5", + "minipass": "^7.1.2", + "minizlib": "^3.0.2", + "mkdirp": "^3.0.1", + "mz": "^2.7.0", + "nanoid": "^3.3.11", + "node-releases": "^2.0.19", + "normalize-path": "^3.0.0", + "normalize-range": "^0.1.2", + "object-assign": "^4.1.1", + "object-hash": "^3.0.0", + "package-json-from-dist": "^1.0.1", + "path-key": "^3.1.1", + "path-parse": "^1.0.7", + "path-scurry": "^1.11.1", + "picocolors": "^1.1.1", + "picomatch": "^2.3.1", + "pify": "^2.3.0", + "pirates": "^4.0.7", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.2", + "postcss-nested": "^6.2.0", + "postcss-selector-parser": "^6.1.2", + "postcss-value-parser": "^4.2.0", + "proxy-from-env": "^1.1.0", + "queue-microtask": "^1.2.3", + "read-cache": "^1.0.0", + "readdirp": "^3.6.0", + "require-directory": "^2.1.1", + "resolve": "^1.22.10", + "reusify": "^1.1.0", + "rollup": "^4.44.0", + "run-parallel": "^1.2.0", + "rxjs": "^7.8.2", + "shebang-command": "^2.0.0", + "shebang-regex": "^3.0.0", + "shell-quote": "^1.8.3", + "signal-exit": "^4.1.0", + "source-map-js": "^1.2.1", + "string-width": "^5.1.2", + "string-width-cjs": "^4.2.3", + "strip-ansi": "^7.1.0", + "strip-ansi-cjs": "^6.0.1", + "sucrase": "^3.35.0", + "supports-color": "^8.1.1", + "supports-preserve-symlinks-flag": "^1.0.0", + "tapable": "^2.2.2", + "tar": "^7.4.3", + "thenify": "^3.3.1", + "thenify-all": "^1.6.0", + "tinyglobby": "^0.2.14", + "to-regex-range": "^5.0.1", + "tree-kill": "^1.2.2", + "ts-interface-checker": "^0.1.13", + "tslib": "^2.8.1", + "update-browserslist-db": "^1.1.3", + "util-deprecate": "^1.0.2", + "vite-plugin-full-reload": "^1.2.0", + "which": "^2.0.2", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "^7.0.0", + "y18n": "^5.0.8", + "yallist": "^5.0.0", + "yaml": "^2.8.0", + "yargs": "^17.7.2", + "yargs-parser": "^21.1.1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/website/phpunit.xml b/website/phpunit.xml new file mode 100644 index 0000000..61c031c --- /dev/null +++ b/website/phpunit.xml @@ -0,0 +1,33 @@ + + + + + tests/Unit + + + tests/Feature + + + + + app + + + + + + + + + + + + + + + + diff --git a/website/postcss.config.js b/website/postcss.config.js new file mode 100644 index 0000000..49c0612 --- /dev/null +++ b/website/postcss.config.js @@ -0,0 +1,6 @@ +export default { + plugins: { + tailwindcss: {}, + autoprefixer: {}, + }, +}; diff --git a/website/public/.htaccess b/website/public/.htaccess new file mode 100644 index 0000000..3aec5e2 --- /dev/null +++ b/website/public/.htaccess @@ -0,0 +1,21 @@ + + + Options -MultiViews -Indexes + + + RewriteEngine On + + # Handle Authorization Header + RewriteCond %{HTTP:Authorization} . + RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + + # Redirect Trailing Slashes If Not A Folder... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_URI} (.+)/$ + RewriteRule ^ %1 [L,R=301] + + # Send Requests To Front Controller... + RewriteCond %{REQUEST_FILENAME} !-d + RewriteCond %{REQUEST_FILENAME} !-f + RewriteRule ^ index.php [L] + diff --git a/website/public/assets/css/nucleo-icons.css b/website/public/assets/css/nucleo-icons.css new file mode 100644 index 0000000..d77d1db --- /dev/null +++ b/website/public/assets/css/nucleo-icons.css @@ -0,0 +1,597 @@ +/*-------------------------------- + +hermes-dashboard-icons Web Font - built using nucleoapp.com +License - nucleoapp.com/license/ + +-------------------------------- */ +@font-face { + font-family: 'NucleoIcons'; + src: url('../fonts/nucleo-icons.eot'); + src: url('../fonts/nucleo-icons.eot') format('embedded-opentype'), url('../fonts/nucleo-icons.woff2') format('woff2'), url('../fonts/nucleo-icons.woff') format('woff'), url('../fonts/nucleo-icons.ttf') format('truetype'), url('../fonts/nucleo-icons.svg') format('svg'); + font-weight: normal; + font-style: normal; +} + +/*------------------------ + base class definition +-------------------------*/ +.ni { + display: inline-block; + font: normal normal normal 14px/1 NucleoIcons; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/*------------------------ + change icon size +-------------------------*/ +.ni-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} + +.ni-2x { + font-size: 2em; +} + +.ni-3x { + font-size: 3em; +} + +.ni-4x { + font-size: 4em; +} + +.ni-5x { + font-size: 5em; +} + +/*---------------------------------- + add a square/circle background +-----------------------------------*/ +.ni.square, +.ni.circle { + padding: 0.33333333em; + vertical-align: -16%; + background-color: #eee; +} + +.ni.circle { + border-radius: 50%; +} + +/*------------------------ + list icons +-------------------------*/ +.ni-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} + +.ni-ul>li { + position: relative; +} + +.ni-ul>li>.ni { + position: absolute; + left: -1.57142857em; + top: 0.14285714em; + text-align: center; +} + +.ni-ul>li>.ni.lg { + top: 0; + left: -1.35714286em; +} + +.ni-ul>li>.ni.circle, +.ni-ul>li>.ni.square { + top: -0.19047619em; + left: -1.9047619em; +} + +/*------------------------ + spinning icons +-------------------------*/ +.ni.spin { + -webkit-animation: nc-spin 2s infinite linear; + -moz-animation: nc-spin 2s infinite linear; + animation: nc-spin 2s infinite linear; +} + +@-webkit-keyframes nc-spin { + 0% { + -webkit-transform: rotate(0deg); + } + + 100% { + -webkit-transform: rotate(360deg); + } +} + +@-moz-keyframes nc-spin { + 0% { + -moz-transform: rotate(0deg); + } + + 100% { + -moz-transform: rotate(360deg); + } +} + +@keyframes nc-spin { + 0% { + -webkit-transform: rotate(0deg); + -moz-transform: rotate(0deg); + -ms-transform: rotate(0deg); + -o-transform: rotate(0deg); + transform: rotate(0deg); + } + + 100% { + -webkit-transform: rotate(360deg); + -moz-transform: rotate(360deg); + -ms-transform: rotate(360deg); + -o-transform: rotate(360deg); + transform: rotate(360deg); + } +} + +/*------------------------ + rotated/flipped icons +-------------------------*/ +.ni.rotate-90 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=1); + -webkit-transform: rotate(90deg); + -moz-transform: rotate(90deg); + -ms-transform: rotate(90deg); + -o-transform: rotate(90deg); + transform: rotate(90deg); +} + +.ni.rotate-180 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: rotate(180deg); + -moz-transform: rotate(180deg); + -ms-transform: rotate(180deg); + -o-transform: rotate(180deg); + transform: rotate(180deg); +} + +.ni.rotate-270 { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3); + -webkit-transform: rotate(270deg); + -moz-transform: rotate(270deg); + -ms-transform: rotate(270deg); + -o-transform: rotate(270deg); + transform: rotate(270deg); +} + +.ni.flip-y { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0); + -webkit-transform: scale(-1, 1); + -moz-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + -o-transform: scale(-1, 1); + transform: scale(-1, 1); +} + +.ni.flip-x { + filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=2); + -webkit-transform: scale(1, -1); + -moz-transform: scale(1, -1); + -ms-transform: scale(1, -1); + -o-transform: scale(1, -1); + transform: scale(1, -1); +} + +/*------------------------ + font icons +-------------------------*/ + +.ni-active-40::before { + content: "\ea02"; +} + +.ni-air-baloon::before { + content: "\ea03"; +} + +.ni-album-2::before { + content: "\ea04"; +} + +.ni-align-center::before { + content: "\ea05"; +} + +.ni-align-left-2::before { + content: "\ea06"; +} + +.ni-ambulance::before { + content: "\ea07"; +} + +.ni-app::before { + content: "\ea08"; +} + +.ni-archive-2::before { + content: "\ea09"; +} + +.ni-atom::before { + content: "\ea0a"; +} + +.ni-badge::before { + content: "\ea0b"; +} + +.ni-bag-17::before { + content: "\ea0c"; +} + +.ni-basket::before { + content: "\ea0d"; +} + +.ni-bell-55::before { + content: "\ea0e"; +} + +.ni-bold-down::before { + content: "\ea0f"; +} + +.ni-bold-left::before { + content: "\ea10"; +} + +.ni-bold-right::before { + content: "\ea11"; +} + +.ni-bold-up::before { + content: "\ea12"; +} + +.ni-bold::before { + content: "\ea13"; +} + +.ni-book-bookmark::before { + content: "\ea14"; +} + +.ni-books::before { + content: "\ea15"; +} + +.ni-box-2::before { + content: "\ea16"; +} + +.ni-briefcase-24::before { + content: "\ea17"; +} + +.ni-building::before { + content: "\ea18"; +} + +.ni-bulb-61::before { + content: "\ea19"; +} + +.ni-bullet-list-67::before { + content: "\ea1a"; +} + +.ni-bus-front-12::before { + content: "\ea1b"; +} + +.ni-button-pause::before { + content: "\ea1c"; +} + +.ni-button-play::before { + content: "\ea1d"; +} + +.ni-button-power::before { + content: "\ea1e"; +} + +.ni-calendar-grid-58::before { + content: "\ea1f"; +} + +.ni-camera-compact::before { + content: "\ea20"; +} + +.ni-caps-small::before { + content: "\ea21"; +} + +.ni-cart::before { + content: "\ea22"; +} + +.ni-chart-bar-32::before { + content: "\ea23"; +} + +.ni-chart-pie-35::before { + content: "\ea24"; +} + +.ni-chat-round::before { + content: "\ea25"; +} + +.ni-check-bold::before { + content: "\ea26"; +} + +.ni-circle-08::before { + content: "\ea27"; +} + +.ni-cloud-download-95::before { + content: "\ea28"; +} + +.ni-cloud-upload-96::before { + content: "\ea29"; +} + +.ni-compass-04::before { + content: "\ea2a"; +} + +.ni-controller::before { + content: "\ea2b"; +} + +.ni-credit-card::before { + content: "\ea2c"; +} + +.ni-curved-next::before { + content: "\ea2d"; +} + +.ni-delivery-fast::before { + content: "\ea2e"; +} + +.ni-diamond::before { + content: "\ea2f"; +} + +.ni-email-83::before { + content: "\ea30"; +} + +.ni-fat-add::before { + content: "\ea31"; +} + +.ni-fat-delete::before { + content: "\ea32"; +} + +.ni-fat-remove::before { + content: "\ea33"; +} + +.ni-favourite-28::before { + content: "\ea34"; +} + +.ni-folder-17::before { + content: "\ea35"; +} + +.ni-glasses-2::before { + content: "\ea36"; +} + +.ni-hat-3::before { + content: "\ea37"; +} + +.ni-headphones::before { + content: "\ea38"; +} + +.ni-html5::before { + content: "\ea39"; +} + +.ni-istanbul::before { + content: "\ea3a"; +} + +.ni-key-25::before { + content: "\ea3b"; +} + +.ni-laptop::before { + content: "\ea3c"; +} + +.ni-like-2::before { + content: "\ea3d"; +} + +.ni-lock-circle-open::before { + content: "\ea3e"; +} + +.ni-map-big::before { + content: "\ea3f"; +} + +.ni-mobile-button::before { + content: "\ea40"; +} + +.ni-money-coins::before { + content: "\ea41"; +} + +.ni-note-03::before { + content: "\ea42"; +} + +.ni-notification-70::before { + content: "\ea43"; +} + +.ni-palette::before { + content: "\ea44"; +} + +.ni-paper-diploma::before { + content: "\ea45"; +} + +.ni-pin-3::before { + content: "\ea46"; +} + +.ni-planet::before { + content: "\ea47"; +} + +.ni-ruler-pencil::before { + content: "\ea48"; +} + +.ni-satisfied::before { + content: "\ea49"; +} + +.ni-scissors::before { + content: "\ea4a"; +} + +.ni-send::before { + content: "\ea4b"; +} + +.ni-settings-gear-65::before { + content: "\ea4c"; +} + +.ni-settings::before { + content: "\ea4d"; +} + +.ni-single-02::before { + content: "\ea4e"; +} + +.ni-single-copy-04::before { + content: "\ea4f"; +} + +.ni-sound-wave::before { + content: "\ea50"; +} + +.ni-spaceship::before { + content: "\ea51"; +} + +.ni-square-pin::before { + content: "\ea52"; +} + +.ni-support-16::before { + content: "\ea53"; +} + +.ni-tablet-button::before { + content: "\ea54"; +} + +.ni-tag::before { + content: "\ea55"; +} + +.ni-tie-bow::before { + content: "\ea56"; +} + +.ni-time-alarm::before { + content: "\ea57"; +} + +.ni-trophy::before { + content: "\ea58"; +} + +.ni-tv-2::before { + content: "\ea59"; +} + +.ni-umbrella-13::before { + content: "\ea5a"; +} + +.ni-user-run::before { + content: "\ea5b"; +} + +.ni-vector::before { + content: "\ea5c"; +} + +.ni-watch-time::before { + content: "\ea5d"; +} + +.ni-world::before { + content: "\ea5e"; +} + +.ni-zoom-split-in::before { + content: "\ea5f"; +} + +.ni-collection::before { + content: "\ea60"; +} + +.ni-image::before { + content: "\ea61"; +} + +.ni-shop::before { + content: "\ea62"; +} + +.ni-ungroup::before { + content: "\ea63"; +} + +.ni-world-2::before { + content: "\ea64"; +} + +.ni-ui-04::before { + content: "\ea65"; +} + + +/* all icon font classes list here */ \ No newline at end of file diff --git a/website/public/assets/css/nucleo-svg.css b/website/public/assets/css/nucleo-svg.css new file mode 100644 index 0000000..c68c10e --- /dev/null +++ b/website/public/assets/css/nucleo-svg.css @@ -0,0 +1,135 @@ +/* Generated using nucleoapp.com */ +/* -------------------------------- + +Icon colors + +-------------------------------- */ + +.icon { + display: inline-block; + /* icon primary color */ + color: #111111; + height: 1em; + width: 1em; +} + +.icon use { + /* icon secondary color - fill */ + fill: #7ea6f6; +} + +.icon.icon-outline use { + /* icon secondary color - stroke */ + stroke: #7ea6f6; +} + +/* -------------------------------- + +Change icon size + +-------------------------------- */ + +.icon-xs { + height: 0.5em; + width: 0.5em; +} + +.icon-sm { + height: 0.8em; + width: 0.8em; +} + +.icon-lg { + height: 1.6em; + width: 1.6em; +} + +.icon-xl { + height: 2em; + width: 2em; +} + +/* -------------------------------- + +Align icon and text + +-------------------------------- */ + +.icon-text-aligner { + /* add this class to parent element that contains icon + text */ + display: flex; + align-items: center; +} + +.icon-text-aligner .icon { + color: inherit; + margin-right: 0.4em; +} + +.icon-text-aligner .icon use { + color: inherit; + fill: currentColor; +} + +.icon-text-aligner .icon.icon-outline use { + stroke: currentColor; +} + +/* -------------------------------- + +Icon reset values - used to enable color customizations + +-------------------------------- */ + +.icon { + fill: currentColor; + stroke: none; +} + +.icon.icon-outline { + fill: none; + stroke: currentColor; +} + +.icon use { + stroke: none; +} + +.icon.icon-outline use { + fill: none; +} + +/* -------------------------------- + +Stroke effects - Nucleo outline icons + +- 16px icons -> up to 1px stroke (16px outline icons do not support stroke changes) +- 24px, 32px icons -> up to 2px stroke +- 48px, 64px icons -> up to 4px stroke + +-------------------------------- */ + +.icon-outline.icon-stroke-1 { + stroke-width: 1px; +} + +.icon-outline.icon-stroke-2 { + stroke-width: 2px; +} + +.icon-outline.icon-stroke-3 { + stroke-width: 3px; +} + +.icon-outline.icon-stroke-4 { + stroke-width: 4px; +} + +.icon-outline.icon-stroke-1 use, +.icon-outline.icon-stroke-3 use { + -webkit-transform: translateX(0.5px) translateY(0.5px); + -moz-transform: translateX(0.5px) translateY(0.5px); + -ms-transform: translateX(0.5px) translateY(0.5px); + -o-transform: translateX(0.5px) translateY(0.5px); + transform: translateX(0.5px) translateY(0.5px); +} \ No newline at end of file diff --git a/website/public/assets/css/soft-ui-dashboard.css b/website/public/assets/css/soft-ui-dashboard.css new file mode 100644 index 0000000..4fc577b --- /dev/null +++ b/website/public/assets/css/soft-ui-dashboard.css @@ -0,0 +1,26 @@ +@charset "UTF-8"; +/*! + * Bootstrap v5.0.2 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */:root{--bs-blue:#63b3ed;--bs-indigo:#596cff;--bs-purple:#6f42c1;--bs-pink:#d63384;--bs-red:#f56565;--bs-orange:#fd7e14;--bs-yellow:#fbd38d;--bs-green:#81e6d9;--bs-teal:#20c997;--bs-cyan:#0dcaf0;--bs-gray:#6c757d;--bs-gray-dark:#343a40;--bs-primary:#cb0c9f;--bs-secondary:#8392ab;--bs-success:#82d616;--bs-info:#17c1e8;--bs-warning:#fbcf33;--bs-danger:#ea0606;--bs-light:#e9ecef;--bs-dark:#344767;--bs-white:#fff;--bs-font-sans-serif:"Open Sans";--bs-font-monospace:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace;--bs-gradient:linear-gradient(180deg,hsla(0,0%,100%,.15),hsla(0,0%,100%,0))}*,:after,:before{box-sizing:border-box}@media (prefers-reduced-motion:no-preference){:root{scroll-behavior:smooth}}body{-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0);background-color:#fff;color:#67748e;font-family:var(--bs-font-sans-serif);font-size:1rem;line-height:1.5;margin:0}hr{background-color:currentColor;border:0;color:inherit;margin:1rem 0;opacity:.25}hr:not([size]){height:1px}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{color:#344767;font-weight:400;line-height:1.2;margin-bottom:.5rem;margin-top:0}.h1,h1{font-size:calc(1.425rem + 2.1vw)}@media (min-width:1200px){.h1,h1{font-size:3rem}}.h2,h2{font-size:calc(1.35rem + 1.2vw)}@media (min-width:1200px){.h2,h2{font-size:2.25rem}}.h3,h3{font-size:calc(1.3125rem + .75vw)}@media (min-width:1200px){.h3,h3{font-size:1.875rem}}.h4,h4{font-size:calc(1.275rem + .3vw)}@media (min-width:1200px){.h4,h4{font-size:1.5rem}}p{margin-bottom:1rem;margin-top:0}abbr[data-bs-original-title],abbr[title]{cursor:help;-webkit-text-decoration:underline dotted;text-decoration:underline dotted;-webkit-text-decoration-skip-ink:none;text-decoration-skip-ink:none}address{font-style:normal;line-height:inherit;margin-bottom:1rem}ol,ul{padding-left:2rem}dl,ol,ul{margin-bottom:1rem;margin-top:0}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:600}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem}b,strong{font-weight:700}.small,small{font-size:.875em}.mark,mark{background-color:#fcf8e3;padding:.2em}sub,sup{font-size:.75em;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#cb0c9f}a,a:hover{text-decoration:none}a:hover{color:#830866}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}code,kbd,pre,samp{direction:ltr;font-family:var(--bs-font-monospace);font-size:1em;unicode-bidi:bidi-override}pre{display:block;font-size:.875em;margin-bottom:1rem;margin-top:0;overflow:auto}pre code{color:inherit;font-size:inherit;word-break:normal}code{word-wrap:break-word;color:#d63384;font-size:.875em}a>code{color:inherit}kbd{background-color:#212529;border-radius:.25rem;color:#fff;font-size:.875em;padding:.2rem .4rem}kbd kbd{font-size:1em;font-weight:600;padding:0}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{border-collapse:collapse;caption-side:bottom}caption{color:#6c757d;padding-bottom:.5rem;padding-top:.5rem;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}tbody,td,tfoot,th,thead,tr{border:0 solid;border-color:inherit}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}button,input,optgroup,select,textarea{font-family:inherit;font-size:inherit;line-height:inherit;margin:0}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled),button:not(:disabled){cursor:pointer}::-moz-focus-inner{border-style:none;padding:0}textarea{resize:vertical}fieldset{border:0;margin:0;min-width:0;padding:0}legend{float:left;font-size:calc(1.275rem + .3vw);line-height:inherit;margin-bottom:.5rem;padding:0;width:100%}@media (min-width:1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-text,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}output{display:inline-block}iframe{border:0}summary{cursor:pointer;display:list-item}progress{vertical-align:baseline}[hidden]{display:none!important}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media (min-width:1200px){.display-6{font-size:2.5rem}}.list-inline,.list-unstyled{list-style:none;padding-left:0}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:.875em;text-transform:uppercase}.blockquote{font-size:1.25rem;margin-bottom:1rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{color:#6c757d;font-size:.875em;margin-bottom:1rem;margin-top:-1rem}.blockquote-footer:before{content:"— "}.img-fluid,.img-thumbnail{height:auto;max-width:100%}.img-thumbnail{background-color:#fff;border:1px solid #dee2e6;border-radius:.5rem;padding:.25rem}.figure{display:inline-block}.figure-img{line-height:1;margin-bottom:.5rem}.figure-caption{color:#6c757d;font-size:.875em}.container,.container-fluid,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{margin-left:auto;margin-right:auto;padding-left:var(--bs-gutter-x,1.5rem);padding-right:var(--bs-gutter-x,1.5rem);width:100%}@media (min-width:576px){.container,.container-sm{max-width:540px}}@media (min-width:768px){.container,.container-md,.container-sm{max-width:720px}}@media (min-width:992px){.container,.container-lg,.container-md,.container-sm{max-width:960px}}@media (min-width:1200px){.container,.container-lg,.container-md,.container-sm,.container-xl{max-width:1140px}}@media (min-width:1400px){.container,.container-lg,.container-md,.container-sm,.container-xl,.container-xxl{max-width:1320px}}.row{--bs-gutter-x:1.5rem;--bs-gutter-y:0;display:flex;flex-wrap:wrap;margin-left:calc(var(--bs-gutter-x)*-.5);margin-right:calc(var(--bs-gutter-x)*-.5);margin-top:calc(var(--bs-gutter-y)*-1)}.row>*{flex-shrink:0;margin-top:var(--bs-gutter-y);max-width:100%;padding-left:calc(var(--bs-gutter-x)*.5);padding-right:calc(var(--bs-gutter-x)*.5);width:100%}.col{flex:1 0 0%}.row-cols-auto>*{flex:0 0 auto;width:auto}.row-cols-1>*{flex:0 0 auto;width:100%}.row-cols-2>*{flex:0 0 auto;width:50%}.row-cols-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-4>*{flex:0 0 auto;width:25%}.row-cols-5>*{flex:0 0 auto;width:20%}.row-cols-6>*{flex:0 0 auto;width:16.6666666667%}@media (min-width:576px){.col-sm{flex:1 0 0%}.row-cols-sm-auto>*{flex:0 0 auto;width:auto}.row-cols-sm-1>*{flex:0 0 auto;width:100%}.row-cols-sm-2>*{flex:0 0 auto;width:50%}.row-cols-sm-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-sm-4>*{flex:0 0 auto;width:25%}.row-cols-sm-5>*{flex:0 0 auto;width:20%}.row-cols-sm-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:768px){.col-md{flex:1 0 0%}.row-cols-md-auto>*{flex:0 0 auto;width:auto}.row-cols-md-1>*{flex:0 0 auto;width:100%}.row-cols-md-2>*{flex:0 0 auto;width:50%}.row-cols-md-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-md-4>*{flex:0 0 auto;width:25%}.row-cols-md-5>*{flex:0 0 auto;width:20%}.row-cols-md-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:992px){.col-lg{flex:1 0 0%}.row-cols-lg-auto>*{flex:0 0 auto;width:auto}.row-cols-lg-1>*{flex:0 0 auto;width:100%}.row-cols-lg-2>*{flex:0 0 auto;width:50%}.row-cols-lg-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-lg-4>*{flex:0 0 auto;width:25%}.row-cols-lg-5>*{flex:0 0 auto;width:20%}.row-cols-lg-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1200px){.col-xl{flex:1 0 0%}.row-cols-xl-auto>*{flex:0 0 auto;width:auto}.row-cols-xl-1>*{flex:0 0 auto;width:100%}.row-cols-xl-2>*{flex:0 0 auto;width:50%}.row-cols-xl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xl-4>*{flex:0 0 auto;width:25%}.row-cols-xl-5>*{flex:0 0 auto;width:20%}.row-cols-xl-6>*{flex:0 0 auto;width:16.6666666667%}}@media (min-width:1400px){.col-xxl{flex:1 0 0%}.row-cols-xxl-auto>*{flex:0 0 auto;width:auto}.row-cols-xxl-1>*{flex:0 0 auto;width:100%}.row-cols-xxl-2>*{flex:0 0 auto;width:50%}.row-cols-xxl-3>*{flex:0 0 auto;width:33.3333333333%}.row-cols-xxl-4>*{flex:0 0 auto;width:25%}.row-cols-xxl-5>*{flex:0 0 auto;width:20%}.row-cols-xxl-6>*{flex:0 0 auto;width:16.6666666667%}}.col-auto{flex:0 0 auto;width:auto}.col-1{flex:0 0 auto;width:8.33333333%}.col-2{flex:0 0 auto;width:16.66666667%}.col-3{flex:0 0 auto;width:25%}.col-4{flex:0 0 auto;width:33.33333333%}.col-5{flex:0 0 auto;width:41.66666667%}.col-6{flex:0 0 auto;width:50%}.col-7{flex:0 0 auto;width:58.33333333%}.col-8{flex:0 0 auto;width:66.66666667%}.col-9{flex:0 0 auto;width:75%}.col-10{flex:0 0 auto;width:83.33333333%}.col-11{flex:0 0 auto;width:91.66666667%}.col-12{flex:0 0 auto;width:100%}.offset-1{margin-left:8.33333333%}.offset-2{margin-left:16.66666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333333%}.offset-5{margin-left:41.66666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333333%}.offset-8{margin-left:66.66666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333333%}.offset-11{margin-left:91.66666667%}.g-0,.gx-0{--bs-gutter-x:0}.g-0,.gy-0{--bs-gutter-y:0}.g-1,.gx-1{--bs-gutter-x:0.25rem}.g-1,.gy-1{--bs-gutter-y:0.25rem}.g-2,.gx-2{--bs-gutter-x:0.5rem}.g-2,.gy-2{--bs-gutter-y:0.5rem}.g-3,.gx-3{--bs-gutter-x:1rem}.g-3,.gy-3{--bs-gutter-y:1rem}.g-4,.gx-4{--bs-gutter-x:1.5rem}.g-4,.gy-4{--bs-gutter-y:1.5rem}.g-5,.gx-5{--bs-gutter-x:3rem}.g-5,.gy-5{--bs-gutter-y:3rem}.g-6,.gx-6{--bs-gutter-x:4rem}.g-6,.gy-6{--bs-gutter-y:4rem}.g-7,.gx-7{--bs-gutter-x:6rem}.g-7,.gy-7{--bs-gutter-y:6rem}.g-8,.gx-8{--bs-gutter-x:8rem}.g-8,.gy-8{--bs-gutter-y:8rem}.g-9,.gx-9{--bs-gutter-x:10rem}.g-9,.gy-9{--bs-gutter-y:10rem}.g-10,.gx-10{--bs-gutter-x:12rem}.g-10,.gy-10{--bs-gutter-y:12rem}.g-11,.gx-11{--bs-gutter-x:14rem}.g-11,.gy-11{--bs-gutter-y:14rem}.g-12,.gx-12{--bs-gutter-x:16rem}.g-12,.gy-12{--bs-gutter-y:16rem}@media (min-width:576px){.col-sm-auto{flex:0 0 auto;width:auto}.col-sm-1{flex:0 0 auto;width:8.33333333%}.col-sm-2{flex:0 0 auto;width:16.66666667%}.col-sm-3{flex:0 0 auto;width:25%}.col-sm-4{flex:0 0 auto;width:33.33333333%}.col-sm-5{flex:0 0 auto;width:41.66666667%}.col-sm-6{flex:0 0 auto;width:50%}.col-sm-7{flex:0 0 auto;width:58.33333333%}.col-sm-8{flex:0 0 auto;width:66.66666667%}.col-sm-9{flex:0 0 auto;width:75%}.col-sm-10{flex:0 0 auto;width:83.33333333%}.col-sm-11{flex:0 0 auto;width:91.66666667%}.col-sm-12{flex:0 0 auto;width:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333333%}.offset-sm-2{margin-left:16.66666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333333%}.offset-sm-5{margin-left:41.66666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333333%}.offset-sm-8{margin-left:66.66666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333333%}.offset-sm-11{margin-left:91.66666667%}.g-sm-0,.gx-sm-0{--bs-gutter-x:0}.g-sm-0,.gy-sm-0{--bs-gutter-y:0}.g-sm-1,.gx-sm-1{--bs-gutter-x:0.25rem}.g-sm-1,.gy-sm-1{--bs-gutter-y:0.25rem}.g-sm-2,.gx-sm-2{--bs-gutter-x:0.5rem}.g-sm-2,.gy-sm-2{--bs-gutter-y:0.5rem}.g-sm-3,.gx-sm-3{--bs-gutter-x:1rem}.g-sm-3,.gy-sm-3{--bs-gutter-y:1rem}.g-sm-4,.gx-sm-4{--bs-gutter-x:1.5rem}.g-sm-4,.gy-sm-4{--bs-gutter-y:1.5rem}.g-sm-5,.gx-sm-5{--bs-gutter-x:3rem}.g-sm-5,.gy-sm-5{--bs-gutter-y:3rem}.g-sm-6,.gx-sm-6{--bs-gutter-x:4rem}.g-sm-6,.gy-sm-6{--bs-gutter-y:4rem}.g-sm-7,.gx-sm-7{--bs-gutter-x:6rem}.g-sm-7,.gy-sm-7{--bs-gutter-y:6rem}.g-sm-8,.gx-sm-8{--bs-gutter-x:8rem}.g-sm-8,.gy-sm-8{--bs-gutter-y:8rem}.g-sm-9,.gx-sm-9{--bs-gutter-x:10rem}.g-sm-9,.gy-sm-9{--bs-gutter-y:10rem}.g-sm-10,.gx-sm-10{--bs-gutter-x:12rem}.g-sm-10,.gy-sm-10{--bs-gutter-y:12rem}.g-sm-11,.gx-sm-11{--bs-gutter-x:14rem}.g-sm-11,.gy-sm-11{--bs-gutter-y:14rem}.g-sm-12,.gx-sm-12{--bs-gutter-x:16rem}.g-sm-12,.gy-sm-12{--bs-gutter-y:16rem}}@media (min-width:768px){.col-md-auto{flex:0 0 auto;width:auto}.col-md-1{flex:0 0 auto;width:8.33333333%}.col-md-2{flex:0 0 auto;width:16.66666667%}.col-md-3{flex:0 0 auto;width:25%}.col-md-4{flex:0 0 auto;width:33.33333333%}.col-md-5{flex:0 0 auto;width:41.66666667%}.col-md-6{flex:0 0 auto;width:50%}.col-md-7{flex:0 0 auto;width:58.33333333%}.col-md-8{flex:0 0 auto;width:66.66666667%}.col-md-9{flex:0 0 auto;width:75%}.col-md-10{flex:0 0 auto;width:83.33333333%}.col-md-11{flex:0 0 auto;width:91.66666667%}.col-md-12{flex:0 0 auto;width:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333333%}.offset-md-2{margin-left:16.66666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333333%}.offset-md-5{margin-left:41.66666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333333%}.offset-md-8{margin-left:66.66666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333333%}.offset-md-11{margin-left:91.66666667%}.g-md-0,.gx-md-0{--bs-gutter-x:0}.g-md-0,.gy-md-0{--bs-gutter-y:0}.g-md-1,.gx-md-1{--bs-gutter-x:0.25rem}.g-md-1,.gy-md-1{--bs-gutter-y:0.25rem}.g-md-2,.gx-md-2{--bs-gutter-x:0.5rem}.g-md-2,.gy-md-2{--bs-gutter-y:0.5rem}.g-md-3,.gx-md-3{--bs-gutter-x:1rem}.g-md-3,.gy-md-3{--bs-gutter-y:1rem}.g-md-4,.gx-md-4{--bs-gutter-x:1.5rem}.g-md-4,.gy-md-4{--bs-gutter-y:1.5rem}.g-md-5,.gx-md-5{--bs-gutter-x:3rem}.g-md-5,.gy-md-5{--bs-gutter-y:3rem}.g-md-6,.gx-md-6{--bs-gutter-x:4rem}.g-md-6,.gy-md-6{--bs-gutter-y:4rem}.g-md-7,.gx-md-7{--bs-gutter-x:6rem}.g-md-7,.gy-md-7{--bs-gutter-y:6rem}.g-md-8,.gx-md-8{--bs-gutter-x:8rem}.g-md-8,.gy-md-8{--bs-gutter-y:8rem}.g-md-9,.gx-md-9{--bs-gutter-x:10rem}.g-md-9,.gy-md-9{--bs-gutter-y:10rem}.g-md-10,.gx-md-10{--bs-gutter-x:12rem}.g-md-10,.gy-md-10{--bs-gutter-y:12rem}.g-md-11,.gx-md-11{--bs-gutter-x:14rem}.g-md-11,.gy-md-11{--bs-gutter-y:14rem}.g-md-12,.gx-md-12{--bs-gutter-x:16rem}.g-md-12,.gy-md-12{--bs-gutter-y:16rem}}@media (min-width:992px){.col-lg-auto{flex:0 0 auto;width:auto}.col-lg-1{flex:0 0 auto;width:8.33333333%}.col-lg-2{flex:0 0 auto;width:16.66666667%}.col-lg-3{flex:0 0 auto;width:25%}.col-lg-4{flex:0 0 auto;width:33.33333333%}.col-lg-5{flex:0 0 auto;width:41.66666667%}.col-lg-6{flex:0 0 auto;width:50%}.col-lg-7{flex:0 0 auto;width:58.33333333%}.col-lg-8{flex:0 0 auto;width:66.66666667%}.col-lg-9{flex:0 0 auto;width:75%}.col-lg-10{flex:0 0 auto;width:83.33333333%}.col-lg-11{flex:0 0 auto;width:91.66666667%}.col-lg-12{flex:0 0 auto;width:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333333%}.offset-lg-2{margin-left:16.66666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333333%}.offset-lg-5{margin-left:41.66666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333333%}.offset-lg-8{margin-left:66.66666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333333%}.offset-lg-11{margin-left:91.66666667%}.g-lg-0,.gx-lg-0{--bs-gutter-x:0}.g-lg-0,.gy-lg-0{--bs-gutter-y:0}.g-lg-1,.gx-lg-1{--bs-gutter-x:0.25rem}.g-lg-1,.gy-lg-1{--bs-gutter-y:0.25rem}.g-lg-2,.gx-lg-2{--bs-gutter-x:0.5rem}.g-lg-2,.gy-lg-2{--bs-gutter-y:0.5rem}.g-lg-3,.gx-lg-3{--bs-gutter-x:1rem}.g-lg-3,.gy-lg-3{--bs-gutter-y:1rem}.g-lg-4,.gx-lg-4{--bs-gutter-x:1.5rem}.g-lg-4,.gy-lg-4{--bs-gutter-y:1.5rem}.g-lg-5,.gx-lg-5{--bs-gutter-x:3rem}.g-lg-5,.gy-lg-5{--bs-gutter-y:3rem}.g-lg-6,.gx-lg-6{--bs-gutter-x:4rem}.g-lg-6,.gy-lg-6{--bs-gutter-y:4rem}.g-lg-7,.gx-lg-7{--bs-gutter-x:6rem}.g-lg-7,.gy-lg-7{--bs-gutter-y:6rem}.g-lg-8,.gx-lg-8{--bs-gutter-x:8rem}.g-lg-8,.gy-lg-8{--bs-gutter-y:8rem}.g-lg-9,.gx-lg-9{--bs-gutter-x:10rem}.g-lg-9,.gy-lg-9{--bs-gutter-y:10rem}.g-lg-10,.gx-lg-10{--bs-gutter-x:12rem}.g-lg-10,.gy-lg-10{--bs-gutter-y:12rem}.g-lg-11,.gx-lg-11{--bs-gutter-x:14rem}.g-lg-11,.gy-lg-11{--bs-gutter-y:14rem}.g-lg-12,.gx-lg-12{--bs-gutter-x:16rem}.g-lg-12,.gy-lg-12{--bs-gutter-y:16rem}}@media (min-width:1200px){.col-xl-auto{flex:0 0 auto;width:auto}.col-xl-1{flex:0 0 auto;width:8.33333333%}.col-xl-2{flex:0 0 auto;width:16.66666667%}.col-xl-3{flex:0 0 auto;width:25%}.col-xl-4{flex:0 0 auto;width:33.33333333%}.col-xl-5{flex:0 0 auto;width:41.66666667%}.col-xl-6{flex:0 0 auto;width:50%}.col-xl-7{flex:0 0 auto;width:58.33333333%}.col-xl-8{flex:0 0 auto;width:66.66666667%}.col-xl-9{flex:0 0 auto;width:75%}.col-xl-10{flex:0 0 auto;width:83.33333333%}.col-xl-11{flex:0 0 auto;width:91.66666667%}.col-xl-12{flex:0 0 auto;width:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333333%}.offset-xl-2{margin-left:16.66666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333333%}.offset-xl-5{margin-left:41.66666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333333%}.offset-xl-8{margin-left:66.66666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333333%}.offset-xl-11{margin-left:91.66666667%}.g-xl-0,.gx-xl-0{--bs-gutter-x:0}.g-xl-0,.gy-xl-0{--bs-gutter-y:0}.g-xl-1,.gx-xl-1{--bs-gutter-x:0.25rem}.g-xl-1,.gy-xl-1{--bs-gutter-y:0.25rem}.g-xl-2,.gx-xl-2{--bs-gutter-x:0.5rem}.g-xl-2,.gy-xl-2{--bs-gutter-y:0.5rem}.g-xl-3,.gx-xl-3{--bs-gutter-x:1rem}.g-xl-3,.gy-xl-3{--bs-gutter-y:1rem}.g-xl-4,.gx-xl-4{--bs-gutter-x:1.5rem}.g-xl-4,.gy-xl-4{--bs-gutter-y:1.5rem}.g-xl-5,.gx-xl-5{--bs-gutter-x:3rem}.g-xl-5,.gy-xl-5{--bs-gutter-y:3rem}.g-xl-6,.gx-xl-6{--bs-gutter-x:4rem}.g-xl-6,.gy-xl-6{--bs-gutter-y:4rem}.g-xl-7,.gx-xl-7{--bs-gutter-x:6rem}.g-xl-7,.gy-xl-7{--bs-gutter-y:6rem}.g-xl-8,.gx-xl-8{--bs-gutter-x:8rem}.g-xl-8,.gy-xl-8{--bs-gutter-y:8rem}.g-xl-9,.gx-xl-9{--bs-gutter-x:10rem}.g-xl-9,.gy-xl-9{--bs-gutter-y:10rem}.g-xl-10,.gx-xl-10{--bs-gutter-x:12rem}.g-xl-10,.gy-xl-10{--bs-gutter-y:12rem}.g-xl-11,.gx-xl-11{--bs-gutter-x:14rem}.g-xl-11,.gy-xl-11{--bs-gutter-y:14rem}.g-xl-12,.gx-xl-12{--bs-gutter-x:16rem}.g-xl-12,.gy-xl-12{--bs-gutter-y:16rem}}@media (min-width:1400px){.col-xxl-auto{flex:0 0 auto;width:auto}.col-xxl-1{flex:0 0 auto;width:8.33333333%}.col-xxl-2{flex:0 0 auto;width:16.66666667%}.col-xxl-3{flex:0 0 auto;width:25%}.col-xxl-4{flex:0 0 auto;width:33.33333333%}.col-xxl-5{flex:0 0 auto;width:41.66666667%}.col-xxl-6{flex:0 0 auto;width:50%}.col-xxl-7{flex:0 0 auto;width:58.33333333%}.col-xxl-8{flex:0 0 auto;width:66.66666667%}.col-xxl-9{flex:0 0 auto;width:75%}.col-xxl-10{flex:0 0 auto;width:83.33333333%}.col-xxl-11{flex:0 0 auto;width:91.66666667%}.col-xxl-12{flex:0 0 auto;width:100%}.offset-xxl-0{margin-left:0}.offset-xxl-1{margin-left:8.33333333%}.offset-xxl-2{margin-left:16.66666667%}.offset-xxl-3{margin-left:25%}.offset-xxl-4{margin-left:33.33333333%}.offset-xxl-5{margin-left:41.66666667%}.offset-xxl-6{margin-left:50%}.offset-xxl-7{margin-left:58.33333333%}.offset-xxl-8{margin-left:66.66666667%}.offset-xxl-9{margin-left:75%}.offset-xxl-10{margin-left:83.33333333%}.offset-xxl-11{margin-left:91.66666667%}.g-xxl-0,.gx-xxl-0{--bs-gutter-x:0}.g-xxl-0,.gy-xxl-0{--bs-gutter-y:0}.g-xxl-1,.gx-xxl-1{--bs-gutter-x:0.25rem}.g-xxl-1,.gy-xxl-1{--bs-gutter-y:0.25rem}.g-xxl-2,.gx-xxl-2{--bs-gutter-x:0.5rem}.g-xxl-2,.gy-xxl-2{--bs-gutter-y:0.5rem}.g-xxl-3,.gx-xxl-3{--bs-gutter-x:1rem}.g-xxl-3,.gy-xxl-3{--bs-gutter-y:1rem}.g-xxl-4,.gx-xxl-4{--bs-gutter-x:1.5rem}.g-xxl-4,.gy-xxl-4{--bs-gutter-y:1.5rem}.g-xxl-5,.gx-xxl-5{--bs-gutter-x:3rem}.g-xxl-5,.gy-xxl-5{--bs-gutter-y:3rem}.g-xxl-6,.gx-xxl-6{--bs-gutter-x:4rem}.g-xxl-6,.gy-xxl-6{--bs-gutter-y:4rem}.g-xxl-7,.gx-xxl-7{--bs-gutter-x:6rem}.g-xxl-7,.gy-xxl-7{--bs-gutter-y:6rem}.g-xxl-8,.gx-xxl-8{--bs-gutter-x:8rem}.g-xxl-8,.gy-xxl-8{--bs-gutter-y:8rem}.g-xxl-9,.gx-xxl-9{--bs-gutter-x:10rem}.g-xxl-9,.gy-xxl-9{--bs-gutter-y:10rem}.g-xxl-10,.gx-xxl-10{--bs-gutter-x:12rem}.g-xxl-10,.gy-xxl-10{--bs-gutter-y:12rem}.g-xxl-11,.gx-xxl-11{--bs-gutter-x:14rem}.g-xxl-11,.gy-xxl-11{--bs-gutter-y:14rem}.g-xxl-12,.gx-xxl-12{--bs-gutter-x:16rem}.g-xxl-12,.gy-xxl-12{--bs-gutter-y:16rem}}.table{--bs-table-bg:transparent;--bs-table-accent-bg:transparent;--bs-table-striped-color:#67748e;--bs-table-striped-bg:rgba(0,0,0,.05);--bs-table-active-color:#67748e;--bs-table-active-bg:rgba(0,0,0,.1);--bs-table-hover-color:#67748e;--bs-table-hover-bg:rgba(0,0,0,.075);border-color:#e9ecef;color:#67748e;margin-bottom:1rem;vertical-align:top;width:100%}.table>:not(caption)>*>*{background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg);padding:.5rem}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:last-child)>:last-child>*{border-bottom-color:currentColor}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-striped>tbody>tr:nth-of-type(odd){--bs-table-accent-bg:var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg:var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover{--bs-table-accent-bg:var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg:#f5ceec;--bs-table-striped-bg:#e9c4e0;--bs-table-striped-color:#000;--bs-table-active-bg:#ddb9d4;--bs-table-active-color:#000;--bs-table-hover-bg:#e3bfda;--bs-table-hover-color:#000;border-color:#ddb9d4;color:#000}.table-secondary{--bs-table-bg:#e6e9ee;--bs-table-striped-bg:#dbdde2;--bs-table-striped-color:#000;--bs-table-active-bg:#cfd2d6;--bs-table-active-color:#000;--bs-table-hover-bg:#d5d8dc;--bs-table-hover-color:#000;border-color:#cfd2d6;color:#000}.table-success{--bs-table-bg:#e6f7d0;--bs-table-striped-bg:#dbebc6;--bs-table-striped-color:#000;--bs-table-active-bg:#cfdebb;--bs-table-active-color:#000;--bs-table-hover-bg:#d5e4c0;--bs-table-hover-color:#000;border-color:#cfdebb;color:#000}.table-info{--bs-table-bg:#d1f3fa;--bs-table-striped-bg:#c7e7ee;--bs-table-striped-color:#000;--bs-table-active-bg:#bcdbe1;--bs-table-active-color:#000;--bs-table-hover-bg:#c1e1e7;--bs-table-hover-color:#000;border-color:#bcdbe1;color:#000}.table-warning{--bs-table-bg:#fef5d6;--bs-table-striped-bg:#f1e9cb;--bs-table-striped-color:#000;--bs-table-active-bg:#e5ddc1;--bs-table-active-color:#000;--bs-table-hover-bg:#ebe3c6;--bs-table-hover-color:#000;border-color:#e5ddc1;color:#000}.table-danger{--bs-table-bg:#fbcdcd;--bs-table-striped-bg:#eec3c3;--bs-table-striped-color:#000;--bs-table-active-bg:#e2b9b9;--bs-table-active-color:#000;--bs-table-hover-bg:#e8bebe;--bs-table-hover-color:#000;border-color:#e2b9b9;color:#000}.table-light{--bs-table-bg:#e9ecef;--bs-table-striped-bg:#dde0e3;--bs-table-striped-color:#000;--bs-table-active-bg:#d2d4d7;--bs-table-active-color:#000;--bs-table-hover-bg:#d8dadd;--bs-table-hover-color:#000;border-color:#d2d4d7;color:#000}.table-dark{--bs-table-bg:#344767;--bs-table-striped-bg:#3e506f;--bs-table-striped-color:#fff;--bs-table-active-bg:#485976;--bs-table-active-color:#fff;--bs-table-hover-bg:#435572;--bs-table-hover-color:#fff;border-color:#485976;color:#fff}.table-responsive{-webkit-overflow-scrolling:touch;overflow-x:auto}@media (max-width:575.98px){.table-responsive-sm{-webkit-overflow-scrolling:touch;overflow-x:auto}}@media (max-width:767.98px){.table-responsive-md{-webkit-overflow-scrolling:touch;overflow-x:auto}}@media (max-width:991.98px){.table-responsive-lg{-webkit-overflow-scrolling:touch;overflow-x:auto}}@media (max-width:1199.98px){.table-responsive-xl{-webkit-overflow-scrolling:touch;overflow-x:auto}}@media (max-width:1399.98px){.table-responsive-xxl{-webkit-overflow-scrolling:touch;overflow-x:auto}}.form-label{font-size:.75rem;margin-bottom:.5rem}.col-form-label,.form-label{color:#344767;font-weight:700}.col-form-label{font-size:inherit;line-height:1.4rem;margin-bottom:0;padding-bottom:calc(.5rem + 1px);padding-top:calc(.5rem + 1px)}.col-form-label-lg{font-size:.875rem;padding-bottom:calc(.75rem + 1px);padding-top:calc(.75rem + 1px)}.col-form-label-sm{font-size:.75rem;padding-bottom:calc(.25rem + 1px);padding-top:calc(.25rem + 1px)}.form-text{color:#6c757d;font-size:.875em;margin-top:.25rem}.form-control{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-clip:padding-box;background-color:#fff;border:1px solid #d2d6da;border-radius:.5rem;color:#495057;display:block;font-size:.875rem;font-weight:400;line-height:1.4rem;padding:.5rem .75rem;transition:box-shadow .15s ease,border-color .15s ease;width:100%}@media (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{background-color:#fff;border-color:#e293d3;box-shadow:0 0 0 2px #e9aede;color:#495057;outline:0}.form-control::-webkit-date-and-time-value{height:1.4rem}.form-control::-moz-placeholder{color:#adb5bd;opacity:1}.form-control:-ms-input-placeholder{color:#adb5bd;opacity:1}.form-control::placeholder{color:#adb5bd;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{-webkit-margin-end:.75rem;background-color:#fff;border:0 solid;border-color:inherit;border-inline-end-width:1px;border-radius:0;color:#495057;margin:-.5rem -.75rem;margin-inline-end:.75rem;padding:.5rem .75rem;pointer-events:none;transition:all .15s ease-in}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#f2f2f2}.form-control::-webkit-file-upload-button{-webkit-margin-end:.75rem;background-color:#fff;border:0 solid;border-color:inherit;border-inline-end-width:1px;border-radius:0;color:#495057;margin:-.5rem -.75rem;margin-inline-end:.75rem;padding:.5rem .75rem;pointer-events:none;-webkit-transition:all .15s ease-in;transition:all .15s ease-in}@media (prefers-reduced-motion:reduce){.form-control::-webkit-file-upload-button{-webkit-transition:none;transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#f2f2f2}.form-control-plaintext{background-color:transparent;border:solid transparent;border-width:1px 0;color:#344767;display:block;line-height:1.4rem;margin-bottom:0;padding:.5rem 0;width:100%}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-left:0;padding-right:0}.form-control-sm{border-radius:.5rem;font-size:.75rem;min-height:unset;padding:.25rem .75rem}.form-control-sm::file-selector-button{-webkit-margin-end:.75rem;margin:-.25rem -.75rem;margin-inline-end:.75rem;padding:.25rem .75rem}.form-control-sm::-webkit-file-upload-button{-webkit-margin-end:.75rem;margin:-.25rem -.75rem;margin-inline-end:.75rem;padding:.25rem .75rem}.form-control-lg{border-radius:.5rem;font-size:.875rem;min-height:unset;padding:.75rem}.form-control-lg::file-selector-button{-webkit-margin-end:.75rem;margin:-.75rem;margin-inline-end:.75rem;padding:.75rem}.form-control-lg::-webkit-file-upload-button{-webkit-margin-end:.75rem;margin:-.75rem;margin-inline-end:.75rem;padding:.75rem}textarea.form-control,textarea.form-control-lg,textarea.form-control-sm{min-height:unset}.form-control-color{height:auto;max-width:3rem;padding:.5rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{border-radius:.5rem;height:1.4rem}.form-control-color::-webkit-color-swatch{border-radius:.5rem;height:1.4rem}.form-select{-moz-padding-start:calc(.75rem - 3px);-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3E%3C/svg%3E");background-position:right .75rem center;background-repeat:no-repeat;background-size:16px 12px;border:1px solid #d2d6da;border-radius:.5rem;color:#495057;display:block;font-size:.875rem;font-weight:400;line-height:1.4rem;padding:.5rem 1rem .5rem .75rem;width:100%}@media (prefers-reduced-motion:reduce){.form-select{transition:none}}.form-select:focus{border-color:#e293d3;box-shadow:0 0 0 2px #e9aede;outline:0}.form-select[multiple],.form-select[size]:not([size="1"]){background-image:none;padding-right:.75rem}.form-select:disabled{background-color:#e9ecef;color:#6c757d}.form-select:-moz-focusring{color:transparent;text-shadow:0 0 0 #495057}.form-select-sm{font-size:.75rem;padding-bottom:.25rem;padding-left:.75rem;padding-top:.25rem}.form-select-lg{font-size:.875rem;padding-bottom:.75rem;padding-left:.75rem;padding-top:.75rem}.form-check{display:block;margin-bottom:.125rem;min-height:1.5rem;padding-left:1.73em}.form-check .form-check-input{float:left;margin-left:-1.73em}.form-check-input{color-adjust:exact;background-color:#fff;background-position:50%;background-repeat:no-repeat;background-size:contain;border:none;height:1.23em;margin-top:.135em;-webkit-print-color-adjust:exact;transition:background-color .25s ease,border-color .25s ease,background-position .15s ease-in-out,opacity .15s ease-out,box-shadow .15s ease-in-out;vertical-align:top;width:1.23em}@media (prefers-reduced-motion:reduce){.form-check-input{transition:none}}.form-check-input[type=checkbox]{border-radius:.35rem}.form-check-input[type=radio]{border-radius:50%}.form-check-input:active{filter:brightness(99%)}.form-check-input:focus{border-color:none;box-shadow:none;outline:0}.form-check-input:checked{background-color:transparent;border-color:transparent}.form-check-input:checked[type=checkbox],.form-check-input:checked[type=radio]{background-image:linear-gradient(310deg,#141727,#3a416f)}.form-check-input[type=checkbox]:indeterminate{background-color:#cb0c9f;background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3E%3Cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3E%3C/svg%3E");border-color:#cb0c9f}.form-check-input:disabled{filter:none;opacity:.5;pointer-events:none}.form-check-input:disabled~.form-check-label,.form-check-input[disabled]~.form-check-label{opacity:.5}.form-switch{padding-left:3rem}.form-switch .form-check-input{background-image:none;background-position:0;border-radius:2.5rem;margin-left:-3rem;transition:background-color .25s ease,border-color .25s ease,background-position .15s ease-in-out,opacity .15s ease-out,box-shadow .15s ease-in-out;width:2.5rem}@media (prefers-reduced-motion:reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:none}.form-switch .form-check-input:checked{background-image:none;background-position:100%}.form-check-inline{display:inline-block;margin-right:1rem}.btn-check{clip:rect(0,0,0,0);pointer-events:none;position:absolute}.btn-check:disabled+.btn,.btn-check[disabled]+.btn{filter:none;opacity:.65;pointer-events:none}.form-range{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:transparent;height:calc(1rem + 4px);padding:0;width:100%}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 2px #e9aede}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 2px #e9aede}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{-webkit-appearance:none;appearance:none;background-color:#cb0c9f;border:0;border-radius:1rem;height:1rem;margin-top:-.25rem;-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:1rem}@media (prefers-reduced-motion:reduce){.form-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#f891e1}.form-range::-webkit-slider-runnable-track{background-color:#dee2e6;border-color:transparent;border-radius:1rem;color:transparent;cursor:pointer;height:.5rem;width:100%}.form-range::-moz-range-thumb{-moz-appearance:none;appearance:none;background-color:#cb0c9f;border:0;border-radius:1rem;height:1rem;-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;width:1rem}@media (prefers-reduced-motion:reduce){.form-range::-moz-range-thumb{-moz-transition:none;transition:none}}.form-range::-moz-range-thumb:active{background-color:#f891e1}.form-range::-moz-range-track{background-color:#dee2e6;border-color:transparent;border-radius:1rem;color:transparent;cursor:pointer;height:.5rem;width:100%}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{border:1px solid transparent;height:100%;left:0;padding:1rem .75rem;pointer-events:none;position:absolute;top:0;transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media (prefers-reduced-motion:reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::-moz-placeholder{color:transparent}.form-floating>.form-control:-ms-input-placeholder{color:transparent}.form-floating>.form-control::placeholder{color:transparent}.form-floating>.form-control:not(:-moz-placeholder-shown){padding-bottom:.625rem;padding-top:1.625rem}.form-floating>.form-control:not(:-ms-input-placeholder){padding-bottom:.625rem;padding-top:1.625rem}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-bottom:.625rem;padding-top:1.625rem}.form-floating>.form-control:-webkit-autofill{padding-bottom:.625rem;padding-top:1.625rem}.form-floating>.form-select{padding-bottom:.625rem;padding-top:1.625rem}.form-floating>.form-control:not(:-moz-placeholder-shown)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:not(:-ms-input-placeholder)~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(.85) translateY(-.5rem) translateX(.15rem)}.input-group{align-items:stretch;display:flex;flex-wrap:wrap;position:relative;width:100%}.input-group>.form-control,.input-group>.form-select{flex:1 1 auto;min-width:0;position:relative;width:1%}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{align-items:center;background-color:#fff;border:1px solid #d2d6da;border-radius:.5rem;color:#344767;display:flex;font-size:.875rem;font-weight:400;line-height:1.4rem;padding:.5rem .75rem;text-align:center;white-space:nowrap}.input-group-lg>.btn,.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text{border-radius:.5rem;font-size:.875rem;padding:.75rem}.input-group-sm>.btn,.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text{border-radius:.5rem;font-size:.75rem;padding:.25rem .75rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:1.75rem}.input-group.has-validation>.dropdown-toggle:nth-last-child(n+4),.input-group.has-validation>:nth-last-child(n+3):not(.dropdown-toggle):not(.dropdown-menu),.input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-bottom-right-radius:0;border-top-right-radius:0}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){border-bottom-left-radius:0;border-top-left-radius:0;margin-left:-1px}.valid-feedback{color:#66d432;display:none;font-size:.875em;margin-top:.25rem;width:100%}.valid-tooltip{background-color:rgba(102,212,50,.9);border-radius:.5rem;color:#000;display:none;font-size:.875rem;margin-top:.1rem;max-width:100%;padding:.25rem .5rem;position:absolute;top:100%;z-index:5}.is-valid~.valid-feedback,.is-valid~.valid-tooltip,.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip{display:block}.form-control.is-valid,.was-validated .form-control:valid{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath fill='%2366d432' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E");background-position:right .75rem center;background-repeat:no-repeat;background-size:1rem 1rem;border-color:#66d432;padding-right:unset}.form-control.is-valid:focus,.was-validated .form-control:valid:focus{border-color:#66d432;box-shadow:0 0 0 2px rgba(102,212,50,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{background-position:top .75rem right .75rem;padding-right:unset}.form-select.is-valid,.was-validated .form-select:valid{border-color:#66d432}.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"],.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"]{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3E%3C/svg%3E"),url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 10 8'%3E%3Cpath fill='%2366d432' d='M2.3 6.73.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3E%3C/svg%3E");background-position:right .75rem center,center right 1.75rem;background-size:16px 12px,1rem 1rem;padding-right:2.875rem}.form-select.is-valid:focus,.was-validated .form-select:valid:focus{border-color:#66d432;box-shadow:0 0 0 2px rgba(102,212,50,.25)}.form-check-input.is-valid,.was-validated .form-check-input:valid{border-color:#66d432}.form-check-input.is-valid:checked,.was-validated .form-check-input:valid:checked{background-color:#66d432}.form-check-input.is-valid:focus,.was-validated .form-check-input:valid:focus{box-shadow:0 0 0 2px rgba(102,212,50,.25)}.form-check-input.is-valid~.form-check-label,.was-validated .form-check-input:valid~.form-check-label{color:#66d432}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.input-group .form-control.is-valid,.input-group .form-select.is-valid,.was-validated .input-group .form-control:valid,.was-validated .input-group .form-select:valid{z-index:1}.input-group .form-control.is-valid:focus,.input-group .form-select.is-valid:focus,.was-validated .input-group .form-control:valid:focus,.was-validated .input-group .form-select:valid:focus{z-index:3}.invalid-feedback{color:#fd5c70;display:none;font-size:.875em;margin-top:.25rem;width:100%}.invalid-tooltip{background-color:rgba(253,92,112,.9);border-radius:.5rem;color:#000;display:none;font-size:.875rem;margin-top:.1rem;max-width:100%;padding:.25rem .5rem;position:absolute;top:100%;z-index:5}.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip,.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip{display:block}.form-control.is-invalid,.was-validated .form-control:invalid{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23fd5c70'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23fd5c70' stroke='none'/%3E%3C/svg%3E");background-position:right .75rem center;background-repeat:no-repeat;background-size:1rem 1rem;border-color:#fd5c70;padding-right:unset}.form-control.is-invalid:focus,.was-validated .form-control:invalid:focus{border-color:#fd5c70;box-shadow:0 0 0 2px rgba(253,92,112,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{background-position:top .75rem right .75rem;padding-right:unset}.form-select.is-invalid,.was-validated .form-select:invalid{border-color:#fd5c70}.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"],.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"]{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath fill='none' stroke='%23343a40' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3E%3C/svg%3E"),url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' fill='none' stroke='%23fd5c70'%3E%3Ccircle cx='6' cy='6' r='4.5'/%3E%3Cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3E%3Ccircle cx='6' cy='8.2' r='.6' fill='%23fd5c70' stroke='none'/%3E%3C/svg%3E");background-position:right .75rem center,center right 1.75rem;background-size:16px 12px,1rem 1rem;padding-right:2.875rem}.form-select.is-invalid:focus,.was-validated .form-select:invalid:focus{border-color:#fd5c70;box-shadow:0 0 0 2px rgba(253,92,112,.25)}.form-check-input.is-invalid,.was-validated .form-check-input:invalid{border-color:#fd5c70}.form-check-input.is-invalid:checked,.was-validated .form-check-input:invalid:checked{background-color:#fd5c70}.form-check-input.is-invalid:focus,.was-validated .form-check-input:invalid:focus{box-shadow:0 0 0 2px rgba(253,92,112,.25)}.form-check-input.is-invalid~.form-check-label,.was-validated .form-check-input:invalid~.form-check-label{color:#fd5c70}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.input-group .form-control.is-invalid,.input-group .form-select.is-invalid,.was-validated .input-group .form-control:invalid,.was-validated .input-group .form-select:invalid{z-index:2}.input-group .form-control.is-invalid:focus,.input-group .form-select.is-invalid:focus,.was-validated .input-group .form-control:invalid:focus,.was-validated .input-group .form-select:invalid:focus{z-index:3}.btn{background-color:transparent;border:1px solid transparent;border-radius:.5rem;color:#67748e;cursor:pointer;display:inline-block;font-size:.75rem;font-weight:700;line-height:1.4;padding:.75rem 1.5rem;text-align:center;transition:all .15s ease-in;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;vertical-align:middle}@media (prefers-reduced-motion:reduce){.btn{transition:none}}.btn:hover{color:#67748e}.btn-check:focus+.btn,.btn:focus{box-shadow:0 3px 5px -1px rgba(0,0,0,.09),0 2px 3px -1px rgba(0,0,0,.07);outline:0}.btn.disabled,.btn:disabled,fieldset:disabled .btn{opacity:.65;pointer-events:none}.btn-primary{background-color:#cb0c9f;border-color:#cb0c9f;color:#fff}.btn-check:focus+.btn-primary,.btn-primary:focus,.btn-primary:hover{background-color:#ad0a87;border-color:#a20a7f;color:#fff}.btn-check:focus+.btn-primary,.btn-primary:focus{box-shadow:0 0 0 .2rem rgba(211,48,173,.5)}.btn-check:active+.btn-primary,.btn-check:checked+.btn-primary,.btn-primary.active,.btn-primary:active,.show>.btn-primary.dropdown-toggle{background-color:#a20a7f;border-color:#980977;color:#fff}.btn-check:active+.btn-primary:focus,.btn-check:checked+.btn-primary:focus,.btn-primary.active:focus,.btn-primary:active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(211,48,173,.5)}.btn-primary.disabled,.btn-primary:disabled{background-color:#cb0c9f;border-color:#cb0c9f;color:#fff}.btn-secondary{background-color:#8392ab;border-color:#8392ab;color:#000}.btn-check:focus+.btn-secondary,.btn-secondary:focus,.btn-secondary:hover{background-color:#96a2b8;border-color:#8f9db3;color:#000}.btn-check:focus+.btn-secondary,.btn-secondary:focus{box-shadow:0 0 0 .2rem rgba(111,124,145,.5)}.btn-check:active+.btn-secondary,.btn-check:checked+.btn-secondary,.btn-secondary.active,.btn-secondary:active,.show>.btn-secondary.dropdown-toggle{background-color:#9ca8bc;border-color:#8f9db3;color:#000}.btn-check:active+.btn-secondary:focus,.btn-check:checked+.btn-secondary:focus,.btn-secondary.active:focus,.btn-secondary:active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(111,124,145,.5)}.btn-secondary.disabled,.btn-secondary:disabled{background-color:#8392ab;border-color:#8392ab;color:#000}.btn-success{background-color:#82d616;border-color:#82d616;color:#000}.btn-check:focus+.btn-success,.btn-success:focus,.btn-success:hover{background-color:#95dc39;border-color:#8fda2d;color:#000}.btn-check:focus+.btn-success,.btn-success:focus{box-shadow:0 0 0 .2rem rgba(111,182,19,.5)}.btn-check:active+.btn-success,.btn-check:checked+.btn-success,.btn-success.active,.btn-success:active,.show>.btn-success.dropdown-toggle{background-color:#9bde45;border-color:#8fda2d;color:#000}.btn-check:active+.btn-success:focus,.btn-check:checked+.btn-success:focus,.btn-success.active:focus,.btn-success:active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(111,182,19,.5)}.btn-success.disabled,.btn-success:disabled{background-color:#82d616;border-color:#82d616;color:#000}.btn-info{background-color:#17c1e8;border-color:#17c1e8;color:#000}.btn-check:focus+.btn-info,.btn-info:focus,.btn-info:hover{background-color:#3acaeb;border-color:#2ec7ea;color:#000}.btn-check:focus+.btn-info,.btn-info:focus{box-shadow:0 0 0 .2rem rgba(20,164,197,.5)}.btn-check:active+.btn-info,.btn-check:checked+.btn-info,.btn-info.active,.btn-info:active,.show>.btn-info.dropdown-toggle{background-color:#45cded;border-color:#2ec7ea;color:#000}.btn-check:active+.btn-info:focus,.btn-check:checked+.btn-info:focus,.btn-info.active:focus,.btn-info:active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(20,164,197,.5)}.btn-info.disabled,.btn-info:disabled{background-color:#17c1e8;border-color:#17c1e8;color:#000}.btn-warning{background-color:#fbcf33;border-color:#fbcf33;color:#000}.btn-check:focus+.btn-warning,.btn-warning:focus,.btn-warning:hover{background-color:#fcd652;border-color:#fbd447;color:#000}.btn-check:focus+.btn-warning,.btn-warning:focus{box-shadow:0 0 0 .2rem rgba(213,176,43,.5)}.btn-check:active+.btn-warning,.btn-check:checked+.btn-warning,.btn-warning.active,.btn-warning:active,.show>.btn-warning.dropdown-toggle{background-color:#fcd95c;border-color:#fbd447;color:#000}.btn-check:active+.btn-warning:focus,.btn-check:checked+.btn-warning:focus,.btn-warning.active:focus,.btn-warning:active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(213,176,43,.5)}.btn-warning.disabled,.btn-warning:disabled{background-color:#fbcf33;border-color:#fbcf33;color:#000}.btn-danger{background-color:#ea0606;border-color:#ea0606;color:#fff}.btn-check:focus+.btn-danger,.btn-danger:focus,.btn-danger:hover{background-color:#c70505;border-color:#bb0505;color:#fff}.btn-check:focus+.btn-danger,.btn-danger:focus{box-shadow:0 0 0 .2rem rgba(237,43,43,.5)}.btn-check:active+.btn-danger,.btn-check:checked+.btn-danger,.btn-danger.active,.btn-danger:active,.show>.btn-danger.dropdown-toggle{background-color:#bb0505;border-color:#b00505;color:#fff}.btn-check:active+.btn-danger:focus,.btn-check:checked+.btn-danger:focus,.btn-danger.active:focus,.btn-danger:active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(237,43,43,.5)}.btn-danger.disabled,.btn-danger:disabled{background-color:#ea0606;border-color:#ea0606;color:#fff}.btn-light{background-color:#e9ecef;border-color:#e9ecef;color:#000}.btn-check:focus+.btn-light,.btn-light:focus,.btn-light:hover{background-color:#eceff1;border-color:#ebeef1;color:#000}.btn-check:focus+.btn-light,.btn-light:focus{box-shadow:0 0 0 .2rem hsla(204,5%,79%,.5)}.btn-check:active+.btn-light,.btn-check:checked+.btn-light,.btn-light.active,.btn-light:active,.show>.btn-light.dropdown-toggle{background-color:#edf0f2;border-color:#ebeef1;color:#000}.btn-check:active+.btn-light:focus,.btn-check:checked+.btn-light:focus,.btn-light.active:focus,.btn-light:active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .2rem hsla(204,5%,79%,.5)}.btn-light.disabled,.btn-light:disabled{background-color:#e9ecef;border-color:#e9ecef;color:#000}.btn-dark{background-color:#344767;border-color:#344767;color:#fff}.btn-check:focus+.btn-dark,.btn-dark:focus,.btn-dark:hover{background-color:#2c3c58;border-color:#2a3952;color:#fff}.btn-check:focus+.btn-dark,.btn-dark:focus{box-shadow:0 0 0 .2rem rgba(82,99,126,.5)}.btn-check:active+.btn-dark,.btn-check:checked+.btn-dark,.btn-dark.active,.btn-dark:active,.show>.btn-dark.dropdown-toggle{background-color:#2a3952;border-color:#27354d;color:#fff}.btn-check:active+.btn-dark:focus,.btn-check:checked+.btn-dark:focus,.btn-dark.active:focus,.btn-dark:active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .2rem rgba(82,99,126,.5)}.btn-dark.disabled,.btn-dark:disabled{background-color:#344767;border-color:#344767;color:#fff}.btn-check:focus+.btn-white,.btn-white,.btn-white:focus,.btn-white:hover{background-color:#fff;border-color:#fff;color:#000}.btn-check:focus+.btn-white,.btn-white:focus{box-shadow:0 0 0 .2rem hsla(0,0%,85%,.5)}.btn-check:active+.btn-white,.btn-check:checked+.btn-white,.btn-white.active,.btn-white:active,.show>.btn-white.dropdown-toggle{background-color:#fff;border-color:#fff;color:#000}.btn-check:active+.btn-white:focus,.btn-check:checked+.btn-white:focus,.btn-white.active:focus,.btn-white:active:focus,.show>.btn-white.dropdown-toggle:focus{box-shadow:0 0 0 .2rem hsla(0,0%,85%,.5)}.btn-white.disabled,.btn-white:disabled{background-color:#fff;border-color:#fff;color:#000}.btn-outline-primary{border-color:#cb0c9f;color:#cb0c9f}.btn-outline-primary:hover{background-color:#cb0c9f;border-color:#cb0c9f;color:#fff}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .2rem rgba(203,12,159,.5)}.btn-check:active+.btn-outline-primary,.btn-check:checked+.btn-outline-primary,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show,.btn-outline-primary:active{background-color:#cb0c9f;border-color:#cb0c9f;color:#fff}.btn-check:active+.btn-outline-primary:focus,.btn-check:checked+.btn-outline-primary:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus,.btn-outline-primary:active:focus{box-shadow:0 0 0 .2rem rgba(203,12,159,.5)}.btn-outline-primary.disabled,.btn-outline-primary:disabled{background-color:transparent;color:#cb0c9f}.btn-outline-secondary{border-color:#8392ab;color:#8392ab}.btn-outline-secondary:hover{background-color:#8392ab;border-color:#8392ab;color:#000}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .2rem rgba(131,146,171,.5)}.btn-check:active+.btn-outline-secondary,.btn-check:checked+.btn-outline-secondary,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show,.btn-outline-secondary:active{background-color:#8392ab;border-color:#8392ab;color:#000}.btn-check:active+.btn-outline-secondary:focus,.btn-check:checked+.btn-outline-secondary:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus,.btn-outline-secondary:active:focus{box-shadow:0 0 0 .2rem rgba(131,146,171,.5)}.btn-outline-secondary.disabled,.btn-outline-secondary:disabled{background-color:transparent;color:#8392ab}.btn-outline-success{border-color:#82d616;color:#82d616}.btn-outline-success:hover{background-color:#82d616;border-color:#82d616;color:#000}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .2rem rgba(130,214,22,.5)}.btn-check:active+.btn-outline-success,.btn-check:checked+.btn-outline-success,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show,.btn-outline-success:active{background-color:#82d616;border-color:#82d616;color:#000}.btn-check:active+.btn-outline-success:focus,.btn-check:checked+.btn-outline-success:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus,.btn-outline-success:active:focus{box-shadow:0 0 0 .2rem rgba(130,214,22,.5)}.btn-outline-success.disabled,.btn-outline-success:disabled{background-color:transparent;color:#82d616}.btn-outline-info{border-color:#17c1e8;color:#17c1e8}.btn-outline-info:hover{background-color:#17c1e8;border-color:#17c1e8;color:#000}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .2rem rgba(23,193,232,.5)}.btn-check:active+.btn-outline-info,.btn-check:checked+.btn-outline-info,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show,.btn-outline-info:active{background-color:#17c1e8;border-color:#17c1e8;color:#000}.btn-check:active+.btn-outline-info:focus,.btn-check:checked+.btn-outline-info:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus,.btn-outline-info:active:focus{box-shadow:0 0 0 .2rem rgba(23,193,232,.5)}.btn-outline-info.disabled,.btn-outline-info:disabled{background-color:transparent;color:#17c1e8}.btn-outline-warning{border-color:#fbcf33;color:#fbcf33}.btn-outline-warning:hover{background-color:#fbcf33;border-color:#fbcf33;color:#000}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .2rem rgba(251,207,51,.5)}.btn-check:active+.btn-outline-warning,.btn-check:checked+.btn-outline-warning,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show,.btn-outline-warning:active{background-color:#fbcf33;border-color:#fbcf33;color:#000}.btn-check:active+.btn-outline-warning:focus,.btn-check:checked+.btn-outline-warning:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus,.btn-outline-warning:active:focus{box-shadow:0 0 0 .2rem rgba(251,207,51,.5)}.btn-outline-warning.disabled,.btn-outline-warning:disabled{background-color:transparent;color:#fbcf33}.btn-outline-danger{border-color:#ea0606;color:#ea0606}.btn-outline-danger:hover{background-color:#ea0606;border-color:#ea0606;color:#fff}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .2rem rgba(234,6,6,.5)}.btn-check:active+.btn-outline-danger,.btn-check:checked+.btn-outline-danger,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show,.btn-outline-danger:active{background-color:#ea0606;border-color:#ea0606;color:#fff}.btn-check:active+.btn-outline-danger:focus,.btn-check:checked+.btn-outline-danger:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus,.btn-outline-danger:active:focus{box-shadow:0 0 0 .2rem rgba(234,6,6,.5)}.btn-outline-danger.disabled,.btn-outline-danger:disabled{background-color:transparent;color:#ea0606}.btn-outline-light{border-color:#e9ecef;color:#e9ecef}.btn-outline-light:hover{background-color:#e9ecef;border-color:#e9ecef;color:#000}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .2rem rgba(233,236,239,.5)}.btn-check:active+.btn-outline-light,.btn-check:checked+.btn-outline-light,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show,.btn-outline-light:active{background-color:#e9ecef;border-color:#e9ecef;color:#000}.btn-check:active+.btn-outline-light:focus,.btn-check:checked+.btn-outline-light:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus,.btn-outline-light:active:focus{box-shadow:0 0 0 .2rem rgba(233,236,239,.5)}.btn-outline-light.disabled,.btn-outline-light:disabled{background-color:transparent;color:#e9ecef}.btn-outline-dark{border-color:#344767;color:#344767}.btn-outline-dark:hover{background-color:#344767;border-color:#344767;color:#fff}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .2rem rgba(52,71,103,.5)}.btn-check:active+.btn-outline-dark,.btn-check:checked+.btn-outline-dark,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show,.btn-outline-dark:active{background-color:#344767;border-color:#344767;color:#fff}.btn-check:active+.btn-outline-dark:focus,.btn-check:checked+.btn-outline-dark:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus,.btn-outline-dark:active:focus{box-shadow:0 0 0 .2rem rgba(52,71,103,.5)}.btn-outline-dark.disabled,.btn-outline-dark:disabled{background-color:transparent;color:#344767}.btn-outline-white{border-color:#fff;color:#fff}.btn-outline-white:hover{background-color:#fff;border-color:#fff;color:#000}.btn-check:focus+.btn-outline-white,.btn-outline-white:focus{box-shadow:0 0 0 .2rem hsla(0,0%,100%,.5)}.btn-check:active+.btn-outline-white,.btn-check:checked+.btn-outline-white,.btn-outline-white.active,.btn-outline-white.dropdown-toggle.show,.btn-outline-white:active{background-color:#fff;border-color:#fff;color:#000}.btn-check:active+.btn-outline-white:focus,.btn-check:checked+.btn-outline-white:focus,.btn-outline-white.active:focus,.btn-outline-white.dropdown-toggle.show:focus,.btn-outline-white:active:focus{box-shadow:0 0 0 .2rem hsla(0,0%,100%,.5)}.btn-outline-white.disabled,.btn-outline-white:disabled{background-color:transparent;color:#fff}.btn-link{color:#cb0c9f;font-weight:400;text-decoration:none}.btn-link:hover{color:#830866}.btn-link:focus,.btn-link:hover{text-decoration:none}.btn-link.disabled,.btn-link:disabled{color:#6c757d}.btn-group-lg>.btn,.btn-lg{border-radius:.5rem;font-size:.875rem;padding:.875rem 4rem}.btn-group-sm>.btn,.btn-sm{border-radius:.5rem;font-size:.75rem;padding:.5rem 2rem}.fade{transition:opacity .15s linear}@media (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .35s ease}@media (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown,.dropend,.dropstart,.dropup{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle:after{border-bottom:0;border-left:.3em solid transparent;border-right:.3em solid transparent;border-top:.3em solid;content:"";display:inline-block;margin-left:.255em;vertical-align:.255em}.dropdown-toggle:empty:after{margin-left:0}.dropdown-menu{background-clip:padding-box;background-color:#fff;border:0 solid transparent;border-radius:.5rem;color:#67748e;display:none;font-size:.875rem;list-style:none;margin:0;min-width:11rem;padding:.5rem 0;position:absolute;text-align:left;z-index:1000}.dropdown-menu[data-bs-popper]{left:0;margin-top:1.625rem;top:100%}.dropdown-menu-start{--bs-position:start}.dropdown-menu-start[data-bs-popper]{left:0;right:auto}.dropdown-menu-end{--bs-position:end}.dropdown-menu-end[data-bs-popper]{left:auto;right:0}@media (min-width:576px){.dropdown-menu-sm-start{--bs-position:start}.dropdown-menu-sm-start[data-bs-popper]{left:0;right:auto}.dropdown-menu-sm-end{--bs-position:end}.dropdown-menu-sm-end[data-bs-popper]{left:auto;right:0}}@media (min-width:768px){.dropdown-menu-md-start{--bs-position:start}.dropdown-menu-md-start[data-bs-popper]{left:0;right:auto}.dropdown-menu-md-end{--bs-position:end}.dropdown-menu-md-end[data-bs-popper]{left:auto;right:0}}@media (min-width:992px){.dropdown-menu-lg-start{--bs-position:start}.dropdown-menu-lg-start[data-bs-popper]{left:0;right:auto}.dropdown-menu-lg-end{--bs-position:end}.dropdown-menu-lg-end[data-bs-popper]{left:auto;right:0}}@media (min-width:1200px){.dropdown-menu-xl-start{--bs-position:start}.dropdown-menu-xl-start[data-bs-popper]{left:0;right:auto}.dropdown-menu-xl-end{--bs-position:end}.dropdown-menu-xl-end[data-bs-popper]{left:auto;right:0}}@media (min-width:1400px){.dropdown-menu-xxl-start{--bs-position:start}.dropdown-menu-xxl-start[data-bs-popper]{left:0;right:auto}.dropdown-menu-xxl-end{--bs-position:end}.dropdown-menu-xxl-end[data-bs-popper]{left:auto;right:0}}.dropup .dropdown-menu[data-bs-popper]{bottom:100%;margin-bottom:1.625rem;margin-top:0;top:auto}.dropup .dropdown-toggle:after{border-bottom:.3em solid;border-left:.3em solid transparent;border-right:.3em solid transparent;border-top:0;content:"";display:inline-block;margin-left:.255em;vertical-align:.255em}.dropup .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{left:100%;margin-left:1.625rem;margin-top:0;right:auto;top:0}.dropend .dropdown-toggle:after{border-bottom:.3em solid transparent;border-left:.3em solid;border-right:0;border-top:.3em solid transparent;content:"";display:inline-block;margin-left:.255em;vertical-align:.255em}.dropend .dropdown-toggle:empty:after{margin-left:0}.dropend .dropdown-toggle:after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{left:auto;margin-right:1.625rem;margin-top:0;right:100%;top:0}.dropstart .dropdown-toggle:after{content:"";display:inline-block;display:none;margin-left:.255em;vertical-align:.255em}.dropstart .dropdown-toggle:before{border-bottom:.3em solid transparent;border-right:.3em solid;border-top:.3em solid transparent;content:"";display:inline-block;margin-right:.255em;vertical-align:.255em}.dropstart .dropdown-toggle:empty:after{margin-left:0}.dropstart .dropdown-toggle:before{vertical-align:0}.dropdown-divider{border-top:1px solid transparent;height:0;margin:.5rem 0;overflow:hidden}.dropdown-item{background-color:transparent;border:0;clear:both;color:#67748e;display:block;font-weight:400;padding:.3rem 1rem;text-align:inherit;white-space:nowrap;width:100%}.dropdown-item:focus,.dropdown-item:hover{background-color:#e9ecef;color:#344767}.dropdown-item.active,.dropdown-item:active{background-color:transparent;color:#67748e;text-decoration:none}.dropdown-item.disabled,.dropdown-item:disabled{background-color:transparent;color:#6c757d;pointer-events:none}.dropdown-menu.show{display:block}.dropdown-header{color:#6c757d;display:block;font-size:.875rem;margin-bottom:0;padding:.5rem 1rem;white-space:nowrap}.dropdown-item-text{color:#67748e;display:block;padding:.3rem 1rem}.dropdown-menu-dark{background-color:#343a40;border-color:transparent;color:#dee2e6}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:focus,.dropdown-menu-dark .dropdown-item:hover{background-color:hsla(0,0%,100%,.15);color:#fff}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{background-color:transparent;color:#67748e}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:transparent}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{display:inline-flex;position:relative;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{flex:1 1 auto;position:relative}.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn-group:not(:first-child),.btn-group>.btn:not(:first-child){margin-left:-1px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-top-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:nth-child(n+3),.btn-group>:not(.btn-check)+.btn{border-bottom-left-radius:0;border-top-left-radius:0}.dropdown-toggle-split{padding-left:1.125rem;padding-right:1.125rem}.dropdown-toggle-split:after,.dropend .dropdown-toggle-split:after,.dropup .dropdown-toggle-split:after{margin-left:0}.dropstart .dropdown-toggle-split:before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-left:1.5rem;padding-right:1.5rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-left:3rem;padding-right:3rem}.btn-group-vertical{align-items:flex-start;flex-direction:column;justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn-group:not(:first-child),.btn-group-vertical>.btn:not(:first-child){margin-top:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-left-radius:0;border-bottom-right-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn~.btn{border-top-left-radius:0;border-top-right-radius:0}.nav{display:flex;flex-wrap:wrap;list-style:none;margin-bottom:0;padding-left:0}.nav-link{color:#cb0c9f;display:block;padding:.5rem 1rem;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media (prefers-reduced-motion:reduce){.nav-link{transition:none}}.nav-link:focus,.nav-link:hover{color:#830866}.nav-link.disabled{color:#6c757d;cursor:default;pointer-events:none}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{background:none;border:1px solid transparent;border-top-left-radius:.5rem;border-top-right-radius:.5rem;margin-bottom:-1px}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{background-color:transparent;border-color:transparent;color:#6c757d}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{background-color:#fff;border-color:#dee2e6 #dee2e6 #fff;color:#495057}.nav-tabs .dropdown-menu{border-top-left-radius:0;border-top-right-radius:0;margin-top:-1px}.nav-pills .nav-link{background:none;border:0;border-radius:.75rem}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{background-color:#fff;color:#344767}.nav-fill .nav-item,.nav-fill>.nav-link{flex:1 1 auto;text-align:center}.nav-justified .nav-item,.nav-justified>.nav-link{flex-basis:0;flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{align-items:center;display:flex;flex-wrap:wrap;justify-content:space-between;padding:.5rem 1rem;position:relative}.navbar>.container,.navbar>.container-fluid,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container-xl,.navbar>.container-xxl{align-items:center;display:flex;flex-wrap:inherit;justify-content:space-between}.navbar-brand{font-size:1.125rem;margin-right:1rem;padding-bottom:.40625rem;padding-top:.40625rem;white-space:nowrap}.navbar-nav{display:flex;flex-direction:column;list-style:none;margin-bottom:0;padding-left:0}.navbar-nav .nav-link{padding-left:0;padding-right:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-bottom:.5rem;padding-top:.5rem}.navbar-collapse{align-items:center;flex-basis:100%;flex-grow:1}.navbar-toggler{background-color:transparent;border:1px solid transparent;border-radius:.5rem;font-size:1.125rem;line-height:1;padding:.25rem .75rem;transition:box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{box-shadow:0 0 0 .2rem;outline:0;text-decoration:none}.navbar-toggler-icon{background-position:50%;background-repeat:no-repeat;background-size:100%;display:inline-block;height:1.5em;vertical-align:middle;width:1.5em}.navbar-nav-scroll{max-height:var(--bs-scroll-height,75vh);overflow-y:auto}@media (min-width:576px){.navbar-expand-sm{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (min-width:768px){.navbar-expand-md{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (min-width:992px){.navbar-expand-lg{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (min-width:1200px){.navbar-expand-xl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}@media (min-width:1400px){.navbar-expand-xxl{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}}.navbar-expand{flex-wrap:nowrap;justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-left:.5rem;padding-right:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(52,71,103,.9)}.navbar-light .navbar-nav .nav-link{color:#344767}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(52,71,103,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(52,71,103,.3)}.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .show>.nav-link{color:rgba(52,71,103,.9)}.navbar-light .navbar-toggler{border-color:rgba(52,71,103,.1);color:#344767}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3E%3Cpath stroke='%23344767' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-light .navbar-text{color:#344767}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(52,71,103,.9)}.navbar-dark .navbar-brand,.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:hsla(0,0%,100%,.85)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:hsla(0,0%,100%,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:hsla(0,0%,100%,.25)}.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{border-color:hsla(0,0%,100%,.1);color:hsla(0,0%,100%,.85)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3E%3Cpath stroke='rgba(255, 255, 255, 0.85)' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E")}.navbar-dark .navbar-text{color:hsla(0,0%,100%,.85)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{word-wrap:break-word;background-clip:border-box;background-color:#fff;border:0 solid rgba(0,0,0,.125);border-radius:1rem;display:flex;flex-direction:column;min-width:0;position:relative}.card>hr{margin-left:0;margin-right:0}.card>.list-group{border-bottom:inherit;border-top:inherit}.card>.list-group:first-child{border-top-left-radius:1rem;border-top-right-radius:1rem;border-top-width:0}.card>.list-group:last-child{border-bottom-left-radius:1rem;border-bottom-right-radius:1rem;border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;padding:1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-.25rem}.card-subtitle,.card-text:last-child{margin-bottom:0}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1rem}.card-header{background-color:#fff;border-bottom:0 solid rgba(0,0,0,.125);margin-bottom:0;padding:.5rem 1rem}.card-header:first-child{border-radius:1rem 1rem 0 0}.card-footer{background-color:#fff;border-top:0 solid rgba(0,0,0,.125);padding:.5rem 1rem}.card-footer:last-child{border-radius:0 0 1rem 1rem}.card-header-tabs{border-bottom:0;margin-bottom:-.5rem}.card-header-pills,.card-header-tabs{margin-left:-.5rem;margin-right:-.5rem}.card-img-overlay{border-radius:1rem;bottom:0;left:0;padding:1rem;position:absolute;right:0;top:0}.card-img,.card-img-bottom,.card-img-top{width:100%}.card-img,.card-img-top{border-top-left-radius:1rem;border-top-right-radius:1rem}.card-img,.card-img-bottom{border-bottom-left-radius:1rem;border-bottom-right-radius:1rem}.card-group>.card{margin-bottom:.75rem}@media (min-width:576px){.card-group{display:flex;flex-flow:row wrap}.card-group>.card{flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{border-left:0;margin-left:0}.card-group>.card:not(:last-child){border-bottom-right-radius:0;border-top-right-radius:0}.card-group>.card:not(:last-child) .card-header,.card-group>.card:not(:last-child) .card-img-top{border-top-right-radius:0}.card-group>.card:not(:last-child) .card-footer,.card-group>.card:not(:last-child) .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:not(:first-child){border-bottom-left-radius:0;border-top-left-radius:0}.card-group>.card:not(:first-child) .card-header,.card-group>.card:not(:first-child) .card-img-top{border-top-left-radius:0}.card-group>.card:not(:first-child) .card-footer,.card-group>.card:not(:first-child) .card-img-bottom{border-bottom-left-radius:0}}.accordion-button{align-items:center;background-color:transparent;border:0;border-radius:0;color:#67748e;display:flex;font-size:1rem;overflow-anchor:none;padding:1rem;position:relative;text-align:left;transition:all .15s ease-in,border-radius .15s ease;width:100%}@media (prefers-reduced-motion:reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){background-color:transparent;box-shadow:inset 0 0 0 rgba(0,0,0,.125);color:#344767}.accordion-button:not(.collapsed):after{background-image:none;transform:rotate(180deg)}.accordion-button:after{background-image:none;background-repeat:no-repeat;background-size:1rem;content:"";flex-shrink:0;height:1rem;margin-left:auto;transition:transform .2s ease-in-out;width:1rem}@media (prefers-reduced-motion:reduce){.accordion-button:after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{border-color:#e293d3;box-shadow:none;outline:0;z-index:3}.accordion-header{margin-bottom:0}.accordion-item{background-color:transparent;border:0 solid rgba(0,0,0,.125)}.accordion-item:first-of-type,.accordion-item:first-of-type .accordion-button{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.accordion-item:not(:first-of-type){border-top:0}.accordion-item:last-of-type,.accordion-item:last-of-type .accordion-button.collapsed,.accordion-item:last-of-type .accordion-collapse{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.accordion-body{padding:1rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-left:0;border-radius:0;border-right:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.accordion-flush .accordion-item .accordion-button{border-radius:0}.breadcrumb{background-color:#e9ecef;border-radius:.5rem;display:flex;flex-wrap:wrap;list-style:none;margin-bottom:1rem;padding:.5rem 1rem}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item:before{color:#6c757d;content:var(--bs-breadcrumb-divider,"/");float:left;padding-right:.5rem}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;list-style:none;padding-left:0}.page-link{background-color:#fff;border:1px solid #dee2e6;color:#cb0c9f;display:block;position:relative;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media (prefers-reduced-motion:reduce){.page-link{transition:none}}.page-link:hover{border-color:#dee2e6;z-index:2}.page-link:focus,.page-link:hover{background-color:#e9ecef;color:#830866}.page-link:focus{box-shadow:0 0 0 .2rem rgba(203,12,159,.25);outline:0;z-index:3}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{background-color:#cb0c9f;border-color:#cb0c9f;color:#fff;z-index:3}.page-item.disabled .page-link{background-color:#fff;border-color:#dee2e6;color:#6c757d;pointer-events:none}.page-link{padding:.375rem .75rem}.page-item:first-child .page-link{border-bottom-left-radius:.5rem;border-top-left-radius:.5rem}.page-item:last-child .page-link{border-bottom-right-radius:.5rem;border-top-right-radius:.5rem}.pagination-lg .page-link{font-size:1.125rem;padding:.75rem 1.5rem}.pagination-lg .page-item:first-child .page-link{border-bottom-left-radius:.75rem;border-top-left-radius:.75rem}.pagination-lg .page-item:last-child .page-link{border-bottom-right-radius:.75rem;border-top-right-radius:.75rem}.pagination-sm .page-link{font-size:.875rem;padding:.25rem .5rem}.pagination-sm .page-item:first-child .page-link{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.pagination-sm .page-item:last-child .page-link{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.badge{border-radius:.45rem;color:#fff;display:inline-block;font-size:.75em;font-weight:700;line-height:1;padding:.55em .9em;text-align:center;vertical-align:baseline;white-space:nowrap}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{border:1px solid transparent;border-radius:.5rem;margin-bottom:1rem;padding:1rem;position:relative}.alert-heading{color:inherit}.alert-link{font-weight:600}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{padding:1.25rem 1rem;position:absolute;right:0;top:0;z-index:2}.alert-primary{background-color:#f5ceec;border-color:#efb6e2;color:#7a075f}.alert-primary .alert-link{color:#62064c}.alert-secondary{background-color:#e6e9ee;border-color:#dadee6;color:#4f5867}.alert-secondary .alert-link{color:#3f4652}.alert-success{background-color:#e6f7d0;border-color:#daf3b9;color:#345609}.alert-success .alert-link{color:#2a4507}.alert-info{background-color:#d1f3fa;border-color:#b9ecf8;color:#0e748b}.alert-info .alert-link{color:#0b5d6f}.alert-warning{background-color:#fef5d6;border-color:#fef1c2;color:#645314}.alert-warning .alert-link{color:#504210}.alert-danger{background-color:#fbcdcd;border-color:#f9b4b4;color:#8c0404}.alert-danger .alert-link{color:#700303}.alert-light{background-color:#fbfbfc;border-color:#f8f9fa;color:#5d5e60}.alert-light .alert-link{color:#4a4b4d}.alert-dark{background-color:#d6dae1;border-color:#c2c8d1;color:#1f2b3e}.alert-dark .alert-link{color:#192232}.alert-white{background-color:#fff;border-color:#fff;color:#666}.alert-white .alert-link{color:#525252}@-webkit-keyframes progress-bar-stripes{0%{background-position-x:3px}}@keyframes progress-bar-stripes{0%{background-position-x:3px}}.progress{background-color:#e9ecef;border-radius:.5rem;font-size:.75rem;height:3px}.progress,.progress-bar{display:flex;overflow:hidden}.progress-bar{background-color:#cb0c9f;color:#fff;flex-direction:column;justify-content:center;text-align:center;transition:width .6s ease;white-space:nowrap}@media (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,hsla(0,0%,100%,.15) 25%,transparent 0,transparent 50%,hsla(0,0%,100%,.15) 0,hsla(0,0%,100%,.15) 75%,transparent 0,transparent);background-size:3px 3px}.progress-bar-animated{-webkit-animation:progress-bar-stripes 1s linear infinite;animation:progress-bar-stripes 1s linear infinite}@media (prefers-reduced-motion:reduce){.progress-bar-animated{-webkit-animation:none;animation:none}}.list-group{border-radius:.5rem;display:flex;flex-direction:column;margin-bottom:0;padding-left:0}.list-group-numbered{counter-reset:section;list-style-type:none}.list-group-numbered>li:before{content:counters(section,".") ". ";counter-increment:section}.list-group-item-action{color:#495057;text-align:inherit;width:100%}.list-group-item-action:focus,.list-group-item-action:hover{background-color:#f8f9fa;color:#495057;text-decoration:none;z-index:1}.list-group-item-action:active{background-color:#e9ecef;color:#67748e}.list-group-item{background-color:#fff;border:1px solid rgba(0,0,0,.125);color:inherit;display:block;padding:.5rem 1rem;position:relative}.list-group-item:first-child{border-top-left-radius:inherit;border-top-right-radius:inherit}.list-group-item:last-child{border-bottom-left-radius:inherit;border-bottom-right-radius:inherit}.list-group-item.disabled,.list-group-item:disabled{background-color:#fff;color:#6c757d;pointer-events:none}.list-group-item.active{background-color:#cb0c9f;border-color:#cb0c9f;color:#fff;z-index:2}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{border-top-width:1px;margin-top:-1px}.list-group-horizontal{flex-direction:row}.list-group-horizontal>.list-group-item:first-child{border-bottom-left-radius:.5rem;border-top-right-radius:0}.list-group-horizontal>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.5rem}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}@media (min-width:576px){.list-group-horizontal-sm{flex-direction:row}.list-group-horizontal-sm>.list-group-item:first-child{border-bottom-left-radius:.5rem;border-top-right-radius:0}.list-group-horizontal-sm>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.5rem}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}}@media (min-width:768px){.list-group-horizontal-md{flex-direction:row}.list-group-horizontal-md>.list-group-item:first-child{border-bottom-left-radius:.5rem;border-top-right-radius:0}.list-group-horizontal-md>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.5rem}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal-md>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}}@media (min-width:992px){.list-group-horizontal-lg{flex-direction:row}.list-group-horizontal-lg>.list-group-item:first-child{border-bottom-left-radius:.5rem;border-top-right-radius:0}.list-group-horizontal-lg>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.5rem}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}}@media (min-width:1200px){.list-group-horizontal-xl{flex-direction:row}.list-group-horizontal-xl>.list-group-item:first-child{border-bottom-left-radius:.5rem;border-top-right-radius:0}.list-group-horizontal-xl>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.5rem}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}}@media (min-width:1400px){.list-group-horizontal-xxl{flex-direction:row}.list-group-horizontal-xxl>.list-group-item:first-child{border-bottom-left-radius:.5rem;border-top-right-radius:0}.list-group-horizontal-xxl>.list-group-item:last-child{border-bottom-left-radius:0;border-top-right-radius:.5rem}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-left-width:0;border-top-width:1px}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{border-left-width:1px;margin-left:-1px}}.list-group-flush{border-radius:0}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-primary{background-color:#f5ceec;color:#7a075f}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{background-color:#ddb9d4;color:#7a075f}.list-group-item-primary.list-group-item-action.active{background-color:#7a075f;border-color:#7a075f;color:#fff}.list-group-item-secondary{background-color:#e6e9ee;color:#4f5867}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{background-color:#cfd2d6;color:#4f5867}.list-group-item-secondary.list-group-item-action.active{background-color:#4f5867;border-color:#4f5867;color:#fff}.list-group-item-success{background-color:#e6f7d0;color:#345609}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{background-color:#cfdebb;color:#345609}.list-group-item-success.list-group-item-action.active{background-color:#345609;border-color:#345609;color:#fff}.list-group-item-info{background-color:#d1f3fa;color:#0e748b}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{background-color:#bcdbe1;color:#0e748b}.list-group-item-info.list-group-item-action.active{background-color:#0e748b;border-color:#0e748b;color:#fff}.list-group-item-warning{background-color:#fef5d6;color:#645314}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{background-color:#e5ddc1;color:#645314}.list-group-item-warning.list-group-item-action.active{background-color:#645314;border-color:#645314;color:#fff}.list-group-item-danger{background-color:#fbcdcd;color:#8c0404}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{background-color:#e2b9b9;color:#8c0404}.list-group-item-danger.list-group-item-action.active{background-color:#8c0404;border-color:#8c0404;color:#fff}.list-group-item-light{background-color:#fbfbfc;color:#5d5e60}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{background-color:#e2e2e3;color:#5d5e60}.list-group-item-light.list-group-item-action.active{background-color:#5d5e60;border-color:#5d5e60;color:#fff}.list-group-item-dark{background-color:#d6dae1;color:#1f2b3e}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{background-color:#c1c4cb;color:#1f2b3e}.list-group-item-dark.list-group-item-action.active{background-color:#1f2b3e;border-color:#1f2b3e;color:#fff}.list-group-item-white{background-color:#fff;color:#666}.list-group-item-white.list-group-item-action:focus,.list-group-item-white.list-group-item-action:hover{background-color:#e6e6e6;color:#666}.list-group-item-white.list-group-item-action.active{background-color:#666;border-color:#666;color:#fff}.btn-close{background:transparent url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M.293.293a1 1 0 0 1 1.414 0L8 6.586 14.293.293a1 1 0 1 1 1.414 1.414L9.414 8l6.293 6.293a1 1 0 0 1-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 0 1-1.414-1.414L6.586 8 .293 1.707a1 1 0 0 1 0-1.414z'/%3E%3C/svg%3E") 50%/1em auto no-repeat;border:0;border-radius:.25rem;box-sizing:content-box;color:#fff;height:1em;opacity:.5;padding:.25em;width:1em}.btn-close:hover{color:#fff;opacity:.75;text-decoration:none}.btn-close:focus{box-shadow:0 0 0 .2rem rgba(203,12,159,.25);opacity:1;outline:0}.btn-close.disabled,.btn-close:disabled{opacity:.25;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{background-clip:padding-box;background-color:hsla(0,0%,100%,.85);border:0 solid transparent;border-radius:.5rem;box-shadow:0 .25rem .375rem -.0625rem hsla(0,0%,8%,.12),0 .125rem .25rem -.0625rem hsla(0,0%,8%,.07);font-size:.875rem;max-width:100%;pointer-events:auto;width:350px}.toast:not(.showing):not(.show){opacity:0}.toast.hide{display:none}.toast-container{max-width:100%;pointer-events:none;width:-webkit-max-content;width:-moz-max-content;width:max-content}.toast-container>:not(:last-child){margin-bottom:1.5rem}.toast-header{align-items:center;background-clip:padding-box;background-color:hsla(0,0%,100%,.85);border-bottom:0 solid rgba(0,0,0,.05);border-top-left-radius:.5rem;border-top-right-radius:.5rem;color:#344767;display:flex;padding:.75rem}.toast-header .btn-close{margin-left:.75rem;margin-right:-.375rem}.toast-body{word-wrap:break-word;padding:.75rem}.modal{display:none;height:100%;left:0;outline:0;overflow-x:hidden;overflow-y:auto;position:fixed;top:0;width:100%;z-index:1050}.modal-dialog{margin:.5rem;pointer-events:none;position:relative;width:auto}.modal.fade .modal-dialog{transform:translateY(-50px);transition:transform .3s ease-out}@media (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{align-items:center;display:flex;min-height:calc(100% - 1rem)}.modal-content{background-clip:padding-box;background-color:#fff;border:1px solid rgba(0,0,0,.2);border-radius:.75rem;display:flex;flex-direction:column;outline:0;pointer-events:auto;position:relative;width:100%}.modal-backdrop{background-color:#000;height:100vh;left:0;position:fixed;top:0;width:100vw;z-index:1040}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{align-items:center;border-bottom:1px solid #dee2e6;border-top-left-radius:calc(.75rem - 1px);border-top-right-radius:calc(.75rem - 1px);display:flex;flex-shrink:0;justify-content:space-between;padding:1rem}.modal-header .btn-close{margin:-.5rem -.5rem -.5rem auto;padding:.5rem}.modal-title{line-height:1.5;margin-bottom:0}.modal-body{flex:1 1 auto;padding:1rem;position:relative}.modal-footer{align-items:center;border-bottom-left-radius:calc(.75rem - 1px);border-bottom-right-radius:calc(.75rem - 1px);border-top:1px solid #dee2e6;display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;padding:.75rem}.modal-footer>*{margin:.25rem}@media (min-width:576px){.modal-dialog{margin:1.75rem auto;max-width:500px}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media (min-width:992px){.modal-lg,.modal-xl{max-width:800px}}@media (min-width:1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{height:100%;margin:0;max-width:none;width:100vw}.modal-fullscreen .modal-content{border:0;border-radius:0;height:100%}.modal-fullscreen .modal-header{border-radius:0}.modal-fullscreen .modal-body{overflow-y:auto}.modal-fullscreen .modal-footer{border-radius:0}@media (max-width:575.98px){.modal-fullscreen-sm-down{height:100%;margin:0;max-width:none;width:100vw}.modal-fullscreen-sm-down .modal-content{border:0;border-radius:0;height:100%}.modal-fullscreen-sm-down .modal-header{border-radius:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}.modal-fullscreen-sm-down .modal-footer{border-radius:0}}@media (max-width:767.98px){.modal-fullscreen-md-down{height:100%;margin:0;max-width:none;width:100vw}.modal-fullscreen-md-down .modal-content{border:0;border-radius:0;height:100%}.modal-fullscreen-md-down .modal-header{border-radius:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}.modal-fullscreen-md-down .modal-footer{border-radius:0}}@media (max-width:991.98px){.modal-fullscreen-lg-down{height:100%;margin:0;max-width:none;width:100vw}.modal-fullscreen-lg-down .modal-content{border:0;border-radius:0;height:100%}.modal-fullscreen-lg-down .modal-header{border-radius:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}.modal-fullscreen-lg-down .modal-footer{border-radius:0}}@media (max-width:1199.98px){.modal-fullscreen-xl-down{height:100%;margin:0;max-width:none;width:100vw}.modal-fullscreen-xl-down .modal-content{border:0;border-radius:0;height:100%}.modal-fullscreen-xl-down .modal-header{border-radius:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}.modal-fullscreen-xl-down .modal-footer{border-radius:0}}@media (max-width:1399.98px){.modal-fullscreen-xxl-down{height:100%;margin:0;max-width:none;width:100vw}.modal-fullscreen-xxl-down .modal-content{border:0;border-radius:0;height:100%}.modal-fullscreen-xxl-down .modal-header{border-radius:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}.modal-fullscreen-xxl-down .modal-footer{border-radius:0}}.tooltip{word-wrap:break-word;display:block;font-family:var(--bs-font-sans-serif);font-size:.875rem;font-style:normal;font-weight:400;letter-spacing:normal;line-break:auto;line-height:1.5;margin:0;opacity:0;position:absolute;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;white-space:normal;word-break:normal;word-spacing:normal;z-index:1070}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{display:block;height:.4rem;position:absolute;width:.8rem}.tooltip .tooltip-arrow:before{border-color:transparent;border-style:solid;content:"";position:absolute}.bs-tooltip-auto[data-popper-placement^=top],.bs-tooltip-top{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow,.bs-tooltip-top .tooltip-arrow{bottom:0}.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow:before,.bs-tooltip-top .tooltip-arrow:before{border-top-color:#000;border-width:.4rem .4rem 0;top:-1px}.bs-tooltip-auto[data-popper-placement^=right],.bs-tooltip-end{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow,.bs-tooltip-end .tooltip-arrow{height:.8rem;left:0;width:.4rem}.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow:before,.bs-tooltip-end .tooltip-arrow:before{border-right-color:#000;border-width:.4rem .4rem .4rem 0;right:-1px}.bs-tooltip-auto[data-popper-placement^=bottom],.bs-tooltip-bottom{padding:.4rem 0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow,.bs-tooltip-bottom .tooltip-arrow{top:0}.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow:before,.bs-tooltip-bottom .tooltip-arrow:before{border-bottom-color:#000;border-width:0 .4rem .4rem;bottom:-1px}.bs-tooltip-auto[data-popper-placement^=left],.bs-tooltip-start{padding:0 .4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow,.bs-tooltip-start .tooltip-arrow{height:.8rem;right:0;width:.4rem}.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow:before,.bs-tooltip-start .tooltip-arrow:before{border-left-color:#000;border-width:.4rem 0 .4rem .4rem;left:-1px}.tooltip-inner{background-color:#000;border-radius:.5rem;color:#fff;max-width:200px;padding:.25rem .5rem;text-align:center}.popover{word-wrap:break-word;background-clip:padding-box;background-color:#fff;border:0 solid rgba(0,0,0,.2);border-radius:.75rem;display:block;font-family:var(--bs-font-sans-serif);font-size:.75rem;font-style:normal;font-weight:400;left:0;letter-spacing:normal;line-break:auto;line-height:1.5;max-width:276px;position:absolute;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;top:0;white-space:normal;word-break:normal;word-spacing:normal;z-index:1060}.popover .popover-arrow{display:block;height:.5rem;position:absolute;width:1rem}.popover .popover-arrow:after,.popover .popover-arrow:before{border-color:transparent;border-style:solid;content:"";display:block;position:absolute}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow,.bs-popover-top>.popover-arrow{bottom:-.5rem}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:before,.bs-popover-top>.popover-arrow:before{border-top-color:rgba(0,0,0,.25);border-width:.5rem .5rem 0;bottom:0}.bs-popover-auto[data-popper-placement^=top]>.popover-arrow:after,.bs-popover-top>.popover-arrow:after{border-top-color:#fff;border-width:.5rem .5rem 0;bottom:0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow,.bs-popover-end>.popover-arrow{height:1rem;left:-.5rem;width:.5rem}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:before,.bs-popover-end>.popover-arrow:before{border-right-color:rgba(0,0,0,.25);border-width:.5rem .5rem .5rem 0;left:0}.bs-popover-auto[data-popper-placement^=right]>.popover-arrow:after,.bs-popover-end>.popover-arrow:after{border-right-color:#fff;border-width:.5rem .5rem .5rem 0;left:0}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow,.bs-popover-bottom>.popover-arrow{top:-.5rem}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:before,.bs-popover-bottom>.popover-arrow:before{border-bottom-color:rgba(0,0,0,.25);border-width:0 .5rem .5rem;top:0}.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow:after,.bs-popover-bottom>.popover-arrow:after{border-bottom-color:#fff;border-width:0 .5rem .5rem;top:0}.bs-popover-auto[data-popper-placement^=bottom] .popover-header:before,.bs-popover-bottom .popover-header:before{border-bottom:0 solid #e9ecef;content:"";display:block;left:50%;margin-left:-.5rem;position:absolute;top:0;width:1rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow,.bs-popover-start>.popover-arrow{height:1rem;right:-.5rem;width:.5rem}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:before,.bs-popover-start>.popover-arrow:before{border-left-color:rgba(0,0,0,.25);border-width:.5rem 0 .5rem .5rem;right:0}.bs-popover-auto[data-popper-placement^=left]>.popover-arrow:after,.bs-popover-start>.popover-arrow:after{border-left-color:#fff;border-width:.5rem 0 .5rem .5rem;right:0}.popover-header{background-color:#e9ecef;border-bottom:0 solid rgba(0,0,0,.2);border-top-left-radius:.75rem;border-top-right-radius:.75rem;color:#344767;font-size:1rem;margin-bottom:0;padding:.5rem 1rem}.popover-header:empty{display:none}.popover-body{color:#67748e;padding:1rem}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y}.carousel-inner{overflow:hidden;position:relative;width:100%}.carousel-inner:after{clear:both;content:"";display:block}.carousel-item{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:none;float:left;margin-right:-100%;position:relative;transition:transform .6s ease-in-out;width:100%}@media (prefers-reduced-motion:reduce){.carousel-item{transition:none}}.carousel-item-next,.carousel-item-prev,.carousel-item.active{display:block}.active.carousel-item-end,.carousel-item-next:not(.carousel-item-start){transform:translateX(100%)}.active.carousel-item-start,.carousel-item-prev:not(.carousel-item-end){transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transform:none;transition-property:opacity}.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end,.carousel-fade .carousel-item.active{opacity:1;z-index:1}.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{opacity:0;transition:opacity 0s .6s;z-index:0}@media (prefers-reduced-motion:reduce){.carousel-fade .active.carousel-item-end,.carousel-fade .active.carousel-item-start{transition:none}}.carousel-control-next,.carousel-control-prev{align-items:center;background:none;border:0;bottom:0;color:#fff;display:flex;justify-content:center;opacity:.5;padding:0;position:absolute;text-align:center;top:0;transition:opacity .15s ease;width:15%;z-index:1}@media (prefers-reduced-motion:reduce){.carousel-control-next,.carousel-control-prev{transition:none}}.carousel-control-next:focus,.carousel-control-next:hover,.carousel-control-prev:focus,.carousel-control-prev:hover{color:#fff;opacity:.9;outline:0;text-decoration:none}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-next-icon,.carousel-control-prev-icon{background-position:50%;background-repeat:no-repeat;background-size:100% 100%;display:inline-block;height:2rem;width:2rem}.carousel-control-prev-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3E%3C/svg%3E")}.carousel-control-next-icon{background-image:url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='%23fff' viewBox='0 0 16 16'%3E%3Cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3E%3C/svg%3E")}.carousel-indicators{bottom:0;display:flex;justify-content:center;left:0;list-style:none;margin-bottom:1rem;margin-left:15%;margin-right:15%;padding:0;position:absolute;right:0;z-index:2}.carousel-indicators [data-bs-target]{background-clip:padding-box;background-color:#fff;border:0;border-bottom:10px solid transparent;border-top:10px solid transparent;box-sizing:content-box;cursor:pointer;flex:0 1 auto;height:3px;margin-left:3px;margin-right:3px;opacity:.5;padding:0;text-indent:-999px;transition:opacity .6s ease;width:30px}@media (prefers-reduced-motion:reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{bottom:1.25rem;color:#fff;left:15%;padding-bottom:1.25rem;padding-top:1.25rem;position:absolute;right:15%;text-align:center}.carousel-dark .carousel-control-next-icon,.carousel-dark .carousel-control-prev-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@-webkit-keyframes spinner-border{to{transform:rotate(1turn)}}@keyframes spinner-border{to{transform:rotate(1turn)}}.spinner-border{-webkit-animation:spinner-border .75s linear infinite;animation:spinner-border .75s linear infinite;border:.25em solid;border-radius:50%;border-right:.25em solid transparent;display:inline-block;height:2rem;vertical-align:-.125em;width:2rem}.spinner-border-sm{border-width:.2em;height:1rem;width:1rem}@-webkit-keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{-webkit-animation:spinner-grow .75s linear infinite;animation:spinner-grow .75s linear infinite;background-color:currentColor;border-radius:50%;display:inline-block;height:2rem;opacity:0;vertical-align:-.125em;width:2rem}.spinner-grow-sm{height:1rem;width:1rem}@media (prefers-reduced-motion:reduce){.spinner-border,.spinner-grow{-webkit-animation-duration:1.5s;animation-duration:1.5s}}.offcanvas{background-clip:padding-box;background-color:#fff;bottom:0;display:flex;flex-direction:column;max-width:100%;outline:0;position:fixed;transition:transform .3s ease-in-out;visibility:hidden;z-index:1050}@media (prefers-reduced-motion:reduce){.offcanvas{transition:none}}.offcanvas-header{align-items:center;display:flex;justify-content:space-between;padding:1rem}.offcanvas-header .btn-close{margin-bottom:-.5rem;margin-right:-.5rem;margin-top:-.5rem;padding:.5rem}.offcanvas-title{line-height:1.5;margin-bottom:0}.offcanvas-body{flex-grow:1;overflow-y:auto;padding:1rem}.offcanvas-start{border-right:1px solid rgba(0,0,0,.2);left:0;top:0;transform:translateX(-100%);width:400px}.offcanvas-end{border-left:1px solid rgba(0,0,0,.2);right:0;top:0;transform:translateX(100%);width:400px}.offcanvas-top{border-bottom:1px solid rgba(0,0,0,.2);top:0;transform:translateY(-100%)}.offcanvas-bottom,.offcanvas-top{height:30vh;left:0;max-height:100%;right:0}.offcanvas-bottom{border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.clearfix:after{clear:both;content:"";display:block}.link-primary{color:#cb0c9f}.link-primary:focus,.link-primary:hover{color:#a20a7f}.link-secondary{color:#8392ab}.link-secondary:focus,.link-secondary:hover{color:#9ca8bc}.link-success{color:#82d616}.link-success:focus,.link-success:hover{color:#9bde45}.link-info{color:#17c1e8}.link-info:focus,.link-info:hover{color:#45cded}.link-warning{color:#fbcf33}.link-warning:focus,.link-warning:hover{color:#fcd95c}.link-danger{color:#ea0606}.link-danger:focus,.link-danger:hover{color:#bb0505}.link-light{color:#e9ecef}.link-light:focus,.link-light:hover{color:#edf0f2}.link-dark{color:#344767}.link-dark:focus,.link-dark:hover{color:#2a3952}.link-white,.link-white:focus,.link-white:hover{color:#fff}.ratio{position:relative;width:100%}.ratio:before{content:"";display:block;padding-top:var(--bs-aspect-ratio)}.ratio>*{height:100%;left:0;position:absolute;top:0;width:100%}.ratio-1x1{--bs-aspect-ratio:100%}.ratio-4x3{--bs-aspect-ratio:75%}.ratio-16x9{--bs-aspect-ratio:56.25%}.ratio-21x9{--bs-aspect-ratio:42.8571428571%}.fixed-top{top:0}.fixed-bottom,.fixed-top{left:0;position:fixed;right:0;z-index:1030}.fixed-bottom{bottom:0}.sticky-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}@media (min-width:576px){.sticky-sm-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:768px){.sticky-md-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:992px){.sticky-lg-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1200px){.sticky-xl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}@media (min-width:1400px){.sticky-xxl-top{position:-webkit-sticky;position:sticky;top:0;z-index:1020}}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){clip:rect(0,0,0,0)!important;border:0!important;height:1px!important;margin:-1px!important;overflow:hidden!important;padding:0!important;position:absolute!important;white-space:nowrap!important;width:1px!important}.stretched-link:after{bottom:0;content:"";left:0;position:absolute;right:0;top:0;z-index:1}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.float-start{float:left!important}.float-end{float:right!important}.float-none{float:none!important}.overflow-auto{overflow:auto!important}.overflow-hidden{overflow:hidden!important}.overflow-scroll{overflow:scroll!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-grid{display:grid!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.d-none{display:none!important}.shadow{box-shadow:0 .25rem .375rem -.0625rem hsla(0,0%,8%,.12),0 .125rem .25rem -.0625rem hsla(0,0%,8%,.07)!important}.shadow-sm{box-shadow:0 .3125rem .625rem 0 rgba(0,0,0,.12)!important}.shadow-lg{box-shadow:0 8px 26px -4px hsla(0,0%,8%,.15),0 8px 9px -5px hsla(0,0%,8%,.06)!important}.shadow-xl{box-shadow:0 23px 45px -11px hsla(0,0%,8%,.25)!important}.shadow-none{box-shadow:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.top-0{top:0!important}.top-1{top:1%!important}.top-2{top:2%!important}.top-3{top:3%!important}.top-4{top:4%!important}.top-5{top:5%!important}.top-6{top:6%!important}.top-7{top:7%!important}.top-8{top:8%!important}.top-9{top:9%!important}.top-10{top:10%!important}.top-50{top:50%!important}.top-100{top:100%!important}.bottom-0{bottom:0!important}.bottom-1{bottom:1%!important}.bottom-2{bottom:2%!important}.bottom-3{bottom:3%!important}.bottom-4{bottom:4%!important}.bottom-5{bottom:5%!important}.bottom-6{bottom:6%!important}.bottom-7{bottom:7%!important}.bottom-8{bottom:8%!important}.bottom-9{bottom:9%!important}.bottom-10{bottom:10%!important}.bottom-50{bottom:50%!important}.bottom-100{bottom:100%!important}.start-0{left:0!important}.start-1{left:1%!important}.start-2{left:2%!important}.start-3{left:3%!important}.start-4{left:4%!important}.start-5{left:5%!important}.start-6{left:6%!important}.start-7{left:7%!important}.start-8{left:8%!important}.start-9{left:9%!important}.start-10{left:10%!important}.start-50{left:50%!important}.start-100{left:100%!important}.end-0{right:0!important}.end-1{right:1%!important}.end-2{right:2%!important}.end-3{right:3%!important}.end-4{right:4%!important}.end-5{right:5%!important}.end-6{right:6%!important}.end-7{right:7%!important}.end-8{right:8%!important}.end-9{right:9%!important}.end-10{right:10%!important}.end-50{right:50%!important}.end-100{right:100%!important}.translate-middle{transform:translate(-50%,-50%)!important}.translate-middle-x{transform:translateX(-50%)!important}.translate-middle-y{transform:translateY(-50%)!important}.border{border:1px solid #dee2e6!important}.border-0{border:0!important}.border-top{border-top:1px solid #dee2e6!important}.border-top-0{border-top:0!important}.border-end{border-right:1px solid #dee2e6!important}.border-end-0{border-right:0!important}.border-bottom{border-bottom:1px solid #dee2e6!important}.border-bottom-0{border-bottom:0!important}.border-start{border-left:1px solid #dee2e6!important}.border-start-0{border-left:0!important}.border-primary{border-color:#cb0c9f!important}.border-secondary{border-color:#8392ab!important}.border-success{border-color:#82d616!important}.border-info{border-color:#17c1e8!important}.border-warning{border-color:#fbcf33!important}.border-danger{border-color:#ea0606!important}.border-light{border-color:#e9ecef!important}.border-dark{border-color:#344767!important}.border-white{border-color:#fff!important}.border-0{border-width:0!important}.border-1{border-width:1px!important}.border-2{border-width:2px!important}.border-3{border-width:3px!important}.border-4{border-width:4px!important}.border-5{border-width:5px!important}.w-0{width:0!important}.w-1{width:1%!important}.w-2{width:2%!important}.w-3{width:3%!important}.w-4{width:4%!important}.w-5{width:5%!important}.w-6{width:6%!important}.w-7{width:7%!important}.w-8{width:8%!important}.w-9{width:9%!important}.w-10{width:10%!important}.w-15{width:15%!important}.w-20{width:20%!important}.w-25{width:25%!important}.w-30{width:30%!important}.w-35{width:35%!important}.w-40{width:40%!important}.w-45{width:45%!important}.w-50{width:50%!important}.w-55{width:55%!important}.w-60{width:60%!important}.w-65{width:65%!important}.w-70{width:70%!important}.w-75{width:75%!important}.w-80{width:80%!important}.w-85{width:85%!important}.w-90{width:90%!important}.w-95{width:95%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.mw-100{max-width:100%!important}.vw-100{width:100vw!important}.min-vw-100{min-width:100vw!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mh-100{max-height:100%!important}.vh-100{height:100vh!important}.min-vh-25{min-height:25vh!important}.min-vh-50{min-height:50vh!important}.min-vh-75{min-height:75vh!important}.min-vh-85{min-height:85vh!important}.min-vh-100{min-height:100vh!important}.flex-fill{flex:1 1 auto!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-0{gap:0!important}.gap-1{gap:.25rem!important}.gap-2{gap:.5rem!important}.gap-3{gap:1rem!important}.gap-4{gap:1.5rem!important}.gap-5{gap:3rem!important}.gap-6{gap:4rem!important}.gap-7{gap:6rem!important}.gap-8{gap:8rem!important}.gap-9{gap:10rem!important}.gap-10{gap:12rem!important}.gap-11{gap:14rem!important}.gap-12{gap:16rem!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.justify-content-evenly{justify-content:space-evenly!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.order-first{order:-1!important}.order-0{order:0!important}.order-1{order:1!important}.order-2{order:2!important}.order-3{order:3!important}.order-4{order:4!important}.order-5{order:5!important}.order-last{order:6!important}.m-0{margin:0!important}.m-1{margin:.25rem!important}.m-2{margin:.5rem!important}.m-3{margin:1rem!important}.m-4{margin:1.5rem!important}.m-5{margin:3rem!important}.m-6{margin:4rem!important}.m-7{margin:6rem!important}.m-8{margin:8rem!important}.m-9{margin:10rem!important}.m-10{margin:12rem!important}.m-11{margin:14rem!important}.m-12{margin:16rem!important}.m-auto{margin:auto!important}.mx-0{margin-left:0!important;margin-right:0!important}.mx-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-3{margin-left:1rem!important;margin-right:1rem!important}.mx-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-5{margin-left:3rem!important;margin-right:3rem!important}.mx-6{margin-left:4rem!important;margin-right:4rem!important}.mx-7{margin-left:6rem!important;margin-right:6rem!important}.mx-8{margin-left:8rem!important;margin-right:8rem!important}.mx-9{margin-left:10rem!important;margin-right:10rem!important}.mx-10{margin-left:12rem!important;margin-right:12rem!important}.mx-11{margin-left:14rem!important;margin-right:14rem!important}.mx-12{margin-left:16rem!important;margin-right:16rem!important}.mx-auto{margin-left:auto!important;margin-right:auto!important}.my-0{margin-bottom:0!important;margin-top:0!important}.my-1{margin-bottom:.25rem!important;margin-top:.25rem!important}.my-2{margin-bottom:.5rem!important;margin-top:.5rem!important}.my-3{margin-bottom:1rem!important;margin-top:1rem!important}.my-4{margin-bottom:1.5rem!important;margin-top:1.5rem!important}.my-5{margin-bottom:3rem!important;margin-top:3rem!important}.my-6{margin-bottom:4rem!important;margin-top:4rem!important}.my-7{margin-bottom:6rem!important;margin-top:6rem!important}.my-8{margin-bottom:8rem!important;margin-top:8rem!important}.my-9{margin-bottom:10rem!important;margin-top:10rem!important}.my-10{margin-bottom:12rem!important;margin-top:12rem!important}.my-11{margin-bottom:14rem!important;margin-top:14rem!important}.my-12{margin-bottom:16rem!important;margin-top:16rem!important}.my-auto{margin-bottom:auto!important;margin-top:auto!important}.mt-0{margin-top:0!important}.mt-1{margin-top:.25rem!important}.mt-2{margin-top:.5rem!important}.mt-3{margin-top:1rem!important}.mt-4{margin-top:1.5rem!important}.mt-5{margin-top:3rem!important}.mt-6{margin-top:4rem!important}.mt-7{margin-top:6rem!important}.mt-8{margin-top:8rem!important}.mt-9{margin-top:10rem!important}.mt-10{margin-top:12rem!important}.mt-11{margin-top:14rem!important}.mt-12{margin-top:16rem!important}.mt-auto{margin-top:auto!important}.me-0{margin-right:0!important}.me-1{margin-right:.25rem!important}.me-2{margin-right:.5rem!important}.me-3{margin-right:1rem!important}.me-4{margin-right:1.5rem!important}.me-5{margin-right:3rem!important}.me-6{margin-right:4rem!important}.me-7{margin-right:6rem!important}.me-8{margin-right:8rem!important}.me-9{margin-right:10rem!important}.me-10{margin-right:12rem!important}.me-11{margin-right:14rem!important}.me-12{margin-right:16rem!important}.me-auto{margin-right:auto!important}.mb-0{margin-bottom:0!important}.mb-1{margin-bottom:.25rem!important}.mb-2{margin-bottom:.5rem!important}.mb-3{margin-bottom:1rem!important}.mb-4{margin-bottom:1.5rem!important}.mb-5{margin-bottom:3rem!important}.mb-6{margin-bottom:4rem!important}.mb-7{margin-bottom:6rem!important}.mb-8{margin-bottom:8rem!important}.mb-9{margin-bottom:10rem!important}.mb-10{margin-bottom:12rem!important}.mb-11{margin-bottom:14rem!important}.mb-12{margin-bottom:16rem!important}.mb-auto{margin-bottom:auto!important}.ms-0{margin-left:0!important}.ms-1{margin-left:.25rem!important}.ms-2{margin-left:.5rem!important}.ms-3{margin-left:1rem!important}.ms-4{margin-left:1.5rem!important}.ms-5{margin-left:3rem!important}.ms-6{margin-left:4rem!important}.ms-7{margin-left:6rem!important}.ms-8{margin-left:8rem!important}.ms-9{margin-left:10rem!important}.ms-10{margin-left:12rem!important}.ms-11{margin-left:14rem!important}.ms-12{margin-left:16rem!important}.ms-auto{margin-left:auto!important}.m-n1{margin:-.25rem!important}.m-n2{margin:-.5rem!important}.m-n3{margin:-1rem!important}.m-n4{margin:-1.5rem!important}.m-n5{margin:-3rem!important}.m-n6{margin:-4rem!important}.m-n7{margin:-6rem!important}.m-n8{margin:-8rem!important}.m-n9{margin:-10rem!important}.m-n10{margin:-12rem!important}.m-n11{margin:-14rem!important}.m-n12{margin:-16rem!important}.mx-n1{margin-left:-.25rem!important;margin-right:-.25rem!important}.mx-n2{margin-left:-.5rem!important;margin-right:-.5rem!important}.mx-n3{margin-left:-1rem!important;margin-right:-1rem!important}.mx-n4{margin-left:-1.5rem!important;margin-right:-1.5rem!important}.mx-n5{margin-left:-3rem!important;margin-right:-3rem!important}.mx-n6{margin-left:-4rem!important;margin-right:-4rem!important}.mx-n7{margin-left:-6rem!important;margin-right:-6rem!important}.mx-n8{margin-left:-8rem!important;margin-right:-8rem!important}.mx-n9{margin-left:-10rem!important;margin-right:-10rem!important}.mx-n10{margin-left:-12rem!important;margin-right:-12rem!important}.mx-n11{margin-left:-14rem!important;margin-right:-14rem!important}.mx-n12{margin-left:-16rem!important;margin-right:-16rem!important}.my-n1{margin-bottom:-.25rem!important;margin-top:-.25rem!important}.my-n2{margin-bottom:-.5rem!important;margin-top:-.5rem!important}.my-n3{margin-bottom:-1rem!important;margin-top:-1rem!important}.my-n4{margin-bottom:-1.5rem!important;margin-top:-1.5rem!important}.my-n5{margin-bottom:-3rem!important;margin-top:-3rem!important}.my-n6{margin-bottom:-4rem!important;margin-top:-4rem!important}.my-n7{margin-bottom:-6rem!important;margin-top:-6rem!important}.my-n8{margin-bottom:-8rem!important;margin-top:-8rem!important}.my-n9{margin-bottom:-10rem!important;margin-top:-10rem!important}.my-n10{margin-bottom:-12rem!important;margin-top:-12rem!important}.my-n11{margin-bottom:-14rem!important;margin-top:-14rem!important}.my-n12{margin-bottom:-16rem!important;margin-top:-16rem!important}.mt-n1{margin-top:-.25rem!important}.mt-n2{margin-top:-.5rem!important}.mt-n3{margin-top:-1rem!important}.mt-n4{margin-top:-1.5rem!important}.mt-n5{margin-top:-3rem!important}.mt-n6{margin-top:-4rem!important}.mt-n7{margin-top:-6rem!important}.mt-n8{margin-top:-8rem!important}.mt-n9{margin-top:-10rem!important}.mt-n10{margin-top:-12rem!important}.mt-n11{margin-top:-14rem!important}.mt-n12{margin-top:-16rem!important}.me-n1{margin-right:-.25rem!important}.me-n2{margin-right:-.5rem!important}.me-n3{margin-right:-1rem!important}.me-n4{margin-right:-1.5rem!important}.me-n5{margin-right:-3rem!important}.me-n6{margin-right:-4rem!important}.me-n7{margin-right:-6rem!important}.me-n8{margin-right:-8rem!important}.me-n9{margin-right:-10rem!important}.me-n10{margin-right:-12rem!important}.me-n11{margin-right:-14rem!important}.me-n12{margin-right:-16rem!important}.mb-n1{margin-bottom:-.25rem!important}.mb-n2{margin-bottom:-.5rem!important}.mb-n3{margin-bottom:-1rem!important}.mb-n4{margin-bottom:-1.5rem!important}.mb-n5{margin-bottom:-3rem!important}.mb-n6{margin-bottom:-4rem!important}.mb-n7{margin-bottom:-6rem!important}.mb-n8{margin-bottom:-8rem!important}.mb-n9{margin-bottom:-10rem!important}.mb-n10{margin-bottom:-12rem!important}.mb-n11{margin-bottom:-14rem!important}.mb-n12{margin-bottom:-16rem!important}.ms-n1{margin-left:-.25rem!important}.ms-n2{margin-left:-.5rem!important}.ms-n3{margin-left:-1rem!important}.ms-n4{margin-left:-1.5rem!important}.ms-n5{margin-left:-3rem!important}.ms-n6{margin-left:-4rem!important}.ms-n7{margin-left:-6rem!important}.ms-n8{margin-left:-8rem!important}.ms-n9{margin-left:-10rem!important}.ms-n10{margin-left:-12rem!important}.ms-n11{margin-left:-14rem!important}.ms-n12{margin-left:-16rem!important}.p-0{padding:0!important}.p-1{padding:.25rem!important}.p-2{padding:.5rem!important}.p-3{padding:1rem!important}.p-4{padding:1.5rem!important}.p-5{padding:3rem!important}.p-6{padding:4rem!important}.p-7{padding:6rem!important}.p-8{padding:8rem!important}.p-9{padding:10rem!important}.p-10{padding:12rem!important}.p-11{padding:14rem!important}.p-12{padding:16rem!important}.px-0{padding-left:0!important;padding-right:0!important}.px-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-3{padding-left:1rem!important;padding-right:1rem!important}.px-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-5{padding-left:3rem!important;padding-right:3rem!important}.px-6{padding-left:4rem!important;padding-right:4rem!important}.px-7{padding-left:6rem!important;padding-right:6rem!important}.px-8{padding-left:8rem!important;padding-right:8rem!important}.px-9{padding-left:10rem!important;padding-right:10rem!important}.px-10{padding-left:12rem!important;padding-right:12rem!important}.px-11{padding-left:14rem!important;padding-right:14rem!important}.px-12{padding-left:16rem!important;padding-right:16rem!important}.py-0{padding-bottom:0!important;padding-top:0!important}.py-1{padding-bottom:.25rem!important;padding-top:.25rem!important}.py-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.py-3{padding-bottom:1rem!important;padding-top:1rem!important}.py-4{padding-bottom:1.5rem!important;padding-top:1.5rem!important}.py-5{padding-bottom:3rem!important;padding-top:3rem!important}.py-6{padding-bottom:4rem!important;padding-top:4rem!important}.py-7{padding-bottom:6rem!important;padding-top:6rem!important}.py-8{padding-bottom:8rem!important;padding-top:8rem!important}.py-9{padding-bottom:10rem!important;padding-top:10rem!important}.py-10{padding-bottom:12rem!important;padding-top:12rem!important}.py-11{padding-bottom:14rem!important;padding-top:14rem!important}.py-12{padding-bottom:16rem!important;padding-top:16rem!important}.pt-0{padding-top:0!important}.pt-1{padding-top:.25rem!important}.pt-2{padding-top:.5rem!important}.pt-3{padding-top:1rem!important}.pt-4{padding-top:1.5rem!important}.pt-5{padding-top:3rem!important}.pt-6{padding-top:4rem!important}.pt-7{padding-top:6rem!important}.pt-8{padding-top:8rem!important}.pt-9{padding-top:10rem!important}.pt-10{padding-top:12rem!important}.pt-11{padding-top:14rem!important}.pt-12{padding-top:16rem!important}.pe-0{padding-right:0!important}.pe-1{padding-right:.25rem!important}.pe-2{padding-right:.5rem!important}.pe-3{padding-right:1rem!important}.pe-4{padding-right:1.5rem!important}.pe-5{padding-right:3rem!important}.pe-6{padding-right:4rem!important}.pe-7{padding-right:6rem!important}.pe-8{padding-right:8rem!important}.pe-9{padding-right:10rem!important}.pe-10{padding-right:12rem!important}.pe-11{padding-right:14rem!important}.pe-12{padding-right:16rem!important}.pb-0{padding-bottom:0!important}.pb-1{padding-bottom:.25rem!important}.pb-2{padding-bottom:.5rem!important}.pb-3{padding-bottom:1rem!important}.pb-4{padding-bottom:1.5rem!important}.pb-5{padding-bottom:3rem!important}.pb-6{padding-bottom:4rem!important}.pb-7{padding-bottom:6rem!important}.pb-8{padding-bottom:8rem!important}.pb-9{padding-bottom:10rem!important}.pb-10{padding-bottom:12rem!important}.pb-11{padding-bottom:14rem!important}.pb-12{padding-bottom:16rem!important}.ps-0{padding-left:0!important}.ps-1{padding-left:.25rem!important}.ps-2{padding-left:.5rem!important}.ps-3{padding-left:1rem!important}.ps-4{padding-left:1.5rem!important}.ps-5{padding-left:3rem!important}.ps-6{padding-left:4rem!important}.ps-7{padding-left:6rem!important}.ps-8{padding-left:8rem!important}.ps-9{padding-left:10rem!important}.ps-10{padding-left:12rem!important}.ps-11{padding-left:14rem!important}.ps-12{padding-left:16rem!important}.font-monospace{font-family:var(--bs-font-monospace)!important}.fs-1{font-size:calc(1.425rem + 2.1vw)!important}.fs-2{font-size:calc(1.35rem + 1.2vw)!important}.fs-3{font-size:calc(1.3125rem + .75vw)!important}.fs-4{font-size:calc(1.275rem + .3vw)!important}.fs-5{font-size:1.25rem!important}.fs-6{font-size:1rem!important}.fst-italic{font-style:italic!important}.fst-normal{font-style:normal!important}.fw-light{font-weight:300!important}.fw-lighter{font-weight:lighter!important}.fw-normal{font-weight:400!important}.fw-bold{font-weight:600!important}.fw-bolder{font-weight:700!important}.lh-1{line-height:1!important}.lh-sm{line-height:1.25!important}.lh-base{line-height:1.5!important}.lh-lg{line-height:2!important}.text-start{text-align:left!important}.text-end{text-align:right!important}.text-center{text-align:center!important}.text-decoration-underline{text-decoration:underline!important}.text-decoration-line-through{text-decoration:line-through!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.text-break{word-break:break-word!important}.text-primary{color:#cb0c9f!important}.text-secondary{color:#8392ab!important}.text-success{color:#82d616!important}.text-info{color:#17c1e8!important}.text-warning{color:#fbcf33!important}.text-danger{color:#ea0606!important}.text-light{color:#e9ecef!important}.text-dark{color:#344767!important}.text-white{color:#fff!important}.text-body{color:#67748e!important}.text-muted{color:#6c757d!important}.bg-primary{background-color:#cb0c9f!important}.bg-secondary{background-color:#8392ab!important}.bg-success{background-color:#82d616!important}.bg-info{background-color:#17c1e8!important}.bg-warning{background-color:#fbcf33!important}.bg-danger{background-color:#ea0606!important}.bg-light{background-color:#e9ecef!important}.bg-dark{background-color:#344767!important}.bg-body,.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.bg-gray-100{background-color:#f8f9fa!important}.bg-gray-200{background-color:#e9ecef!important}.bg-gray-300{background-color:#dee2e6!important}.bg-gray-400{background-color:#ced4da!important}.bg-gray-500{background-color:#adb5bd!important}.bg-gray-600{background-color:#6c757d!important}.bg-gray-700{background-color:#495057!important}.bg-gray-800{background-color:#343a40!important}.bg-gray-900{background-color:#212529!important}.bg-gradient{background-image:var(--bs-gradient)!important}.user-select-all{-webkit-user-select:all!important;-moz-user-select:all!important;user-select:all!important}.user-select-auto{-webkit-user-select:auto!important;-moz-user-select:auto!important;-ms-user-select:auto!important;user-select:auto!important}.user-select-none{-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.pe-none{pointer-events:none!important}.pe-auto{pointer-events:auto!important}.rounded{border-radius:.25rem!important}.rounded-0{border-radius:0!important}.rounded-1,.rounded-2{border-radius:.25rem!important}.rounded-3{border-radius:.75rem!important}.avatar.rounded-circle img,.rounded-circle{border-radius:50%!important}.rounded-pill{border-radius:50rem!important}.rounded-top{border-top-left-radius:.25rem!important}.rounded-end,.rounded-top{border-top-right-radius:.25rem!important}.rounded-bottom,.rounded-end{border-bottom-right-radius:.25rem!important}.rounded-bottom,.rounded-start{border-bottom-left-radius:.25rem!important}.rounded-start{border-top-left-radius:.25rem!important}.visible{visibility:visible!important}.invisible{visibility:hidden!important}.transform-scale-5{transform:scale(.5)!important}.transform-scale-6{transform:scale(.6)!important}.transform-scale-7{transform:scale(.7)!important}.transform-scale-8{transform:scale(.8)!important}.transform-scale-9{transform:scale(.9)!important}.transform-scale-10{transform:scale(1)!important}.opacity-0{opacity:0!important}.opacity-1{opacity:.1!important}.opacity-2{opacity:.2!important}.opacity-3{opacity:.3!important}.opacity-4{opacity:.4!important}.opacity-5{opacity:.5!important}.opacity-6{opacity:.6!important}.opacity-7{opacity:.7!important}.opacity-8{opacity:.8!important}.opacity-9{opacity:.9!important}.opacity-10{opacity:1!important}.z-index-0{z-index:0!important}.z-index-1{z-index:1!important}.z-index-2{z-index:2!important}.z-index-3{z-index:3!important}.letter-spacing-1{letter-spacing:1px!important}.letter-spacing-2{letter-spacing:2px!important}.letter-spacing-3{letter-spacing:3px!important}.letter-spacing-4{letter-spacing:4px!important}.letter-spacing-5{letter-spacing:5px!important}.border-radius-top-start-0{border-top-left-radius:0!important}.border-radius-top-end-0{border-top-right-radius:0!important}.border-radius-bottom-start-0{border-bottom-left-radius:0!important}.border-radius-bottom-end-0{border-bottom-right-radius:0!important}.max-height-100{max-height:100px!important}.max-height-150{max-height:150px!important}.max-height-160{max-height:160px!important}.max-height-200,.max-height-250{max-height:200px!important}.max-height-300{max-height:300px!important}.max-height-400{max-height:400px!important}.max-height-500{max-height:500px!important}.max-height-600{max-height:600px!important}.max-height-vh-10{max-height:10vh!important}.max-height-vh-20{max-height:20vh!important}.max-height-vh-30{max-height:30vh!important}.max-height-vh-40{max-height:40vh!important}.max-height-vh-50{max-height:50vh!important}.max-height-vh-60{max-height:60vh!important}.max-height-vh-70{max-height:70vh!important}.max-height-vh-80{max-height:80vh!important}.max-height-vh-90{max-height:90vh!important}.max-height-vh-100{max-height:100vh!important}.min-height-100{min-height:100px!important}.min-height-150{min-height:150px!important}.min-height-160{min-height:160px!important}.min-height-200,.min-height-250{min-height:200px!important}.min-height-300{min-height:300px!important}.min-height-400{min-height:400px!important}.min-height-500{min-height:500px!important}.min-height-600{min-height:600px!important}.height-100{height:100px!important}.height-200{height:200px!important}.height-300{height:300px!important}.height-400{height:400px!important}.height-500{height:500px!important}.height-600{height:600px!important}.max-width-100{max-width:100px!important}.max-width-200{max-width:200px!important}.max-width-300{max-width:300px!important}.max-width-400{max-width:400px!important}.max-width-500{max-width:500px!important}@media (min-width:576px){.float-sm-start{float:left!important}.float-sm-end{float:right!important}.float-sm-none{float:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-grid{display:grid!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.d-sm-none{display:none!important}.border-top-sm{border-top:1px solid #dee2e6!important}.border-top-sm-0{border-top:0!important}.border-end-sm{border-right:1px solid #dee2e6!important}.border-end-sm-0{border-right:0!important}.border-bottom-sm{border-bottom:1px solid #dee2e6!important}.border-bottom-sm-0{border-bottom:0!important}.border-start-sm{border-left:1px solid #dee2e6!important}.border-start-sm-0{border-left:0!important}.w-sm-0{width:0!important}.w-sm-1{width:1%!important}.w-sm-2{width:2%!important}.w-sm-3{width:3%!important}.w-sm-4{width:4%!important}.w-sm-5{width:5%!important}.w-sm-6{width:6%!important}.w-sm-7{width:7%!important}.w-sm-8{width:8%!important}.w-sm-9{width:9%!important}.w-sm-10{width:10%!important}.w-sm-15{width:15%!important}.w-sm-20{width:20%!important}.w-sm-25{width:25%!important}.w-sm-30{width:30%!important}.w-sm-35{width:35%!important}.w-sm-40{width:40%!important}.w-sm-45{width:45%!important}.w-sm-50{width:50%!important}.w-sm-55{width:55%!important}.w-sm-60{width:60%!important}.w-sm-65{width:65%!important}.w-sm-70{width:70%!important}.w-sm-75{width:75%!important}.w-sm-80{width:80%!important}.w-sm-85{width:85%!important}.w-sm-90{width:90%!important}.w-sm-95{width:95%!important}.w-sm-100{width:100%!important}.w-sm-auto{width:auto!important}.flex-sm-fill{flex:1 1 auto!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-sm-0{gap:0!important}.gap-sm-1{gap:.25rem!important}.gap-sm-2{gap:.5rem!important}.gap-sm-3{gap:1rem!important}.gap-sm-4{gap:1.5rem!important}.gap-sm-5{gap:3rem!important}.gap-sm-6{gap:4rem!important}.gap-sm-7{gap:6rem!important}.gap-sm-8{gap:8rem!important}.gap-sm-9{gap:10rem!important}.gap-sm-10{gap:12rem!important}.gap-sm-11{gap:14rem!important}.gap-sm-12{gap:16rem!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.justify-content-sm-evenly{justify-content:space-evenly!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.order-sm-first{order:-1!important}.order-sm-0{order:0!important}.order-sm-1{order:1!important}.order-sm-2{order:2!important}.order-sm-3{order:3!important}.order-sm-4{order:4!important}.order-sm-5{order:5!important}.order-sm-last{order:6!important}.m-sm-0{margin:0!important}.m-sm-1{margin:.25rem!important}.m-sm-2{margin:.5rem!important}.m-sm-3{margin:1rem!important}.m-sm-4{margin:1.5rem!important}.m-sm-5{margin:3rem!important}.m-sm-6{margin:4rem!important}.m-sm-7{margin:6rem!important}.m-sm-8{margin:8rem!important}.m-sm-9{margin:10rem!important}.m-sm-10{margin:12rem!important}.m-sm-11{margin:14rem!important}.m-sm-12{margin:16rem!important}.m-sm-auto{margin:auto!important}.mx-sm-0{margin-left:0!important;margin-right:0!important}.mx-sm-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-sm-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-sm-3{margin-left:1rem!important;margin-right:1rem!important}.mx-sm-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-sm-5{margin-left:3rem!important;margin-right:3rem!important}.mx-sm-6{margin-left:4rem!important;margin-right:4rem!important}.mx-sm-7{margin-left:6rem!important;margin-right:6rem!important}.mx-sm-8{margin-left:8rem!important;margin-right:8rem!important}.mx-sm-9{margin-left:10rem!important;margin-right:10rem!important}.mx-sm-10{margin-left:12rem!important;margin-right:12rem!important}.mx-sm-11{margin-left:14rem!important;margin-right:14rem!important}.mx-sm-12{margin-left:16rem!important;margin-right:16rem!important}.mx-sm-auto{margin-left:auto!important;margin-right:auto!important}.my-sm-0{margin-bottom:0!important;margin-top:0!important}.my-sm-1{margin-bottom:.25rem!important;margin-top:.25rem!important}.my-sm-2{margin-bottom:.5rem!important;margin-top:.5rem!important}.my-sm-3{margin-bottom:1rem!important;margin-top:1rem!important}.my-sm-4{margin-bottom:1.5rem!important;margin-top:1.5rem!important}.my-sm-5{margin-bottom:3rem!important;margin-top:3rem!important}.my-sm-6{margin-bottom:4rem!important;margin-top:4rem!important}.my-sm-7{margin-bottom:6rem!important;margin-top:6rem!important}.my-sm-8{margin-bottom:8rem!important;margin-top:8rem!important}.my-sm-9{margin-bottom:10rem!important;margin-top:10rem!important}.my-sm-10{margin-bottom:12rem!important;margin-top:12rem!important}.my-sm-11{margin-bottom:14rem!important;margin-top:14rem!important}.my-sm-12{margin-bottom:16rem!important;margin-top:16rem!important}.my-sm-auto{margin-bottom:auto!important;margin-top:auto!important}.mt-sm-0{margin-top:0!important}.mt-sm-1{margin-top:.25rem!important}.mt-sm-2{margin-top:.5rem!important}.mt-sm-3{margin-top:1rem!important}.mt-sm-4{margin-top:1.5rem!important}.mt-sm-5{margin-top:3rem!important}.mt-sm-6{margin-top:4rem!important}.mt-sm-7{margin-top:6rem!important}.mt-sm-8{margin-top:8rem!important}.mt-sm-9{margin-top:10rem!important}.mt-sm-10{margin-top:12rem!important}.mt-sm-11{margin-top:14rem!important}.mt-sm-12{margin-top:16rem!important}.mt-sm-auto{margin-top:auto!important}.me-sm-0{margin-right:0!important}.me-sm-1{margin-right:.25rem!important}.me-sm-2{margin-right:.5rem!important}.me-sm-3{margin-right:1rem!important}.me-sm-4{margin-right:1.5rem!important}.me-sm-5{margin-right:3rem!important}.me-sm-6{margin-right:4rem!important}.me-sm-7{margin-right:6rem!important}.me-sm-8{margin-right:8rem!important}.me-sm-9{margin-right:10rem!important}.me-sm-10{margin-right:12rem!important}.me-sm-11{margin-right:14rem!important}.me-sm-12{margin-right:16rem!important}.me-sm-auto{margin-right:auto!important}.mb-sm-0{margin-bottom:0!important}.mb-sm-1{margin-bottom:.25rem!important}.mb-sm-2{margin-bottom:.5rem!important}.mb-sm-3{margin-bottom:1rem!important}.mb-sm-4{margin-bottom:1.5rem!important}.mb-sm-5{margin-bottom:3rem!important}.mb-sm-6{margin-bottom:4rem!important}.mb-sm-7{margin-bottom:6rem!important}.mb-sm-8{margin-bottom:8rem!important}.mb-sm-9{margin-bottom:10rem!important}.mb-sm-10{margin-bottom:12rem!important}.mb-sm-11{margin-bottom:14rem!important}.mb-sm-12{margin-bottom:16rem!important}.mb-sm-auto{margin-bottom:auto!important}.ms-sm-0{margin-left:0!important}.ms-sm-1{margin-left:.25rem!important}.ms-sm-2{margin-left:.5rem!important}.ms-sm-3{margin-left:1rem!important}.ms-sm-4{margin-left:1.5rem!important}.ms-sm-5{margin-left:3rem!important}.ms-sm-6{margin-left:4rem!important}.ms-sm-7{margin-left:6rem!important}.ms-sm-8{margin-left:8rem!important}.ms-sm-9{margin-left:10rem!important}.ms-sm-10{margin-left:12rem!important}.ms-sm-11{margin-left:14rem!important}.ms-sm-12{margin-left:16rem!important}.ms-sm-auto{margin-left:auto!important}.m-sm-n1{margin:-.25rem!important}.m-sm-n2{margin:-.5rem!important}.m-sm-n3{margin:-1rem!important}.m-sm-n4{margin:-1.5rem!important}.m-sm-n5{margin:-3rem!important}.m-sm-n6{margin:-4rem!important}.m-sm-n7{margin:-6rem!important}.m-sm-n8{margin:-8rem!important}.m-sm-n9{margin:-10rem!important}.m-sm-n10{margin:-12rem!important}.m-sm-n11{margin:-14rem!important}.m-sm-n12{margin:-16rem!important}.mx-sm-n1{margin-left:-.25rem!important;margin-right:-.25rem!important}.mx-sm-n2{margin-left:-.5rem!important;margin-right:-.5rem!important}.mx-sm-n3{margin-left:-1rem!important;margin-right:-1rem!important}.mx-sm-n4{margin-left:-1.5rem!important;margin-right:-1.5rem!important}.mx-sm-n5{margin-left:-3rem!important;margin-right:-3rem!important}.mx-sm-n6{margin-left:-4rem!important;margin-right:-4rem!important}.mx-sm-n7{margin-left:-6rem!important;margin-right:-6rem!important}.mx-sm-n8{margin-left:-8rem!important;margin-right:-8rem!important}.mx-sm-n9{margin-left:-10rem!important;margin-right:-10rem!important}.mx-sm-n10{margin-left:-12rem!important;margin-right:-12rem!important}.mx-sm-n11{margin-left:-14rem!important;margin-right:-14rem!important}.mx-sm-n12{margin-left:-16rem!important;margin-right:-16rem!important}.my-sm-n1{margin-bottom:-.25rem!important;margin-top:-.25rem!important}.my-sm-n2{margin-bottom:-.5rem!important;margin-top:-.5rem!important}.my-sm-n3{margin-bottom:-1rem!important;margin-top:-1rem!important}.my-sm-n4{margin-bottom:-1.5rem!important;margin-top:-1.5rem!important}.my-sm-n5{margin-bottom:-3rem!important;margin-top:-3rem!important}.my-sm-n6{margin-bottom:-4rem!important;margin-top:-4rem!important}.my-sm-n7{margin-bottom:-6rem!important;margin-top:-6rem!important}.my-sm-n8{margin-bottom:-8rem!important;margin-top:-8rem!important}.my-sm-n9{margin-bottom:-10rem!important;margin-top:-10rem!important}.my-sm-n10{margin-bottom:-12rem!important;margin-top:-12rem!important}.my-sm-n11{margin-bottom:-14rem!important;margin-top:-14rem!important}.my-sm-n12{margin-bottom:-16rem!important;margin-top:-16rem!important}.mt-sm-n1{margin-top:-.25rem!important}.mt-sm-n2{margin-top:-.5rem!important}.mt-sm-n3{margin-top:-1rem!important}.mt-sm-n4{margin-top:-1.5rem!important}.mt-sm-n5{margin-top:-3rem!important}.mt-sm-n6{margin-top:-4rem!important}.mt-sm-n7{margin-top:-6rem!important}.mt-sm-n8{margin-top:-8rem!important}.mt-sm-n9{margin-top:-10rem!important}.mt-sm-n10{margin-top:-12rem!important}.mt-sm-n11{margin-top:-14rem!important}.mt-sm-n12{margin-top:-16rem!important}.me-sm-n1{margin-right:-.25rem!important}.me-sm-n2{margin-right:-.5rem!important}.me-sm-n3{margin-right:-1rem!important}.me-sm-n4{margin-right:-1.5rem!important}.me-sm-n5{margin-right:-3rem!important}.me-sm-n6{margin-right:-4rem!important}.me-sm-n7{margin-right:-6rem!important}.me-sm-n8{margin-right:-8rem!important}.me-sm-n9{margin-right:-10rem!important}.me-sm-n10{margin-right:-12rem!important}.me-sm-n11{margin-right:-14rem!important}.me-sm-n12{margin-right:-16rem!important}.mb-sm-n1{margin-bottom:-.25rem!important}.mb-sm-n2{margin-bottom:-.5rem!important}.mb-sm-n3{margin-bottom:-1rem!important}.mb-sm-n4{margin-bottom:-1.5rem!important}.mb-sm-n5{margin-bottom:-3rem!important}.mb-sm-n6{margin-bottom:-4rem!important}.mb-sm-n7{margin-bottom:-6rem!important}.mb-sm-n8{margin-bottom:-8rem!important}.mb-sm-n9{margin-bottom:-10rem!important}.mb-sm-n10{margin-bottom:-12rem!important}.mb-sm-n11{margin-bottom:-14rem!important}.mb-sm-n12{margin-bottom:-16rem!important}.ms-sm-n1{margin-left:-.25rem!important}.ms-sm-n2{margin-left:-.5rem!important}.ms-sm-n3{margin-left:-1rem!important}.ms-sm-n4{margin-left:-1.5rem!important}.ms-sm-n5{margin-left:-3rem!important}.ms-sm-n6{margin-left:-4rem!important}.ms-sm-n7{margin-left:-6rem!important}.ms-sm-n8{margin-left:-8rem!important}.ms-sm-n9{margin-left:-10rem!important}.ms-sm-n10{margin-left:-12rem!important}.ms-sm-n11{margin-left:-14rem!important}.ms-sm-n12{margin-left:-16rem!important}.p-sm-0{padding:0!important}.p-sm-1{padding:.25rem!important}.p-sm-2{padding:.5rem!important}.p-sm-3{padding:1rem!important}.p-sm-4{padding:1.5rem!important}.p-sm-5{padding:3rem!important}.p-sm-6{padding:4rem!important}.p-sm-7{padding:6rem!important}.p-sm-8{padding:8rem!important}.p-sm-9{padding:10rem!important}.p-sm-10{padding:12rem!important}.p-sm-11{padding:14rem!important}.p-sm-12{padding:16rem!important}.px-sm-0{padding-left:0!important;padding-right:0!important}.px-sm-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-sm-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-sm-3{padding-left:1rem!important;padding-right:1rem!important}.px-sm-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-sm-5{padding-left:3rem!important;padding-right:3rem!important}.px-sm-6{padding-left:4rem!important;padding-right:4rem!important}.px-sm-7{padding-left:6rem!important;padding-right:6rem!important}.px-sm-8{padding-left:8rem!important;padding-right:8rem!important}.px-sm-9{padding-left:10rem!important;padding-right:10rem!important}.px-sm-10{padding-left:12rem!important;padding-right:12rem!important}.px-sm-11{padding-left:14rem!important;padding-right:14rem!important}.px-sm-12{padding-left:16rem!important;padding-right:16rem!important}.py-sm-0{padding-bottom:0!important;padding-top:0!important}.py-sm-1{padding-bottom:.25rem!important;padding-top:.25rem!important}.py-sm-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.py-sm-3{padding-bottom:1rem!important;padding-top:1rem!important}.py-sm-4{padding-bottom:1.5rem!important;padding-top:1.5rem!important}.py-sm-5{padding-bottom:3rem!important;padding-top:3rem!important}.py-sm-6{padding-bottom:4rem!important;padding-top:4rem!important}.py-sm-7{padding-bottom:6rem!important;padding-top:6rem!important}.py-sm-8{padding-bottom:8rem!important;padding-top:8rem!important}.py-sm-9{padding-bottom:10rem!important;padding-top:10rem!important}.py-sm-10{padding-bottom:12rem!important;padding-top:12rem!important}.py-sm-11{padding-bottom:14rem!important;padding-top:14rem!important}.py-sm-12{padding-bottom:16rem!important;padding-top:16rem!important}.pt-sm-0{padding-top:0!important}.pt-sm-1{padding-top:.25rem!important}.pt-sm-2{padding-top:.5rem!important}.pt-sm-3{padding-top:1rem!important}.pt-sm-4{padding-top:1.5rem!important}.pt-sm-5{padding-top:3rem!important}.pt-sm-6{padding-top:4rem!important}.pt-sm-7{padding-top:6rem!important}.pt-sm-8{padding-top:8rem!important}.pt-sm-9{padding-top:10rem!important}.pt-sm-10{padding-top:12rem!important}.pt-sm-11{padding-top:14rem!important}.pt-sm-12{padding-top:16rem!important}.pe-sm-0{padding-right:0!important}.pe-sm-1{padding-right:.25rem!important}.pe-sm-2{padding-right:.5rem!important}.pe-sm-3{padding-right:1rem!important}.pe-sm-4{padding-right:1.5rem!important}.pe-sm-5{padding-right:3rem!important}.pe-sm-6{padding-right:4rem!important}.pe-sm-7{padding-right:6rem!important}.pe-sm-8{padding-right:8rem!important}.pe-sm-9{padding-right:10rem!important}.pe-sm-10{padding-right:12rem!important}.pe-sm-11{padding-right:14rem!important}.pe-sm-12{padding-right:16rem!important}.pb-sm-0{padding-bottom:0!important}.pb-sm-1{padding-bottom:.25rem!important}.pb-sm-2{padding-bottom:.5rem!important}.pb-sm-3{padding-bottom:1rem!important}.pb-sm-4{padding-bottom:1.5rem!important}.pb-sm-5{padding-bottom:3rem!important}.pb-sm-6{padding-bottom:4rem!important}.pb-sm-7{padding-bottom:6rem!important}.pb-sm-8{padding-bottom:8rem!important}.pb-sm-9{padding-bottom:10rem!important}.pb-sm-10{padding-bottom:12rem!important}.pb-sm-11{padding-bottom:14rem!important}.pb-sm-12{padding-bottom:16rem!important}.ps-sm-0{padding-left:0!important}.ps-sm-1{padding-left:.25rem!important}.ps-sm-2{padding-left:.5rem!important}.ps-sm-3{padding-left:1rem!important}.ps-sm-4{padding-left:1.5rem!important}.ps-sm-5{padding-left:3rem!important}.ps-sm-6{padding-left:4rem!important}.ps-sm-7{padding-left:6rem!important}.ps-sm-8{padding-left:8rem!important}.ps-sm-9{padding-left:10rem!important}.ps-sm-10{padding-left:12rem!important}.ps-sm-11{padding-left:14rem!important}.ps-sm-12{padding-left:16rem!important}.text-sm-start{text-align:left!important}.text-sm-end{text-align:right!important}.text-sm-center{text-align:center!important}.transform-scale-sm-5{transform:scale(.5)!important}.transform-scale-sm-6{transform:scale(.6)!important}.transform-scale-sm-7{transform:scale(.7)!important}.transform-scale-sm-8{transform:scale(.8)!important}.transform-scale-sm-9{transform:scale(.9)!important}.transform-scale-sm-10{transform:scale(1)!important}.border-radius-top-start-sm-0{border-top-left-radius:0!important}.border-radius-top-end-sm-0{border-top-right-radius:0!important}.border-radius-bottom-start-sm-0{border-bottom-left-radius:0!important}.border-radius-bottom-end-sm-0{border-bottom-right-radius:0!important}}@media (min-width:768px){.float-md-start{float:left!important}.float-md-end{float:right!important}.float-md-none{float:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-grid{display:grid!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.d-md-none{display:none!important}.border-top-md{border-top:1px solid #dee2e6!important}.border-top-md-0{border-top:0!important}.border-end-md{border-right:1px solid #dee2e6!important}.border-end-md-0{border-right:0!important}.border-bottom-md{border-bottom:1px solid #dee2e6!important}.border-bottom-md-0{border-bottom:0!important}.border-start-md{border-left:1px solid #dee2e6!important}.border-start-md-0{border-left:0!important}.w-md-0{width:0!important}.w-md-1{width:1%!important}.w-md-2{width:2%!important}.w-md-3{width:3%!important}.w-md-4{width:4%!important}.w-md-5{width:5%!important}.w-md-6{width:6%!important}.w-md-7{width:7%!important}.w-md-8{width:8%!important}.w-md-9{width:9%!important}.w-md-10{width:10%!important}.w-md-15{width:15%!important}.w-md-20{width:20%!important}.w-md-25{width:25%!important}.w-md-30{width:30%!important}.w-md-35{width:35%!important}.w-md-40{width:40%!important}.w-md-45{width:45%!important}.w-md-50{width:50%!important}.w-md-55{width:55%!important}.w-md-60{width:60%!important}.w-md-65{width:65%!important}.w-md-70{width:70%!important}.w-md-75{width:75%!important}.w-md-80{width:80%!important}.w-md-85{width:85%!important}.w-md-90{width:90%!important}.w-md-95{width:95%!important}.w-md-100{width:100%!important}.w-md-auto{width:auto!important}.flex-md-fill{flex:1 1 auto!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-md-0{gap:0!important}.gap-md-1{gap:.25rem!important}.gap-md-2{gap:.5rem!important}.gap-md-3{gap:1rem!important}.gap-md-4{gap:1.5rem!important}.gap-md-5{gap:3rem!important}.gap-md-6{gap:4rem!important}.gap-md-7{gap:6rem!important}.gap-md-8{gap:8rem!important}.gap-md-9{gap:10rem!important}.gap-md-10{gap:12rem!important}.gap-md-11{gap:14rem!important}.gap-md-12{gap:16rem!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.justify-content-md-evenly{justify-content:space-evenly!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.order-md-first{order:-1!important}.order-md-0{order:0!important}.order-md-1{order:1!important}.order-md-2{order:2!important}.order-md-3{order:3!important}.order-md-4{order:4!important}.order-md-5{order:5!important}.order-md-last{order:6!important}.m-md-0{margin:0!important}.m-md-1{margin:.25rem!important}.m-md-2{margin:.5rem!important}.m-md-3{margin:1rem!important}.m-md-4{margin:1.5rem!important}.m-md-5{margin:3rem!important}.m-md-6{margin:4rem!important}.m-md-7{margin:6rem!important}.m-md-8{margin:8rem!important}.m-md-9{margin:10rem!important}.m-md-10{margin:12rem!important}.m-md-11{margin:14rem!important}.m-md-12{margin:16rem!important}.m-md-auto{margin:auto!important}.mx-md-0{margin-left:0!important;margin-right:0!important}.mx-md-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-md-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-md-3{margin-left:1rem!important;margin-right:1rem!important}.mx-md-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-md-5{margin-left:3rem!important;margin-right:3rem!important}.mx-md-6{margin-left:4rem!important;margin-right:4rem!important}.mx-md-7{margin-left:6rem!important;margin-right:6rem!important}.mx-md-8{margin-left:8rem!important;margin-right:8rem!important}.mx-md-9{margin-left:10rem!important;margin-right:10rem!important}.mx-md-10{margin-left:12rem!important;margin-right:12rem!important}.mx-md-11{margin-left:14rem!important;margin-right:14rem!important}.mx-md-12{margin-left:16rem!important;margin-right:16rem!important}.mx-md-auto{margin-left:auto!important;margin-right:auto!important}.my-md-0{margin-bottom:0!important;margin-top:0!important}.my-md-1{margin-bottom:.25rem!important;margin-top:.25rem!important}.my-md-2{margin-bottom:.5rem!important;margin-top:.5rem!important}.my-md-3{margin-bottom:1rem!important;margin-top:1rem!important}.my-md-4{margin-bottom:1.5rem!important;margin-top:1.5rem!important}.my-md-5{margin-bottom:3rem!important;margin-top:3rem!important}.my-md-6{margin-bottom:4rem!important;margin-top:4rem!important}.my-md-7{margin-bottom:6rem!important;margin-top:6rem!important}.my-md-8{margin-bottom:8rem!important;margin-top:8rem!important}.my-md-9{margin-bottom:10rem!important;margin-top:10rem!important}.my-md-10{margin-bottom:12rem!important;margin-top:12rem!important}.my-md-11{margin-bottom:14rem!important;margin-top:14rem!important}.my-md-12{margin-bottom:16rem!important;margin-top:16rem!important}.my-md-auto{margin-bottom:auto!important;margin-top:auto!important}.mt-md-0{margin-top:0!important}.mt-md-1{margin-top:.25rem!important}.mt-md-2{margin-top:.5rem!important}.mt-md-3{margin-top:1rem!important}.mt-md-4{margin-top:1.5rem!important}.mt-md-5{margin-top:3rem!important}.mt-md-6{margin-top:4rem!important}.mt-md-7{margin-top:6rem!important}.mt-md-8{margin-top:8rem!important}.mt-md-9{margin-top:10rem!important}.mt-md-10{margin-top:12rem!important}.mt-md-11{margin-top:14rem!important}.mt-md-12{margin-top:16rem!important}.mt-md-auto{margin-top:auto!important}.me-md-0{margin-right:0!important}.me-md-1{margin-right:.25rem!important}.me-md-2{margin-right:.5rem!important}.me-md-3{margin-right:1rem!important}.me-md-4{margin-right:1.5rem!important}.me-md-5{margin-right:3rem!important}.me-md-6{margin-right:4rem!important}.me-md-7{margin-right:6rem!important}.me-md-8{margin-right:8rem!important}.me-md-9{margin-right:10rem!important}.me-md-10{margin-right:12rem!important}.me-md-11{margin-right:14rem!important}.me-md-12{margin-right:16rem!important}.me-md-auto{margin-right:auto!important}.mb-md-0{margin-bottom:0!important}.mb-md-1{margin-bottom:.25rem!important}.mb-md-2{margin-bottom:.5rem!important}.mb-md-3{margin-bottom:1rem!important}.mb-md-4{margin-bottom:1.5rem!important}.mb-md-5{margin-bottom:3rem!important}.mb-md-6{margin-bottom:4rem!important}.mb-md-7{margin-bottom:6rem!important}.mb-md-8{margin-bottom:8rem!important}.mb-md-9{margin-bottom:10rem!important}.mb-md-10{margin-bottom:12rem!important}.mb-md-11{margin-bottom:14rem!important}.mb-md-12{margin-bottom:16rem!important}.mb-md-auto{margin-bottom:auto!important}.ms-md-0{margin-left:0!important}.ms-md-1{margin-left:.25rem!important}.ms-md-2{margin-left:.5rem!important}.ms-md-3{margin-left:1rem!important}.ms-md-4{margin-left:1.5rem!important}.ms-md-5{margin-left:3rem!important}.ms-md-6{margin-left:4rem!important}.ms-md-7{margin-left:6rem!important}.ms-md-8{margin-left:8rem!important}.ms-md-9{margin-left:10rem!important}.ms-md-10{margin-left:12rem!important}.ms-md-11{margin-left:14rem!important}.ms-md-12{margin-left:16rem!important}.ms-md-auto{margin-left:auto!important}.m-md-n1{margin:-.25rem!important}.m-md-n2{margin:-.5rem!important}.m-md-n3{margin:-1rem!important}.m-md-n4{margin:-1.5rem!important}.m-md-n5{margin:-3rem!important}.m-md-n6{margin:-4rem!important}.m-md-n7{margin:-6rem!important}.m-md-n8{margin:-8rem!important}.m-md-n9{margin:-10rem!important}.m-md-n10{margin:-12rem!important}.m-md-n11{margin:-14rem!important}.m-md-n12{margin:-16rem!important}.mx-md-n1{margin-left:-.25rem!important;margin-right:-.25rem!important}.mx-md-n2{margin-left:-.5rem!important;margin-right:-.5rem!important}.mx-md-n3{margin-left:-1rem!important;margin-right:-1rem!important}.mx-md-n4{margin-left:-1.5rem!important;margin-right:-1.5rem!important}.mx-md-n5{margin-left:-3rem!important;margin-right:-3rem!important}.mx-md-n6{margin-left:-4rem!important;margin-right:-4rem!important}.mx-md-n7{margin-left:-6rem!important;margin-right:-6rem!important}.mx-md-n8{margin-left:-8rem!important;margin-right:-8rem!important}.mx-md-n9{margin-left:-10rem!important;margin-right:-10rem!important}.mx-md-n10{margin-left:-12rem!important;margin-right:-12rem!important}.mx-md-n11{margin-left:-14rem!important;margin-right:-14rem!important}.mx-md-n12{margin-left:-16rem!important;margin-right:-16rem!important}.my-md-n1{margin-bottom:-.25rem!important;margin-top:-.25rem!important}.my-md-n2{margin-bottom:-.5rem!important;margin-top:-.5rem!important}.my-md-n3{margin-bottom:-1rem!important;margin-top:-1rem!important}.my-md-n4{margin-bottom:-1.5rem!important;margin-top:-1.5rem!important}.my-md-n5{margin-bottom:-3rem!important;margin-top:-3rem!important}.my-md-n6{margin-bottom:-4rem!important;margin-top:-4rem!important}.my-md-n7{margin-bottom:-6rem!important;margin-top:-6rem!important}.my-md-n8{margin-bottom:-8rem!important;margin-top:-8rem!important}.my-md-n9{margin-bottom:-10rem!important;margin-top:-10rem!important}.my-md-n10{margin-bottom:-12rem!important;margin-top:-12rem!important}.my-md-n11{margin-bottom:-14rem!important;margin-top:-14rem!important}.my-md-n12{margin-bottom:-16rem!important;margin-top:-16rem!important}.mt-md-n1{margin-top:-.25rem!important}.mt-md-n2{margin-top:-.5rem!important}.mt-md-n3{margin-top:-1rem!important}.mt-md-n4{margin-top:-1.5rem!important}.mt-md-n5{margin-top:-3rem!important}.mt-md-n6{margin-top:-4rem!important}.mt-md-n7{margin-top:-6rem!important}.mt-md-n8{margin-top:-8rem!important}.mt-md-n9{margin-top:-10rem!important}.mt-md-n10{margin-top:-12rem!important}.mt-md-n11{margin-top:-14rem!important}.mt-md-n12{margin-top:-16rem!important}.me-md-n1{margin-right:-.25rem!important}.me-md-n2{margin-right:-.5rem!important}.me-md-n3{margin-right:-1rem!important}.me-md-n4{margin-right:-1.5rem!important}.me-md-n5{margin-right:-3rem!important}.me-md-n6{margin-right:-4rem!important}.me-md-n7{margin-right:-6rem!important}.me-md-n8{margin-right:-8rem!important}.me-md-n9{margin-right:-10rem!important}.me-md-n10{margin-right:-12rem!important}.me-md-n11{margin-right:-14rem!important}.me-md-n12{margin-right:-16rem!important}.mb-md-n1{margin-bottom:-.25rem!important}.mb-md-n2{margin-bottom:-.5rem!important}.mb-md-n3{margin-bottom:-1rem!important}.mb-md-n4{margin-bottom:-1.5rem!important}.mb-md-n5{margin-bottom:-3rem!important}.mb-md-n6{margin-bottom:-4rem!important}.mb-md-n7{margin-bottom:-6rem!important}.mb-md-n8{margin-bottom:-8rem!important}.mb-md-n9{margin-bottom:-10rem!important}.mb-md-n10{margin-bottom:-12rem!important}.mb-md-n11{margin-bottom:-14rem!important}.mb-md-n12{margin-bottom:-16rem!important}.ms-md-n1{margin-left:-.25rem!important}.ms-md-n2{margin-left:-.5rem!important}.ms-md-n3{margin-left:-1rem!important}.ms-md-n4{margin-left:-1.5rem!important}.ms-md-n5{margin-left:-3rem!important}.ms-md-n6{margin-left:-4rem!important}.ms-md-n7{margin-left:-6rem!important}.ms-md-n8{margin-left:-8rem!important}.ms-md-n9{margin-left:-10rem!important}.ms-md-n10{margin-left:-12rem!important}.ms-md-n11{margin-left:-14rem!important}.ms-md-n12{margin-left:-16rem!important}.p-md-0{padding:0!important}.p-md-1{padding:.25rem!important}.p-md-2{padding:.5rem!important}.p-md-3{padding:1rem!important}.p-md-4{padding:1.5rem!important}.p-md-5{padding:3rem!important}.p-md-6{padding:4rem!important}.p-md-7{padding:6rem!important}.p-md-8{padding:8rem!important}.p-md-9{padding:10rem!important}.p-md-10{padding:12rem!important}.p-md-11{padding:14rem!important}.p-md-12{padding:16rem!important}.px-md-0{padding-left:0!important;padding-right:0!important}.px-md-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-md-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-md-3{padding-left:1rem!important;padding-right:1rem!important}.px-md-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-md-5{padding-left:3rem!important;padding-right:3rem!important}.px-md-6{padding-left:4rem!important;padding-right:4rem!important}.px-md-7{padding-left:6rem!important;padding-right:6rem!important}.px-md-8{padding-left:8rem!important;padding-right:8rem!important}.px-md-9{padding-left:10rem!important;padding-right:10rem!important}.px-md-10{padding-left:12rem!important;padding-right:12rem!important}.px-md-11{padding-left:14rem!important;padding-right:14rem!important}.px-md-12{padding-left:16rem!important;padding-right:16rem!important}.py-md-0{padding-bottom:0!important;padding-top:0!important}.py-md-1{padding-bottom:.25rem!important;padding-top:.25rem!important}.py-md-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.py-md-3{padding-bottom:1rem!important;padding-top:1rem!important}.py-md-4{padding-bottom:1.5rem!important;padding-top:1.5rem!important}.py-md-5{padding-bottom:3rem!important;padding-top:3rem!important}.py-md-6{padding-bottom:4rem!important;padding-top:4rem!important}.py-md-7{padding-bottom:6rem!important;padding-top:6rem!important}.py-md-8{padding-bottom:8rem!important;padding-top:8rem!important}.py-md-9{padding-bottom:10rem!important;padding-top:10rem!important}.py-md-10{padding-bottom:12rem!important;padding-top:12rem!important}.py-md-11{padding-bottom:14rem!important;padding-top:14rem!important}.py-md-12{padding-bottom:16rem!important;padding-top:16rem!important}.pt-md-0{padding-top:0!important}.pt-md-1{padding-top:.25rem!important}.pt-md-2{padding-top:.5rem!important}.pt-md-3{padding-top:1rem!important}.pt-md-4{padding-top:1.5rem!important}.pt-md-5{padding-top:3rem!important}.pt-md-6{padding-top:4rem!important}.pt-md-7{padding-top:6rem!important}.pt-md-8{padding-top:8rem!important}.pt-md-9{padding-top:10rem!important}.pt-md-10{padding-top:12rem!important}.pt-md-11{padding-top:14rem!important}.pt-md-12{padding-top:16rem!important}.pe-md-0{padding-right:0!important}.pe-md-1{padding-right:.25rem!important}.pe-md-2{padding-right:.5rem!important}.pe-md-3{padding-right:1rem!important}.pe-md-4{padding-right:1.5rem!important}.pe-md-5{padding-right:3rem!important}.pe-md-6{padding-right:4rem!important}.pe-md-7{padding-right:6rem!important}.pe-md-8{padding-right:8rem!important}.pe-md-9{padding-right:10rem!important}.pe-md-10{padding-right:12rem!important}.pe-md-11{padding-right:14rem!important}.pe-md-12{padding-right:16rem!important}.pb-md-0{padding-bottom:0!important}.pb-md-1{padding-bottom:.25rem!important}.pb-md-2{padding-bottom:.5rem!important}.pb-md-3{padding-bottom:1rem!important}.pb-md-4{padding-bottom:1.5rem!important}.pb-md-5{padding-bottom:3rem!important}.pb-md-6{padding-bottom:4rem!important}.pb-md-7{padding-bottom:6rem!important}.pb-md-8{padding-bottom:8rem!important}.pb-md-9{padding-bottom:10rem!important}.pb-md-10{padding-bottom:12rem!important}.pb-md-11{padding-bottom:14rem!important}.pb-md-12{padding-bottom:16rem!important}.ps-md-0{padding-left:0!important}.ps-md-1{padding-left:.25rem!important}.ps-md-2{padding-left:.5rem!important}.ps-md-3{padding-left:1rem!important}.ps-md-4{padding-left:1.5rem!important}.ps-md-5{padding-left:3rem!important}.ps-md-6{padding-left:4rem!important}.ps-md-7{padding-left:6rem!important}.ps-md-8{padding-left:8rem!important}.ps-md-9{padding-left:10rem!important}.ps-md-10{padding-left:12rem!important}.ps-md-11{padding-left:14rem!important}.ps-md-12{padding-left:16rem!important}.text-md-start{text-align:left!important}.text-md-end{text-align:right!important}.text-md-center{text-align:center!important}.transform-scale-md-5{transform:scale(.5)!important}.transform-scale-md-6{transform:scale(.6)!important}.transform-scale-md-7{transform:scale(.7)!important}.transform-scale-md-8{transform:scale(.8)!important}.transform-scale-md-9{transform:scale(.9)!important}.transform-scale-md-10{transform:scale(1)!important}.border-radius-top-start-md-0{border-top-left-radius:0!important}.border-radius-top-end-md-0{border-top-right-radius:0!important}.border-radius-bottom-start-md-0{border-bottom-left-radius:0!important}.border-radius-bottom-end-md-0{border-bottom-right-radius:0!important}}@media (min-width:992px){.float-lg-start{float:left!important}.float-lg-end{float:right!important}.float-lg-none{float:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-grid{display:grid!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.d-lg-none{display:none!important}.border-top-lg{border-top:1px solid #dee2e6!important}.border-top-lg-0{border-top:0!important}.border-end-lg{border-right:1px solid #dee2e6!important}.border-end-lg-0{border-right:0!important}.border-bottom-lg{border-bottom:1px solid #dee2e6!important}.border-bottom-lg-0{border-bottom:0!important}.border-start-lg{border-left:1px solid #dee2e6!important}.border-start-lg-0{border-left:0!important}.w-lg-0{width:0!important}.w-lg-1{width:1%!important}.w-lg-2{width:2%!important}.w-lg-3{width:3%!important}.w-lg-4{width:4%!important}.w-lg-5{width:5%!important}.w-lg-6{width:6%!important}.w-lg-7{width:7%!important}.w-lg-8{width:8%!important}.w-lg-9{width:9%!important}.w-lg-10{width:10%!important}.w-lg-15{width:15%!important}.w-lg-20{width:20%!important}.w-lg-25{width:25%!important}.w-lg-30{width:30%!important}.w-lg-35{width:35%!important}.w-lg-40{width:40%!important}.w-lg-45{width:45%!important}.w-lg-50{width:50%!important}.w-lg-55{width:55%!important}.w-lg-60{width:60%!important}.w-lg-65{width:65%!important}.w-lg-70{width:70%!important}.w-lg-75{width:75%!important}.w-lg-80{width:80%!important}.w-lg-85{width:85%!important}.w-lg-90{width:90%!important}.w-lg-95{width:95%!important}.w-lg-100{width:100%!important}.w-lg-auto{width:auto!important}.flex-lg-fill{flex:1 1 auto!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-lg-0{gap:0!important}.gap-lg-1{gap:.25rem!important}.gap-lg-2{gap:.5rem!important}.gap-lg-3{gap:1rem!important}.gap-lg-4{gap:1.5rem!important}.gap-lg-5{gap:3rem!important}.gap-lg-6{gap:4rem!important}.gap-lg-7{gap:6rem!important}.gap-lg-8{gap:8rem!important}.gap-lg-9{gap:10rem!important}.gap-lg-10{gap:12rem!important}.gap-lg-11{gap:14rem!important}.gap-lg-12{gap:16rem!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.justify-content-lg-evenly{justify-content:space-evenly!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.order-lg-first{order:-1!important}.order-lg-0{order:0!important}.order-lg-1{order:1!important}.order-lg-2{order:2!important}.order-lg-3{order:3!important}.order-lg-4{order:4!important}.order-lg-5{order:5!important}.order-lg-last{order:6!important}.m-lg-0{margin:0!important}.m-lg-1{margin:.25rem!important}.m-lg-2{margin:.5rem!important}.m-lg-3{margin:1rem!important}.m-lg-4{margin:1.5rem!important}.m-lg-5{margin:3rem!important}.m-lg-6{margin:4rem!important}.m-lg-7{margin:6rem!important}.m-lg-8{margin:8rem!important}.m-lg-9{margin:10rem!important}.m-lg-10{margin:12rem!important}.m-lg-11{margin:14rem!important}.m-lg-12{margin:16rem!important}.m-lg-auto{margin:auto!important}.mx-lg-0{margin-left:0!important;margin-right:0!important}.mx-lg-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-lg-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-lg-3{margin-left:1rem!important;margin-right:1rem!important}.mx-lg-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-lg-5{margin-left:3rem!important;margin-right:3rem!important}.mx-lg-6{margin-left:4rem!important;margin-right:4rem!important}.mx-lg-7{margin-left:6rem!important;margin-right:6rem!important}.mx-lg-8{margin-left:8rem!important;margin-right:8rem!important}.mx-lg-9{margin-left:10rem!important;margin-right:10rem!important}.mx-lg-10{margin-left:12rem!important;margin-right:12rem!important}.mx-lg-11{margin-left:14rem!important;margin-right:14rem!important}.mx-lg-12{margin-left:16rem!important;margin-right:16rem!important}.mx-lg-auto{margin-left:auto!important;margin-right:auto!important}.my-lg-0{margin-bottom:0!important;margin-top:0!important}.my-lg-1{margin-bottom:.25rem!important;margin-top:.25rem!important}.my-lg-2{margin-bottom:.5rem!important;margin-top:.5rem!important}.my-lg-3{margin-bottom:1rem!important;margin-top:1rem!important}.my-lg-4{margin-bottom:1.5rem!important;margin-top:1.5rem!important}.my-lg-5{margin-bottom:3rem!important;margin-top:3rem!important}.my-lg-6{margin-bottom:4rem!important;margin-top:4rem!important}.my-lg-7{margin-bottom:6rem!important;margin-top:6rem!important}.my-lg-8{margin-bottom:8rem!important;margin-top:8rem!important}.my-lg-9{margin-bottom:10rem!important;margin-top:10rem!important}.my-lg-10{margin-bottom:12rem!important;margin-top:12rem!important}.my-lg-11{margin-bottom:14rem!important;margin-top:14rem!important}.my-lg-12{margin-bottom:16rem!important;margin-top:16rem!important}.my-lg-auto{margin-bottom:auto!important;margin-top:auto!important}.mt-lg-0{margin-top:0!important}.mt-lg-1{margin-top:.25rem!important}.mt-lg-2{margin-top:.5rem!important}.mt-lg-3{margin-top:1rem!important}.mt-lg-4{margin-top:1.5rem!important}.mt-lg-5{margin-top:3rem!important}.mt-lg-6{margin-top:4rem!important}.mt-lg-7{margin-top:6rem!important}.mt-lg-8{margin-top:8rem!important}.mt-lg-9{margin-top:10rem!important}.mt-lg-10{margin-top:12rem!important}.mt-lg-11{margin-top:14rem!important}.mt-lg-12{margin-top:16rem!important}.mt-lg-auto{margin-top:auto!important}.me-lg-0{margin-right:0!important}.me-lg-1{margin-right:.25rem!important}.me-lg-2{margin-right:.5rem!important}.me-lg-3{margin-right:1rem!important}.me-lg-4{margin-right:1.5rem!important}.me-lg-5{margin-right:3rem!important}.me-lg-6{margin-right:4rem!important}.me-lg-7{margin-right:6rem!important}.me-lg-8{margin-right:8rem!important}.me-lg-9{margin-right:10rem!important}.me-lg-10{margin-right:12rem!important}.me-lg-11{margin-right:14rem!important}.me-lg-12{margin-right:16rem!important}.me-lg-auto{margin-right:auto!important}.mb-lg-0{margin-bottom:0!important}.mb-lg-1{margin-bottom:.25rem!important}.mb-lg-2{margin-bottom:.5rem!important}.mb-lg-3{margin-bottom:1rem!important}.mb-lg-4{margin-bottom:1.5rem!important}.mb-lg-5{margin-bottom:3rem!important}.mb-lg-6{margin-bottom:4rem!important}.mb-lg-7{margin-bottom:6rem!important}.mb-lg-8{margin-bottom:8rem!important}.mb-lg-9{margin-bottom:10rem!important}.mb-lg-10{margin-bottom:12rem!important}.mb-lg-11{margin-bottom:14rem!important}.mb-lg-12{margin-bottom:16rem!important}.mb-lg-auto{margin-bottom:auto!important}.ms-lg-0{margin-left:0!important}.ms-lg-1{margin-left:.25rem!important}.ms-lg-2{margin-left:.5rem!important}.ms-lg-3{margin-left:1rem!important}.ms-lg-4{margin-left:1.5rem!important}.ms-lg-5{margin-left:3rem!important}.ms-lg-6{margin-left:4rem!important}.ms-lg-7{margin-left:6rem!important}.ms-lg-8{margin-left:8rem!important}.ms-lg-9{margin-left:10rem!important}.ms-lg-10{margin-left:12rem!important}.ms-lg-11{margin-left:14rem!important}.ms-lg-12{margin-left:16rem!important}.ms-lg-auto{margin-left:auto!important}.m-lg-n1{margin:-.25rem!important}.m-lg-n2{margin:-.5rem!important}.m-lg-n3{margin:-1rem!important}.m-lg-n4{margin:-1.5rem!important}.m-lg-n5{margin:-3rem!important}.m-lg-n6{margin:-4rem!important}.m-lg-n7{margin:-6rem!important}.m-lg-n8{margin:-8rem!important}.m-lg-n9{margin:-10rem!important}.m-lg-n10{margin:-12rem!important}.m-lg-n11{margin:-14rem!important}.m-lg-n12{margin:-16rem!important}.mx-lg-n1{margin-left:-.25rem!important;margin-right:-.25rem!important}.mx-lg-n2{margin-left:-.5rem!important;margin-right:-.5rem!important}.mx-lg-n3{margin-left:-1rem!important;margin-right:-1rem!important}.mx-lg-n4{margin-left:-1.5rem!important;margin-right:-1.5rem!important}.mx-lg-n5{margin-left:-3rem!important;margin-right:-3rem!important}.mx-lg-n6{margin-left:-4rem!important;margin-right:-4rem!important}.mx-lg-n7{margin-left:-6rem!important;margin-right:-6rem!important}.mx-lg-n8{margin-left:-8rem!important;margin-right:-8rem!important}.mx-lg-n9{margin-left:-10rem!important;margin-right:-10rem!important}.mx-lg-n10{margin-left:-12rem!important;margin-right:-12rem!important}.mx-lg-n11{margin-left:-14rem!important;margin-right:-14rem!important}.mx-lg-n12{margin-left:-16rem!important;margin-right:-16rem!important}.my-lg-n1{margin-bottom:-.25rem!important;margin-top:-.25rem!important}.my-lg-n2{margin-bottom:-.5rem!important;margin-top:-.5rem!important}.my-lg-n3{margin-bottom:-1rem!important;margin-top:-1rem!important}.my-lg-n4{margin-bottom:-1.5rem!important;margin-top:-1.5rem!important}.my-lg-n5{margin-bottom:-3rem!important;margin-top:-3rem!important}.my-lg-n6{margin-bottom:-4rem!important;margin-top:-4rem!important}.my-lg-n7{margin-bottom:-6rem!important;margin-top:-6rem!important}.my-lg-n8{margin-bottom:-8rem!important;margin-top:-8rem!important}.my-lg-n9{margin-bottom:-10rem!important;margin-top:-10rem!important}.my-lg-n10{margin-bottom:-12rem!important;margin-top:-12rem!important}.my-lg-n11{margin-bottom:-14rem!important;margin-top:-14rem!important}.my-lg-n12{margin-bottom:-16rem!important;margin-top:-16rem!important}.mt-lg-n1{margin-top:-.25rem!important}.mt-lg-n2{margin-top:-.5rem!important}.mt-lg-n3{margin-top:-1rem!important}.mt-lg-n4{margin-top:-1.5rem!important}.mt-lg-n5{margin-top:-3rem!important}.mt-lg-n6{margin-top:-4rem!important}.mt-lg-n7{margin-top:-6rem!important}.mt-lg-n8{margin-top:-8rem!important}.mt-lg-n9{margin-top:-10rem!important}.mt-lg-n10{margin-top:-12rem!important}.mt-lg-n11{margin-top:-14rem!important}.mt-lg-n12{margin-top:-16rem!important}.me-lg-n1{margin-right:-.25rem!important}.me-lg-n2{margin-right:-.5rem!important}.me-lg-n3{margin-right:-1rem!important}.me-lg-n4{margin-right:-1.5rem!important}.me-lg-n5{margin-right:-3rem!important}.me-lg-n6{margin-right:-4rem!important}.me-lg-n7{margin-right:-6rem!important}.me-lg-n8{margin-right:-8rem!important}.me-lg-n9{margin-right:-10rem!important}.me-lg-n10{margin-right:-12rem!important}.me-lg-n11{margin-right:-14rem!important}.me-lg-n12{margin-right:-16rem!important}.mb-lg-n1{margin-bottom:-.25rem!important}.mb-lg-n2{margin-bottom:-.5rem!important}.mb-lg-n3{margin-bottom:-1rem!important}.mb-lg-n4{margin-bottom:-1.5rem!important}.mb-lg-n5{margin-bottom:-3rem!important}.mb-lg-n6{margin-bottom:-4rem!important}.mb-lg-n7{margin-bottom:-6rem!important}.mb-lg-n8{margin-bottom:-8rem!important}.mb-lg-n9{margin-bottom:-10rem!important}.mb-lg-n10{margin-bottom:-12rem!important}.mb-lg-n11{margin-bottom:-14rem!important}.mb-lg-n12{margin-bottom:-16rem!important}.ms-lg-n1{margin-left:-.25rem!important}.ms-lg-n2{margin-left:-.5rem!important}.ms-lg-n3{margin-left:-1rem!important}.ms-lg-n4{margin-left:-1.5rem!important}.ms-lg-n5{margin-left:-3rem!important}.ms-lg-n6{margin-left:-4rem!important}.ms-lg-n7{margin-left:-6rem!important}.ms-lg-n8{margin-left:-8rem!important}.ms-lg-n9{margin-left:-10rem!important}.ms-lg-n10{margin-left:-12rem!important}.ms-lg-n11{margin-left:-14rem!important}.ms-lg-n12{margin-left:-16rem!important}.p-lg-0{padding:0!important}.p-lg-1{padding:.25rem!important}.p-lg-2{padding:.5rem!important}.p-lg-3{padding:1rem!important}.p-lg-4{padding:1.5rem!important}.p-lg-5{padding:3rem!important}.p-lg-6{padding:4rem!important}.p-lg-7{padding:6rem!important}.p-lg-8{padding:8rem!important}.p-lg-9{padding:10rem!important}.p-lg-10{padding:12rem!important}.p-lg-11{padding:14rem!important}.p-lg-12{padding:16rem!important}.px-lg-0{padding-left:0!important;padding-right:0!important}.px-lg-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-lg-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-lg-3{padding-left:1rem!important;padding-right:1rem!important}.px-lg-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-lg-5{padding-left:3rem!important;padding-right:3rem!important}.px-lg-6{padding-left:4rem!important;padding-right:4rem!important}.px-lg-7{padding-left:6rem!important;padding-right:6rem!important}.px-lg-8{padding-left:8rem!important;padding-right:8rem!important}.px-lg-9{padding-left:10rem!important;padding-right:10rem!important}.px-lg-10{padding-left:12rem!important;padding-right:12rem!important}.px-lg-11{padding-left:14rem!important;padding-right:14rem!important}.px-lg-12{padding-left:16rem!important;padding-right:16rem!important}.py-lg-0{padding-bottom:0!important;padding-top:0!important}.py-lg-1{padding-bottom:.25rem!important;padding-top:.25rem!important}.py-lg-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.py-lg-3{padding-bottom:1rem!important;padding-top:1rem!important}.py-lg-4{padding-bottom:1.5rem!important;padding-top:1.5rem!important}.py-lg-5{padding-bottom:3rem!important;padding-top:3rem!important}.py-lg-6{padding-bottom:4rem!important;padding-top:4rem!important}.py-lg-7{padding-bottom:6rem!important;padding-top:6rem!important}.py-lg-8{padding-bottom:8rem!important;padding-top:8rem!important}.py-lg-9{padding-bottom:10rem!important;padding-top:10rem!important}.py-lg-10{padding-bottom:12rem!important;padding-top:12rem!important}.py-lg-11{padding-bottom:14rem!important;padding-top:14rem!important}.py-lg-12{padding-bottom:16rem!important;padding-top:16rem!important}.pt-lg-0{padding-top:0!important}.pt-lg-1{padding-top:.25rem!important}.pt-lg-2{padding-top:.5rem!important}.pt-lg-3{padding-top:1rem!important}.pt-lg-4{padding-top:1.5rem!important}.pt-lg-5{padding-top:3rem!important}.pt-lg-6{padding-top:4rem!important}.pt-lg-7{padding-top:6rem!important}.pt-lg-8{padding-top:8rem!important}.pt-lg-9{padding-top:10rem!important}.pt-lg-10{padding-top:12rem!important}.pt-lg-11{padding-top:14rem!important}.pt-lg-12{padding-top:16rem!important}.pe-lg-0{padding-right:0!important}.pe-lg-1{padding-right:.25rem!important}.pe-lg-2{padding-right:.5rem!important}.pe-lg-3{padding-right:1rem!important}.pe-lg-4{padding-right:1.5rem!important}.pe-lg-5{padding-right:3rem!important}.pe-lg-6{padding-right:4rem!important}.pe-lg-7{padding-right:6rem!important}.pe-lg-8{padding-right:8rem!important}.pe-lg-9{padding-right:10rem!important}.pe-lg-10{padding-right:12rem!important}.pe-lg-11{padding-right:14rem!important}.pe-lg-12{padding-right:16rem!important}.pb-lg-0{padding-bottom:0!important}.pb-lg-1{padding-bottom:.25rem!important}.pb-lg-2{padding-bottom:.5rem!important}.pb-lg-3{padding-bottom:1rem!important}.pb-lg-4{padding-bottom:1.5rem!important}.pb-lg-5{padding-bottom:3rem!important}.pb-lg-6{padding-bottom:4rem!important}.pb-lg-7{padding-bottom:6rem!important}.pb-lg-8{padding-bottom:8rem!important}.pb-lg-9{padding-bottom:10rem!important}.pb-lg-10{padding-bottom:12rem!important}.pb-lg-11{padding-bottom:14rem!important}.pb-lg-12{padding-bottom:16rem!important}.ps-lg-0{padding-left:0!important}.ps-lg-1{padding-left:.25rem!important}.ps-lg-2{padding-left:.5rem!important}.ps-lg-3{padding-left:1rem!important}.ps-lg-4{padding-left:1.5rem!important}.ps-lg-5{padding-left:3rem!important}.ps-lg-6{padding-left:4rem!important}.ps-lg-7{padding-left:6rem!important}.ps-lg-8{padding-left:8rem!important}.ps-lg-9{padding-left:10rem!important}.ps-lg-10{padding-left:12rem!important}.ps-lg-11{padding-left:14rem!important}.ps-lg-12{padding-left:16rem!important}.text-lg-start{text-align:left!important}.text-lg-end{text-align:right!important}.text-lg-center{text-align:center!important}.transform-scale-lg-5{transform:scale(.5)!important}.transform-scale-lg-6{transform:scale(.6)!important}.transform-scale-lg-7{transform:scale(.7)!important}.transform-scale-lg-8{transform:scale(.8)!important}.transform-scale-lg-9{transform:scale(.9)!important}.transform-scale-lg-10{transform:scale(1)!important}.border-radius-top-start-lg-0{border-top-left-radius:0!important}.border-radius-top-end-lg-0{border-top-right-radius:0!important}.border-radius-bottom-start-lg-0{border-bottom-left-radius:0!important}.border-radius-bottom-end-lg-0{border-bottom-right-radius:0!important}}@media (min-width:1200px){.float-xl-start{float:left!important}.float-xl-end{float:right!important}.float-xl-none{float:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-grid{display:grid!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.d-xl-none{display:none!important}.border-top-xl{border-top:1px solid #dee2e6!important}.border-top-xl-0{border-top:0!important}.border-end-xl{border-right:1px solid #dee2e6!important}.border-end-xl-0{border-right:0!important}.border-bottom-xl{border-bottom:1px solid #dee2e6!important}.border-bottom-xl-0{border-bottom:0!important}.border-start-xl{border-left:1px solid #dee2e6!important}.border-start-xl-0{border-left:0!important}.w-xl-0{width:0!important}.w-xl-1{width:1%!important}.w-xl-2{width:2%!important}.w-xl-3{width:3%!important}.w-xl-4{width:4%!important}.w-xl-5{width:5%!important}.w-xl-6{width:6%!important}.w-xl-7{width:7%!important}.w-xl-8{width:8%!important}.w-xl-9{width:9%!important}.w-xl-10{width:10%!important}.w-xl-15{width:15%!important}.w-xl-20{width:20%!important}.w-xl-25{width:25%!important}.w-xl-30{width:30%!important}.w-xl-35{width:35%!important}.w-xl-40{width:40%!important}.w-xl-45{width:45%!important}.w-xl-50{width:50%!important}.w-xl-55{width:55%!important}.w-xl-60{width:60%!important}.w-xl-65{width:65%!important}.w-xl-70{width:70%!important}.w-xl-75{width:75%!important}.w-xl-80{width:80%!important}.w-xl-85{width:85%!important}.w-xl-90{width:90%!important}.w-xl-95{width:95%!important}.w-xl-100{width:100%!important}.w-xl-auto{width:auto!important}.flex-xl-fill{flex:1 1 auto!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xl-0{gap:0!important}.gap-xl-1{gap:.25rem!important}.gap-xl-2{gap:.5rem!important}.gap-xl-3{gap:1rem!important}.gap-xl-4{gap:1.5rem!important}.gap-xl-5{gap:3rem!important}.gap-xl-6{gap:4rem!important}.gap-xl-7{gap:6rem!important}.gap-xl-8{gap:8rem!important}.gap-xl-9{gap:10rem!important}.gap-xl-10{gap:12rem!important}.gap-xl-11{gap:14rem!important}.gap-xl-12{gap:16rem!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.justify-content-xl-evenly{justify-content:space-evenly!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.order-xl-first{order:-1!important}.order-xl-0{order:0!important}.order-xl-1{order:1!important}.order-xl-2{order:2!important}.order-xl-3{order:3!important}.order-xl-4{order:4!important}.order-xl-5{order:5!important}.order-xl-last{order:6!important}.m-xl-0{margin:0!important}.m-xl-1{margin:.25rem!important}.m-xl-2{margin:.5rem!important}.m-xl-3{margin:1rem!important}.m-xl-4{margin:1.5rem!important}.m-xl-5{margin:3rem!important}.m-xl-6{margin:4rem!important}.m-xl-7{margin:6rem!important}.m-xl-8{margin:8rem!important}.m-xl-9{margin:10rem!important}.m-xl-10{margin:12rem!important}.m-xl-11{margin:14rem!important}.m-xl-12{margin:16rem!important}.m-xl-auto{margin:auto!important}.mx-xl-0{margin-left:0!important;margin-right:0!important}.mx-xl-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-xl-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-xl-3{margin-left:1rem!important;margin-right:1rem!important}.mx-xl-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-xl-5{margin-left:3rem!important;margin-right:3rem!important}.mx-xl-6{margin-left:4rem!important;margin-right:4rem!important}.mx-xl-7{margin-left:6rem!important;margin-right:6rem!important}.mx-xl-8{margin-left:8rem!important;margin-right:8rem!important}.mx-xl-9{margin-left:10rem!important;margin-right:10rem!important}.mx-xl-10{margin-left:12rem!important;margin-right:12rem!important}.mx-xl-11{margin-left:14rem!important;margin-right:14rem!important}.mx-xl-12{margin-left:16rem!important;margin-right:16rem!important}.mx-xl-auto{margin-left:auto!important;margin-right:auto!important}.my-xl-0{margin-bottom:0!important;margin-top:0!important}.my-xl-1{margin-bottom:.25rem!important;margin-top:.25rem!important}.my-xl-2{margin-bottom:.5rem!important;margin-top:.5rem!important}.my-xl-3{margin-bottom:1rem!important;margin-top:1rem!important}.my-xl-4{margin-bottom:1.5rem!important;margin-top:1.5rem!important}.my-xl-5{margin-bottom:3rem!important;margin-top:3rem!important}.my-xl-6{margin-bottom:4rem!important;margin-top:4rem!important}.my-xl-7{margin-bottom:6rem!important;margin-top:6rem!important}.my-xl-8{margin-bottom:8rem!important;margin-top:8rem!important}.my-xl-9{margin-bottom:10rem!important;margin-top:10rem!important}.my-xl-10{margin-bottom:12rem!important;margin-top:12rem!important}.my-xl-11{margin-bottom:14rem!important;margin-top:14rem!important}.my-xl-12{margin-bottom:16rem!important;margin-top:16rem!important}.my-xl-auto{margin-bottom:auto!important;margin-top:auto!important}.mt-xl-0{margin-top:0!important}.mt-xl-1{margin-top:.25rem!important}.mt-xl-2{margin-top:.5rem!important}.mt-xl-3{margin-top:1rem!important}.mt-xl-4{margin-top:1.5rem!important}.mt-xl-5{margin-top:3rem!important}.mt-xl-6{margin-top:4rem!important}.mt-xl-7{margin-top:6rem!important}.mt-xl-8{margin-top:8rem!important}.mt-xl-9{margin-top:10rem!important}.mt-xl-10{margin-top:12rem!important}.mt-xl-11{margin-top:14rem!important}.mt-xl-12{margin-top:16rem!important}.mt-xl-auto{margin-top:auto!important}.me-xl-0{margin-right:0!important}.me-xl-1{margin-right:.25rem!important}.me-xl-2{margin-right:.5rem!important}.me-xl-3{margin-right:1rem!important}.me-xl-4{margin-right:1.5rem!important}.me-xl-5{margin-right:3rem!important}.me-xl-6{margin-right:4rem!important}.me-xl-7{margin-right:6rem!important}.me-xl-8{margin-right:8rem!important}.me-xl-9{margin-right:10rem!important}.me-xl-10{margin-right:12rem!important}.me-xl-11{margin-right:14rem!important}.me-xl-12{margin-right:16rem!important}.me-xl-auto{margin-right:auto!important}.mb-xl-0{margin-bottom:0!important}.mb-xl-1{margin-bottom:.25rem!important}.mb-xl-2{margin-bottom:.5rem!important}.mb-xl-3{margin-bottom:1rem!important}.mb-xl-4{margin-bottom:1.5rem!important}.mb-xl-5{margin-bottom:3rem!important}.mb-xl-6{margin-bottom:4rem!important}.mb-xl-7{margin-bottom:6rem!important}.mb-xl-8{margin-bottom:8rem!important}.mb-xl-9{margin-bottom:10rem!important}.mb-xl-10{margin-bottom:12rem!important}.mb-xl-11{margin-bottom:14rem!important}.mb-xl-12{margin-bottom:16rem!important}.mb-xl-auto{margin-bottom:auto!important}.ms-xl-0{margin-left:0!important}.ms-xl-1{margin-left:.25rem!important}.ms-xl-2{margin-left:.5rem!important}.ms-xl-3{margin-left:1rem!important}.ms-xl-4{margin-left:1.5rem!important}.ms-xl-5{margin-left:3rem!important}.ms-xl-6{margin-left:4rem!important}.ms-xl-7{margin-left:6rem!important}.ms-xl-8{margin-left:8rem!important}.ms-xl-9{margin-left:10rem!important}.ms-xl-10{margin-left:12rem!important}.ms-xl-11{margin-left:14rem!important}.ms-xl-12{margin-left:16rem!important}.ms-xl-auto{margin-left:auto!important}.m-xl-n1{margin:-.25rem!important}.m-xl-n2{margin:-.5rem!important}.m-xl-n3{margin:-1rem!important}.m-xl-n4{margin:-1.5rem!important}.m-xl-n5{margin:-3rem!important}.m-xl-n6{margin:-4rem!important}.m-xl-n7{margin:-6rem!important}.m-xl-n8{margin:-8rem!important}.m-xl-n9{margin:-10rem!important}.m-xl-n10{margin:-12rem!important}.m-xl-n11{margin:-14rem!important}.m-xl-n12{margin:-16rem!important}.mx-xl-n1{margin-left:-.25rem!important;margin-right:-.25rem!important}.mx-xl-n2{margin-left:-.5rem!important;margin-right:-.5rem!important}.mx-xl-n3{margin-left:-1rem!important;margin-right:-1rem!important}.mx-xl-n4{margin-left:-1.5rem!important;margin-right:-1.5rem!important}.mx-xl-n5{margin-left:-3rem!important;margin-right:-3rem!important}.mx-xl-n6{margin-left:-4rem!important;margin-right:-4rem!important}.mx-xl-n7{margin-left:-6rem!important;margin-right:-6rem!important}.mx-xl-n8{margin-left:-8rem!important;margin-right:-8rem!important}.mx-xl-n9{margin-left:-10rem!important;margin-right:-10rem!important}.mx-xl-n10{margin-left:-12rem!important;margin-right:-12rem!important}.mx-xl-n11{margin-left:-14rem!important;margin-right:-14rem!important}.mx-xl-n12{margin-left:-16rem!important;margin-right:-16rem!important}.my-xl-n1{margin-bottom:-.25rem!important;margin-top:-.25rem!important}.my-xl-n2{margin-bottom:-.5rem!important;margin-top:-.5rem!important}.my-xl-n3{margin-bottom:-1rem!important;margin-top:-1rem!important}.my-xl-n4{margin-bottom:-1.5rem!important;margin-top:-1.5rem!important}.my-xl-n5{margin-bottom:-3rem!important;margin-top:-3rem!important}.my-xl-n6{margin-bottom:-4rem!important;margin-top:-4rem!important}.my-xl-n7{margin-bottom:-6rem!important;margin-top:-6rem!important}.my-xl-n8{margin-bottom:-8rem!important;margin-top:-8rem!important}.my-xl-n9{margin-bottom:-10rem!important;margin-top:-10rem!important}.my-xl-n10{margin-bottom:-12rem!important;margin-top:-12rem!important}.my-xl-n11{margin-bottom:-14rem!important;margin-top:-14rem!important}.my-xl-n12{margin-bottom:-16rem!important;margin-top:-16rem!important}.mt-xl-n1{margin-top:-.25rem!important}.mt-xl-n2{margin-top:-.5rem!important}.mt-xl-n3{margin-top:-1rem!important}.mt-xl-n4{margin-top:-1.5rem!important}.mt-xl-n5{margin-top:-3rem!important}.mt-xl-n6{margin-top:-4rem!important}.mt-xl-n7{margin-top:-6rem!important}.mt-xl-n8{margin-top:-8rem!important}.mt-xl-n9{margin-top:-10rem!important}.mt-xl-n10{margin-top:-12rem!important}.mt-xl-n11{margin-top:-14rem!important}.mt-xl-n12{margin-top:-16rem!important}.me-xl-n1{margin-right:-.25rem!important}.me-xl-n2{margin-right:-.5rem!important}.me-xl-n3{margin-right:-1rem!important}.me-xl-n4{margin-right:-1.5rem!important}.me-xl-n5{margin-right:-3rem!important}.me-xl-n6{margin-right:-4rem!important}.me-xl-n7{margin-right:-6rem!important}.me-xl-n8{margin-right:-8rem!important}.me-xl-n9{margin-right:-10rem!important}.me-xl-n10{margin-right:-12rem!important}.me-xl-n11{margin-right:-14rem!important}.me-xl-n12{margin-right:-16rem!important}.mb-xl-n1{margin-bottom:-.25rem!important}.mb-xl-n2{margin-bottom:-.5rem!important}.mb-xl-n3{margin-bottom:-1rem!important}.mb-xl-n4{margin-bottom:-1.5rem!important}.mb-xl-n5{margin-bottom:-3rem!important}.mb-xl-n6{margin-bottom:-4rem!important}.mb-xl-n7{margin-bottom:-6rem!important}.mb-xl-n8{margin-bottom:-8rem!important}.mb-xl-n9{margin-bottom:-10rem!important}.mb-xl-n10{margin-bottom:-12rem!important}.mb-xl-n11{margin-bottom:-14rem!important}.mb-xl-n12{margin-bottom:-16rem!important}.ms-xl-n1{margin-left:-.25rem!important}.ms-xl-n2{margin-left:-.5rem!important}.ms-xl-n3{margin-left:-1rem!important}.ms-xl-n4{margin-left:-1.5rem!important}.ms-xl-n5{margin-left:-3rem!important}.ms-xl-n6{margin-left:-4rem!important}.ms-xl-n7{margin-left:-6rem!important}.ms-xl-n8{margin-left:-8rem!important}.ms-xl-n9{margin-left:-10rem!important}.ms-xl-n10{margin-left:-12rem!important}.ms-xl-n11{margin-left:-14rem!important}.ms-xl-n12{margin-left:-16rem!important}.p-xl-0{padding:0!important}.p-xl-1{padding:.25rem!important}.p-xl-2{padding:.5rem!important}.p-xl-3{padding:1rem!important}.p-xl-4{padding:1.5rem!important}.p-xl-5{padding:3rem!important}.p-xl-6{padding:4rem!important}.p-xl-7{padding:6rem!important}.p-xl-8{padding:8rem!important}.p-xl-9{padding:10rem!important}.p-xl-10{padding:12rem!important}.p-xl-11{padding:14rem!important}.p-xl-12{padding:16rem!important}.px-xl-0{padding-left:0!important;padding-right:0!important}.px-xl-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-xl-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-xl-3{padding-left:1rem!important;padding-right:1rem!important}.px-xl-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-xl-5{padding-left:3rem!important;padding-right:3rem!important}.px-xl-6{padding-left:4rem!important;padding-right:4rem!important}.px-xl-7{padding-left:6rem!important;padding-right:6rem!important}.px-xl-8{padding-left:8rem!important;padding-right:8rem!important}.px-xl-9{padding-left:10rem!important;padding-right:10rem!important}.px-xl-10{padding-left:12rem!important;padding-right:12rem!important}.px-xl-11{padding-left:14rem!important;padding-right:14rem!important}.px-xl-12{padding-left:16rem!important;padding-right:16rem!important}.py-xl-0{padding-bottom:0!important;padding-top:0!important}.py-xl-1{padding-bottom:.25rem!important;padding-top:.25rem!important}.py-xl-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.py-xl-3{padding-bottom:1rem!important;padding-top:1rem!important}.py-xl-4{padding-bottom:1.5rem!important;padding-top:1.5rem!important}.py-xl-5{padding-bottom:3rem!important;padding-top:3rem!important}.py-xl-6{padding-bottom:4rem!important;padding-top:4rem!important}.py-xl-7{padding-bottom:6rem!important;padding-top:6rem!important}.py-xl-8{padding-bottom:8rem!important;padding-top:8rem!important}.py-xl-9{padding-bottom:10rem!important;padding-top:10rem!important}.py-xl-10{padding-bottom:12rem!important;padding-top:12rem!important}.py-xl-11{padding-bottom:14rem!important;padding-top:14rem!important}.py-xl-12{padding-bottom:16rem!important;padding-top:16rem!important}.pt-xl-0{padding-top:0!important}.pt-xl-1{padding-top:.25rem!important}.pt-xl-2{padding-top:.5rem!important}.pt-xl-3{padding-top:1rem!important}.pt-xl-4{padding-top:1.5rem!important}.pt-xl-5{padding-top:3rem!important}.pt-xl-6{padding-top:4rem!important}.pt-xl-7{padding-top:6rem!important}.pt-xl-8{padding-top:8rem!important}.pt-xl-9{padding-top:10rem!important}.pt-xl-10{padding-top:12rem!important}.pt-xl-11{padding-top:14rem!important}.pt-xl-12{padding-top:16rem!important}.pe-xl-0{padding-right:0!important}.pe-xl-1{padding-right:.25rem!important}.pe-xl-2{padding-right:.5rem!important}.pe-xl-3{padding-right:1rem!important}.pe-xl-4{padding-right:1.5rem!important}.pe-xl-5{padding-right:3rem!important}.pe-xl-6{padding-right:4rem!important}.pe-xl-7{padding-right:6rem!important}.pe-xl-8{padding-right:8rem!important}.pe-xl-9{padding-right:10rem!important}.pe-xl-10{padding-right:12rem!important}.pe-xl-11{padding-right:14rem!important}.pe-xl-12{padding-right:16rem!important}.pb-xl-0{padding-bottom:0!important}.pb-xl-1{padding-bottom:.25rem!important}.pb-xl-2{padding-bottom:.5rem!important}.pb-xl-3{padding-bottom:1rem!important}.pb-xl-4{padding-bottom:1.5rem!important}.pb-xl-5{padding-bottom:3rem!important}.pb-xl-6{padding-bottom:4rem!important}.pb-xl-7{padding-bottom:6rem!important}.pb-xl-8{padding-bottom:8rem!important}.pb-xl-9{padding-bottom:10rem!important}.pb-xl-10{padding-bottom:12rem!important}.pb-xl-11{padding-bottom:14rem!important}.pb-xl-12{padding-bottom:16rem!important}.ps-xl-0{padding-left:0!important}.ps-xl-1{padding-left:.25rem!important}.ps-xl-2{padding-left:.5rem!important}.ps-xl-3{padding-left:1rem!important}.ps-xl-4{padding-left:1.5rem!important}.ps-xl-5{padding-left:3rem!important}.ps-xl-6{padding-left:4rem!important}.ps-xl-7{padding-left:6rem!important}.ps-xl-8{padding-left:8rem!important}.ps-xl-9{padding-left:10rem!important}.ps-xl-10{padding-left:12rem!important}.ps-xl-11{padding-left:14rem!important}.ps-xl-12{padding-left:16rem!important}.text-xl-start{text-align:left!important}.text-xl-end{text-align:right!important}.text-xl-center{text-align:center!important}.transform-scale-xl-5{transform:scale(.5)!important}.transform-scale-xl-6{transform:scale(.6)!important}.transform-scale-xl-7{transform:scale(.7)!important}.transform-scale-xl-8{transform:scale(.8)!important}.transform-scale-xl-9{transform:scale(.9)!important}.transform-scale-xl-10{transform:scale(1)!important}.border-radius-top-start-xl-0{border-top-left-radius:0!important}.border-radius-top-end-xl-0{border-top-right-radius:0!important}.border-radius-bottom-start-xl-0{border-bottom-left-radius:0!important}.border-radius-bottom-end-xl-0{border-bottom-right-radius:0!important}}@media (min-width:1400px){.float-xxl-start{float:left!important}.float-xxl-end{float:right!important}.float-xxl-none{float:none!important}.d-xxl-inline{display:inline!important}.d-xxl-inline-block{display:inline-block!important}.d-xxl-block{display:block!important}.d-xxl-grid{display:grid!important}.d-xxl-table{display:table!important}.d-xxl-table-row{display:table-row!important}.d-xxl-table-cell{display:table-cell!important}.d-xxl-flex{display:flex!important}.d-xxl-inline-flex{display:inline-flex!important}.d-xxl-none{display:none!important}.border-top-xxl{border-top:1px solid #dee2e6!important}.border-top-xxl-0{border-top:0!important}.border-end-xxl{border-right:1px solid #dee2e6!important}.border-end-xxl-0{border-right:0!important}.border-bottom-xxl{border-bottom:1px solid #dee2e6!important}.border-bottom-xxl-0{border-bottom:0!important}.border-start-xxl{border-left:1px solid #dee2e6!important}.border-start-xxl-0{border-left:0!important}.w-xxl-0{width:0!important}.w-xxl-1{width:1%!important}.w-xxl-2{width:2%!important}.w-xxl-3{width:3%!important}.w-xxl-4{width:4%!important}.w-xxl-5{width:5%!important}.w-xxl-6{width:6%!important}.w-xxl-7{width:7%!important}.w-xxl-8{width:8%!important}.w-xxl-9{width:9%!important}.w-xxl-10{width:10%!important}.w-xxl-15{width:15%!important}.w-xxl-20{width:20%!important}.w-xxl-25{width:25%!important}.w-xxl-30{width:30%!important}.w-xxl-35{width:35%!important}.w-xxl-40{width:40%!important}.w-xxl-45{width:45%!important}.w-xxl-50{width:50%!important}.w-xxl-55{width:55%!important}.w-xxl-60{width:60%!important}.w-xxl-65{width:65%!important}.w-xxl-70{width:70%!important}.w-xxl-75{width:75%!important}.w-xxl-80{width:80%!important}.w-xxl-85{width:85%!important}.w-xxl-90{width:90%!important}.w-xxl-95{width:95%!important}.w-xxl-100{width:100%!important}.w-xxl-auto{width:auto!important}.flex-xxl-fill{flex:1 1 auto!important}.flex-xxl-row{flex-direction:row!important}.flex-xxl-column{flex-direction:column!important}.flex-xxl-row-reverse{flex-direction:row-reverse!important}.flex-xxl-column-reverse{flex-direction:column-reverse!important}.flex-xxl-grow-0{flex-grow:0!important}.flex-xxl-grow-1{flex-grow:1!important}.flex-xxl-shrink-0{flex-shrink:0!important}.flex-xxl-shrink-1{flex-shrink:1!important}.flex-xxl-wrap{flex-wrap:wrap!important}.flex-xxl-nowrap{flex-wrap:nowrap!important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse!important}.gap-xxl-0{gap:0!important}.gap-xxl-1{gap:.25rem!important}.gap-xxl-2{gap:.5rem!important}.gap-xxl-3{gap:1rem!important}.gap-xxl-4{gap:1.5rem!important}.gap-xxl-5{gap:3rem!important}.gap-xxl-6{gap:4rem!important}.gap-xxl-7{gap:6rem!important}.gap-xxl-8{gap:8rem!important}.gap-xxl-9{gap:10rem!important}.gap-xxl-10{gap:12rem!important}.gap-xxl-11{gap:14rem!important}.gap-xxl-12{gap:16rem!important}.justify-content-xxl-start{justify-content:flex-start!important}.justify-content-xxl-end{justify-content:flex-end!important}.justify-content-xxl-center{justify-content:center!important}.justify-content-xxl-between{justify-content:space-between!important}.justify-content-xxl-around{justify-content:space-around!important}.justify-content-xxl-evenly{justify-content:space-evenly!important}.align-items-xxl-start{align-items:flex-start!important}.align-items-xxl-end{align-items:flex-end!important}.align-items-xxl-center{align-items:center!important}.align-items-xxl-baseline{align-items:baseline!important}.align-items-xxl-stretch{align-items:stretch!important}.align-content-xxl-start{align-content:flex-start!important}.align-content-xxl-end{align-content:flex-end!important}.align-content-xxl-center{align-content:center!important}.align-content-xxl-between{align-content:space-between!important}.align-content-xxl-around{align-content:space-around!important}.align-content-xxl-stretch{align-content:stretch!important}.align-self-xxl-auto{align-self:auto!important}.align-self-xxl-start{align-self:flex-start!important}.align-self-xxl-end{align-self:flex-end!important}.align-self-xxl-center{align-self:center!important}.align-self-xxl-baseline{align-self:baseline!important}.align-self-xxl-stretch{align-self:stretch!important}.order-xxl-first{order:-1!important}.order-xxl-0{order:0!important}.order-xxl-1{order:1!important}.order-xxl-2{order:2!important}.order-xxl-3{order:3!important}.order-xxl-4{order:4!important}.order-xxl-5{order:5!important}.order-xxl-last{order:6!important}.m-xxl-0{margin:0!important}.m-xxl-1{margin:.25rem!important}.m-xxl-2{margin:.5rem!important}.m-xxl-3{margin:1rem!important}.m-xxl-4{margin:1.5rem!important}.m-xxl-5{margin:3rem!important}.m-xxl-6{margin:4rem!important}.m-xxl-7{margin:6rem!important}.m-xxl-8{margin:8rem!important}.m-xxl-9{margin:10rem!important}.m-xxl-10{margin:12rem!important}.m-xxl-11{margin:14rem!important}.m-xxl-12{margin:16rem!important}.m-xxl-auto{margin:auto!important}.mx-xxl-0{margin-left:0!important;margin-right:0!important}.mx-xxl-1{margin-left:.25rem!important;margin-right:.25rem!important}.mx-xxl-2{margin-left:.5rem!important;margin-right:.5rem!important}.mx-xxl-3{margin-left:1rem!important;margin-right:1rem!important}.mx-xxl-4{margin-left:1.5rem!important;margin-right:1.5rem!important}.mx-xxl-5{margin-left:3rem!important;margin-right:3rem!important}.mx-xxl-6{margin-left:4rem!important;margin-right:4rem!important}.mx-xxl-7{margin-left:6rem!important;margin-right:6rem!important}.mx-xxl-8{margin-left:8rem!important;margin-right:8rem!important}.mx-xxl-9{margin-left:10rem!important;margin-right:10rem!important}.mx-xxl-10{margin-left:12rem!important;margin-right:12rem!important}.mx-xxl-11{margin-left:14rem!important;margin-right:14rem!important}.mx-xxl-12{margin-left:16rem!important;margin-right:16rem!important}.mx-xxl-auto{margin-left:auto!important;margin-right:auto!important}.my-xxl-0{margin-bottom:0!important;margin-top:0!important}.my-xxl-1{margin-bottom:.25rem!important;margin-top:.25rem!important}.my-xxl-2{margin-bottom:.5rem!important;margin-top:.5rem!important}.my-xxl-3{margin-bottom:1rem!important;margin-top:1rem!important}.my-xxl-4{margin-bottom:1.5rem!important;margin-top:1.5rem!important}.my-xxl-5{margin-bottom:3rem!important;margin-top:3rem!important}.my-xxl-6{margin-bottom:4rem!important;margin-top:4rem!important}.my-xxl-7{margin-bottom:6rem!important;margin-top:6rem!important}.my-xxl-8{margin-bottom:8rem!important;margin-top:8rem!important}.my-xxl-9{margin-bottom:10rem!important;margin-top:10rem!important}.my-xxl-10{margin-bottom:12rem!important;margin-top:12rem!important}.my-xxl-11{margin-bottom:14rem!important;margin-top:14rem!important}.my-xxl-12{margin-bottom:16rem!important;margin-top:16rem!important}.my-xxl-auto{margin-bottom:auto!important;margin-top:auto!important}.mt-xxl-0{margin-top:0!important}.mt-xxl-1{margin-top:.25rem!important}.mt-xxl-2{margin-top:.5rem!important}.mt-xxl-3{margin-top:1rem!important}.mt-xxl-4{margin-top:1.5rem!important}.mt-xxl-5{margin-top:3rem!important}.mt-xxl-6{margin-top:4rem!important}.mt-xxl-7{margin-top:6rem!important}.mt-xxl-8{margin-top:8rem!important}.mt-xxl-9{margin-top:10rem!important}.mt-xxl-10{margin-top:12rem!important}.mt-xxl-11{margin-top:14rem!important}.mt-xxl-12{margin-top:16rem!important}.mt-xxl-auto{margin-top:auto!important}.me-xxl-0{margin-right:0!important}.me-xxl-1{margin-right:.25rem!important}.me-xxl-2{margin-right:.5rem!important}.me-xxl-3{margin-right:1rem!important}.me-xxl-4{margin-right:1.5rem!important}.me-xxl-5{margin-right:3rem!important}.me-xxl-6{margin-right:4rem!important}.me-xxl-7{margin-right:6rem!important}.me-xxl-8{margin-right:8rem!important}.me-xxl-9{margin-right:10rem!important}.me-xxl-10{margin-right:12rem!important}.me-xxl-11{margin-right:14rem!important}.me-xxl-12{margin-right:16rem!important}.me-xxl-auto{margin-right:auto!important}.mb-xxl-0{margin-bottom:0!important}.mb-xxl-1{margin-bottom:.25rem!important}.mb-xxl-2{margin-bottom:.5rem!important}.mb-xxl-3{margin-bottom:1rem!important}.mb-xxl-4{margin-bottom:1.5rem!important}.mb-xxl-5{margin-bottom:3rem!important}.mb-xxl-6{margin-bottom:4rem!important}.mb-xxl-7{margin-bottom:6rem!important}.mb-xxl-8{margin-bottom:8rem!important}.mb-xxl-9{margin-bottom:10rem!important}.mb-xxl-10{margin-bottom:12rem!important}.mb-xxl-11{margin-bottom:14rem!important}.mb-xxl-12{margin-bottom:16rem!important}.mb-xxl-auto{margin-bottom:auto!important}.ms-xxl-0{margin-left:0!important}.ms-xxl-1{margin-left:.25rem!important}.ms-xxl-2{margin-left:.5rem!important}.ms-xxl-3{margin-left:1rem!important}.ms-xxl-4{margin-left:1.5rem!important}.ms-xxl-5{margin-left:3rem!important}.ms-xxl-6{margin-left:4rem!important}.ms-xxl-7{margin-left:6rem!important}.ms-xxl-8{margin-left:8rem!important}.ms-xxl-9{margin-left:10rem!important}.ms-xxl-10{margin-left:12rem!important}.ms-xxl-11{margin-left:14rem!important}.ms-xxl-12{margin-left:16rem!important}.ms-xxl-auto{margin-left:auto!important}.m-xxl-n1{margin:-.25rem!important}.m-xxl-n2{margin:-.5rem!important}.m-xxl-n3{margin:-1rem!important}.m-xxl-n4{margin:-1.5rem!important}.m-xxl-n5{margin:-3rem!important}.m-xxl-n6{margin:-4rem!important}.m-xxl-n7{margin:-6rem!important}.m-xxl-n8{margin:-8rem!important}.m-xxl-n9{margin:-10rem!important}.m-xxl-n10{margin:-12rem!important}.m-xxl-n11{margin:-14rem!important}.m-xxl-n12{margin:-16rem!important}.mx-xxl-n1{margin-left:-.25rem!important;margin-right:-.25rem!important}.mx-xxl-n2{margin-left:-.5rem!important;margin-right:-.5rem!important}.mx-xxl-n3{margin-left:-1rem!important;margin-right:-1rem!important}.mx-xxl-n4{margin-left:-1.5rem!important;margin-right:-1.5rem!important}.mx-xxl-n5{margin-left:-3rem!important;margin-right:-3rem!important}.mx-xxl-n6{margin-left:-4rem!important;margin-right:-4rem!important}.mx-xxl-n7{margin-left:-6rem!important;margin-right:-6rem!important}.mx-xxl-n8{margin-left:-8rem!important;margin-right:-8rem!important}.mx-xxl-n9{margin-left:-10rem!important;margin-right:-10rem!important}.mx-xxl-n10{margin-left:-12rem!important;margin-right:-12rem!important}.mx-xxl-n11{margin-left:-14rem!important;margin-right:-14rem!important}.mx-xxl-n12{margin-left:-16rem!important;margin-right:-16rem!important}.my-xxl-n1{margin-bottom:-.25rem!important;margin-top:-.25rem!important}.my-xxl-n2{margin-bottom:-.5rem!important;margin-top:-.5rem!important}.my-xxl-n3{margin-bottom:-1rem!important;margin-top:-1rem!important}.my-xxl-n4{margin-bottom:-1.5rem!important;margin-top:-1.5rem!important}.my-xxl-n5{margin-bottom:-3rem!important;margin-top:-3rem!important}.my-xxl-n6{margin-bottom:-4rem!important;margin-top:-4rem!important}.my-xxl-n7{margin-bottom:-6rem!important;margin-top:-6rem!important}.my-xxl-n8{margin-bottom:-8rem!important;margin-top:-8rem!important}.my-xxl-n9{margin-bottom:-10rem!important;margin-top:-10rem!important}.my-xxl-n10{margin-bottom:-12rem!important;margin-top:-12rem!important}.my-xxl-n11{margin-bottom:-14rem!important;margin-top:-14rem!important}.my-xxl-n12{margin-bottom:-16rem!important;margin-top:-16rem!important}.mt-xxl-n1{margin-top:-.25rem!important}.mt-xxl-n2{margin-top:-.5rem!important}.mt-xxl-n3{margin-top:-1rem!important}.mt-xxl-n4{margin-top:-1.5rem!important}.mt-xxl-n5{margin-top:-3rem!important}.mt-xxl-n6{margin-top:-4rem!important}.mt-xxl-n7{margin-top:-6rem!important}.mt-xxl-n8{margin-top:-8rem!important}.mt-xxl-n9{margin-top:-10rem!important}.mt-xxl-n10{margin-top:-12rem!important}.mt-xxl-n11{margin-top:-14rem!important}.mt-xxl-n12{margin-top:-16rem!important}.me-xxl-n1{margin-right:-.25rem!important}.me-xxl-n2{margin-right:-.5rem!important}.me-xxl-n3{margin-right:-1rem!important}.me-xxl-n4{margin-right:-1.5rem!important}.me-xxl-n5{margin-right:-3rem!important}.me-xxl-n6{margin-right:-4rem!important}.me-xxl-n7{margin-right:-6rem!important}.me-xxl-n8{margin-right:-8rem!important}.me-xxl-n9{margin-right:-10rem!important}.me-xxl-n10{margin-right:-12rem!important}.me-xxl-n11{margin-right:-14rem!important}.me-xxl-n12{margin-right:-16rem!important}.mb-xxl-n1{margin-bottom:-.25rem!important}.mb-xxl-n2{margin-bottom:-.5rem!important}.mb-xxl-n3{margin-bottom:-1rem!important}.mb-xxl-n4{margin-bottom:-1.5rem!important}.mb-xxl-n5{margin-bottom:-3rem!important}.mb-xxl-n6{margin-bottom:-4rem!important}.mb-xxl-n7{margin-bottom:-6rem!important}.mb-xxl-n8{margin-bottom:-8rem!important}.mb-xxl-n9{margin-bottom:-10rem!important}.mb-xxl-n10{margin-bottom:-12rem!important}.mb-xxl-n11{margin-bottom:-14rem!important}.mb-xxl-n12{margin-bottom:-16rem!important}.ms-xxl-n1{margin-left:-.25rem!important}.ms-xxl-n2{margin-left:-.5rem!important}.ms-xxl-n3{margin-left:-1rem!important}.ms-xxl-n4{margin-left:-1.5rem!important}.ms-xxl-n5{margin-left:-3rem!important}.ms-xxl-n6{margin-left:-4rem!important}.ms-xxl-n7{margin-left:-6rem!important}.ms-xxl-n8{margin-left:-8rem!important}.ms-xxl-n9{margin-left:-10rem!important}.ms-xxl-n10{margin-left:-12rem!important}.ms-xxl-n11{margin-left:-14rem!important}.ms-xxl-n12{margin-left:-16rem!important}.p-xxl-0{padding:0!important}.p-xxl-1{padding:.25rem!important}.p-xxl-2{padding:.5rem!important}.p-xxl-3{padding:1rem!important}.p-xxl-4{padding:1.5rem!important}.p-xxl-5{padding:3rem!important}.p-xxl-6{padding:4rem!important}.p-xxl-7{padding:6rem!important}.p-xxl-8{padding:8rem!important}.p-xxl-9{padding:10rem!important}.p-xxl-10{padding:12rem!important}.p-xxl-11{padding:14rem!important}.p-xxl-12{padding:16rem!important}.px-xxl-0{padding-left:0!important;padding-right:0!important}.px-xxl-1{padding-left:.25rem!important;padding-right:.25rem!important}.px-xxl-2{padding-left:.5rem!important;padding-right:.5rem!important}.px-xxl-3{padding-left:1rem!important;padding-right:1rem!important}.px-xxl-4{padding-left:1.5rem!important;padding-right:1.5rem!important}.px-xxl-5{padding-left:3rem!important;padding-right:3rem!important}.px-xxl-6{padding-left:4rem!important;padding-right:4rem!important}.px-xxl-7{padding-left:6rem!important;padding-right:6rem!important}.px-xxl-8{padding-left:8rem!important;padding-right:8rem!important}.px-xxl-9{padding-left:10rem!important;padding-right:10rem!important}.px-xxl-10{padding-left:12rem!important;padding-right:12rem!important}.px-xxl-11{padding-left:14rem!important;padding-right:14rem!important}.px-xxl-12{padding-left:16rem!important;padding-right:16rem!important}.py-xxl-0{padding-bottom:0!important;padding-top:0!important}.py-xxl-1{padding-bottom:.25rem!important;padding-top:.25rem!important}.py-xxl-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.py-xxl-3{padding-bottom:1rem!important;padding-top:1rem!important}.py-xxl-4{padding-bottom:1.5rem!important;padding-top:1.5rem!important}.py-xxl-5{padding-bottom:3rem!important;padding-top:3rem!important}.py-xxl-6{padding-bottom:4rem!important;padding-top:4rem!important}.py-xxl-7{padding-bottom:6rem!important;padding-top:6rem!important}.py-xxl-8{padding-bottom:8rem!important;padding-top:8rem!important}.py-xxl-9{padding-bottom:10rem!important;padding-top:10rem!important}.py-xxl-10{padding-bottom:12rem!important;padding-top:12rem!important}.py-xxl-11{padding-bottom:14rem!important;padding-top:14rem!important}.py-xxl-12{padding-bottom:16rem!important;padding-top:16rem!important}.pt-xxl-0{padding-top:0!important}.pt-xxl-1{padding-top:.25rem!important}.pt-xxl-2{padding-top:.5rem!important}.pt-xxl-3{padding-top:1rem!important}.pt-xxl-4{padding-top:1.5rem!important}.pt-xxl-5{padding-top:3rem!important}.pt-xxl-6{padding-top:4rem!important}.pt-xxl-7{padding-top:6rem!important}.pt-xxl-8{padding-top:8rem!important}.pt-xxl-9{padding-top:10rem!important}.pt-xxl-10{padding-top:12rem!important}.pt-xxl-11{padding-top:14rem!important}.pt-xxl-12{padding-top:16rem!important}.pe-xxl-0{padding-right:0!important}.pe-xxl-1{padding-right:.25rem!important}.pe-xxl-2{padding-right:.5rem!important}.pe-xxl-3{padding-right:1rem!important}.pe-xxl-4{padding-right:1.5rem!important}.pe-xxl-5{padding-right:3rem!important}.pe-xxl-6{padding-right:4rem!important}.pe-xxl-7{padding-right:6rem!important}.pe-xxl-8{padding-right:8rem!important}.pe-xxl-9{padding-right:10rem!important}.pe-xxl-10{padding-right:12rem!important}.pe-xxl-11{padding-right:14rem!important}.pe-xxl-12{padding-right:16rem!important}.pb-xxl-0{padding-bottom:0!important}.pb-xxl-1{padding-bottom:.25rem!important}.pb-xxl-2{padding-bottom:.5rem!important}.pb-xxl-3{padding-bottom:1rem!important}.pb-xxl-4{padding-bottom:1.5rem!important}.pb-xxl-5{padding-bottom:3rem!important}.pb-xxl-6{padding-bottom:4rem!important}.pb-xxl-7{padding-bottom:6rem!important}.pb-xxl-8{padding-bottom:8rem!important}.pb-xxl-9{padding-bottom:10rem!important}.pb-xxl-10{padding-bottom:12rem!important}.pb-xxl-11{padding-bottom:14rem!important}.pb-xxl-12{padding-bottom:16rem!important}.ps-xxl-0{padding-left:0!important}.ps-xxl-1{padding-left:.25rem!important}.ps-xxl-2{padding-left:.5rem!important}.ps-xxl-3{padding-left:1rem!important}.ps-xxl-4{padding-left:1.5rem!important}.ps-xxl-5{padding-left:3rem!important}.ps-xxl-6{padding-left:4rem!important}.ps-xxl-7{padding-left:6rem!important}.ps-xxl-8{padding-left:8rem!important}.ps-xxl-9{padding-left:10rem!important}.ps-xxl-10{padding-left:12rem!important}.ps-xxl-11{padding-left:14rem!important}.ps-xxl-12{padding-left:16rem!important}.text-xxl-start{text-align:left!important}.text-xxl-end{text-align:right!important}.text-xxl-center{text-align:center!important}.transform-scale-xxl-5{transform:scale(.5)!important}.transform-scale-xxl-6{transform:scale(.6)!important}.transform-scale-xxl-7{transform:scale(.7)!important}.transform-scale-xxl-8{transform:scale(.8)!important}.transform-scale-xxl-9{transform:scale(.9)!important}.transform-scale-xxl-10{transform:scale(1)!important}.border-radius-top-start-xxl-0{border-top-left-radius:0!important}.border-radius-top-end-xxl-0{border-top-right-radius:0!important}.border-radius-bottom-start-xxl-0{border-bottom-left-radius:0!important}.border-radius-bottom-end-xxl-0{border-bottom-right-radius:0!important}}@media (min-width:1200px){.fs-1{font-size:3rem!important}.fs-2{font-size:2.25rem!important}.fs-3{font-size:1.875rem!important}.fs-4{font-size:1.5rem!important}}@media print{.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-grid{display:grid!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}.d-print-none{display:none!important}} +/*! + +========================================================= +* Soft UI Dashboard - v1.0.3 +========================================================= + +* Product Page: https://www.creative-tim.com/product/soft-ui-dashboard +* Copyright 2021 Creative Tim (https://www.creative-tim.com) +* Licensed under MIT (site.license) + +* Coded by www.creative-tim.com + +========================================================= + +* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +*/.alert-primary{background-image:linear-gradient(310deg,#7928ca,#d6006c)}.alert-secondary{background-image:linear-gradient(310deg,#627594,#8ca1cb)}.alert-success{background-image:linear-gradient(310deg,#17ad37,#84dc14)}.alert-info{background-image:linear-gradient(310deg,#2152ff,#02c6f3)}.alert-warning{background-image:linear-gradient(310deg,#f53939,#fac60b)}.alert-danger{background-image:linear-gradient(310deg,#ea0606,#ff3d59)}.alert-light{background-image:linear-gradient(310deg,#ced4da,#d1dae6)}.alert-dark{background-image:linear-gradient(310deg,#141727,#2c3154)}.btn-close:focus{box-shadow:none}.alert-dismissible .btn-close{background-image:none}.avatar{align-items:center;border-radius:.75rem;color:#fff;display:inline-flex;font-size:1rem;height:48px;justify-content:center;transition:all .2s ease-in-out;width:48px}.avatar img{width:100%}.avatar+.avatar-content{display:inline-block;margin-left:.75rem}.avatar.avatar-raised{margin-top:-24px}.active .avatar.avatar-scale-up,.avatar.avatar-scale-up:hover{transform:scale(1.2)}.avatar-xxl{height:110px!important;width:110px!important}.avatar-xxl.avatar-raised{margin-top:-55px}.avatar-xl{height:74px!important;width:74px!important}.avatar-xl.avatar-raised{margin-top:-37px}.avatar-lg{font-size:.875rem;height:58px!important;width:58px!important}.avatar-lg.avatar-raised{margin-top:-29px}.avatar-sm{font-size:.875rem;height:36px!important;width:36px!important}.avatar-sm.avatar-raised{margin-top:-18px}.avatar-xs{font-size:.75rem;height:24px!important;width:24px!important}.avatar-xs.avatar-raised{margin-top:-12px}.avatar-group .avatar{border:2px solid #fff;position:relative;z-index:2}.avatar-group .avatar:hover{z-index:3}.avatar-group .avatar+.avatar{margin-left:-1rem}.badge.bg-primary{background:#cb0c9f}.badge.bg-secondary{background:#8392ab}.badge.bg-success{background:#82d616}.badge.bg-info{background:#17c1e8}.badge.bg-warning{background:#fbcf33}.badge.bg-danger{background:#ea0606}.badge.bg-light{background:#e9ecef}.badge.bg-dark{background:#344767}.badge.bg-white{background:#fff}.badge,.btn{text-transform:uppercase}.btn{background-position-x:25%;background-size:150%;box-shadow:0 4px 7px -1px rgba(0,0,0,.11),0 2px 4px -1px rgba(0,0,0,.07);letter-spacing:-.025rem;margin-bottom:1rem}.btn:not([class*=btn-outline-]){border:0}.btn:active,.btn:active:focus,.btn:active:hover{box-shadow:0 3px 5px -1px rgba(0,0,0,.09),0 2px 3px -1px rgba(0,0,0,.07);opacity:.85;transform:scale(1)}.btn:hover:not(.btn-icon-only){box-shadow:0 3px 5px -1px rgba(0,0,0,.09),0 2px 3px -1px rgba(0,0,0,.07);transform:scale(1.02)}.btn.bg-white:hover{color:#67748e}.btn.btn-link{font-weight:700}.btn.btn-link,.btn.btn-link:focus,.btn.btn-link:hover{box-shadow:none}.btn.btn-round{border-radius:1.875rem}.btn.btn-icon-only{height:2.375rem;padding:.7rem;width:2.375rem}.btn-group-sm>.btn.btn-icon-only,.btn.btn-sm.btn-icon-only{height:1.5875rem;padding:.3rem;width:1.5875rem}.btn-group-sm>.btn i,.btn.btn-sm i{font-size:.5rem}.btn-group-lg>.btn.btn-icon-only,.btn.btn-lg.btn-icon-only{height:3.25rem;padding:1rem;width:3.25rem}.btn-group-lg>.btn i,.btn.btn-lg i{font-size:1.2rem;position:relative;top:2px}.btn.btn-rounded{border-radius:1.875rem}.btn-check:checked+.btn svg .color-background{fill:#fff}.btn-check:checked+.btn:hover svg .color-background{fill:#344767}.icon-move-right i{transition:all .2s cubic-bezier(.34,1.61,.7,1.3)}.icon-move-right:focus i,.icon-move-right:hover i{transform:translateX(5px)}.icon-move-left i{transition:all .2s cubic-bezier(.34,1.61,.7,1.3)}.icon-move-left:focus i,.icon-move-left:hover i{transform:translateX(-5px)}.btn-primary:hover,.btn.bg-gradient-primary:hover{background-color:#cb0c9f;border-color:#cb0c9f}.btn-primary .btn.bg-outline-primary,.btn.bg-gradient-primary .btn.bg-outline-primary{border:1px solid #cb0c9f}.btn-primary:not(:disabled):not(.disabled).active,.btn-primary:not(:disabled):not(.disabled):active,.btn.bg-gradient-primary:not(:disabled):not(.disabled).active,.btn.bg-gradient-primary:not(:disabled):not(.disabled):active,.show>.btn-primary.dropdown-toggle,.show>.btn.bg-gradient-primary.dropdown-toggle{background-color:#cb0c9f;color:color-yiq(#cb0c9f)}.btn-primary.focus,.btn-primary:focus,.btn.bg-gradient-primary.focus,.btn.bg-gradient-primary:focus{color:#fff}.btn-outline-primary{box-shadow:none}.btn-outline-primary:hover:not(.active){background-color:transparent;box-shadow:none;color:#cb0c9f;opacity:.75}.btn-secondary:hover,.btn.bg-gradient-secondary:hover{background-color:#8392ab;border-color:#8392ab}.btn-secondary .btn.bg-outline-secondary,.btn.bg-gradient-secondary .btn.bg-outline-secondary{border:1px solid #8392ab}.btn-secondary:not(:disabled):not(.disabled).active,.btn-secondary:not(:disabled):not(.disabled):active,.btn.bg-gradient-secondary:not(:disabled):not(.disabled).active,.btn.bg-gradient-secondary:not(:disabled):not(.disabled):active,.show>.btn-secondary.dropdown-toggle,.show>.btn.bg-gradient-secondary.dropdown-toggle{background-color:#8392ab;color:color-yiq(#8392ab)}.btn-secondary.focus,.btn-secondary:focus,.btn.bg-gradient-secondary.focus,.btn.bg-gradient-secondary:focus{color:#fff}.btn-outline-secondary{box-shadow:none}.btn-outline-secondary:hover:not(.active){background-color:transparent;box-shadow:none;color:#8392ab;opacity:.75}.btn-success:hover,.btn.bg-gradient-success:hover{background-color:#82d616;border-color:#82d616}.btn-success .btn.bg-outline-success,.btn.bg-gradient-success .btn.bg-outline-success{border:1px solid #82d616}.btn-success:not(:disabled):not(.disabled).active,.btn-success:not(:disabled):not(.disabled):active,.btn.bg-gradient-success:not(:disabled):not(.disabled).active,.btn.bg-gradient-success:not(:disabled):not(.disabled):active,.show>.btn-success.dropdown-toggle,.show>.btn.bg-gradient-success.dropdown-toggle{background-color:#82d616;color:color-yiq(#82d616)}.btn-success.focus,.btn-success:focus,.btn.bg-gradient-success.focus,.btn.bg-gradient-success:focus{color:#fff}.btn-outline-success{box-shadow:none}.btn-outline-success:hover:not(.active){background-color:transparent;box-shadow:none;color:#82d616;opacity:.75}.btn-info:hover,.btn.bg-gradient-info:hover{background-color:#17c1e8;border-color:#17c1e8}.btn-info .btn.bg-outline-info,.btn.bg-gradient-info .btn.bg-outline-info{border:1px solid #17c1e8}.btn-info:not(:disabled):not(.disabled).active,.btn-info:not(:disabled):not(.disabled):active,.btn.bg-gradient-info:not(:disabled):not(.disabled).active,.btn.bg-gradient-info:not(:disabled):not(.disabled):active,.show>.btn-info.dropdown-toggle,.show>.btn.bg-gradient-info.dropdown-toggle{background-color:#17c1e8;color:color-yiq(#17c1e8)}.btn-info.focus,.btn-info:focus,.btn.bg-gradient-info.focus,.btn.bg-gradient-info:focus{color:#fff}.btn-outline-info{box-shadow:none}.btn-outline-info:hover:not(.active){background-color:transparent;box-shadow:none;color:#17c1e8;opacity:.75}.btn-warning:hover,.btn.bg-gradient-warning:hover{background-color:#fbcf33;border-color:#fbcf33}.btn-warning .btn.bg-outline-warning,.btn.bg-gradient-warning .btn.bg-outline-warning{border:1px solid #fbcf33}.btn-warning:not(:disabled):not(.disabled).active,.btn-warning:not(:disabled):not(.disabled):active,.btn.bg-gradient-warning:not(:disabled):not(.disabled).active,.btn.bg-gradient-warning:not(:disabled):not(.disabled):active,.show>.btn-warning.dropdown-toggle,.show>.btn.bg-gradient-warning.dropdown-toggle{background-color:#fbcf33;color:color-yiq(#fbcf33)}.btn-warning.focus,.btn-warning:focus,.btn.bg-gradient-warning.focus,.btn.bg-gradient-warning:focus{color:#fff}.btn-outline-warning{box-shadow:none}.btn-outline-warning:hover:not(.active){background-color:transparent;box-shadow:none;color:#fbcf33;opacity:.75}.btn-danger:hover,.btn.bg-gradient-danger:hover{background-color:#ea0606;border-color:#ea0606}.btn-danger .btn.bg-outline-danger,.btn.bg-gradient-danger .btn.bg-outline-danger{border:1px solid #ea0606}.btn-danger:not(:disabled):not(.disabled).active,.btn-danger:not(:disabled):not(.disabled):active,.btn.bg-gradient-danger:not(:disabled):not(.disabled).active,.btn.bg-gradient-danger:not(:disabled):not(.disabled):active,.show>.btn-danger.dropdown-toggle,.show>.btn.bg-gradient-danger.dropdown-toggle{background-color:#ea0606;color:color-yiq(#ea0606)}.btn-danger.focus,.btn-danger:focus,.btn.bg-gradient-danger.focus,.btn.bg-gradient-danger:focus{color:#fff}.btn-outline-danger{box-shadow:none}.btn-outline-danger:hover:not(.active){background-color:transparent;box-shadow:none;color:#ea0606;opacity:.75}.btn-light:hover,.btn.bg-gradient-light:hover{background-color:#e9ecef;border-color:#e9ecef}.btn-light .btn.bg-outline-light,.btn.bg-gradient-light .btn.bg-outline-light{border:1px solid #e9ecef}.btn-light:not(:disabled):not(.disabled).active,.btn-light:not(:disabled):not(.disabled):active,.btn.bg-gradient-light:not(:disabled):not(.disabled).active,.btn.bg-gradient-light:not(:disabled):not(.disabled):active,.show>.btn-light.dropdown-toggle,.show>.btn.bg-gradient-light.dropdown-toggle{background-color:#e9ecef;color:color-yiq(#e9ecef)}.btn-outline-light{box-shadow:none}.btn-outline-light:hover:not(.active){background-color:transparent;box-shadow:none;color:#e9ecef;opacity:.75}.btn-dark:hover,.btn.bg-gradient-dark:hover{background-color:#344767;border-color:#344767}.btn-dark .btn.bg-outline-dark,.btn.bg-gradient-dark .btn.bg-outline-dark{border:1px solid #344767}.btn-dark:not(:disabled):not(.disabled).active,.btn-dark:not(:disabled):not(.disabled):active,.btn.bg-gradient-dark:not(:disabled):not(.disabled).active,.btn.bg-gradient-dark:not(:disabled):not(.disabled):active,.show>.btn-dark.dropdown-toggle,.show>.btn.bg-gradient-dark.dropdown-toggle{background-color:#344767;color:color-yiq(#344767)}.btn-dark.focus,.btn-dark:focus,.btn.bg-gradient-dark.focus,.btn.bg-gradient-dark:focus{color:#fff}.btn-outline-dark{box-shadow:none}.btn-outline-dark:hover:not(.active){background-color:transparent;box-shadow:none;color:#344767;opacity:.75}.btn-white:hover,.btn.bg-gradient-white:hover{background-color:#fff;border-color:#fff}.btn-white .btn.bg-outline-white,.btn.bg-gradient-white .btn.bg-outline-white{border:1px solid #fff}.btn-white:not(:disabled):not(.disabled).active,.btn-white:not(:disabled):not(.disabled):active,.btn.bg-gradient-white:not(:disabled):not(.disabled).active,.btn.bg-gradient-white:not(:disabled):not(.disabled):active,.show>.btn-white.dropdown-toggle,.show>.btn.bg-gradient-white.dropdown-toggle{background-color:#fff;color:color-yiq(#fff)}.btn-outline-white{box-shadow:none}.btn-outline-white:hover:not(.active){background-color:transparent;box-shadow:none;color:#fff;opacity:.75}.btn-outline-white{background:hsla(0,0%,100%,.1);border-color:hsla(0,0%,100%,.75)}.btn-danger,.btn-danger:hover,.btn-dark,.btn-dark:hover,.btn-info,.btn-info:hover,.btn-primary,.btn-primary:hover,.btn-secondary,.btn-secondary:hover,.btn-success,.btn-success:hover,.btn-warning,.btn-warning:hover,.btn.bg-gradient-danger,.btn.bg-gradient-danger:hover,.btn.bg-gradient-dark,.btn.bg-gradient-dark:hover,.btn.bg-gradient-info,.btn.bg-gradient-info:hover,.btn.bg-gradient-primary,.btn.bg-gradient-primary:hover,.btn.bg-gradient-secondary,.btn.bg-gradient-secondary:hover,.btn.bg-gradient-success,.btn.bg-gradient-success:hover,.btn.bg-gradient-warning,.btn.bg-gradient-warning:hover{color:#fff}.btn-light,.btn-light:hover,.btn.bg-gradient-light,.btn.bg-gradient-light:hover{color:#3a416f}.breadcrumb-item{font-size:.875rem}.breadcrumb-item.text-white:before{color:#fff}.breadcrumb-dark{background-color:#344767}.breadcrumb-dark .breadcrumb-item{font-weight:600}.breadcrumb-dark .breadcrumb-item a{color:#f8f9fa}.breadcrumb-dark .breadcrumb-item a:hover{color:#fff}.breadcrumb-dark .breadcrumb-item+.breadcrumb-item:before{color:#adb5bd}.breadcrumb-dark .breadcrumb-item.active{color:#dee2e6}.breadcrumb-links{background:transparent;margin:0;padding:0}.card{box-shadow:0 20px 27px 0 rgba(0,0,0,.05)}.card .card-header{padding:1.5rem}.card .card-body{font-family:Open Sans;padding:1.5rem}.card.card-plain{background-color:transparent;box-shadow:none}.card .card-footer{background-color:transparent;padding:1.5rem}.author{display:flex}.author .name>span{color:#3a416f;font-size:.875rem;font-weight:600;line-height:1.571}.author .stats{font-size:.875rem;font-weight:400}.card.card-background{align-items:center}.card.card-background .full-background{background-position:50%;background-size:cover;border-radius:1rem;height:100%;margin-bottom:30px;position:absolute;width:100%}.card.card-background .card-body{color:#fff;position:relative;z-index:2}.card.card-background .card-body .content-center,.card.card-background .card-body .content-left{max-width:450px;min-height:330px;padding-bottom:60px;padding-top:60px}.card.card-background .card-body .content-center{text-align:center}.card.card-background .card-body.body-left{width:90%}.card.card-background .card-body .author .name .stats,.card.card-background .card-body .author .name span{color:#fff}.card.card-background:after{background:rgba(0,0,0,.4);border-radius:1rem;bottom:0;content:"";display:block;height:100%;left:0;position:absolute;top:0;width:100%;z-index:1}.card.card-background.card-background-mask-primary:before{background:rgba(0,0,0,.2)}.card.card-background.card-background-mask-primary:after{background-image:linear-gradient(310deg,#7928ca,#ff0080);opacity:.85}.card.card-background.card-background-mask-secondary:before{background:rgba(0,0,0,.2)}.card.card-background.card-background-mask-secondary:after{background-image:linear-gradient(310deg,#627594,#a8b8d8);opacity:.85}.card.card-background.card-background-mask-success:before{background:rgba(0,0,0,.2)}.card.card-background.card-background-mask-success:after{background-image:linear-gradient(310deg,#17ad37,#98ec2d);opacity:.85}.card.card-background.card-background-mask-info:before{background:rgba(0,0,0,.2)}.card.card-background.card-background-mask-info:after{background-image:linear-gradient(310deg,#2152ff,#21d4fd);opacity:.85}.card.card-background.card-background-mask-warning:before{background:rgba(0,0,0,.2)}.card.card-background.card-background-mask-warning:after{background-image:linear-gradient(310deg,#f53939,#fbcf33);opacity:.85}.card.card-background.card-background-mask-danger:before{background:rgba(0,0,0,.2)}.card.card-background.card-background-mask-danger:after{background-image:linear-gradient(310deg,#ea0606,#ff667c);opacity:.85}.card.card-background.card-background-mask-light:before{background:rgba(0,0,0,.2)}.card.card-background.card-background-mask-light:after{background-image:linear-gradient(310deg,#ced4da,#ebeff4);opacity:.85}.card.card-background.card-background-mask-dark:before{background:rgba(0,0,0,.2)}.card.card-background.card-background-mask-dark:after{background-image:linear-gradient(310deg,#141727,#3a416f);opacity:.85}.card.card-background .card-category{font-size:.875rem;font-weight:600}.card.card-background .card-description{margin-bottom:24px;margin-top:24px}@media (min-width:992px){.dropdown .dropdown-menu,.dropend .dropdown-menu,.dropstart .dropdown-menu,.dropup .dropdown-menu{box-shadow:0 8px 26px -4px hsla(0,0%,8%,.15),0 8px 9px -5px hsla(0,0%,8%,.06);cursor:pointer;transition:visibility .25s,opacity .25s,transform .25s}.dropdown .dropdown-toggle:after,.dropend .dropdown-toggle:after,.dropstart .dropdown-toggle:after,.dropup .dropdown-toggle:after{border:none;content:"\f107";font:normal normal normal 14px/1 FontAwesome;font-weight:600;vertical-align:middle}.dropdown .dropdown-toggle.show:after,.dropend .dropdown-toggle.show:after,.dropstart .dropdown-toggle.show:after,.dropup .dropdown-toggle.show:after{transform:rotate(180deg)}.dropdown .dropdown-toggle:after,.dropend .dropdown-toggle:after,.dropstart .dropdown-toggle:after,.dropup .dropdown-toggle:after{transition:.3s ease}.dropdown .dropdown-menu,.dropdown.dropdown-hover .dropdown-menu{-webkit-backface-visibility:hidden;backface-visibility:hidden;display:block;opacity:0;pointer-events:none;top:0;transform:perspective(999px) rotateX(-10deg) translateZ(0) translate3d(0,37px,0)!important;transform-origin:50% 0;will-change:transform,box-shadow}.dropdown .dropdown-menu.show,.dropdown.dropdown-hover:hover>.dropdown-menu{opacity:1;pointer-events:auto;transform:perspective(999px) rotateX(0deg) translateZ(0) translate3d(0,37px,5px)!important;visibility:visible}.dropdown .dropdown-menu.show:before,.dropdown.dropdown-hover:hover>.dropdown-menu:before{top:-20px}.dropdown.dropdown-hover:after{bottom:-24px;content:"";height:100%;left:0;position:absolute;width:100%}.dropdown:not(.dropdown-hover) .dropdown-menu{margin-top:8px!important}.dropdown .dropdown-menu:before{color:#fff;content:"\f0d8";font-family:FontAwesome;font-size:22px;left:28px;position:absolute;right:auto;top:0;transition:top .35s ease}.dropdown .dropdown-item .arrow{transform:rotate(-90deg)}.dropdown-item{transition:background-color .3s ease,color .3s ease}}@media (max-width:991.98px){.dropdown:not(.nav-item) .dropdown-menu{-webkit-backface-visibility:hidden;backface-visibility:hidden;box-shadow:0 8px 26px -4px hsla(0,0%,8%,.15),0 8px 9px -5px hsla(0,0%,8%,.06);display:block;opacity:0;pointer-events:none;top:0;transform:perspective(999px) rotateX(-10deg) translateZ(0) translate3d(0,37px,0)!important;transform-origin:50% 0;transition:visibility .25s,opacity .25s,transform .25s;will-change:transform,box-shadow}.dropdown:not(.nav-item) .dropdown-menu:before{color:#fff;content:"\f0d8";font-family:FontAwesome;font-size:22px;left:28px;position:absolute;right:auto;top:0;transition:top .35s ease}.dropdown:not(.nav-item):not(.dropdown-hover) .dropdown-menu{margin-top:8px!important}.dropdown:not(.nav-item) .dropdown-menu.show{opacity:1;pointer-events:auto;transform:perspective(999px) rotateX(0deg) translateZ(0) translate3d(0,37px,5px)!important;visibility:visible}.dropdown:not(.nav-item) .dropdown-menu.show:before{top:-20px}.dropdown.nav-item .dropdown-menu{background-color:transparent;overflow:scroll}.dropdown.nav-item .dropdown-menu-animation{display:block;height:0;opacity:0;padding-bottom:0!important;padding-top:0!important;transition:all .35s ease}.dropdown.nav-item .dropdown-menu-animation.show{height:250px;opacity:1}}.dropdown-menu li{position:relative}.dropdown.dropdown-subitem:after{bottom:0;left:100%;width:50%}.dropdown .dropdown-menu .dropdown-item+.dropdown-menu:before{left:0;top:0;transform:rotate(-90deg);transition:left .35s ease;z-index:-1}.dropdown .dropdown-menu.dropdown-menu-end{left:auto!important;right:0!important}.dropdown .dropdown-menu.dropdown-menu-end:before{left:auto;right:28px}.dropdown.dropdown-subitem:hover .dropdown-item+.dropdown-menu:before{left:-8px}.dropdown>.dropdown-menu .dropdown-item+.dropdown-menu{transform:perspective(999px) rotateX(0deg) translateZ(0) translateZ(5px)!important}.dropdown .dropdown-menu .dropdown-item+.dropdown-menu{left:auto;right:-197px;top:0}.dropdown-image{background-size:cover}@media (min-width:992px){.dropdown-xl{min-width:40rem}.dropdown-lg{min-width:23rem}.dropdown-md{min-width:15rem}}@media (max-width:1199.98px){.dropdown-lg-responsive{min-width:19rem}}.dropup .dropdown-menu{-webkit-backface-visibility:hidden;backface-visibility:hidden;bottom:100%!important;box-shadow:0 8px 26px -4px hsla(0,0%,8%,.15),0 8px 9px -5px hsla(0,0%,8%,.06);cursor:pointer;display:block;margin-bottom:.5rem!important;opacity:0;pointer-events:none;top:auto!important;transform:perspective(999px) rotateX(12deg) translateZ(0) translateZ(0)!important;transform-origin:bottom;transition:visibility .25s,opacity .25s,transform .25s;will-change:transform,box-shadow}.dropup .dropdown-menu.show{opacity:1;pointer-events:auto;transform:perspective(999px) rotateX(0deg) translateZ(0) translate3d(1px,0,5px)!important}.dropup .dropdown-menu.show:after{bottom:-20px}.dropup .dropdown-menu:after{bottom:22px;color:#fff;content:"\f0d7";font-family:FontAwesome;font-size:22px;left:28px;position:absolute;right:auto;transition:bottom .35s ease;z-index:-1}.page-header{align-items:center;background-position:50%;background-size:cover;display:flex;overflow:hidden;padding:0;position:relative}.page-header .container{z-index:1}.oblique{border-bottom-left-radius:.75rem;overflow:hidden;right:-10rem;transform:skewX(-10deg);width:60%}.oblique .oblique-image{transform:skewX(10deg)}.fixed-plugin .fixed-plugin-button{background:#fff;border-radius:50%;bottom:30px;box-shadow:0 2px 12px 0 rgba(0,0,0,.16);cursor:pointer;font-size:1.25rem;right:30px;z-index:990}.fixed-plugin .fixed-plugin-button i{pointer-events:none}.fixed-plugin .card{border-radius:0;height:100%;left:auto!important;padding:0 10px;position:fixed!important;right:-360px;top:0;transform:unset!important;transition:.2s ease;width:360px;z-index:1020}.fixed-plugin .badge{border:1px solid #fff;border-radius:50%;cursor:pointer;display:inline-block;height:23px;margin-right:5px;position:relative;transition:all .2s ease-in-out;width:23px}.fixed-plugin .badge.active,.fixed-plugin .badge:hover{border-color:#344767}.fixed-plugin .btn.bg-gradient-primary:not(:disabled):not(.disabled){border:1px solid transparent}.fixed-plugin .btn.bg-gradient-primary:not(:disabled):not(.disabled):not(.active){background-color:transparent;background-image:none;border:1px solid #cb0c9f;color:#cb0c9f}.fixed-plugin.show .card{right:0}.input-group{border-radius:.5rem}.input-group,.input-group .input-group-text{transition:box-shadow .15s ease,border-color .15s ease}.input-group>:not(:first-child):not(.dropdown-menu){margin-left:0}.input-group .form-control:focus{border-left:1px solid #e293d3!important;border-right:1px solid #e293d3!important}.input-group .form-control:not(:first-child){border-left:0;padding-left:0}.input-group .form-control:not(:last-child){border-right:0;padding-right:0}.input-group .form-control+.input-group-text{border-left:0;border-right:1px solid #d2d6da}.input-group .input-group-text{border-right:0}.form-group{margin-bottom:1rem}.form-check:not(.form-switch) .form-check-input[type=checkbox],.form-check:not(.form-switch) .form-check-input[type=radio]{border:1px solid #cbd3da;margin-top:.25rem;position:relative}.form-check:not(.form-switch) .form-check-input[type=checkbox]:checked,.form-check:not(.form-switch) .form-check-input[type=radio]:checked{border:0}.form-check:not(.form-switch) .form-check-input[type=checkbox]:after{align-items:center;color:#fff;content:"\f00c";display:flex;font-family:FontAwesome;font-size:.67rem;height:100%;justify-content:center;opacity:0;position:absolute;transition:opacity .25s ease-in-out;width:100%}.form-check:not(.form-switch) .form-check-input[type=checkbox]:checked:after{opacity:1}.form-check:not(.form-switch) .form-check-input[type=radio]{transition:border 0s}.form-check:not(.form-switch) .form-check-input[type=radio]:after{background-color:#fff;border-radius:50%;content:"";height:.4375rem;opacity:0;position:absolute;transition:opacity .25s ease-in-out;width:.4375rem}.form-check:not(.form-switch) .form-check-input[type=radio]:checked{padding:6px}.form-check:not(.form-switch) .form-check-input[type=radio]:checked:after{opacity:1}.form-check-input[type=checkbox],.form-check-label{cursor:pointer}.form-check-label{font-size:.875rem;font-weight:400}.form-check-input{-webkit-appearance:none;-moz-appearance:none;appearance:none}.form-switch .form-check-input{background-color:rgba(58,65,111,.1);border:1px solid #e9ecef;height:1.25em;position:relative}.form-switch .form-check-input:after{background-color:#fff;border-radius:50%;box-shadow:0 .25rem .375rem -.0625rem hsla(0,0%,8%,.12),0 .125rem .25rem -.0625rem hsla(0,0%,8%,.07);content:"";height:1rem;position:absolute;top:1px;transform:translateX(1px);transition:transform .25s ease-in-out,background-color .25s ease-in-out;width:1rem}.form-switch .form-check-input:checked:after{transform:translateX(21px)}.form-switch .form-check-input:checked{background-color:rgba(58,65,111,.95);border-color:rgba(58,65,111,.95)}.form-select{transition:box-shadow .15s ease,border-color .15s ease}.form-label,label{color:#344767;font-size:.75rem;font-weight:700;margin-bottom:.5rem;margin-left:.25rem}.form-control.is-invalid:focus{box-shadow:0 0 0 2px rgba(253,92,112,.6)}.form-control.is-valid:focus{box-shadow:0 0 0 2px rgba(102,212,50,.65)}.footer .nav-link{color:#344767;font-size:.875rem;font-weight:400;padding-bottom:.25rem;padding-top:0}.footer .nav-link:hover{opacity:1!important;transition:opacity .3 ease}.bg-gradient-primary{background-image:linear-gradient(310deg,#7928ca,#ff0080)}.bg-gradient-secondary{background-image:linear-gradient(310deg,#627594,#a8b8d8)}.bg-gradient-success{background-image:linear-gradient(310deg,#17ad37,#98ec2d)}.bg-gradient-info{background-image:linear-gradient(310deg,#2152ff,#21d4fd)}.bg-gradient-warning{background-image:linear-gradient(310deg,#f53939,#fbcf33)}.bg-gradient-danger{background-image:linear-gradient(310deg,#ea0606,#ff667c)}.bg-gradient-light{background-image:linear-gradient(310deg,#ced4da,#ebeff4)}.bg-gradient-dark{background-image:linear-gradient(310deg,#141727,#3a416f)}.bg-gradient-faded-primary{background-image:radial-gradient(370px circle at 80% 50%,rgba(203,12,159,.6) 0,#9b0979 100%)}.bg-gradient-faded-secondary{background-image:radial-gradient(370px circle at 80% 50%,rgba(131,146,171,.6) 0,#657796 100%)}.bg-gradient-faded-success{background-image:radial-gradient(370px circle at 80% 50%,rgba(130,214,22,.6) 0,#66a811 100%)}.bg-gradient-faded-info{background-image:radial-gradient(370px circle at 80% 50%,rgba(23,193,232,.6) 0,#129aba 100%)}.bg-gradient-faded-warning{background-image:radial-gradient(370px circle at 80% 50%,rgba(251,207,51,.6) 0,#f6c105 100%)}.bg-gradient-faded-danger{background-image:radial-gradient(370px circle at 80% 50%,rgba(234,6,6,.6) 0,#b80505 100%)}.bg-gradient-faded-light{background-image:radial-gradient(370px circle at 80% 50%,rgba(233,236,239,.6) 0,#cbd3da 100%)}.bg-gradient-faded-dark{background-image:radial-gradient(370px circle at 80% 50%,rgba(52,71,103,.6) 0,#233045 100%)}.bg-gradient-faded-white{background-image:radial-gradient(370px circle at 80% 50%,hsla(0,0%,100%,.6) 0,#e6e6e6 100%)}.bg-gradient-faded-primary-vertical{background-image:radial-gradient(200px circle at 50% 70%,rgba(203,12,159,.3) 0,#cb0c9f 100%)}.bg-gradient-faded-secondary-vertical{background-image:radial-gradient(200px circle at 50% 70%,rgba(131,146,171,.3) 0,#8392ab 100%)}.bg-gradient-faded-success-vertical{background-image:radial-gradient(200px circle at 50% 70%,rgba(130,214,22,.3) 0,#82d616 100%)}.bg-gradient-faded-info-vertical{background-image:radial-gradient(200px circle at 50% 70%,rgba(23,193,232,.3) 0,#17c1e8 100%)}.bg-gradient-faded-warning-vertical{background-image:radial-gradient(200px circle at 50% 70%,rgba(251,207,51,.3) 0,#fbcf33 100%)}.bg-gradient-faded-danger-vertical{background-image:radial-gradient(200px circle at 50% 70%,rgba(234,6,6,.3) 0,#ea0606 100%)}.bg-gradient-faded-light-vertical{background-image:radial-gradient(200px circle at 50% 70%,rgba(233,236,239,.3) 0,#e9ecef 100%)}.bg-gradient-faded-dark-vertical{background-image:radial-gradient(200px circle at 50% 70%,rgba(52,71,103,.3) 0,#344767 100%)}.bg-gradient-faded-white-vertical{background-image:radial-gradient(200px circle at 50% 70%,hsla(0,0%,100%,.3) 0,#fff 100%)}.icon-shape{background-position:50%;border-radius:.75rem;height:48px;width:48px}.icon-shape i{color:#fff;opacity:.8;position:relative;top:11px}.icon-shape .ni{top:14px}.icon-xxs{height:20px;width:20px}.icon-xxs i{font-size:.5rem;top:-4px}.icon-xs{height:24px;width:24px}.icon-xs i{font-size:.5rem;top:-4px}.icon-sm{height:32px;width:32px}.icon-sm i{font-size:.65rem;top:2px}.icon-md{height:48px;width:48px}.icon-md i{font-size:.875rem;top:22%}.icon-md.icon-striped{background-position-x:85px;background-position-y:85px}.icon-md.icon-striped i{font-size:.875rem;margin-left:-10px;top:11%}.icon-lg{height:64px;width:64px}.icon-lg i{font-size:1.25rem;top:31%}.icon-lg.icon-striped{background-position-x:111px;background-position-y:111px}.icon-lg.icon-striped i{margin-left:-15px;top:21%}.icon-xl{border-radius:.75rem;height:100px;width:100px}.icon-xl i{font-size:1.6rem;top:37%}.icon-xl.icon-striped{background-position-x:80px;background-position-y:80px}.icon-xl.icon-striped i{margin-left:-15px;top:30%}.info-horizontal{text-align:left!important}.info-horizontal .icon{float:left}.info-horizontal .description{overflow:hidden}svg.text-primary .color-foreground{fill:#7928ca}svg.text-primary .color-background{fill:#ff0080}svg.text-secondary .color-foreground{fill:#627594}svg.text-secondary .color-background{fill:#a8b8d8}svg.text-info .color-foreground{fill:#2152ff}svg.text-info .color-background{fill:#21d4fd}svg.text-warning .color-foreground{fill:#f53939}svg.text-warning .color-background{fill:#fbcf33}svg.text-danger .color-foreground{fill:#ea0606}svg.text-danger .color-background{fill:#ff667c}svg.text-success .color-foreground{fill:#17ad37}svg.text-success .color-background{fill:#98ec2d}svg.text-dark .color-foreground{fill:#141727}svg.text-dark .color-background{fill:#3a416f}.blur{-webkit-backdrop-filter:saturate(200%) blur(30px);backdrop-filter:saturate(200%) blur(30px);background-color:hsla(0,0%,100%,.8)!important;box-shadow:inset 0 0 2px hsla(0,0%,100%,.82)}.blur.saturation-less{-webkit-backdrop-filter:saturate(20%) blur(30px);backdrop-filter:saturate(20%) blur(30px)}.blur.blur-rounded{border-radius:40px}.blur.blur-light{background-color:hsla(0,0%,100%,.4)}.blur.blur-dark{background-color:rgba(0,0,0,.3)}.shadow-blur{box-shadow:inset 0 0 1px 1px hsla(0,0%,100%,.9),0 20px 27px 0 rgba(0,0,0,.05)!important}.shadow-card{box-shadow:0 20px 27px 0 rgba(0,0,0,.05)!important}.navbar-blur{background-color:hsla(0,0%,100%,.58)!important}.blur-section,.navbar-blur{-webkit-backdrop-filter:saturate(200%) blur(30px);backdrop-filter:saturate(200%) blur(30px)}.blur-section.blur-gradient-primary{background-image:linear-gradient(310deg,rgba(121,40,202,.95),rgba(255,0,128,.95))}.move-on-hover{-webkit-backface-visibility:hidden;backface-visibility:hidden;overflow:hidden;transform:perspective(999px) rotateX(0deg) translateZ(0);transform-origin:50% 0;transition:.2s ease-out;will-change:transform,box-shadow}.move-on-hover:hover{transform:perspective(999px) rotateX(7deg) translate3d(0,-4px,5px)}.gradient-animation{-webkit-animation:gradient 10s ease infinite;animation:gradient 10s ease infinite;background:linear-gradient(-45deg,#2152ff,#ea0606,#fbcf33,#7928ca,#344767);background-size:400% 400%!important}hr.vertical{background-color:transparent;height:100%;position:absolute;right:0;top:0;width:1px}hr.vertical.light{background-image:linear-gradient(180deg,hsla(0,0%,100%,0),#fff,hsla(0,0%,100%,0))}hr.vertical.dark{background-image:linear-gradient(180deg,transparent,rgba(0,0,0,.4),transparent)}hr.vertical.gray-light{background-image:linear-gradient(90deg,transparent,rgba(0,0,0,.1),transparent)}hr.horizontal{background-color:transparent}hr.horizontal.light{background-image:linear-gradient(90deg,hsla(0,0%,100%,0),#fff,hsla(0,0%,100%,0))}hr.horizontal.dark{background-image:linear-gradient(90deg,transparent,rgba(0,0,0,.4),transparent)}hr.horizontal.gray-light{background-image:linear-gradient(90deg,transparent,rgba(0,0,0,.1),transparent)}.lock-size{height:1.7rem;width:1.7rem}.border-radius-xs{border-radius:.125rem}.border-radius-sm{border-radius:.25rem}.border-radius-md{border-radius:.5rem}.border-radius-lg{border-radius:.75rem}.border-radius-xl{border-radius:1rem}.border-radius-2xl{border-radius:1.5rem}.border-radius-section{border-radius:10rem}.border-bottom-end-radius-0{border-bottom-right-radius:0}.border-top-end-radius-0{border-top-right-radius:0}.border-bottom-start-radius-0{border-bottom-left-radius:0}.border-top-start-radius-0{border-top-left-radius:0}.border-dashed{border-style:dashed}.z-index-sticky{z-index:1020}.waves{height:16vh;margin-bottom:-7px;max-height:150px;min-height:100px;position:relative;width:100%}.waves.waves-sm{height:50px;min-height:50px}.waves.no-animation .moving-waves>use{-webkit-animation:none;animation:none}.wave-rotate{transform:rotate(180deg)}.moving-waves>use{-webkit-animation:move-forever 40s cubic-bezier(.55,.5,.45,.5) infinite;animation:move-forever 40s cubic-bezier(.55,.5,.45,.5) infinite}.moving-waves>use:first-child{-webkit-animation-delay:-2s;animation-delay:-2s;-webkit-animation-duration:11s;animation-duration:11s}.moving-waves>use:nth-child(2){-webkit-animation-delay:-4s;animation-delay:-4s;-webkit-animation-duration:13s;animation-duration:13s}.moving-waves>use:nth-child(3){-webkit-animation-delay:-3s;animation-delay:-3s;-webkit-animation-duration:15s;animation-duration:15s}.moving-waves>use:nth-child(4){-webkit-animation-delay:-4s;animation-delay:-4s;-webkit-animation-duration:20s;animation-duration:20s}.moving-waves>use:nth-child(5){-webkit-animation-delay:-4s;animation-delay:-4s;-webkit-animation-duration:25s;animation-duration:25s}.moving-waves>use:nth-child(6){-webkit-animation-delay:-3s;animation-delay:-3s;-webkit-animation-duration:30s;animation-duration:30s}@-webkit-keyframes move-forever{0%{transform:translate3d(-90px,0,0)}to{transform:translate3d(85px,0,0)}}@keyframes move-forever{0%{transform:translate3d(-90px,0,0)}to{transform:translate3d(85px,0,0)}}@media (max-width:767.98px){.waves{height:40px;min-height:40px}hr.horizontal{background-color:transparent}hr.horizontal:not(.dark){background-image:linear-gradient(90deg,hsla(0,0%,100%,0),#fff,hsla(0,0%,100%,0))}hr.horizontal.vertical{transform:rotate(90deg)}hr.horizontal.dark{background-image:linear-gradient(90deg,transparent,rgba(0,0,0,.4),transparent)}}.overflow-visible{overflow:visible!important}.bg-cover,.mask{background-size:cover}.mask{background-position:50%;height:100%;left:0;opacity:.8;position:absolute;top:0;width:100%}.cursor-pointer{cursor:pointer}.transform-translate-50{transform:translateY(-50%)}@media (min-width:992px){.virtual-reality .sidenav{-webkit-animation-duration:1.5s;animation-duration:1.5s;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-name:fadeInBottom;animation-name:fadeInBottom;background:#fff;left:18%!important;margin-top:1.5rem;position:absolute;transform:scale(.6)}}.navbar{box-shadow:0 2px 12px 0 rgba(0,0,0,.16)}.navbar .nav-link,.navbar .navbar-brand{color:#344767;font-size:.875rem}.navbar .nav-link{font-weight:400;padding:.5rem 1rem}.navbar.navbar-absolute{position:absolute;width:100%;z-index:1}.navbar.navbar-transparent .nav-link,.navbar.navbar-transparent .nav-link i{color:#fff}.navbar.navbar-transparent .nav-link:focus,.navbar.navbar-transparent .nav-link:hover{color:hsla(0,0%,100%,.75)}.navbar.navbar-transparent .navbar-toggler .navbar-toggler-icon .navbar-toggler-bar{background:#fff}.navbar.navbar-transparent .navbar-collapse{border-radius:1rem}.navbar.navbar-dark .navbar-collapse.collapsing .dropdown-header.text-dark,.navbar.navbar-dark .navbar-collapse.show .dropdown-header.text-dark{color:#fff!important}.navbar .sidenav-toggler-inner{width:18px}.navbar .sidenav-toggler-inner .sidenav-toggler-line{background:#67748e;border-radius:.125rem;display:block;height:2px;position:relative;transition:all .15s ease}.navbar .sidenav-toggler-inner .sidenav-toggler-line:not(:last-child){margin-bottom:3px}.g-sidenav-show.g-sidenav-pinned .navbar .sidenav-toggler-inner .sidenav-toggler-line:first-child,.g-sidenav-show.g-sidenav-pinned .navbar .sidenav-toggler-inner .sidenav-toggler-line:last-child{transform:translateX(5px);width:13px}.navbar-light{background-color:#fff!important}.navbar-light .navbar-toggler{border:none}.navbar-light .navbar-toggler:focus{box-shadow:none}.navbar-toggler .navbar-toggler-icon{background-image:none}.navbar-toggler .navbar-toggler-icon .navbar-toggler-bar{background:#6c757d;border-radius:1px;display:block;height:1px;margin:0 auto;position:relative;transition:all .2s;width:22px}.navbar-toggler .navbar-toggler-icon .navbar-toggler-bar.bar2,.navbar-toggler .navbar-toggler-icon .navbar-toggler-bar.bar3{margin-top:7px}.navbar-toggler[aria-expanded=true] .navbar-toggler-bar.bar1{margin-top:4px;transform:rotate(45deg);transform-origin:10% 10%}.navbar-toggler[aria-expanded=true] .navbar-toggler-bar.bar2{opacity:0}.navbar-toggler[aria-expanded=true] .navbar-toggler-bar.bar3{margin-top:3px;transform:rotate(-45deg);transform-origin:10% 90%}@media (max-width:991.98px){.navbar.navbar-transparent .navbar-collapse{padding-bottom:.5rem;padding-top:.5rem}.navbar.navbar-transparent .navbar-collapse.collapsing,.navbar.navbar-transparent .navbar-collapse.show{background:#fff}.navbar.navbar-transparent .navbar-collapse.show .nav-link,.navbar.navbar-transparent .navbar-collapse.show i{color:#344767}.g-sidenav-show .navbar:not(.sidenav).navbar-main .navbar-collapse{display:flex!important;flex-basis:auto}.g-sidenav-show .navbar:not(.sidenav).navbar-main .navbar-nav{flex-direction:row}}@media (max-width:767.98px){.navbar-collapse{position:relative}.navbar-collapse .navbar-nav{width:100%}.navbar-collapse .navbar-nav .nav-item.dropdown{position:static}.navbar-collapse .navbar-nav .nav-item.dropdown .dropdown-menu{left:0;right:0}.navbar-collapse .navbar-nav .nav-item.dropdown .dropdown-menu.show:before{content:none}}@media (max-width:575.98px){.navbar-nav .nav-item.dropdown .dropdown-menu{left:0;right:auto}}.navbar-vertical .navbar-brand-img,.navbar-vertical .navbar-brand>img{max-height:2rem;max-width:100%}.navbar-vertical .navbar-nav .nav-link{color:#67748e;font-weight:500;padding-left:1rem;padding-right:1rem}.navbar-vertical .navbar-nav .nav-link>i{font-size:.9375rem;line-height:1.5rem;min-width:1.8rem}.navbar-vertical .navbar-nav .nav-link .dropdown-menu{border:none}.navbar-vertical .navbar-nav .nav-link .dropdown-menu .dropdown-menu{margin-left:.5rem}.navbar-vertical .navbar-nav .nav-sm .nav-link{font-size:.8125rem}.navbar-vertical .navbar-nav .nav-link{align-items:center;display:flex;white-space:nowrap}.navbar-vertical .navbar-heading{font-size:.75rem;letter-spacing:.04em;padding-bottom:.5rem;padding-top:.5rem;text-transform:uppercase}.navbar-vertical.navbar-expand-xs{bottom:0;box-shadow:none;display:block;max-width:15.625rem!important;overflow-y:auto;padding:0;position:fixed;top:0;width:100%}.navbar-vertical.navbar-expand-xs .navbar-collapse{display:block;height:calc(100vh - 360px);overflow:auto}.navbar-vertical.navbar-expand-xs>[class*=container]{align-items:stretch;flex-direction:column;min-height:100%;padding-left:0;padding-right:0}@media (-ms-high-contrast:active),(-ms-high-contrast:none){.navbar-vertical.navbar-expand-xs>[class*=container]{height:100%;min-height:none}}.navbar-vertical.navbar-expand-xs.fixed-start{left:0}.navbar-vertical.navbar-expand-xs.fixed-end{right:0}.navbar-vertical.navbar-expand-xs .navbar-nav .nav-link{margin:0 1rem;padding-bottom:.675rem;padding-top:.675rem}.navbar-vertical.navbar-expand-xs .navbar-nav .nav-link .nav-link-text,.navbar-vertical.navbar-expand-xs .navbar-nav .nav-link .sidenav-mini-icon,.navbar-vertical.navbar-expand-xs .navbar-nav .nav-link .sidenav-normal,.navbar-vertical.navbar-expand-xs .navbar-nav .nav-link i{pointer-events:none}.navbar-vertical.navbar-expand-xs .navbar-nav .nav-item{width:100%}.navbar-vertical.navbar-expand-xs .navbar-nav>.nav-item{margin-top:.125rem}.navbar-vertical.navbar-expand-xs .navbar-nav>.nav-item .icon .ni{top:0}.navbar-vertical.navbar-expand-xs .navbar-nav>.nav-item>.nav-link .icon svg .color-background{fill:#3a416f}.navbar-vertical.navbar-expand-xs .navbar-nav>.nav-item>.nav-link .icon svg .color-foreground{fill:#141727}.navbar-vertical.navbar-expand-xs .lavalamp-object{background:theme-color("primary");border-radius:.25rem;color:color-yiq(#cb0c9f);margin-left:.5rem;margin-right:.5rem;padding-left:1rem;padding-right:1rem;width:calc(100% - 1rem)!important}.navbar-vertical.navbar-expand-xs .navbar-nav .nav .nav-link{padding-bottom:.45rem;padding-left:15px;padding-top:.45rem}.navbar-vertical.navbar-expand-xs .navbar-nav .nav .nav-link>span.sidenav-normal{transition:all .1s ease 0s}@media (min-width:576px){.navbar-vertical.navbar-expand-sm{bottom:0;box-shadow:none;display:block;max-width:15.625rem!important;overflow-y:auto;padding:0;position:fixed;top:0;width:100%}.navbar-vertical.navbar-expand-sm .navbar-collapse{display:block;height:calc(100vh - 360px);overflow:auto}.navbar-vertical.navbar-expand-sm>[class*=container]{align-items:stretch;flex-direction:column;min-height:100%;padding-left:0;padding-right:0}}@media (min-width:576px) and (-ms-high-contrast:active),(min-width:576px) and (-ms-high-contrast:none){.navbar-vertical.navbar-expand-sm>[class*=container]{height:100%;min-height:none}}@media (min-width:576px){.navbar-vertical.navbar-expand-sm.fixed-start{left:0}.navbar-vertical.navbar-expand-sm.fixed-end{right:0}.navbar-vertical.navbar-expand-sm .navbar-nav .nav-link{margin:0 1rem;padding-bottom:.675rem;padding-top:.675rem}.navbar-vertical.navbar-expand-sm .navbar-nav .nav-link .nav-link-text,.navbar-vertical.navbar-expand-sm .navbar-nav .nav-link .sidenav-mini-icon,.navbar-vertical.navbar-expand-sm .navbar-nav .nav-link .sidenav-normal,.navbar-vertical.navbar-expand-sm .navbar-nav .nav-link i{pointer-events:none}.navbar-vertical.navbar-expand-sm .navbar-nav .nav-item{width:100%}.navbar-vertical.navbar-expand-sm .navbar-nav>.nav-item{margin-top:.125rem}.navbar-vertical.navbar-expand-sm .navbar-nav>.nav-item .icon .ni{top:0}.navbar-vertical.navbar-expand-sm .navbar-nav>.nav-item>.nav-link .icon svg .color-background{fill:#3a416f}.navbar-vertical.navbar-expand-sm .navbar-nav>.nav-item>.nav-link .icon svg .color-foreground{fill:#141727}.navbar-vertical.navbar-expand-sm .lavalamp-object{background:theme-color("primary");border-radius:.25rem;color:color-yiq(#cb0c9f);margin-left:.5rem;margin-right:.5rem;padding-left:1rem;padding-right:1rem;width:calc(100% - 1rem)!important}.navbar-vertical.navbar-expand-sm .navbar-nav .nav .nav-link{padding-bottom:.45rem;padding-left:15px;padding-top:.45rem}.navbar-vertical.navbar-expand-sm .navbar-nav .nav .nav-link>span.sidenav-normal{transition:all .1s ease 0s}}@media (min-width:768px){.navbar-vertical.navbar-expand-md{bottom:0;box-shadow:none;display:block;max-width:15.625rem!important;overflow-y:auto;padding:0;position:fixed;top:0;width:100%}.navbar-vertical.navbar-expand-md .navbar-collapse{display:block;height:calc(100vh - 360px);overflow:auto}.navbar-vertical.navbar-expand-md>[class*=container]{align-items:stretch;flex-direction:column;min-height:100%;padding-left:0;padding-right:0}}@media (min-width:768px) and (-ms-high-contrast:active),(min-width:768px) and (-ms-high-contrast:none){.navbar-vertical.navbar-expand-md>[class*=container]{height:100%;min-height:none}}@media (min-width:768px){.navbar-vertical.navbar-expand-md.fixed-start{left:0}.navbar-vertical.navbar-expand-md.fixed-end{right:0}.navbar-vertical.navbar-expand-md .navbar-nav .nav-link{margin:0 1rem;padding-bottom:.675rem;padding-top:.675rem}.navbar-vertical.navbar-expand-md .navbar-nav .nav-link .nav-link-text,.navbar-vertical.navbar-expand-md .navbar-nav .nav-link .sidenav-mini-icon,.navbar-vertical.navbar-expand-md .navbar-nav .nav-link .sidenav-normal,.navbar-vertical.navbar-expand-md .navbar-nav .nav-link i{pointer-events:none}.navbar-vertical.navbar-expand-md .navbar-nav .nav-item{width:100%}.navbar-vertical.navbar-expand-md .navbar-nav>.nav-item{margin-top:.125rem}.navbar-vertical.navbar-expand-md .navbar-nav>.nav-item .icon .ni{top:0}.navbar-vertical.navbar-expand-md .navbar-nav>.nav-item>.nav-link .icon svg .color-background{fill:#3a416f}.navbar-vertical.navbar-expand-md .navbar-nav>.nav-item>.nav-link .icon svg .color-foreground{fill:#141727}.navbar-vertical.navbar-expand-md .lavalamp-object{background:theme-color("primary");border-radius:.25rem;color:color-yiq(#cb0c9f);margin-left:.5rem;margin-right:.5rem;padding-left:1rem;padding-right:1rem;width:calc(100% - 1rem)!important}.navbar-vertical.navbar-expand-md .navbar-nav .nav .nav-link{padding-bottom:.45rem;padding-left:15px;padding-top:.45rem}.navbar-vertical.navbar-expand-md .navbar-nav .nav .nav-link>span.sidenav-normal{transition:all .1s ease 0s}}@media (min-width:992px){.navbar-vertical.navbar-expand-lg{bottom:0;box-shadow:none;display:block;max-width:15.625rem!important;overflow-y:auto;padding:0;position:fixed;top:0;width:100%}.navbar-vertical.navbar-expand-lg .navbar-collapse{display:block;height:calc(100vh - 360px);overflow:auto}.navbar-vertical.navbar-expand-lg>[class*=container]{align-items:stretch;flex-direction:column;min-height:100%;padding-left:0;padding-right:0}}@media (min-width:992px) and (-ms-high-contrast:active),(min-width:992px) and (-ms-high-contrast:none){.navbar-vertical.navbar-expand-lg>[class*=container]{height:100%;min-height:none}}@media (min-width:992px){.navbar-vertical.navbar-expand-lg.fixed-start{left:0}.navbar-vertical.navbar-expand-lg.fixed-end{right:0}.navbar-vertical.navbar-expand-lg .navbar-nav .nav-link{margin:0 1rem;padding-bottom:.675rem;padding-top:.675rem}.navbar-vertical.navbar-expand-lg .navbar-nav .nav-link .nav-link-text,.navbar-vertical.navbar-expand-lg .navbar-nav .nav-link .sidenav-mini-icon,.navbar-vertical.navbar-expand-lg .navbar-nav .nav-link .sidenav-normal,.navbar-vertical.navbar-expand-lg .navbar-nav .nav-link i{pointer-events:none}.navbar-vertical.navbar-expand-lg .navbar-nav .nav-item{width:100%}.navbar-vertical.navbar-expand-lg .navbar-nav>.nav-item{margin-top:.125rem}.navbar-vertical.navbar-expand-lg .navbar-nav>.nav-item .icon .ni{top:0}.navbar-vertical.navbar-expand-lg .navbar-nav>.nav-item>.nav-link .icon svg .color-background{fill:#3a416f}.navbar-vertical.navbar-expand-lg .navbar-nav>.nav-item>.nav-link .icon svg .color-foreground{fill:#141727}.navbar-vertical.navbar-expand-lg .lavalamp-object{background:theme-color("primary");border-radius:.25rem;color:color-yiq(#cb0c9f);margin-left:.5rem;margin-right:.5rem;padding-left:1rem;padding-right:1rem;width:calc(100% - 1rem)!important}.navbar-vertical.navbar-expand-lg .navbar-nav .nav .nav-link{padding-bottom:.45rem;padding-left:15px;padding-top:.45rem}.navbar-vertical.navbar-expand-lg .navbar-nav .nav .nav-link>span.sidenav-normal{transition:all .1s ease 0s}}@media (min-width:1200px){.navbar-vertical.navbar-expand-xl{bottom:0;box-shadow:none;display:block;max-width:15.625rem!important;overflow-y:auto;padding:0;position:fixed;top:0;width:100%}.navbar-vertical.navbar-expand-xl .navbar-collapse{display:block;height:calc(100vh - 360px);overflow:auto}.navbar-vertical.navbar-expand-xl>[class*=container]{align-items:stretch;flex-direction:column;min-height:100%;padding-left:0;padding-right:0}}@media (min-width:1200px) and (-ms-high-contrast:active),(min-width:1200px) and (-ms-high-contrast:none){.navbar-vertical.navbar-expand-xl>[class*=container]{height:100%;min-height:none}}@media (min-width:1200px){.navbar-vertical.navbar-expand-xl.fixed-start{left:0}.navbar-vertical.navbar-expand-xl.fixed-end{right:0}.navbar-vertical.navbar-expand-xl .navbar-nav .nav-link{margin:0 1rem;padding-bottom:.675rem;padding-top:.675rem}.navbar-vertical.navbar-expand-xl .navbar-nav .nav-link .nav-link-text,.navbar-vertical.navbar-expand-xl .navbar-nav .nav-link .sidenav-mini-icon,.navbar-vertical.navbar-expand-xl .navbar-nav .nav-link .sidenav-normal,.navbar-vertical.navbar-expand-xl .navbar-nav .nav-link i{pointer-events:none}.navbar-vertical.navbar-expand-xl .navbar-nav .nav-item{width:100%}.navbar-vertical.navbar-expand-xl .navbar-nav>.nav-item{margin-top:.125rem}.navbar-vertical.navbar-expand-xl .navbar-nav>.nav-item .icon .ni{top:0}.navbar-vertical.navbar-expand-xl .navbar-nav>.nav-item>.nav-link .icon svg .color-background{fill:#3a416f}.navbar-vertical.navbar-expand-xl .navbar-nav>.nav-item>.nav-link .icon svg .color-foreground{fill:#141727}.navbar-vertical.navbar-expand-xl .lavalamp-object{background:theme-color("primary");border-radius:.25rem;color:color-yiq(#cb0c9f);margin-left:.5rem;margin-right:.5rem;padding-left:1rem;padding-right:1rem;width:calc(100% - 1rem)!important}.navbar-vertical.navbar-expand-xl .navbar-nav .nav .nav-link{padding-bottom:.45rem;padding-left:15px;padding-top:.45rem}.navbar-vertical.navbar-expand-xl .navbar-nav .nav .nav-link>span.sidenav-normal{transition:all .1s ease 0s}}@media (min-width:1400px){.navbar-vertical.navbar-expand-xxl{bottom:0;box-shadow:none;display:block;max-width:15.625rem!important;overflow-y:auto;padding:0;position:fixed;top:0;width:100%}.navbar-vertical.navbar-expand-xxl .navbar-collapse{display:block;height:calc(100vh - 360px);overflow:auto}.navbar-vertical.navbar-expand-xxl>[class*=container]{align-items:stretch;flex-direction:column;min-height:100%;padding-left:0;padding-right:0}}@media (min-width:1400px) and (-ms-high-contrast:active),(min-width:1400px) and (-ms-high-contrast:none){.navbar-vertical.navbar-expand-xxl>[class*=container]{height:100%;min-height:none}}@media (min-width:1400px){.navbar-vertical.navbar-expand-xxl.fixed-start{left:0}.navbar-vertical.navbar-expand-xxl.fixed-end{right:0}.navbar-vertical.navbar-expand-xxl .navbar-nav .nav-link{margin:0 1rem;padding-bottom:.675rem;padding-top:.675rem}.navbar-vertical.navbar-expand-xxl .navbar-nav .nav-link .nav-link-text,.navbar-vertical.navbar-expand-xxl .navbar-nav .nav-link .sidenav-mini-icon,.navbar-vertical.navbar-expand-xxl .navbar-nav .nav-link .sidenav-normal,.navbar-vertical.navbar-expand-xxl .navbar-nav .nav-link i{pointer-events:none}.navbar-vertical.navbar-expand-xxl .navbar-nav .nav-item{width:100%}.navbar-vertical.navbar-expand-xxl .navbar-nav>.nav-item{margin-top:.125rem}.navbar-vertical.navbar-expand-xxl .navbar-nav>.nav-item .icon .ni{top:0}.navbar-vertical.navbar-expand-xxl .navbar-nav>.nav-item>.nav-link .icon svg .color-background{fill:#3a416f}.navbar-vertical.navbar-expand-xxl .navbar-nav>.nav-item>.nav-link .icon svg .color-foreground{fill:#141727}.navbar-vertical.navbar-expand-xxl .lavalamp-object{background:theme-color("primary");border-radius:.25rem;color:color-yiq(#cb0c9f);margin-left:.5rem;margin-right:.5rem;padding-left:1rem;padding-right:1rem;width:calc(100% - 1rem)!important}.navbar-vertical.navbar-expand-xxl .navbar-nav .nav .nav-link{padding-bottom:.45rem;padding-left:15px;padding-top:.45rem}.navbar-vertical.navbar-expand-xxl .navbar-nav .nav .nav-link>span.sidenav-normal{transition:all .1s ease 0s}}.sidenav[data-color=primary] .navbar-nav>.nav-item>.nav-link.active .icon{background-image:linear-gradient(310deg,#cb0c9f,#cb0c9f)}.sidenav[data-color=secondary] .navbar-nav>.nav-item>.nav-link.active .icon{background-image:linear-gradient(310deg,#8392ab,#8392ab)}.sidenav[data-color=success] .navbar-nav>.nav-item>.nav-link.active .icon{background-image:linear-gradient(310deg,#82d616,#82d616)}.sidenav[data-color=info] .navbar-nav>.nav-item>.nav-link.active .icon{background-image:linear-gradient(310deg,#17c1e8,#17c1e8)}.sidenav[data-color=warning] .navbar-nav>.nav-item>.nav-link.active .icon{background-image:linear-gradient(310deg,#fbcf33,#fbcf33)}.sidenav[data-color=danger] .navbar-nav>.nav-item>.nav-link.active .icon{background-image:linear-gradient(310deg,#ea0606,#ea0606)}.sidenav[data-color=light] .navbar-nav>.nav-item>.nav-link.active .icon{background-image:linear-gradient(310deg,#e9ecef,#e9ecef)}.sidenav[data-color=dark] .navbar-nav>.nav-item>.nav-link.active .icon{background-image:linear-gradient(310deg,#344767,#344767)}.sidenav[data-color=white] .navbar-nav>.nav-item>.nav-link.active .icon{background-image:linear-gradient(310deg,#fff,#fff)}.main-content,.sidenav{transition:all .2s ease-in-out}.sidenav{z-index:990}.sidenav .navbar-brand,.sidenav .navbar-heading{display:block}@media (min-width:1200px){.sidenav:hover{max-width:15.625rem}.sidenav .sidenav-toggler{padding:1.5rem}.sidenav.fixed-start+.main-content{margin-left:17.125rem}.sidenav.fixed-end+.main-content{margin-right:17.125rem}}.sidenav .navbar-heading .docs-mini{padding-left:3px}.sidenav .navbar-heading{transition:all .1s ease}.sidenav .navbar-brand{padding:1.5rem 2rem}.sidenav-header{height:4.875rem}.sidenav-footer .card.card-background:after{opacity:.65}.g-sidenav-show .sidenav .nav-item .collapse{height:auto;transition:all .2s ease-in-out}@media (prefers-reduced-motion:reduce){.g-sidenav-show .sidenav .nav-item .collapse{transition:none}}.g-sidenav-show .sidenav .nav-link-text{opacity:1;transition:.3s ease}@media (max-width:1199.98px){.g-sidenav-show.rtl .sidenav{transform:translateX(17.125rem)}.g-sidenav-show:not(.rtl) .sidenav{transform:translateX(-17.125rem)}.g-sidenav-show .sidenav.fixed-start+.main-content{margin-left:0!important}.g-sidenav-show.g-sidenav-pinned .sidenav{transform:translateX(0)}}.navbar-vertical.bg-white{box-shadow:0 20px 27px 0 rgba(0,0,0,.05)}.navbar-vertical.bg-white .navbar-nav .nav-link.active{box-shadow:none}.navbar-vertical.bg-white .navbar-nav .nav-link .icon{background-image:linear-gradient(310deg,#e9ecef,#e9ecef)}.navbar-vertical .navbar-nav .nav-link.active{border-radius:.5rem;box-shadow:0 20px 27px 0 rgba(0,0,0,.05);font-weight:600}.navbar-vertical .navbar-nav>.nav-item .nav-link.active{background-color:#fff;color:#344767}.navbar-vertical .navbar-nav>.nav-item .nav-link.active .icon{background-image:linear-gradient(310deg,#cb0c9f,#cb0c9f)}.navbar-vertical .navbar-nav>.nav-item .nav-link.active .icon svg .color-background,.navbar-vertical .navbar-nav>.nav-item .nav-link.active .icon svg .color-foreground{fill:#fff}.navbar-main{transition:box-shadow .25s ease-in,background-color .25s ease-in}.navbar-main.fixed-top{width:calc(100% - 20.125rem)}.navbar-main.fixed-top+[class*=container]{margin-top:7.1875rem!important}.navbar-vertical .navbar-nav .nav-link[data-bs-toggle=collapse]:after{text-rendering:auto;-webkit-font-smoothing:antialiased;color:rgba(58,65,111,.5);content:"\f107";display:inline-block;font-family:Font Awesome\ 5 Free;font-style:normal;font-variant:normal;font-weight:700;margin-left:auto;transition:all .2s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-vertical .navbar-nav .nav-link[data-bs-toggle=collapse]:after{transition:none}}.navbar-vertical .navbar-nav .nav-link[data-bs-toggle=collapse][aria-expanded=true]:after{color:#3a416f;transform:rotate(180deg)}.navbar-vertical .navbar-nav .nav-item .collapse .nav,.navbar-vertical .navbar-nav .nav-item .collapsing .nav{transition:all .2s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-vertical .navbar-nav .nav-item .collapse .nav,.navbar-vertical .navbar-nav .nav-item .collapsing .nav{transition:none}}.navbar-vertical .navbar-nav .nav-item .collapse .nav .nav-item .nav-link,.navbar-vertical .navbar-nav .nav-item .collapsing .nav .nav-item .nav-link{background-color:transparent;box-shadow:none;color:rgba(58,65,111,.5);margin-left:1.35rem;position:relative}.navbar-vertical .navbar-nav .nav-item .collapse .nav .nav-item .nav-link:before,.navbar-vertical .navbar-nav .nav-item .collapsing .nav .nav-item .nav-link:before{background:rgba(58,65,111,.5);border-radius:1.5rem;content:"";height:5px;left:-18px;position:absolute;top:50%;transform:translateY(-50%);width:5px}.navbar-vertical .navbar-nav .nav-item .collapse .nav .nav-item .nav-link.active,.navbar-vertical .navbar-nav .nav-item .collapsing .nav .nav-item .nav-link.active{color:#3a416f}.navbar-vertical .navbar-nav .nav-item .collapse .nav .nav-item .nav-link.active:before,.navbar-vertical .navbar-nav .nav-item .collapsing .nav .nav-item .nav-link.active:before{background:#3a416f;height:8px;width:8px}.navbar-vertical .navbar-nav .nav-item .collapse .nav .nav-item.active .nav-link,.navbar-vertical .navbar-nav .nav-item .collapsing .nav .nav-item.active .nav-link{color:#3a416f}.navbar-vertical .navbar-nav .nav-item .collapse .nav .nav-item.active .nav-link:before,.navbar-vertical .navbar-nav .nav-item .collapsing .nav .nav-item.active .nav-link:before{background:#3a416f;height:8px;width:8px}.navbar-vertical .navbar-nav .nav-item .collapse .nav .nav-item .nav-item .nav-link:before,.navbar-vertical .navbar-nav .nav-item .collapsing .nav .nav-item .nav-item .nav-link:before{content:none}.navbar-vertical.blur .navbar-nav>.nav-item .nav-link{background-color:transparent;box-shadow:none}.navbar-vertical .navbar-brand .navbar-brand-img,.navbar-vertical .navbar-brand span{transition:all .2s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-vertical .navbar-brand .navbar-brand-img,.navbar-vertical .navbar-brand span{transition:none}}.navbar-vertical .nav-item .nav-link span.sidenav-mini-icon{text-align:center;transition:all .2s ease-in-out;width:0}@media (prefers-reduced-motion:reduce){.navbar-vertical .nav-item .nav-link span.sidenav-mini-icon{transition:none}}.navbar-vertical .docs-info{transition:all .2s ease-in-out}@media (prefers-reduced-motion:reduce){.navbar-vertical .docs-info{transition:none}}.g-sidenav-show:not(.g-sidenav-hidden) .navbar-vertical .nav-item .nav-link span.sidenav-mini-icon{opacity:0}@media (min-width:1200px){.navbar-vertical .navbar-nav .nav-item .nav-link .icon{padding:10px}.g-sidenav-hidden.rtl .main-content{margin-right:6rem!important}.g-sidenav-hidden.rtl .main-content .navbar-vertical:hover{max-width:15.625rem!important}.g-sidenav-hidden.rtl .sidenav:hover+.main-content{margin-right:17.125rem!important}.g-sidenav-hidden .navbar-vertical{max-width:6rem!important}.g-sidenav-hidden .navbar-vertical.fixed-start+.main-content{margin-left:7.5rem}.g-sidenav-hidden .navbar-vertical .navbar-brand img{width:auto!important}.g-sidenav-hidden .navbar-vertical .navbar-brand span{opacity:0}.g-sidenav-hidden .navbar-vertical .nav-item .nav-link .icon{padding:10px}.g-sidenav-hidden .navbar-vertical .nav-item .nav-link .nav-link-text,.g-sidenav-hidden .navbar-vertical .nav-item .nav-link .sidenav-normal{opacity:0;width:0}.g-sidenav-hidden .navbar-vertical .nav-item .nav-link .sidenav-mini-icon{margin-left:.15rem;min-width:1.8rem;opacity:1}.g-sidenav-hidden .navbar-vertical .nav-item .nav-link[data-bs-toggle=collapse]:after{content:""}.g-sidenav-hidden .navbar-vertical .nav-item .collapse .nav{margin-left:0!important;padding-left:0!important}.g-sidenav-hidden .navbar-vertical .nav-item .collapse .nav .nav-item .nav-link{margin-left:1rem}.g-sidenav-hidden .navbar-vertical .nav-item .collapse .nav .nav-item .nav-link:before{content:none}.g-sidenav-hidden .navbar-vertical .nav-item .collapse .nav .nav-item .nav-link[data-bs-toggle=collapse]:after{content:"\f107"}.g-sidenav-hidden .navbar-vertical .card.card-background .icon-shape{margin-bottom:0!important}.g-sidenav-hidden .navbar-vertical .card.card-background .docs-info{height:0;opacity:0;width:0}.g-sidenav-hidden .navbar-vertical:hover{max-width:15.625rem!important}.g-sidenav-hidden .navbar-vertical:hover.fixed-start+.main-content{margin-left:17.125rem}.g-sidenav-hidden .navbar-vertical:hover .navbar-brand span{opacity:1}.g-sidenav-hidden .navbar-vertical:hover .nav-item .nav-link .nav-link-text,.g-sidenav-hidden .navbar-vertical:hover .nav-item .nav-link .sidenav-normal{opacity:1;width:auto}.g-sidenav-hidden .navbar-vertical:hover .nav-item .nav-link .sidenav-mini-icon{min-width:0;opacity:0;width:0}.g-sidenav-hidden .navbar-vertical:hover .nav-item .nav-link[data-bs-toggle=collapse]:after{content:"\f107"}.g-sidenav-hidden .navbar-vertical:hover .nav-item .collapse .nav{margin-left:1.5rem!important;padding-left:1rem!important}.g-sidenav-hidden .navbar-vertical:hover .nav-item .collapse .nav .nav-item .nav-link{margin-left:1.35rem}.g-sidenav-hidden .navbar-vertical:hover .nav-item .collapse .nav .nav-item .nav-link:before{content:""}.g-sidenav-hidden .navbar-vertical:hover .nav-item .collapse .nav .nav-item .collapse .nav,.g-sidenav-hidden .navbar-vertical:hover .nav-item .collapse .nav .nav-item .collapsing .nav{margin-left:0!important;padding-left:0!important}.g-sidenav-hidden .navbar-vertical:hover .nav-item .collapse .nav .nav-item .collapse .nav .nav-item .nav-link:before,.g-sidenav-hidden .navbar-vertical:hover .nav-item .collapse .nav .nav-item .collapsing .nav .nav-item .nav-link:before{content:none}.g-sidenav-hidden .navbar-vertical:hover .card.card-background .icon-shape{margin-bottom:1rem!important}.g-sidenav-hidden .navbar-vertical:hover .card.card-background .docs-info{height:auto;opacity:1;width:auto}}.nav.nav-pills{background:#f8f9fa;border-radius:.75rem;position:relative}.nav.nav-pills.nav-pills-vertical{border-radius:1.1875rem}.nav.nav-pills.nav-pills-vertical .nav-link.active{border-radius:.875rem}.nav.nav-pills .nav-link{background-color:inherit;border-radius:.5rem;color:#344767;z-index:3}.nav.nav-pills .nav-link.active{-webkit-animation:.2s ease;animation:.2s ease}.nav.nav-pills .nav-link:hover:not(.active){color:#344767}.nav.nav-pills.nav-pills-primary{background:#fff;color:#fff}.nav.nav-pills.nav-pills-primary .nav-link.active{color:#fff}.nav.nav-pills.nav-pills-primary .moving-tab .nav-link.active{background:#7928ca;color:#7928ca}.nav.nav-pills.nav-pills-info{background:#fff;color:#fff}.nav.nav-pills.nav-pills-info .nav-link.active{color:#fff}.nav.nav-pills.nav-pills-info .moving-tab .nav-link.active{background:#2152ff;color:#2152ff}.nav.nav-pills.nav-pills-success{background:#fff;color:#fff}.nav.nav-pills.nav-pills-success .nav-link.active{color:#fff}.nav.nav-pills.nav-pills-success .moving-tab .nav-link.active{background:#17ad37;color:#17ad37}.nav.nav-pills.nav-pills-warning{background:#fff;color:#fff}.nav.nav-pills.nav-pills-warning .nav-link.active{color:#fff}.nav.nav-pills.nav-pills-warning .moving-tab .nav-link.active{background:#f53939;color:#f53939}.nav.nav-pills.nav-pills-danger{background:#fff;color:#fff}.nav.nav-pills.nav-pills-danger .nav-link.active{color:#fff}.nav.nav-pills.nav-pills-danger .moving-tab .nav-link.active{background:#ea0606;color:#ea0606}.nav.nav-pills .nav-item{z-index:3}.moving-tab{z-index:1!important}.moving-tab .nav-link{border-radius:.5rem;color:#fff;transition:.2s ease}.moving-tab .nav-link.active{-webkit-animation:.2s ease;animation:.2s ease;background:#fff;box-shadow:0 1px 5px 1px #ddd;color:#fff;font-weight:600}.moving-tab .nav-link:hover:not(.active){color:#344767}.page-item.active .page-link{box-shadow:0 3px 5px -1px rgba(0,0,0,.09),0 2px 3px -1px rgba(0,0,0,.07)}.page-item .page-link,.page-item span{align-items:center;border-radius:50%!important;color:#8392ab;display:flex;font-size:.875rem;height:36px;justify-content:center;margin:0 3px;padding:0;width:36px}.pagination-lg .page-item .page-link,.pagination-lg .page-item span{height:46px;line-height:46px;width:46px}.pagination-sm .page-item .page-link,.pagination-sm .page-item span{height:30px;line-height:30px;width:30px}.pagination.pagination-primary .page-item.active>.page-link,.pagination.pagination-primary .page-item.active>.page-link:focus,.pagination.pagination-primary .page-item.active>.page-link:hover{background-image:linear-gradient(310deg,#7928ca,#ff0080);border:none}.pagination.pagination-secondary .page-item.active>.page-link,.pagination.pagination-secondary .page-item.active>.page-link:focus,.pagination.pagination-secondary .page-item.active>.page-link:hover{background-image:linear-gradient(310deg,#627594,#a8b8d8);border:none}.pagination.pagination-success .page-item.active>.page-link,.pagination.pagination-success .page-item.active>.page-link:focus,.pagination.pagination-success .page-item.active>.page-link:hover{background-image:linear-gradient(310deg,#17ad37,#98ec2d);border:none}.pagination.pagination-info .page-item.active>.page-link,.pagination.pagination-info .page-item.active>.page-link:focus,.pagination.pagination-info .page-item.active>.page-link:hover{background-image:linear-gradient(310deg,#2152ff,#21d4fd);border:none}.pagination.pagination-warning .page-item.active>.page-link,.pagination.pagination-warning .page-item.active>.page-link:focus,.pagination.pagination-warning .page-item.active>.page-link:hover{background-image:linear-gradient(310deg,#f53939,#fbcf33);border:none}.pagination.pagination-danger .page-item.active>.page-link,.pagination.pagination-danger .page-item.active>.page-link:focus,.pagination.pagination-danger .page-item.active>.page-link:hover{background-image:linear-gradient(310deg,#ea0606,#ff667c);border:none}.pagination.pagination-light .page-item.active>.page-link,.pagination.pagination-light .page-item.active>.page-link:focus,.pagination.pagination-light .page-item.active>.page-link:hover{background-image:linear-gradient(310deg,#ced4da,#ebeff4);border:none}.pagination.pagination-dark .page-item.active>.page-link,.pagination.pagination-dark .page-item.active>.page-link:focus,.pagination.pagination-dark .page-item.active>.page-link:hover{background-image:linear-gradient(310deg,#141727,#3a416f);border:none}.popover{box-shadow:0 .3125rem .625rem 0 rgba(0,0,0,.12)}.popover .popover-header{font-weight:600}.progress-bar{border-radius:.25rem;height:6px;margin-top:-2px}.progress{overflow:visible}.progress.progress-sm{height:4px}.progress.progress-lg{height:20px}.rtl .breadcrumb .breadcrumb-item+.breadcrumb-item:before{float:right;padding-left:.5rem;padding-right:0}.rtl .sidenav .navbar-nav{padding-right:0;width:100%}.rtl .fixed-plugin .fixed-plugin-button{left:30px;right:auto}.rtl .fixed-plugin .card{left:-360px!important;right:auto}.rtl .fixed-plugin.show .card{left:0!important;right:auto}.rtl .timeline .timeline-content{margin-left:0;margin-right:45px}.rtl .timeline .timeline-step{transform:translateX(50%)}.rtl .timeline.timeline-one-side .timeline-step,.rtl .timeline.timeline-one-side:before{right:1rem}.rtl .form-check.form-switch .form-check-input:after{transform:translateX(-1px)}.rtl .form-check.form-switch .form-check-input:checked:after{transform:translateX(-21px)}.rtl .avatar-group .avatar+.avatar{margin-left:0;margin-right:-1rem}.rtl .dropdown .dropdown-menu{left:0}.rtl .input-group .input-group-text{border-bottom-left-radius:0;border-left:0;border-right:1px solid #d2d6da;border-top-left-radius:0}.rtl .input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){border-bottom-left-radius:.5rem;border-bottom-right-radius:0;border-left:1px solid #d2d6da;border-right:0;border-top-left-radius:.5rem;border-top-right-radius:0;margin-right:-1px}.rtl .input-group:not(.has-validation)>.dropdown-toggle:nth-last-child(n+3),.rtl .input-group:not(.has-validation)>:not(:last-child):not(.dropdown-toggle):not(.dropdown-menu){border-bottom-right-radius:.5rem;border-top-right-radius:.5rem}.btn.btn-facebook{background-color:#3b5998;color:#fff}.btn.btn-facebook:focus,.btn.btn-facebook:hover{background-color:#344e86;color:#fff}.btn.btn-facebook:active,.btn.btn-facebook:active:focus,.btn.btn-facebook:focus{box-shadow:none}.btn.btn-facebook.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#344e86}.btn.btn-facebook.btn-simple:active,.btn.btn-facebook.btn-simple:focus,.btn.btn-facebook.btn-simple:hover,.btn.btn-facebook.btn-simple:hover:focus,.btn.btn-facebook.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#344e86}.btn.btn-facebook.btn-neutral{background-color:#fff;color:#3b5998}.btn.btn-facebook.btn-neutral:active,.btn.btn-facebook.btn-neutral:focus,.btn.btn-facebook.btn-neutral:hover{color:#344e86}.btn.btn-twitter{background-color:#55acee;color:#fff}.btn.btn-twitter:focus,.btn.btn-twitter:hover{background-color:#3ea1ec;color:#fff}.btn.btn-twitter:active,.btn.btn-twitter:active:focus,.btn.btn-twitter:focus{box-shadow:none}.btn.btn-twitter.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#3ea1ec}.btn.btn-twitter.btn-simple:active,.btn.btn-twitter.btn-simple:focus,.btn.btn-twitter.btn-simple:hover,.btn.btn-twitter.btn-simple:hover:focus,.btn.btn-twitter.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#3ea1ec}.btn.btn-twitter.btn-neutral{background-color:#fff;color:#55acee}.btn.btn-twitter.btn-neutral:active,.btn.btn-twitter.btn-neutral:focus,.btn.btn-twitter.btn-neutral:hover{color:#3ea1ec}.btn.btn-pinterest{background-color:#cc2127;color:#fff}.btn.btn-pinterest:focus,.btn.btn-pinterest:hover{background-color:#b21d22;color:#fff}.btn.btn-pinterest:active,.btn.btn-pinterest:active:focus,.btn.btn-pinterest:focus{box-shadow:none}.btn.btn-pinterest.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#b21d22}.btn.btn-pinterest.btn-simple:active,.btn.btn-pinterest.btn-simple:focus,.btn.btn-pinterest.btn-simple:hover,.btn.btn-pinterest.btn-simple:hover:focus,.btn.btn-pinterest.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#b21d22}.btn.btn-pinterest.btn-neutral{background-color:#fff;color:#cc2127}.btn.btn-pinterest.btn-neutral:active,.btn.btn-pinterest.btn-neutral:focus,.btn.btn-pinterest.btn-neutral:hover{color:#b21d22}.btn.btn-linkedin{background-color:#0077b5;color:#fff}.btn.btn-linkedin:focus,.btn.btn-linkedin:hover{background-color:#00669c;color:#fff}.btn.btn-linkedin:active,.btn.btn-linkedin:active:focus,.btn.btn-linkedin:focus{box-shadow:none}.btn.btn-linkedin.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#00669c}.btn.btn-linkedin.btn-simple:active,.btn.btn-linkedin.btn-simple:focus,.btn.btn-linkedin.btn-simple:hover,.btn.btn-linkedin.btn-simple:hover:focus,.btn.btn-linkedin.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#00669c}.btn.btn-linkedin.btn-neutral{background-color:#fff;color:#0077b5}.btn.btn-linkedin.btn-neutral:active,.btn.btn-linkedin.btn-neutral:focus,.btn.btn-linkedin.btn-neutral:hover{color:#00669c}.btn.btn-dribbble{background-color:#ea4c89;color:#fff}.btn.btn-dribbble:focus,.btn.btn-dribbble:hover{background-color:#e73177;color:#fff}.btn.btn-dribbble:active,.btn.btn-dribbble:active:focus,.btn.btn-dribbble:focus{box-shadow:none}.btn.btn-dribbble.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#e73177}.btn.btn-dribbble.btn-simple:active,.btn.btn-dribbble.btn-simple:focus,.btn.btn-dribbble.btn-simple:hover,.btn.btn-dribbble.btn-simple:hover:focus,.btn.btn-dribbble.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#e73177}.btn.btn-dribbble.btn-neutral{background-color:#fff;color:#ea4c89}.btn.btn-dribbble.btn-neutral:active,.btn.btn-dribbble.btn-neutral:focus,.btn.btn-dribbble.btn-neutral:hover{color:#e73177}.btn.btn-github{background-color:#24292e;color:#fff}.btn.btn-github:focus,.btn.btn-github:hover{background-color:#171a1d;color:#fff}.btn.btn-github:active,.btn.btn-github:active:focus,.btn.btn-github:focus{box-shadow:none}.btn.btn-github.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#171a1d}.btn.btn-github.btn-simple:active,.btn.btn-github.btn-simple:focus,.btn.btn-github.btn-simple:hover,.btn.btn-github.btn-simple:hover:focus,.btn.btn-github.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#171a1d}.btn.btn-github.btn-neutral{background-color:#fff;color:#24292e}.btn.btn-github.btn-neutral:active,.btn.btn-github.btn-neutral:focus,.btn.btn-github.btn-neutral:hover{color:#171a1d}.btn.btn-youtube{background-color:#e52d27;color:#fff}.btn.btn-youtube:focus,.btn.btn-youtube:hover{background-color:#d41f1a;color:#fff}.btn.btn-youtube:active,.btn.btn-youtube:active:focus,.btn.btn-youtube:focus{box-shadow:none}.btn.btn-youtube.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#d41f1a}.btn.btn-youtube.btn-simple:active,.btn.btn-youtube.btn-simple:focus,.btn.btn-youtube.btn-simple:hover,.btn.btn-youtube.btn-simple:hover:focus,.btn.btn-youtube.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#d41f1a}.btn.btn-youtube.btn-neutral{background-color:#fff;color:#e52d27}.btn.btn-youtube.btn-neutral:active,.btn.btn-youtube.btn-neutral:focus,.btn.btn-youtube.btn-neutral:hover{color:#d41f1a}.btn.btn-instagram{background-color:#125688;color:#fff}.btn.btn-instagram:focus,.btn.btn-instagram:hover{background-color:#0e456d;color:#fff}.btn.btn-instagram:active,.btn.btn-instagram:active:focus,.btn.btn-instagram:focus{box-shadow:none}.btn.btn-instagram.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#0e456d}.btn.btn-instagram.btn-simple:active,.btn.btn-instagram.btn-simple:focus,.btn.btn-instagram.btn-simple:hover,.btn.btn-instagram.btn-simple:hover:focus,.btn.btn-instagram.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#0e456d}.btn.btn-instagram.btn-neutral{background-color:#fff;color:#125688}.btn.btn-instagram.btn-neutral:active,.btn.btn-instagram.btn-neutral:focus,.btn.btn-instagram.btn-neutral:hover{color:#0e456d}.btn.btn-reddit{background-color:#ff4500;color:#fff}.btn.btn-reddit:focus,.btn.btn-reddit:hover{background-color:#e03d00;color:#fff}.btn.btn-reddit:active,.btn.btn-reddit:active:focus,.btn.btn-reddit:focus{box-shadow:none}.btn.btn-reddit.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#e03d00}.btn.btn-reddit.btn-simple:active,.btn.btn-reddit.btn-simple:focus,.btn.btn-reddit.btn-simple:hover,.btn.btn-reddit.btn-simple:hover:focus,.btn.btn-reddit.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#e03d00}.btn.btn-reddit.btn-neutral{background-color:#fff;color:#ff4500}.btn.btn-reddit.btn-neutral:active,.btn.btn-reddit.btn-neutral:focus,.btn.btn-reddit.btn-neutral:hover{color:#e03d00}.btn.btn-tumblr{background-color:#35465c;color:#fff}.btn.btn-tumblr:focus,.btn.btn-tumblr:hover{background-color:#2a3749;color:#fff}.btn.btn-tumblr:active,.btn.btn-tumblr:active:focus,.btn.btn-tumblr:focus{box-shadow:none}.btn.btn-tumblr.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#2a3749}.btn.btn-tumblr.btn-simple:active,.btn.btn-tumblr.btn-simple:focus,.btn.btn-tumblr.btn-simple:hover,.btn.btn-tumblr.btn-simple:hover:focus,.btn.btn-tumblr.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#2a3749}.btn.btn-tumblr.btn-neutral{background-color:#fff;color:#35465c}.btn.btn-tumblr.btn-neutral:active,.btn.btn-tumblr.btn-neutral:focus,.btn.btn-tumblr.btn-neutral:hover{color:#2a3749}.btn.btn-behance{background-color:#1769ff;color:#fff}.btn.btn-behance:focus,.btn.btn-behance:hover{background-color:#0057f7;color:#fff}.btn.btn-behance:active,.btn.btn-behance:active:focus,.btn.btn-behance:focus{box-shadow:none}.btn.btn-behance.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#0057f7}.btn.btn-behance.btn-simple:active,.btn.btn-behance.btn-simple:focus,.btn.btn-behance.btn-simple:hover,.btn.btn-behance.btn-simple:hover:focus,.btn.btn-behance.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#0057f7}.btn.btn-behance.btn-neutral{background-color:#fff;color:#1769ff}.btn.btn-behance.btn-neutral:active,.btn.btn-behance.btn-neutral:focus,.btn.btn-behance.btn-neutral:hover{color:#0057f7}.btn.btn-vimeo{background-color:#1ab7ea;color:#fff}.btn.btn-vimeo:focus,.btn.btn-vimeo:hover{background-color:#13a3d2;color:#fff}.btn.btn-vimeo:active,.btn.btn-vimeo:active:focus,.btn.btn-vimeo:focus{box-shadow:none}.btn.btn-vimeo.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#13a3d2}.btn.btn-vimeo.btn-simple:active,.btn.btn-vimeo.btn-simple:focus,.btn.btn-vimeo.btn-simple:hover,.btn.btn-vimeo.btn-simple:hover:focus,.btn.btn-vimeo.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#13a3d2}.btn.btn-vimeo.btn-neutral{background-color:#fff;color:#1ab7ea}.btn.btn-vimeo.btn-neutral:active,.btn.btn-vimeo.btn-neutral:focus,.btn.btn-vimeo.btn-neutral:hover{color:#13a3d2}.btn.btn-slack{background-color:#3aaf85;color:#fff}.btn.btn-slack:focus,.btn.btn-slack:hover{background-color:#329874;color:#fff}.btn.btn-slack:active,.btn.btn-slack:active:focus,.btn.btn-slack:focus{box-shadow:none}.btn.btn-slack.btn-simple{background-color:transparent;background-image:none!important;border:none;box-shadow:none;color:#329874}.btn.btn-slack.btn-simple:active,.btn.btn-slack.btn-simple:focus,.btn.btn-slack.btn-simple:hover,.btn.btn-slack.btn-simple:hover:focus,.btn.btn-slack.btn-simple:hover:focus:active{background:transparent!important;box-shadow:none!important;color:#329874}.btn.btn-slack.btn-neutral{background-color:#fff;color:#3aaf85}.btn.btn-slack.btn-neutral:active,.btn.btn-slack.btn-neutral:focus,.btn.btn-slack.btn-neutral:hover{color:#329874}.table thead th{border-bottom:1px solid #e9ecef;letter-spacing:0;padding:.75rem 1.5rem;text-transform:capitalize}.table th{font-weight:600}.table td .progress{height:3px;margin:0;width:120px}.table td,.table th{white-space:nowrap}.table.align-items-center td,.table.align-items-center th{vertical-align:middle}.table tbody tr:last-child td{border-width:0}.table>:not(:last-child)>:last-child>*{border-bottom-color:#e9ecef}.timeline{position:relative}.timeline:before{border-right:2px solid #dee2e6;content:"";height:100%;left:1rem;position:absolute;top:0}.timeline-block{position:relative}.timeline-block:after{clear:both;content:"";display:table}.timeline-block:first-child{margin-top:0}.timeline-block:last-child{margin-bottom:0}.timeline-step{align-items:center;background:#fff;border-radius:50%;display:inline-flex;font-size:1rem;font-weight:600;height:26px;justify-content:center;left:0;position:absolute;text-align:center;transform:translateX(-50%);width:26px;z-index:1}.timeline-step i,.timeline-step svg{line-height:1.4}.timeline-content{margin-left:45px;padding-top:.35rem;position:relative;top:-6px}.timeline-content:after{clear:both;content:"";display:table}@media (min-width:992px){.timeline:before{left:50%;margin-left:-1px}.timeline-step{left:50%}.timeline-content{width:38%}.timeline-block:nth-child(2n) .timeline-content{float:right}}.timeline-one-side .timeline-step,.timeline-one-side:before{left:1rem}.timeline-one-side .timeline-content{width:auto}@media (min-width:992px){.timeline-one-side .timeline-content{max-width:30rem}}.timeline-one-side .timeline-block:nth-child(2n) .timeline-content{float:none}.tilt{transform-style:preserve-3d}.tilt .up{transform:translateZ(50px) scale(.7)!important;transition:all .5s}.bs-tooltip-auto[x-placement^=right] .tooltip-arrow,.bs-tooltip-right .tooltip-arrow{left:1px}.bs-tooltip-auto[x-placement^=left] .tooltip-arrow,.bs-tooltip-left .tooltip-arrow{right:1px}html *{-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{font-weight:400;line-height:1.6}.h1,h1{font-size:3rem;letter-spacing:-.025rem;line-height:1.25}@media (max-width:575.98px){.h1,h1{font-size:calc(1.425rem + 2.1vw)}}.h2,h2{font-size:2.25rem;letter-spacing:.05rem;line-height:1.3}@media (max-width:575.98px){.h2,h2{font-size:calc(1.35rem + 1.2vw)}}.h3,h3{font-size:1.875rem;line-height:1.375}@media (max-width:575.98px){.h3,h3{font-size:calc(1.3125rem + .75vw)}}.h4,h4{font-size:1.5rem;line-height:1.375}@media (max-width:575.98px){.h4,h4{font-size:calc(1.275rem + .3vw)}}.h5,h5{font-size:1.25rem;line-height:1.375}@media (max-width:575.98px){.h5,h5{font-size:1.25rem}}.h6,h6{font-size:1rem;line-height:1.625}.p,p{line-height:1.6}.lead,.p,p{font-weight:400}.lead{line-height:1.625}.h1,.h2,.h3,h1,h2,h3{font-weight:700}.h4,.h5,.h6,h4,h5,h6{font-weight:600}.h1,.h2,.h3,.h4,h1,h2,h3,h4{letter-spacing:-.05rem}a{color:#344767;letter-spacing:-.025rem}.text-sm{line-height:1.5}.text-xs{line-height:1.25}.p,p{font-size:1rem}.lead{font-size:1.25rem}.text-lg{font-size:1.125rem!important}.text-sm{font-size:.875rem!important}.text-xs{font-size:.75rem!important}.text-xxs{font-size:.65rem!important}p{font-weight:400;line-height:1.625}.text-sans-serif{font-family:Open Sans!important}.text-monospace{font-family:SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace!important}.text-justify{text-align:justify!important}.text-wrap{white-space:normal!important}.text-nowrap{white-space:nowrap!important}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.font-weight-light{font-weight:300!important}.font-weight-lighter{font-weight:lighter!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:600!important}.font-weight-bolder{font-weight:700!important}.font-italic{font-style:italic!important}.text-gradient{-webkit-text-fill-color:transparent;background-clip:text;-webkit-background-clip:text;position:relative;z-index:1}.text-gradient.text-primary{background-image:linear-gradient(310deg,#7928ca,#ff0080)}.text-gradient.text-info{background-image:linear-gradient(310deg,#2152ff,#21d4fd)}.text-gradient.text-success{background-image:linear-gradient(310deg,#17ad37,#c1e823)}.text-gradient.text-warning{background-image:linear-gradient(310deg,#f53939,#fbcf33)}.text-gradient.text-danger{background-image:linear-gradient(310deg,#d60808,#ff6690)}.text-gradient.text-dark{background-image:linear-gradient(310deg,#141727,#3a416f)}.blockquote{border-left:3px solid #6c757d}.blockquote>span{font-style:italic}.text-muted{color:#67748e!important}.text-black-50{color:rgba(0,0,0,.5)!important}.text-white-50{color:hsla(0,0%,100%,.5)!important}.text-decoration-none{text-decoration:none!important}.text-break{word-wrap:break-word!important}.text-reset{color:inherit!important}.letter-wider{letter-spacing:.05rem}.letter-normal{letter-spacing:0}.letter-tighter{letter-spacing:-.05rem}.text-lighter{font-weight:lighter}.text-light{font-weight:300}.text-normal{font-weight:400}.text-bold{font-weight:600}.text-bolder{font-weight:700}.flatpickr-calendar{-webkit-animation:none;animation:none;background:transparent;background:#fff;border:0;border-radius:5px;-webkit-box-shadow:0 8px 26px -4px hsla(0,0%,8%,.15),0 8px 9px -5px hsla(0,0%,8%,.06);box-sizing:border-box;direction:ltr;display:none;font-size:14px;line-height:24px;opacity:0;padding:0;position:absolute;text-align:center;touch-action:manipulation;visibility:hidden;width:307.875px}.flatpickr-calendar.inline,.flatpickr-calendar.open{max-height:640px;opacity:1;visibility:visible}.flatpickr-calendar.open{display:inline-block;z-index:99999}.flatpickr-calendar.animate.open{-webkit-animation:fpFadeInDown .3s cubic-bezier(.23,1,.32,1);animation:fpFadeInDown .3s cubic-bezier(.23,1,.32,1)}.flatpickr-calendar.inline{display:block;position:relative;top:2px}.flatpickr-calendar.static{position:absolute;top:calc(100% + 2px)}.flatpickr-calendar.static.open{display:block;z-index:999}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+1) .flatpickr-day.inRange:nth-child(7n+7){box-shadow:none!important}.flatpickr-calendar.multiMonth .flatpickr-days .dayContainer:nth-child(n+2) .flatpickr-day.inRange:nth-child(7n+1){box-shadow:-2px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-calendar .hasTime .dayContainer,.flatpickr-calendar .hasWeeks .dayContainer{border-bottom:0;border-bottom-left-radius:0;border-bottom-right-radius:0}.flatpickr-calendar .hasWeeks .dayContainer{border-left:0}.flatpickr-calendar.hasTime .flatpickr-time{border-top:1px solid #e6e6e6;height:40px}.flatpickr-calendar.noCalendar.hasTime .flatpickr-time{height:auto}.flatpickr-calendar:after,.flatpickr-calendar:before{border:solid transparent;content:"";display:block;height:0;left:22px;pointer-events:none;position:absolute;width:0}.flatpickr-calendar.arrowRight:after,.flatpickr-calendar.arrowRight:before,.flatpickr-calendar.rightMost:after,.flatpickr-calendar.rightMost:before{left:auto;right:22px}.flatpickr-calendar.arrowCenter:after,.flatpickr-calendar.arrowCenter:before{left:50%;right:50%}.flatpickr-calendar:before{border-width:5px;margin:0 -5px}.flatpickr-calendar:after{border-width:4px;margin:0 -4px}.flatpickr-calendar.arrowTop:after,.flatpickr-calendar.arrowTop:before{bottom:100%}.flatpickr-calendar.arrowTop:after,.flatpickr-calendar.arrowTop:before{border-bottom-color:#fff}.flatpickr-calendar.arrowBottom:after,.flatpickr-calendar.arrowBottom:before{top:100%}.flatpickr-calendar.arrowBottom:before{border-top-color:#e6e6e6}.flatpickr-calendar.arrowBottom:after{border-top-color:#fff}.flatpickr-calendar:focus{outline:0}.flatpickr-wrapper{display:inline-block;position:relative}.flatpickr-months{display:flex}.flatpickr-months .flatpickr-month{fill:rgba(0,0,0,.9);background:transparent;color:rgba(0,0,0,.9);flex:1;height:34px;line-height:1;overflow:hidden;position:relative;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.flatpickr-months .flatpickr-next-month,.flatpickr-months .flatpickr-prev-month{fill:rgba(0,0,0,.9);color:rgba(0,0,0,.9);cursor:pointer;height:34px;padding:10px;position:absolute;text-decoration:none;top:0;z-index:3}.flatpickr-months .flatpickr-next-month.flatpickr-disabled,.flatpickr-months .flatpickr-prev-month.flatpickr-disabled{display:none}.flatpickr-months .flatpickr-next-month i,.flatpickr-months .flatpickr-prev-month i{position:relative}.flatpickr-months .flatpickr-next-month.flatpickr-prev-month,.flatpickr-months .flatpickr-prev-month.flatpickr-prev-month{left:0}.flatpickr-months .flatpickr-next-month.flatpickr-next-month,.flatpickr-months .flatpickr-prev-month.flatpickr-next-month{right:0}.flatpickr-months .flatpickr-next-month:hover,.flatpickr-months .flatpickr-prev-month:hover{color:#959ea9}.flatpickr-months .flatpickr-next-month:hover svg,.flatpickr-months .flatpickr-prev-month:hover svg{fill:#f64747}.flatpickr-months .flatpickr-next-month svg,.flatpickr-months .flatpickr-prev-month svg{height:14px;width:14px}.flatpickr-months .flatpickr-next-month svg path,.flatpickr-months .flatpickr-prev-month svg path{fill:inherit;transition:fill .1s}.numInputWrapper{height:auto;position:relative}.numInputWrapper input,.numInputWrapper span{display:inline-block}.numInputWrapper input{width:100%}.numInputWrapper input::-ms-clear{display:none}.numInputWrapper input::-webkit-inner-spin-button,.numInputWrapper input::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.numInputWrapper span{border:1px solid rgba(57,57,57,.15);box-sizing:border-box;cursor:pointer;height:50%;line-height:50%;opacity:0;padding:0 4px 0 2px;position:absolute;right:0;width:14px}.numInputWrapper span:hover{background:rgba(0,0,0,.1)}.numInputWrapper span:active{background:rgba(0,0,0,.2)}.numInputWrapper span:after{content:"";display:block;position:absolute}.numInputWrapper span.arrowUp{border-bottom:0;top:0}.numInputWrapper span.arrowUp:after{border-bottom:4px solid rgba(57,57,57,.6);border-left:4px solid transparent;border-right:4px solid transparent;top:26%}.numInputWrapper span.arrowDown{top:50%}.numInputWrapper span.arrowDown:after{border-left:4px solid transparent;border-right:4px solid transparent;border-top:4px solid rgba(57,57,57,.6);top:40%}.numInputWrapper span svg{height:auto;width:inherit}.numInputWrapper span svg path{fill:rgba(0,0,0,.5)}.numInputWrapper:hover{background:rgba(0,0,0,.05)}.numInputWrapper:hover span{opacity:1}.flatpickr-current-month{color:inherit;display:inline-block;font-size:135%;font-weight:300;height:34px;left:12.5%;line-height:inherit;line-height:1;padding:7.48px 0 0;position:absolute;text-align:center;transform:translateZ(0);width:75%}.flatpickr-current-month span.cur-month{color:inherit;display:inline-block;font-family:inherit;font-weight:700;margin-left:.5ch;padding:0}.flatpickr-current-month span.cur-month:hover{background:rgba(0,0,0,.05)}.flatpickr-current-month .numInputWrapper{display:inline-block;width:6ch;width:7ch\0}.flatpickr-current-month .numInputWrapper span.arrowUp:after{border-bottom-color:rgba(0,0,0,.9)}.flatpickr-current-month .numInputWrapper span.arrowDown:after{border-top-color:rgba(0,0,0,.9)}.flatpickr-current-month input.cur-year{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;background:transparent;border:0;border-radius:0;box-sizing:border-box;color:inherit;cursor:text;display:inline-block;font-family:inherit;font-size:inherit;font-weight:300;height:auto;line-height:inherit;margin:0;padding:0 0 0 .5ch;vertical-align:initial}.flatpickr-current-month input.cur-year:focus{outline:0}.flatpickr-current-month input.cur-year[disabled],.flatpickr-current-month input.cur-year[disabled]:hover{background:transparent;color:rgba(0,0,0,.5);font-size:100%;pointer-events:none}.flatpickr-current-month .flatpickr-monthDropdown-months{appearance:menulist;-webkit-appearance:menulist;-moz-appearance:menulist;background:transparent;border:none;border-radius:0;box-sizing:border-box;-webkit-box-sizing:border-box;color:inherit;cursor:pointer;font-family:inherit;font-size:inherit;font-weight:300;height:auto;line-height:inherit;margin:-1px 0 0;outline:none;padding:0 0 0 .5ch;position:relative;vertical-align:initial;width:auto}.flatpickr-current-month .flatpickr-monthDropdown-months:active,.flatpickr-current-month .flatpickr-monthDropdown-months:focus{outline:none}.flatpickr-current-month .flatpickr-monthDropdown-months:hover{background:rgba(0,0,0,.05)}.flatpickr-current-month .flatpickr-monthDropdown-months .flatpickr-monthDropdown-month{background-color:transparent;outline:none;padding:0}.flatpickr-weekdays{align-items:center;background:transparent;display:flex;height:28px;overflow:hidden;text-align:center;width:100%}.flatpickr-weekdays .flatpickr-weekdaycontainer{display:flex;flex:1}span.flatpickr-weekday{background:transparent;color:rgba(0,0,0,.54);cursor:default;display:block;flex:1;font-size:90%;font-weight:bolder;line-height:1;margin:0;text-align:center}.dayContainer,.flatpickr-weeks{padding:1px 0 0}.flatpickr-days{align-items:flex-start;display:flex;overflow:hidden;position:relative;width:307.875px}.flatpickr-days:focus{outline:0}.dayContainer{box-sizing:border-box;display:inline-block;display:flex;flex-wrap:wrap;-ms-flex-wrap:wrap;justify-content:space-around;max-width:307.875px;min-width:307.875px;opacity:1;outline:0;padding:0;text-align:left;transform:translateZ(0);width:307.875px}.dayContainer+.dayContainer{box-shadow:-1px 0 0 #e6e6e6}.flatpickr-day{background:none;border:1px solid transparent;border-radius:150px;box-sizing:border-box;color:#393939;cursor:pointer;display:inline-block;flex-basis:14.2857143%;font-weight:400;height:39px;justify-content:center;line-height:39px;margin:0;max-width:39px;position:relative;text-align:center;width:14.2857143%}.flatpickr-day.inRange,.flatpickr-day.nextMonthDay.inRange,.flatpickr-day.nextMonthDay.today.inRange,.flatpickr-day.nextMonthDay:focus,.flatpickr-day.nextMonthDay:hover,.flatpickr-day.prevMonthDay.inRange,.flatpickr-day.prevMonthDay.today.inRange,.flatpickr-day.prevMonthDay:focus,.flatpickr-day.prevMonthDay:hover,.flatpickr-day.today.inRange,.flatpickr-day:focus,.flatpickr-day:hover{background:#e6e6e6;border-color:#e6e6e6;cursor:pointer;outline:0}.flatpickr-day.today{border-color:#959ea9}.flatpickr-day.today:focus,.flatpickr-day.today:hover{background:#959ea9;border-color:#959ea9;color:#fff}.flatpickr-day.endRange,.flatpickr-day.endRange.inRange,.flatpickr-day.endRange.nextMonthDay,.flatpickr-day.endRange.prevMonthDay,.flatpickr-day.endRange:focus,.flatpickr-day.endRange:hover,.flatpickr-day.selected,.flatpickr-day.selected.inRange,.flatpickr-day.selected.nextMonthDay,.flatpickr-day.selected.prevMonthDay,.flatpickr-day.selected:focus,.flatpickr-day.selected:hover,.flatpickr-day.startRange,.flatpickr-day.startRange.inRange,.flatpickr-day.startRange.nextMonthDay,.flatpickr-day.startRange.prevMonthDay,.flatpickr-day.startRange:focus,.flatpickr-day.startRange:hover{background:#569ff7;border-color:#569ff7;box-shadow:none;color:#fff}.flatpickr-day.endRange.startRange,.flatpickr-day.selected.startRange,.flatpickr-day.startRange.startRange{border-radius:50px 0 0 50px}.flatpickr-day.endRange.endRange,.flatpickr-day.selected.endRange,.flatpickr-day.startRange.endRange{border-radius:0 50px 50px 0}.flatpickr-day.endRange.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.selected.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange+.endRange:not(:nth-child(7n+1)){box-shadow:-10px 0 0 #569ff7}.flatpickr-day.endRange.startRange.endRange,.flatpickr-day.selected.startRange.endRange,.flatpickr-day.startRange.startRange.endRange{border-radius:50px}.flatpickr-day.inRange{border-radius:0;box-shadow:-5px 0 0 #e6e6e6,5px 0 0 #e6e6e6}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover,.flatpickr-day.nextMonthDay,.flatpickr-day.notAllowed,.flatpickr-day.notAllowed.nextMonthDay,.flatpickr-day.notAllowed.prevMonthDay,.flatpickr-day.prevMonthDay{background:transparent;border-color:transparent;color:rgba(57,57,57,.3);cursor:default}.flatpickr-day.flatpickr-disabled,.flatpickr-day.flatpickr-disabled:hover{color:rgba(57,57,57,.1);cursor:not-allowed}.flatpickr-day.week.selected{border-radius:0;box-shadow:-5px 0 0 #569ff7,5px 0 0 #569ff7}.flatpickr-day.hidden{visibility:hidden}.rangeMode .flatpickr-day{margin-top:1px}.flatpickr-weekwrapper{float:left}.flatpickr-weekwrapper .flatpickr-weeks{box-shadow:1px 0 0 #e6e6e6;padding:0 12px}.flatpickr-weekwrapper .flatpickr-weekday{float:none;line-height:28px;width:100%}.flatpickr-weekwrapper span.flatpickr-day,.flatpickr-weekwrapper span.flatpickr-day:hover{background:transparent;border:none;color:rgba(57,57,57,.3);cursor:default;display:block;max-width:none;width:100%}.flatpickr-innerContainer{box-sizing:border-box;display:block;display:flex;overflow:hidden}.flatpickr-rContainer{box-sizing:border-box;display:inline-block;padding:0}.flatpickr-time{box-sizing:border-box;display:block;display:flex;height:0;line-height:40px;max-height:40px;outline:0;overflow:hidden;text-align:center}.flatpickr-time:after{clear:both;content:"";display:table}.flatpickr-time .numInputWrapper{flex:1;float:left;height:40px;width:40%}.flatpickr-time .numInputWrapper span.arrowUp:after{border-bottom-color:#393939}.flatpickr-time .numInputWrapper span.arrowDown:after{border-top-color:#393939}.flatpickr-time.hasSeconds .numInputWrapper{width:26%}.flatpickr-time.time24hr .numInputWrapper{width:49%}.flatpickr-time input{-webkit-appearance:textfield;-moz-appearance:textfield;appearance:textfield;background:transparent;border:0;border-radius:0;box-shadow:none;box-sizing:border-box;color:#393939;font-size:14px;height:inherit;line-height:inherit;margin:0;padding:0;position:relative;text-align:center}.flatpickr-time input.flatpickr-hour{font-weight:700}.flatpickr-time input.flatpickr-minute,.flatpickr-time input.flatpickr-second{font-weight:400}.flatpickr-time input:focus{border:0;outline:0}.flatpickr-time .flatpickr-am-pm,.flatpickr-time .flatpickr-time-separator{align-self:center;color:#393939;float:left;font-weight:700;height:inherit;line-height:inherit;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;width:2%}.flatpickr-time .flatpickr-am-pm{cursor:pointer;font-weight:400;outline:0;text-align:center;width:18%}.flatpickr-time .flatpickr-am-pm:focus,.flatpickr-time .flatpickr-am-pm:hover,.flatpickr-time input:focus,.flatpickr-time input:hover{background:#eee}.flatpickr-input[readonly]{cursor:pointer}@-webkit-keyframes fpFadeInDown{0%{opacity:0;transform:translate3d(0,-20px,0)}to{opacity:1;transform:translateZ(0)}}@keyframes fpFadeInDown{0%{opacity:0;transform:translate3d(0,-20px,0)}to{opacity:1;transform:translateZ(0)}}.datepicker.flatpickr-input{background-color:#fff}.flatpickr-calendar.open{margin-left:-38px;margin-top:4px}.flatpickr-calendar.arrowBottom{margin-top:-20px}.flatpickr-calendar .flatpickr-innerContainer{margin-top:15px!important}.flatpickr-calendar .numInputWrapper span{border:none;border-bottom:1px solid rgba(57,57,57,.15)}.flatpickr-calendar .numInputWrapper:hover .arrowDown,.flatpickr-calendar .numInputWrapper:hover .arrowUp{margin-top:3px}.flatpickr-calendar .flatpickr-day.endRange,.flatpickr-calendar .flatpickr-day.selected,.flatpickr-calendar .flatpickr-day.startRange,.flatpickr-calendar .flatpickr-day.today{background:#cb0c9f!important;border:none;color:#fff}.flatpickr-calendar .flatpickr-day.inRange{box-shadow:-5px 0 0 #d7dcf8,5px 0 0 #d7dcf8}.flatpickr-calendar .flatpickr-day.inRange,.flatpickr-calendar .flatpickr-day:not(.selected):focus,.flatpickr-calendar .flatpickr-day:not(.selected):hover{background:rgba(94,114,228,.28);border:none}.flatpickr-calendar .flatpickr-time .flatpickr-am-pm:focus,.flatpickr-calendar .flatpickr-time .flatpickr-am-pm:hover,.flatpickr-calendar .flatpickr-time input:focus,.flatpickr-calendar .flatpickr-time input:hover{background:rgba(94,114,228,.28)}.flatpickr.form-control{background:#fff}.flatpickr-day.endRange.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.selected.startRange+.endRange:not(:nth-child(7n+1)),.flatpickr-day.startRange.startRange+.endRange:not(:nth-child(7n+1)){box-shadow:-10px 0 0 #cb0c9f} + +/*! nouislider - 14.6.3 - 11/19/2020 */.noUi-target,.noUi-target *{-webkit-touch-callout:none;-webkit-tap-highlight-color:rgba(0,0,0,0);box-sizing:border-box;touch-action:none;-webkit-user-select:none;-ms-user-select:none;-moz-user-select:none;user-select:none}.noUi-target{position:relative}.noUi-base,.noUi-connects{height:6px;position:relative;top:-1px;width:100%;z-index:1}.noUi-connects{overflow:hidden;z-index:0}.noUi-connect,.noUi-origin{position:absolute;right:0;top:0;-ms-transform-origin:0 0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform-style:preserve-3d;transform-style:flat;will-change:transform;z-index:1}.noUi-connect{border-radius:.25rem;height:100%;width:100%}.noUi-origin{height:10%;width:10%}.noUi-txt-dir-rtl.noUi-horizontal .noUi-origin{left:0;right:auto}.noUi-vertical .noUi-origin{width:0}.noUi-horizontal .noUi-origin{height:0}.noUi-handle{-webkit-backface-visibility:hidden;backface-visibility:hidden;position:absolute}.noUi-touch-area{height:100%;width:100%}.noUi-state-tap .noUi-connect,.noUi-state-tap .noUi-origin{transition:transform .3s}.noUi-state-drag *{cursor:inherit!important}.noUi-horizontal{height:3px}.noUi-horizontal .noUi-handle{background-color:#fff;border-radius:50%;box-shadow:0 1px 13px 0 rgba(0,0,0,.2);cursor:pointer;height:15px;margin-top:-6px;outline:none;right:-10px;width:15px}.noUi-vertical{width:3px}.noUi-vertical .noUi-handle{height:34px;right:-6px;top:-17px;width:28px}.noUi-txt-dir-rtl.noUi-horizontal .noUi-handle{left:-17px;right:auto}.noUi-target{background:#e9ecef;border-radius:.25rem}.noUi-connects{border-radius:3px}.noUi-connect{background-image:linear-gradient(310deg,#7928ca,#ff0080)}.noUi-draggable{cursor:ew-resize}.noUi-vertical .noUi-draggable{cursor:ns-resize}.noUi-handle{webkit-transition:.3s ease 0s;background:#fff;border:1px solid #d9d9d9;border-radius:3px;box-shadow:inset 0 0 1px #fff,inset 0 1px 7px #ebebeb,0 3px 6px -3px #bbb;cursor:default;-o-transform:.3s ease 0s;-moz-transition:.3s ease 0s;-ms-transition:.3s ease 0s;transition:.3s ease 0s}.noUi-active{box-shadow:inset 0 0 1px #fff,inset 0 1px 7px #ddd,0 3px 6px -3px #bbb;transform:scale3d(1.5,1.5,1)}[disabled] .noUi-connect{background:#b8b8b8}[disabled] .noUi-handle,[disabled].noUi-handle,[disabled].noUi-target{cursor:not-allowed}.noUi-pips,.noUi-pips *{box-sizing:border-box}.noUi-pips{color:#999;position:absolute}.noUi-value{position:absolute;text-align:center;white-space:nowrap}.noUi-value-sub{color:#ccc;font-size:10px}.noUi-marker{background:#ccc;position:absolute}.noUi-marker-large,.noUi-marker-sub{background:#aaa}.noUi-pips-horizontal{height:80px;left:0;padding:10px 0;top:100%;width:100%}.noUi-value-horizontal{transform:translate(-50%,50%)}.noUi-rtl .noUi-value-horizontal{transform:translate(50%,50%)}.noUi-marker-horizontal.noUi-marker{height:5px;margin-left:-1px;width:2px}.noUi-marker-horizontal.noUi-marker-sub{height:10px}.noUi-marker-horizontal.noUi-marker-large{height:15px}.noUi-pips-vertical{height:100%;left:100%;padding:0 10px;top:0}.noUi-value-vertical{padding-left:25px;transform:translateY(-50%)}.noUi-rtl .noUi-value-vertical{transform:translateY(50%)}.noUi-marker-vertical.noUi-marker{height:2px;margin-top:-1px;width:5px}.noUi-marker-vertical.noUi-marker-sub{width:10px}.noUi-marker-vertical.noUi-marker-large{width:15px}.noUi-tooltip{background:#fff;border:1px solid #d9d9d9;border-radius:3px;color:#000;display:block;padding:5px;position:absolute;text-align:center;white-space:nowrap}.noUi-horizontal .noUi-tooltip{bottom:120%;left:50%;transform:translate(-50%)}.noUi-vertical .noUi-tooltip{right:120%;top:50%;transform:translateY(-50%)}.noUi-horizontal .noUi-origin>.noUi-tooltip{bottom:10px;left:auto;transform:translate(50%)}.noUi-vertical .noUi-origin>.noUi-tooltip{right:28px;top:auto;transform:translateY(-18px)}code[class*=language-],pre[class*=language-]{word-wrap:normal;background:none;color:#000;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;text-align:left;text-shadow:0 1px #fff;white-space:pre;word-break:normal;word-spacing:normal}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{background:#b3d4fc;text-shadow:none}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{background:#b3d4fc;text-shadow:none}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{border-radius:.75rem;overflow:auto;padding:1em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f8f9fa}:not(pre)>code[class*=language-]{border-radius:.3em;padding:.1em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{background:hsla(0,0%,100%,.5);color:#9a6e3a}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.ps{-ms-overflow-style:none;overflow:hidden!important;overflow-anchor:none;touch-action:auto;-ms-touch-action:auto}.ps__rail-x{bottom:0;height:15px}.ps__rail-x,.ps__rail-y{display:none;opacity:0;position:absolute;transition:background-color .2s linear,opacity .2s linear;-webkit-transition:background-color .2s linear,opacity .2s linear}.ps__rail-y{right:0;width:15px}.ps--active-x>.ps__rail-x,.ps--active-y>.ps__rail-y{background-color:transparent;display:block}.ps--focus>.ps__rail-x,.ps--focus>.ps__rail-y,.ps--scrolling-x>.ps__rail-x,.ps--scrolling-y>.ps__rail-y,.ps:hover>.ps__rail-x,.ps:hover>.ps__rail-y{opacity:.6}.ps .ps__rail-x.ps--clicking,.ps .ps__rail-x:focus,.ps .ps__rail-x:hover,.ps .ps__rail-y.ps--clicking,.ps .ps__rail-y:focus,.ps .ps__rail-y:hover{background-color:#eee;opacity:.9}.ps__thumb-x{bottom:2px;height:6px;transition:background-color .2s linear,height .2s ease-in-out;-webkit-transition:background-color .2s linear,height .2s ease-in-out}.ps__thumb-x,.ps__thumb-y{background-color:#aaa;border-radius:6px;position:absolute}.ps__thumb-y{right:2px;transition:background-color .2s linear,width .2s ease-in-out;-webkit-transition:background-color .2s linear,width .2s ease-in-out;width:6px}.ps__rail-x.ps--clicking .ps__thumb-x,.ps__rail-x:focus>.ps__thumb-x,.ps__rail-x:hover>.ps__thumb-x{background-color:#999;height:11px}.ps__rail-y.ps--clicking .ps__thumb-y,.ps__rail-y:focus>.ps__thumb-y,.ps__rail-y:hover>.ps__thumb-y{background-color:#999;width:11px}@supports (-ms-overflow-style:none){.ps{overflow:auto!important}}@media (-ms-high-contrast:none),screen and (-ms-high-contrast:active){.ps{overflow:auto!important}} diff --git a/website/public/assets/css/soft-ui-dashboard.css.map b/website/public/assets/css/soft-ui-dashboard.css.map new file mode 100644 index 0000000..fbf7ed5 --- /dev/null +++ b/website/public/assets/css/soft-ui-dashboard.css.map @@ -0,0 +1,432 @@ +{ + "version": 3, + "file": "dashboard-pro.css", + "sources": [ + "../scss/dashboard-pro.scss", + "../scss/bootstrap/_functions.scss", + "../scss/custom/_variables.scss", + "../scss//_variables.scss", + "../scss//variables/_animations.scss", + "../scss//variables/_avatars.scss", + "../scss//variables/_cards.scss", + "../scss//variables/_dropdowns.scss", + "../scss//variables/_header.scss", + "../scss//variables/_info-areas.scss", + "../scss//variables/_navbar.scss", + "../scss//variables/_navbar-vertical.scss", + "../scss//variables/_utilities.scss", + "../scss//variables/_utilities-extend.scss", + "../scss//variables/_misc.scss", + "../scss//variables/_misc-extend.scss", + "../scss//variables/_form-switch.scss", + "../scss//variables/_fixed-plugin.scss", + "../scss//variables/_pagination.scss", + "../scss//variables/_badge.scss", + "../scss//variables/_rtl.scss", + "../scss//variables/_cards-extend.scss", + "../scss//variables/_choices.scss", + "../scss//variables/_timeline.scss", + "../scss//variables/_full-calendar.scss", + "../scss//variables/_social-buttons.scss", + "../scss//variables/_virtual-reality.scss", + "../scss//_utilities.scss", + "../scss/bootstrap/_functions.scss", + "../scss/bootstrap/_variables.scss", + "../scss/bootstrap/_utilities.scss", + "../scss/bootstrap/bootstrap.scss", + "../scss/bootstrap/_functions.scss", + "../scss/bootstrap/_variables.scss", + "../scss/bootstrap/_mixins.scss", + "../scss/bootstrap/vendor/_rfs.scss", + "../scss/bootstrap/mixins/_deprecate.scss", + "../scss/bootstrap/mixins/_breakpoints.scss", + "../scss/bootstrap/mixins/_color-scheme.scss", + "../scss/bootstrap/mixins/_image.scss", + "../scss/bootstrap/mixins/_resize.scss", + "../scss/bootstrap/mixins/_visually-hidden.scss", + "../scss/bootstrap/mixins/_reset-text.scss", + "../scss/bootstrap/mixins/_text-truncate.scss", + "../scss/bootstrap/mixins/_utilities.scss", + "../scss/bootstrap/mixins/_alert.scss", + "../scss/bootstrap/mixins/_backdrop.scss", + "../scss/bootstrap/mixins/_buttons.scss", + "../scss/bootstrap/mixins/_caret.scss", + "../scss/bootstrap/mixins/_pagination.scss", + "../scss/bootstrap/mixins/_lists.scss", + "../scss/bootstrap/mixins/_list-group.scss", + "../scss/bootstrap/mixins/_forms.scss", + "../scss/bootstrap/mixins/_table-variants.scss", + "../scss/bootstrap/mixins/_border-radius.scss", + "../scss/bootstrap/mixins/_box-shadow.scss", + "../scss/bootstrap/mixins/_gradients.scss", + "../scss/bootstrap/mixins/_transition.scss", + "../scss/bootstrap/mixins/_clearfix.scss", + "../scss/bootstrap/mixins/_container.scss", + "../scss/bootstrap/mixins/_grid.scss", + "../scss/bootstrap/_utilities.scss", + "../scss/bootstrap/_root.scss", + "../scss/bootstrap/_reboot.scss", + "../scss/bootstrap/_type.scss", + "../scss/bootstrap/_images.scss", + "../scss/bootstrap/_containers.scss", + "../scss/bootstrap/_grid.scss", + "../scss/bootstrap/_tables.scss", + "../scss/bootstrap/_forms.scss", + "../scss/bootstrap/forms/_labels.scss", + "../scss/bootstrap/forms/_form-text.scss", + "../scss/bootstrap/forms/_form-control.scss", + "../scss/bootstrap/forms/_form-select.scss", + "../scss/bootstrap/forms/_form-check.scss", + "../scss/bootstrap/forms/_form-range.scss", + "../scss/bootstrap/forms/_floating-labels.scss", + "../scss/bootstrap/forms/_input-group.scss", + "../scss/bootstrap/forms/_validation.scss", + "../scss/bootstrap/_buttons.scss", + "../scss/bootstrap/_transitions.scss", + "../scss/bootstrap/_dropdown.scss", + "../scss/bootstrap/_button-group.scss", + "../scss/bootstrap/_nav.scss", + "../scss/bootstrap/_navbar.scss", + "../scss/bootstrap/_card.scss", + "../scss/bootstrap/_accordion.scss", + "../scss/bootstrap/_breadcrumb.scss", + "../scss/bootstrap/_pagination.scss", + "../scss/bootstrap/_badge.scss", + "../scss/bootstrap/_alert.scss", + "../scss/bootstrap/_progress.scss", + "../scss/bootstrap/_list-group.scss", + "../scss/bootstrap/_close.scss", + "../scss/bootstrap/_toasts.scss", + "../scss/bootstrap/_modal.scss", + "../scss/bootstrap/_tooltip.scss", + "../scss/bootstrap/_popover.scss", + "../scss/bootstrap/_carousel.scss", + "../scss/bootstrap/_spinners.scss", + "../scss/bootstrap/_offcanvas.scss", + "../scss/bootstrap/_placeholders.scss", + "../scss/bootstrap/_helpers.scss", + "../scss/bootstrap/helpers/_clearfix.scss", + "../scss/bootstrap/helpers/_colored-links.scss", + "../scss/bootstrap/helpers/_ratio.scss", + "../scss/bootstrap/helpers/_position.scss", + "../scss/bootstrap/helpers/_stacks.scss", + "../scss/bootstrap/helpers/_visually-hidden.scss", + "../scss/bootstrap/helpers/_stretched-link.scss", + "../scss/bootstrap/helpers/_text-truncation.scss", + "../scss/bootstrap/helpers/_vr.scss", + "../scss/bootstrap/utilities/_api.scss", + "../scss//theme-pro.scss", + "../scss//theme.scss", + "../scss//variables/_navbar-vertical.scss", + "../scss//variables/_social-buttons.scss", + "../scss//variables/_breadcrumb.scss", + "../scss//mixins/mixins.scss", + "../scss//mixins/_badge.scss", + "../scss//mixins/_hover.scss", + "../scss//mixins/_colored-shadows.scss", + "../scss//mixins/_social-buttons.scss", + "../scss//_alert.scss", + "../scss//_avatars.scss", + "../scss//_badge.scss", + "../scss//_buttons.scss", + "../scss//_breadcrumbs.scss", + "../scss//_cards.scss", + "../scss//cards/card-background.scss", + "../scss//_dropdown.scss", + "../scss//_dropup.scss", + "../scss//_header.scss", + "../scss//_fixed-plugin.scss", + "../scss//forms/_forms.scss", + "../scss//forms/_input-group.scss", + "../scss//forms/_form-check.scss", + "../scss//forms/_form-switch.scss", + "../scss//forms/_form-select.scss", + "../scss//forms/_labels.scss", + "../scss//forms/_inputs.scss", + "../scss//_footer.scss", + "../scss//_gradients.scss", + "../scss//_info-areas.scss", + "../scss//_misc.scss", + "../scss//_navbar.scss", + "../scss//_navbar-vertical.scss", + "../scss//_nav.scss", + "../scss//_pagination.scss", + "../scss//_popovers.scss", + "../scss//_progress.scss", + "../scss//_rtl.scss", + "../scss//_social-buttons.scss", + "../scss//_tables.scss", + "../scss//_timeline.scss", + "../scss//_tilt.scss", + "../scss//_tooltips.scss", + "../scss//_typography.scss", + "../scss//plugins/free/plugins.scss", + "../scss//plugins/free/_flatpickr.scss", + "../scss//plugins/free/_nouislider.scss", + "../scss//plugins/free/_prism.scss", + "../scss//plugins/free/_perfect-scrollbar.scss", + "../scss//mixins/mixins.scss", + "../scss//mixins/_badge.scss", + "../scss//mixins/_hover.scss", + "../scss//mixins/_colored-shadows.scss", + "../scss//mixins/_social-buttons.scss", + "../scss//_accordion.scss", + "../scss//_backgrounds.scss", + "../scss//_cards-extend.scss", + "../scss//cards/card-blog.scss", + "../scss//cards/card-horizontal.scss", + "../scss//cards/card-profile.scss", + "../scss//cards/card-pricing.scss", + "../scss//_components.scss", + "../scss//badges/_badge.scss", + "../scss//badges/_badge-circle.scss", + "../scss//badges/_badge-dot.scss", + "../scss//badges/_badge-floating.scss", + "../scss//_dropdown-extend.scss", + "../scss//_floating-elements.scss", + "../scss//_list-check.scss", + "../scss//_misc-extend.scss", + "../scss//_rtl-extend.scss", + "../scss//plugins/pro/plugins-extend.scss", + "../scss//plugins/free/plugins.scss", + "../scss//plugins/free/_flatpickr.scss", + "../scss//plugins/free/_nouislider.scss", + "../scss//plugins/free/_prism.scss", + "../scss//plugins/free/_perfect-scrollbar.scss", + "../scss//plugins/pro/_choices.scss", + "../scss//plugins/pro/_glidejs.scss", + "../scss//plugins/pro/_fullcalendar.scss", + "../scss//plugins/pro/_fullcalendar-extend.scss", + "../scss//plugins/pro/_datatable.scss", + "../scss//plugins/pro/_datatable-extend.scss", + "../scss//plugins/pro/_dragula.scss", + "../scss//plugins/pro/_kanban.scss", + "../scss//plugins/pro/_sweetalert2.scss", + "../scss//plugins/pro/_sweetalert2-extend.scss", + "../scss//plugins/pro/_dropzone.scss", + "../scss//plugins/pro/_highlight.scss", + "../scss//plugins/pro/_quill.scss", + "../scss//plugins/pro/_choices.scss", + "../scss//plugins/pro/_list-check.scss", + "../scss//plugins/pro/_photoswipe.scss", + "../scss//plugins/pro/_rating-widget.scss", + "../scss//plugins/pro/_leaflet.scss", + "../scss//plugins/pro/multi-step.scss", + "../scss/custom/_styles.scss" + ], + "sourcesContent": [ + "// =========================================================\n// * Soft UI Dashboard Pro - v1.0.4\n// =========================================================\n//\n// * Product Page: https://www.creative-tim.com/product/soft-ui-dashboard-pro\n// * Copyright 2021 Creative Tim (https://www.creative-tim.com)\n//\n// Coded by www.creative-tim.com\n//\n// =========================================================\n//\n// * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.\n\n// Bootstrap Functions\n@import \"bootstrap/functions\";\n\n// Custom Variables\n@import \"custom/variables\";\n\n// Theme Variables\n@import \"/variables\";\n\n// Bootstrap Core\n@import \"bootstrap/bootstrap\";\n\n// Theme Core\n@import \"/theme-pro\";\n\n// Custom Variables\n@import \"custom/styles\";\n", + "// Bootstrap functions\n//\n// Utility mixins and functions for evaluating source code across our variables, maps, and mixins.\n\n// Ascending\n// Used to evaluate Sass maps like our grid breakpoints.\n@mixin _assert-ascending($map, $map-name) {\n $prev-key: null;\n $prev-num: null;\n @each $key, $num in $map {\n @if $prev-num == null or unit($num) == \"%\" or unit($prev-num) == \"%\" {\n // Do nothing\n } @else if not comparable($prev-num, $num) {\n @warn \"Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !\";\n } @else if $prev-num >= $num {\n @warn \"Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !\";\n }\n $prev-key: $key;\n $prev-num: $num;\n }\n}\n\n// Starts at zero\n// Used to ensure the min-width of the lowest breakpoint starts at 0.\n@mixin _assert-starts-at-zero($map, $map-name: \"$grid-breakpoints\") {\n @if length($map) > 0 {\n $values: map-values($map);\n $first-value: nth($values, 1);\n @if $first-value != 0 {\n @warn \"First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}.\";\n }\n }\n}\n\n// Colors\n@function to-rgb($value) {\n @return red($value), green($value), blue($value);\n}\n\n@function rgba-css-var($identifier, $target) {\n @return rgba(var(--#{$variable-prefix}#{$identifier}-rgb), var(--#{$variable-prefix}#{$target}-opacity));\n}\n\n// stylelint-disable scss/dollar-variable-pattern\n@function map-loop($map, $func, $args...) {\n $_map: ();\n\n @each $key, $value in $map {\n // allow to pass the $key and $value of the map as an function argument\n $_args: ();\n @each $arg in $args {\n $_args: append($_args, if($arg == \"$key\", $key, if($arg == \"$value\", $value, $arg)));\n }\n\n $_map: map-merge($_map, ($key: call(get-function($func), $_args...)));\n }\n\n @return $_map;\n}\n// stylelint-enable scss/dollar-variable-pattern\n\n@function varify($list) {\n $result: null;\n @each $entry in $list {\n $result: append($result, var(--#{$variable-prefix}#{$entry}), space);\n }\n @return $result;\n}\n\n// Internal Bootstrap function to turn maps into its negative variant.\n// It prefixes the keys with `n` and makes the value negative.\n@function negativify-map($map) {\n $result: ();\n @each $key, $value in $map {\n @if $key != 0 {\n $result: map-merge($result, (\"n\" + $key: (-$value)));\n }\n }\n @return $result;\n}\n\n// Get multiple keys from a sass map\n@function map-get-multiple($map, $values) {\n $result: ();\n @each $key, $value in $map {\n @if (index($values, $key) != null) {\n $result: map-merge($result, ($key: $value));\n }\n }\n @return $result;\n}\n\n// Merge multiple maps\n@function map-merge-multiple($maps...) {\n $merged-maps: ();\n\n @each $map in $maps {\n $merged-maps: map-merge($merged-maps, $map);\n }\n @return $merged-maps;\n}\n\n// Replace `$search` with `$replace` in `$string`\n// Used on our SVG icon backgrounds for custom forms.\n//\n// @author Hugo Giraudel\n// @param {String} $string - Initial string\n// @param {String} $search - Substring to replace\n// @param {String} $replace ('') - New value\n// @return {String} - Updated string\n@function str-replace($string, $search, $replace: \"\") {\n $index: str-index($string, $search);\n\n @if $index {\n @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);\n }\n\n @return $string;\n}\n\n// See https://codepen.io/kevinweber/pen/dXWoRw\n//\n// Requires the use of quotes around data URIs.\n\n@function escape-svg($string) {\n @if str-index($string, \"data:image/svg+xml\") {\n @each $char, $encoded in $escaped-characters {\n // Do not escape the url brackets\n @if str-index($string, \"url(\") == 1 {\n $string: url(\"#{str-replace(str-slice($string, 6, -3), $char, $encoded)}\");\n } @else {\n $string: str-replace($string, $char, $encoded);\n }\n }\n }\n\n @return $string;\n}\n\n// Color contrast\n// See https://github.com/twbs/bootstrap/pull/30168\n\n// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255)\n// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern\n$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1;\n\n@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) {\n $foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black;\n $max-ratio: 0;\n $max-ratio-color: null;\n\n @each $color in $foregrounds {\n $contrast-ratio: contrast-ratio($background, $color);\n @if $contrast-ratio > $min-contrast-ratio {\n @return $color;\n } @else if $contrast-ratio > $max-ratio {\n $max-ratio: $contrast-ratio;\n $max-ratio-color: $color;\n }\n }\n\n @warn \"Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}...\";\n\n @return $max-ratio-color;\n}\n\n@function contrast-ratio($background, $foreground: $color-contrast-light) {\n $l1: luminance($background);\n $l2: luminance(opaque($background, $foreground));\n\n @return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05));\n}\n\n// Return WCAG2.0 relative luminance\n// See https://www.w3.org/WAI/GL/wiki/Relative_luminance\n// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests\n@function luminance($color) {\n $rgb: (\n \"r\": red($color),\n \"g\": green($color),\n \"b\": blue($color)\n );\n\n @each $name, $value in $rgb {\n $value: if(divide($value, 255) < .03928, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));\n $rgb: map-merge($rgb, ($name: $value));\n }\n\n @return (map-get($rgb, \"r\") * .2126) + (map-get($rgb, \"g\") * .7152) + (map-get($rgb, \"b\") * .0722);\n}\n\n// Return opaque color\n// opaque(#fff, rgba(0, 0, 0, .5)) => #808080\n@function opaque($background, $foreground) {\n @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100);\n}\n\n// scss-docs-start color-functions\n// Tint a color: mix a color with white\n@function tint-color($color, $weight) {\n @return mix(white, $color, $weight);\n}\n\n// Shade a color: mix a color with black\n@function shade-color($color, $weight) {\n @return mix(black, $color, $weight);\n}\n\n// Shade the color if the weight is positive, else tint it\n@function shift-color($color, $weight) {\n @return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight));\n}\n// scss-docs-end color-functions\n\n// Return valid calc\n@function add($value1, $value2, $return-calc: true) {\n @if $value1 == null {\n @return $value2;\n }\n\n @if $value2 == null {\n @return $value1;\n }\n\n @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {\n @return $value1 + $value2;\n }\n\n @return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(\" + \") + $value2);\n}\n\n@function subtract($value1, $value2, $return-calc: true) {\n @if $value1 == null and $value2 == null {\n @return null;\n }\n\n @if $value1 == null {\n @return -$value2;\n }\n\n @if $value2 == null {\n @return $value1;\n }\n\n @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {\n @return $value1 - $value2;\n }\n\n @if type-of($value2) != number {\n $value2: unquote(\"(\") + $value2 + unquote(\")\");\n }\n\n @return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(\" - \") + $value2);\n}\n\n@function divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n $remainder: $dividend;\n $result: 0;\n $factor: 10;\n @while ($remainder > 0 and $precision >= 0) {\n $quotient: 0;\n @while ($remainder >= $divisor) {\n $remainder: $remainder - $divisor;\n $quotient: $quotient + 1;\n }\n $result: $result * 10 + $quotient;\n $factor: $factor * .1;\n $remainder: $remainder * 10;\n $precision: $precision - 1;\n @if ($precision < 0 and $remainder >= $divisor * 5) {\n $result: $result + 1;\n }\n }\n $result: $result * $factor * $sign;\n $dividend-unit: unit($dividend);\n $divisor-unit: unit($divisor);\n $unit-map: (\n \"px\": 1px,\n \"rem\": 1rem,\n \"em\": 1em,\n \"%\": 1%\n );\n @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {\n $result: $result * map-get($unit-map, $dividend-unit);\n }\n @return $result;\n}\n", + "", + "// Variables\n//\n// Variables should follow the `$component-state-property-size` formula for\n// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.\n\n// $soft-background-color: #fbfbfb !default;\n$soft-background-color: #ffffff !default; // Testing\n$font-color: #67748e !default;\n$h-color: #344767 !default;\n\n// Color system\n\n$white: #fff !default;\n$gray-100: #f8f9fa !default;\n$gray-200: #e9ecef !default;\n$gray-300: #dee2e6 !default;\n$gray-400: #ced4da !default;\n$gray-500: #adb5bd !default;\n$gray-600: #6c757d !default;\n$gray-700: #495057 !default;\n$gray-800: #343a40 !default;\n$gray-900: #212529 !default;\n$black: #000 !default;\n\n// fusv-enable\n\n$blue: #63B3ED !default;\n$indigo: #596CFF !default;\n$purple: #6f42c1 !default;\n$pink: #d63384 !default;\n$red: #F56565 !default;\n$orange: #fd7e14 !default;\n$yellow: #FBD38D !default;\n$green: #81E6D9 !default;\n$teal: #20c997 !default;\n$cyan: #0dcaf0 !default;\n\n// scss-docs-start colors-map\n$colors: (\n \"blue\": $blue,\n \"indigo\": $indigo,\n \"purple\": $purple,\n \"pink\": $pink,\n \"red\": $red,\n \"orange\": $orange,\n \"yellow\": $yellow,\n \"green\": $green,\n \"teal\": $teal,\n \"cyan\": $cyan,\n \"white\": $white,\n \"gray\": $gray-600,\n \"gray-dark\": $gray-800,\n) !default;\n// scss-docs-end colors-map\n\n$primary: #cb0c9f !default;\n$secondary: #8392AB !default;\n$info: #17c1e8 !default;\n$success: #82d616 !default;\n$warning: #fbcf33 !default;\n$danger: #ea0606 !default;\n$light: $gray-200 !default;\n$dark: $h-color !default;\n\n// scss-docs-start theme-colors-map\n$theme-colors: (\n \"primary\": $primary,\n \"secondary\": $secondary,\n \"success\": $success,\n \"info\": $info,\n \"warning\": $warning,\n \"danger\": $danger,\n \"light\": $light,\n \"dark\": $dark,\n \"white\": $white\n) !default;\n// scss-docs-end theme-colors-map\n\n\n// Gradient colors\n$primary-gradient: #7928CA !default;\n$primary-gradient-state: #FF0080 !default;\n\n$secondary-gradient: #627594 !default;\n$secondary-gradient-state: #A8B8D8 !default;\n\n$info-gradient: #2152ff !default;\n$info-gradient-state: #21d4fd !default;\n\n$success-gradient: #17ad37 !default;\n$success-gradient-state: #98ec2d !default;\n\n$danger-gradient: #ea0606 !default;\n$danger-gradient-state: #ff667c !default;\n\n$warning-gradient: #f53939 !default;\n$warning-gradient-state: #fbcf33 !default;\n\n$dark-gradient: #141727 !default;\n$dark-gradient-state: #3A416F !default;\n\n$light-gradient: #CED4DA !default;\n$light-gradient-state: #EBEFF4 !default;\n\n// Gradient Colors map\n$theme-gradient-colors: (\n \"primary\": ($primary-gradient, $primary-gradient-state),\n \"secondary\": ($secondary-gradient, $secondary-gradient-state),\n \"success\": ($success-gradient, $success-gradient-state),\n \"info\": ($info-gradient, $info-gradient-state),\n \"warning\": ($warning-gradient, $warning-gradient-state),\n \"danger\": ($danger-gradient, $danger-gradient-state),\n \"light\": ($light-gradient, $light-gradient-state),\n \"dark\": ($dark-gradient, $dark-gradient-state)\n) !default;\n\n// Set a specific jump point for requesting color jumps\n$theme-color-interval: 8% !default;\n\n// The contrast ratio to reach against white, to determine if color changes from \"light\" to \"dark\". Acceptable values for WCAG 2.0 are 3, 4.5 and 7.\n// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast\n$min-contrast-ratio: 4.5 !default;\n\n// Customize the light and dark text colors for use in our color contrast function.\n$color-contrast-dark: $black !default;\n$color-contrast-light: $white !default;\n\n// fusv-disable\n$blue-100: tint-color($blue, 8) !default;\n$blue-200: tint-color($blue, 6) !default;\n$blue-300: tint-color($blue, 4) !default;\n$blue-400: tint-color($blue, 2) !default;\n$blue-500: $blue !default;\n$blue-600: shade-color($blue, 2) !default;\n$blue-700: shade-color($blue, 4) !default;\n$blue-800: shade-color($blue, 6) !default;\n$blue-900: shade-color($blue, 8) !default;\n\n$indigo-100: tint-color($indigo, 8) !default;\n$indigo-200: tint-color($indigo, 6) !default;\n$indigo-300: tint-color($indigo, 4) !default;\n$indigo-400: tint-color($indigo, 2) !default;\n$indigo-500: $indigo !default;\n$indigo-600: shade-color($indigo, 2) !default;\n$indigo-700: shade-color($indigo, 4) !default;\n$indigo-800: shade-color($indigo, 6) !default;\n$indigo-900: shade-color($indigo, 8) !default;\n\n$purple-100: tint-color($purple, 8) !default;\n$purple-200: tint-color($purple, 6) !default;\n$purple-300: tint-color($purple, 4) !default;\n$purple-400: tint-color($purple, 2) !default;\n$purple-500: $purple !default;\n$purple-600: shade-color($purple, 2) !default;\n$purple-700: shade-color($purple, 4) !default;\n$purple-800: shade-color($purple, 6) !default;\n$purple-900: shade-color($purple, 8) !default;\n\n$pink-100: tint-color($pink, 8) !default;\n$pink-200: tint-color($pink, 6) !default;\n$pink-300: tint-color($pink, 4) !default;\n$pink-400: tint-color($pink, 2) !default;\n$pink-500: $pink !default;\n$pink-600: shade-color($pink, 2) !default;\n$pink-700: shade-color($pink, 4) !default;\n$pink-800: shade-color($pink, 6) !default;\n$pink-900: shade-color($pink, 8) !default;\n\n$red-100: tint-color($red, 8) !default;\n$red-200: tint-color($red, 6) !default;\n$red-300: tint-color($red, 4) !default;\n$red-400: tint-color($red, 2) !default;\n$red-500: $red !default;\n$red-600: shade-color($red, 2) !default;\n$red-700: shade-color($red, 4) !default;\n$red-800: shade-color($red, 6) !default;\n$red-900: shade-color($red, 8) !default;\n\n$orange-100: tint-color($orange, 8) !default;\n$orange-200: tint-color($orange, 6) !default;\n$orange-300: tint-color($orange, 4) !default;\n$orange-400: tint-color($orange, 2) !default;\n$orange-500: $orange !default;\n$orange-600: shade-color($orange, 2) !default;\n$orange-700: shade-color($orange, 4) !default;\n$orange-800: shade-color($orange, 6) !default;\n$orange-900: shade-color($orange, 8) !default;\n\n$yellow-100: tint-color($yellow, 8) !default;\n$yellow-200: tint-color($yellow, 6) !default;\n$yellow-300: tint-color($yellow, 4) !default;\n$yellow-400: tint-color($yellow, 2) !default;\n$yellow-500: $yellow !default;\n$yellow-600: shade-color($yellow, 2) !default;\n$yellow-700: shade-color($yellow, 4) !default;\n$yellow-800: shade-color($yellow, 6) !default;\n$yellow-900: shade-color($yellow, 8) !default;\n\n$green-100: tint-color($green, 8) !default;\n$green-200: tint-color($green, 6) !default;\n$green-300: tint-color($green, 4) !default;\n$green-400: tint-color($green, 2) !default;\n$green-500: $green !default;\n$green-600: shade-color($green, 2) !default;\n$green-700: shade-color($green, 4) !default;\n$green-800: shade-color($green, 6) !default;\n$green-900: shade-color($green, 8) !default;\n\n$teal-100: tint-color($teal, 8) !default;\n$teal-200: tint-color($teal, 6) !default;\n$teal-300: tint-color($teal, 4) !default;\n$teal-400: tint-color($teal, 2) !default;\n$teal-500: $teal !default;\n$teal-600: shade-color($teal, 2) !default;\n$teal-700: shade-color($teal, 4) !default;\n$teal-800: shade-color($teal, 6) !default;\n$teal-900: shade-color($teal, 8) !default;\n\n$cyan-100: tint-color($cyan, 8) !default;\n$cyan-200: tint-color($cyan, 6) !default;\n$cyan-300: tint-color($cyan, 4) !default;\n$cyan-400: tint-color($cyan, 2) !default;\n$cyan-500: $cyan !default;\n$cyan-600: shade-color($cyan, 2) !default;\n$cyan-700: shade-color($cyan, 4) !default;\n$cyan-800: shade-color($cyan, 6) !default;\n$cyan-900: shade-color($cyan, 8) !default;\n// fusv-enable\n\n// Characters which are escaped by the escape-svg function\n$escaped-characters: (\n (\"<\", \"%3c\"),\n (\">\", \"%3e\"),\n (\"#\", \"%23\"),\n (\"(\", \"%28\"),\n (\")\", \"%29\"),\n) !default;\n\n// Options\n//\n// Quickly modify global styling by enabling or disabling optional features.\n\n$enable-caret: true !default;\n$enable-rounded: true !default;\n$enable-shadows: false !default;\n$enable-gradients: false !default;\n$enable-transitions: true !default;\n$enable-reduced-motion: true !default;\n$enable-grid-classes: true !default;\n$enable-button-pointers: true !default;\n$enable-rfs: true !default;\n$enable-validation-icons: true !default;\n$enable-negative-margins: true !default;\n$enable-deprecation-messages: true !default;\n$enable-important-utilities: true !default;\n\n// Gradient\n//\n// The gradient which is added to components if `$enable-gradients` is `true`\n// This gradient is also added to elements with `.bg-gradient`\n$gradient: linear-gradient(180deg, rgba($white, .15), rgba($white, 0)) !default;\n\n// Spacing\n//\n// Control the default styling of most Bootstrap elements by modifying these\n// variables. Mostly focused on spacing.\n// You can add more entries to the $spacers map, should you need more variation.\n\n$spacer: 1rem !default;\n$spacers: (\n 0: 0,\n 1: $spacer / 4,\n 2: $spacer / 2,\n 3: $spacer,\n 4: $spacer * 1.5,\n 5: $spacer * 3,\n 6: $spacer * 4,\n 7: $spacer * 6,\n 8: $spacer * 8,\n 9: $spacer * 10,\n 10: $spacer * 12,\n 11: $spacer * 14,\n 12: $spacer * 16,\n) !default;\n\n$negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default;\n\n// Position\n//\n// Define the edge positioning anchors of the position utilities.\n\n$position-values: (\n 0: 0,\n 1: 1%,\n 2: 2%,\n 3: 3%,\n 4: 4%,\n 5: 5%,\n 6: 6%,\n 7: 7%,\n 8: 8%,\n 9: 9%,\n 10: 10%,\n 50: 50%,\n 100: 100%\n) !default;\n\n\n// Body\n//\n// Settings for the `` element.\n\n$body-bg: $white !default;\n$body-color: $font-color !default;\n$body-text-align: null !default;\n\n\n// Links\n//\n// Style anchor elements.\n\n$link-color: $primary !default;\n$link-decoration: none !default;\n$link-hover-color: darken($link-color, 15%) !default;\n$link-hover-decoration: none !default;\n// Darken percentage for links with `.text-*` class (e.g. `.text-success`)\n$emphasized-link-hover-darken-percentage: 15% !default;\n\n$stretched-link-pseudo-element: after !default;\n$stretched-link-z-index: 1 !default;\n\n// Paragraphs\n//\n// Style p element.\n\n$paragraph-margin-bottom: 1rem !default;\n\n\n// Grid breakpoints\n//\n// Define the minimum dimensions at which your layout will change,\n// adapting to different screen sizes, for use in media queries.\n\n// scss-docs-start grid-breakpoints\n$grid-breakpoints: (\n xs: 0,\n sm: 576px,\n md: 768px,\n lg: 992px,\n xl: 1200px,\n xxl: 1400px\n) !default;\n// scss-docs-end grid-breakpoints\n\n@include _assert-ascending($grid-breakpoints, \"$grid-breakpoints\");\n@include _assert-starts-at-zero($grid-breakpoints, \"$grid-breakpoints\");\n\n\n// Grid containers\n//\n// Define the maximum width of `.container` for different screen sizes.\n\n// scss-docs-start container-max-widths\n$container-max-widths: (\n sm: 540px,\n md: 720px,\n lg: 960px,\n xl: 1140px,\n xxl: 1320px\n) !default;\n// scss-docs-end container-max-widths\n\n@include _assert-ascending($container-max-widths, \"$container-max-widths\");\n\n\n// Grid columns\n//\n// Set the number of columns and specify the width of the gutters.\n\n$grid-columns: 12 !default;\n$grid-gutter-width: 1.5rem !default;\n$grid-row-columns: 6 !default;\n\n$gutters: $spacers !default;\n\n// Container padding\n\n$container-padding-x: $grid-gutter-width !default;\n\n\n// Components\n//\n// Define common padding and border radius sizes and more.\n\n$border-width: 1px !default;\n$border-color: $gray-300 !default;\n\n$border-radius-xs: .125rem !default;\n$border-radius-sm: .25rem !default;\n$border-radius-md: .5rem !default;\n$border-radius-lg: .75rem !default;\n$border-radius-xl: 1rem !default;\n$border-radius-2xl: 1.5rem !default;\n$border-radius-section: 10rem !default;\n\n$border-widths: (\n 0: 0,\n 1: 1px,\n 2: 2px,\n 3: 3px,\n 4: 4px,\n 5: 5px\n) !default;\n\n$rounded-pill: 50rem !default;\n\n$box-shadow-xs: 0 2px 9px -5px rgba($black, 0.15) !default;\n$box-shadow-sm: 0 .3125rem .625rem 0 rgba(0, 0, 0, 0.12) !default;\n$box-shadow: 0 .25rem .375rem -.0625rem rgba(20, 20, 20, .12), 0 .125rem .25rem -.0625rem rgba(20, 20, 20, .07) !default;\n$box-shadow-lg: 0 8px 26px -4px rgba(20, 20, 20, 0.15), 0 8px 9px -5px rgba(20, 20, 20, 0.06) !default;\n$box-shadow-xl: 0 23px 45px -11px rgba(20, 20, 20, .25) !default;\n$box-shadow-inset: inset 0 1px 2px rgba($black, .075) !default;\n\n$component-active-color: $white !default;\n$component-active-bg: $primary !default;\n\n$caret-width: .3em !default;\n$caret-vertical-align: $caret-width * .85 !default;\n$caret-spacing: $caret-width * .85 !default;\n\n$transition-base: all .2s ease-in-out !default;\n$transition-fade: opacity .15s linear !default;\n$transition-collapse: height .35s ease !default;\n\n// stylelint-disable function-disallowed-list\n// scss-docs-start aspect-ratios\n$aspect-ratios: (\n \"1x1\": 100%,\n \"4x3\": calc(3 / 4 * 100%),\n \"16x9\": calc(9 / 16 * 100%),\n \"21x9\": calc(9 / 21 * 100%)\n) !default;\n// scss-docs-end aspect-ratios\n// stylelint-enable function-disallowed-list\n\n// Typography\n//\n// Font, line-height, and color for body text, headings, and more.\n\n// stylelint-disable value-keyword-case\n$font-family-sans-serif: 'Open Sans' !default;\n$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace !default;\n// stylelint-enable value-keyword-case\n$font-family-base: var(--bs-font-sans-serif) !default;\n$font-family-code: var(--bs-font-monospace) !default;\n\n// $font-size-root effects the value of `rem`, which is used for as well font sizes, paddings and margins\n// $font-size-base effects the font size of the body text\n$font-size-root: null !default;\n$font-size-base: 1rem !default; // Assumes the browser default, typically `16px`\n$font-size-xxs: $font-size-base * .65 !default;\n$font-size-xs: $font-size-base * .75 !default;\n$font-size-sm: $font-size-base * .875 !default;\n$font-size-lg: $font-size-base * 1.125 !default;\n$font-size-xl: $font-size-base * 1.25 !default;\n$font-size-2xl: $font-size-base * 1.5 !default;\n$font-size-3xl: $font-size-base * 1.875 !default;\n$font-size-4xl: $font-size-base * 2 !default;\n$font-size-5xl: $font-size-base * 2.25 !default;\n$font-size-6xl: $font-size-base * 3 !default;\n$font-size-7xl: $font-size-base * 3.75 !default;\n$font-size-8xl: $font-size-base * 4 !default;\n$font-size-9xl: $font-size-base * 5 !default;\n\n$font-weight-lighter: lighter !default;\n$font-weight-light: 300 !default;\n$font-weight-normal: 400 !default;\n$font-weight-bold: 600 !default;\n$font-weight-bolder: 700 !default;\n\n$font-weight-base: $font-weight-normal !default;\n\n$h1-font-weight: $font-weight-bold !default;\n$h2-font-weight: $font-weight-bold !default;\n$h3-font-weight: $font-weight-bold !default;\n$h4-font-weight: $font-weight-bold !default;\n$h5-font-weight: $font-weight-bold !default;\n$h6-font-weight: $font-weight-bold !default;\n$p-font-weight: $font-weight-normal !default;\n$lead-font-weight: $font-weight-normal !default;\n$text-sm-font-weight: $font-weight-normal !default;\n$text-xs-font-weight: $font-weight-normal !default;\n\n$line-height: 1.75rem !default;\n$line-height-base: 1.5 !default;\n$line-height-sm: 1.25 !default;\n$line-height-lg: 2 !default;\n\n$h1-line-height: 1.25 !default;\n$h2-line-height: 1.3 !default;\n$h3-line-height: 1.375 !default;\n$h4-line-height: 1.375 !default;\n$h5-line-height: 1.375 !default;\n$h6-line-height: 1.625 !default;\n$p-line-height: 1.6 !default;\n$lead-line-height: 1.625 !default;\n$text-sm-line-height: 1.5 !default;\n$text-xs-line-height: 1.25 !default;\n\n$font-size-base: 1rem !default; // Assumes the browser default, typically `16px`\n$h1-font-size: $font-size-base * 3 !default;\n$h2-font-size: $font-size-base * 2.25 !default;\n$h3-font-size: $font-size-base * 1.875 !default;\n$h4-font-size: $font-size-base * 1.5 !default;\n$h5-font-size: $font-size-base * 1.25 !default;\n$h6-font-size: $font-size-base !default;\n$lead-font-size: $font-size-base * 1.25 !default;\n\n\n$text-sm-font-size: .875rem !default;\n$text-xs-font-size: .75rem !default;\n$p-font-size: 1rem !default;\n\n$headings-margin-bottom: $spacer / 2 !default;\n$headings-font-family: null !default;\n$headings-font-style: null !default;\n$headings-font-weight: 400 !default;\n$headings-line-height: 1.2 !default;\n$headings-color: #344767 !default;\n\n// scss-docs-start display-headings\n$display-font-sizes: (\n 1: 5rem,\n 2: 4.5rem,\n 3: 4rem,\n 4: 3.5rem,\n 5: 3rem,\n 6: 2.5rem\n) !default;\n\n$display-font-weight: 300 !default;\n$display-line-height: $headings-line-height !default;\n// scss-docs-end display-headings\n\n$lead-font-size: $font-size-base * 1.25 !default;\n$lead-font-weight: 300 !default;\n\n$small-font-size: .875em !default;\n\n$sub-sup-font-size: .75em !default;\n\n$text-secondary: $font-color !default;\n$text-muted: $gray-600 !default;\n\n// text gradient\n$text-gradient-bg-clip: text !default;\n$text-gradient-text-fill: transparent !default;\n$text-gradient-position: relative !default;\n$text-gradient-zindex: 1 !default;\n$text-gradient-bg-primary: linear-gradient(310deg, #7928CA, #FF0080) !default;\n$text-gradient-bg-info: linear-gradient(310deg, #2152FF, #21D4FD) !default;\n$text-gradient-bg-success: linear-gradient(310deg, #17AD37, #C1E823) !default;\n$text-gradient-bg-warning: linear-gradient(310deg, #F53939, #FBCF33) !default;\n$text-gradient-bg-danger: linear-gradient(310deg, #D60808, #FF6690) !default;\n$text-gradient-bg-dark: linear-gradient(310deg, #141727, #3A416F) !default;\n\n$initialism-font-size: $small-font-size !default;\n\n$blockquote-margin-y: $spacer !default;\n$blockquote-font-size: $font-size-base * 1.25 !default;\n$blockquote-footer-color: $gray-600 !default;\n$blockquote-footer-font-size: $small-font-size !default;\n\n$hr-margin-y: $spacer !default;\n$hr-color: inherit !default;\n$hr-height: $border-width !default;\n$hr-opacity: .25 !default;\n\n$legend-margin-bottom: .5rem !default;\n$legend-font-size: 1.5rem !default;\n$legend-font-weight: null !default;\n\n$mark-padding: .2em !default;\n\n$dt-font-weight: $font-weight-bold !default;\n\n$nested-kbd-font-weight: $font-weight-bold !default;\n\n$list-inline-padding: .5rem !default;\n\n$mark-bg: #fcf8e3 !default;\n\n// Letter Spacing\n$letter-wider: .05rem !default;\n$letter-normal: 0rem !default;\n$letter-tighter: -0.05rem !default;\n$h1-letter-spacing: 0.1rem !default;\n$a-letter-spacing: -0.025rem !default;\n\n// Tables\n//\n// Customizes the `.table` component with basic values, each used across all table variations.\n$table-head-spacer-y: .75rem !default;\n$table-head-spacer-x: 1.5rem !default;\n$table-head-font-size: .65rem !default;\n$table-head-font-weight: $font-weight-bold !default;\n$table-head-text-transform: capitalize !default;\n$table-head-letter-spacing: 0px !default;\n$table-head-bg: $gray-100 !default;\n$table-head-color: $gray-600 !default;\n\n$table-body-font-size: .8125rem !default;\n\n$table-border-width: $border-width !default;\n$table-border-color: $gray-200 !default;\n\n// scss-docs-start table-variables\n$table-cell-padding-y: .5rem !default;\n$table-cell-padding-x: .5rem !default;\n$table-cell-padding-y-sm: .25rem !default;\n$table-cell-padding-x-sm: .25rem !default;\n\n$table-cell-vertical-align: top !default;\n\n$table-color: $body-color !default;\n$table-bg: transparent !default;\n\n$table-th-font-weight: null !default;\n\n$table-striped-color: $table-color !default;\n$table-striped-bg-factor: .05 !default;\n$table-striped-bg: rgba($black, $table-striped-bg-factor) !default;\n\n$table-active-color: $table-color !default;\n$table-active-bg-factor: .1 !default;\n$table-active-bg: rgba($black, $table-active-bg-factor) !default;\n\n$table-hover-color: $table-color !default;\n$table-hover-bg-factor: .075 !default;\n$table-hover-bg: rgba($black, $table-hover-bg-factor) !default;\n\n$table-border-factor: .1 !default;\n$table-border-width: $border-width !default;\n$table-border-color: $border-color !default;\n\n$table-striped-order: odd !default;\n\n$table-group-separator-color: currentColor !default;\n\n$table-caption-color: $text-muted !default;\n\n$table-bg-level: -9 !default;\n$table-bg-scale: -80% !default;\n\n\n$table-variants: (\n \"primary\": shift-color($primary, $table-bg-scale),\n \"secondary\": shift-color($secondary, $table-bg-scale),\n \"success\": shift-color($success, $table-bg-scale),\n \"info\": shift-color($info, $table-bg-scale),\n \"warning\": shift-color($warning, $table-bg-scale),\n \"danger\": shift-color($danger, $table-bg-scale),\n \"light\": $light,\n \"dark\": $dark,\n) !default;\n// scss-docs-end table-variables\n\n\n// Buttons + Forms\n//\n// Shared variables that are reassigned to `$input-` and `$btn-` specific variables.\n\n$input-btn-padding-y: .5rem !default;\n$input-btn-padding-x: .75rem !default;\n$input-btn-font-family: null !default;\n$input-btn-font-size: 1rem !default;\n$input-btn-line-height: 1.4 !default;\n\n$input-btn-focus-width: .2rem !default;\n$input-btn-focus-color-opacity: .25 !default;\n$input-btn-focus-color: rgba($component-active-bg, $input-btn-focus-color-opacity) !default;\n$input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default;\n\n$input-btn-padding-y-sm: .25rem !default;\n$input-btn-padding-x-sm: .75rem !default;\n$input-btn-font-size-sm: .75rem !default;\n\n$input-btn-padding-y-lg: .75rem !default;\n$input-btn-padding-x-lg: .75rem !default;\n$input-btn-font-size-lg: .875rem !default;\n\n$input-btn-border-width: $border-width !default;\n\n\n// Buttons\n//\n// For each of Bootstrap's buttons, define text, background, and border color.\n\n$btn-padding-y: .75rem !default;\n$btn-padding-x: 1.5rem !default;\n$btn-font-family: $input-btn-font-family !default;\n$btn-font-size: $text-xs-font-size !default;\n$btn-line-height: $input-btn-line-height !default;\n$btn-white-space: null !default; // Set to `nowrap` to prevent text wrapping\n$btn-letter-spacing: -0.025rem !default; // Set to `nowrap` to prevent text wrapping\n\n$btn-margin-bottom: 1rem !default;\n$btn-padding-y-sm: .5rem !default;\n$btn-padding-x-sm: 2rem !default;\n$btn-font-size-sm: $input-btn-font-size-sm !default;\n\n$btn-padding-y-lg: .875rem !default;\n$btn-padding-x-lg: 4rem !default;\n$btn-font-size-lg: .875rem !default;\n\n$btn-border-width: $input-btn-border-width !default;\n\n$btn-font-weight: $font-weight-bolder !default;\n$btn-box-shadow: 0 4px 7px -1px rgba(0,0,0,.11), 0 2px 4px -1px rgba(0,0,0,.07) !default;\n$btn-box-shadow-values: 0 5px 8px 0 !default;\n$btn-box-shadow-hover-values: 0 8px 10px 0 !default;\n$btn-hover-box-shadow: 0 3px 5px -1px rgba(0,0,0,.09), 0 2px 3px -1px rgba(0,0,0,.07) !default;\n$btn-focus-box-shadow: $btn-hover-box-shadow !default;\n$btn-focus-width: $input-btn-focus-width !default;\n$btn-hover-opacity: .85 !default;\n$btn-disabled-opacity: .65 !default;\n$btn-active-box-shadow: none !default;\n$btn-background-size: 150% !default;\n$btn-hover-transform: scale(1.02) !default;\n$btn-active-hover-transform: scale(1) !default;\n$btn-background-position-x: 25% !default;\n\n$btn-link-color: $link-color !default;\n$btn-link-hover-color: $link-hover-color !default;\n$btn-link-disabled-color: $gray-600 !default;\n\n$btn-block-spacing-y: .5rem !default;\n\n// Allows for customizing button radius independently from global border radius\n$btn-border-radius: .5rem !default;\n$btn-border-radius-lg: .5rem !default;\n$btn-border-radius-sm: .5rem !default;\n$btn-border-rounded: 1.875rem !default;\n\n$btn-icon-transition: all .2s cubic-bezier(.34,1.61,.7,1.3) !default;\n$btn-icon-transform-right: translateX(5px) !default;\n$btn-icon-transform-left: translateX(-5px) !default;\n\n// Allows for customizing button radius independently from global border radius\n$btn-border-radius: $border-radius-md !default;\n$btn-border-radius-sm: $border-radius-sm !default;\n$btn-border-radius-lg: $border-radius-lg !default;\n\n$btn-transition: all .15s ease-in !default;\n\n$btn-just-icon-padding-x-sm: .3rem !default;\n$btn-just-icon-padding-y-sm: .3rem !default;\n$btn-just-icon-padding-x: .7rem !default;\n$btn-just-icon-padding-y: .7rem !default;\n$btn-just-icon-padding-x-lg: 1rem !default;\n$btn-just-icon-padding-y-lg: 1rem !default;\n$btn-just-icon-width: 2.375rem !default;\n$btn-just-icon-height: $btn-just-icon-width !default;\n$btn-just-icon-width-sm: 1.5875rem !default;\n$btn-just-icon-height-sm: $btn-just-icon-width-sm !default;\n$btn-just-icon-sm-font-size: .5rem !default;\n$btn-just-icon-width-lg: 3.25rem !default;\n$btn-just-icon-height-lg: $btn-just-icon-width-lg !default;\n$btn-just-icon-lg-font-size: 1.2rem !default;\n$btn-just-icon-lg-position: relative !default;\n$btn-just-icon-lg-top: 2px !default;\n\n// we've overwritten the default Bootstrap function\n// for dynamically adding font color since the colors\n// added by that function were not correctly set\n$btn-primary-font-color: #fff !default;\n$btn-secondary-font-color: #fff !default;\n$btn-danger-font-color: #fff !default;\n$btn-info-font-color: #fff !default;\n$btn-success-font-color: #fff !default;\n$btn-warning-font-color: #fff !default;\n$btn-dark-font-color: #fff !default;\n$btn-light-font-color: #3A416F !default;\n\n$btn-font-colors: () !default;\n\n$btn-font-colors: map-merge(\n (\n \"primary\": $btn-primary-font-color,\n \"secondary\": $btn-secondary-font-color,\n \"danger\": $btn-danger-font-color,\n \"info\": $btn-info-font-color,\n \"success\": $btn-success-font-color,\n \"warning\": $btn-warning-font-color,\n \"dark\": $btn-dark-font-color,\n \"light\": $btn-light-font-color\n ),\n $btn-font-colors\n);\n\n// Forms\n\n$form-text-margin-top: .25rem !default;\n$form-text-font-size: $small-font-size !default;\n$form-text-font-style: null !default;\n$form-text-font-weight: null !default;\n$form-text-color: $text-muted !default;\n\n$form-label-margin-bottom: .5rem !default;\n$form-label-margin-left: .25rem !default;\n$form-label-font-size: .75rem !default;\n$form-label-font-style: null !default;\n$form-label-font-weight: 700 !default;\n$form-label-color: $dark !default;\n\n$input-padding-y: .5rem !default;\n$input-padding-x: .75rem !default;\n$input-font-family: $input-btn-font-family !default;\n$input-font-size: $font-size-sm !default;\n$input-font-weight: $font-weight-base !default;\n$input-line-height: 1.4rem !default;\n\n$input-padding-y-sm: $input-btn-padding-y-sm !default;\n$input-padding-x-sm: $input-btn-padding-x-sm !default;\n$input-font-size-sm: .75rem !default;\n\n$input-padding-y-lg: $input-btn-padding-y-lg !default;\n$input-padding-x-lg: $input-btn-padding-x-lg !default;\n$input-font-size-lg: .875rem !default;\n\n$input-bg: $white !default;\n$input-disabled-bg: $gray-200 !default;\n$input-disabled-border-color: null !default;\n\n$input-color: $gray-700 !default;\n$input-border-color: #d2d6da !default;\n$input-border-width: $input-btn-border-width !default;\n$input-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05) !default;\n\n$input-border-radius: $border-radius-md !default;\n$input-border-radius-sm: $border-radius-md !default;\n$input-border-radius-lg: $border-radius-md !default;\n\n$input-focus-bg: $white !default;\n$input-focus-border-color: #e293d3 !default;\n$input-focus-color: $input-color !default;\n$input-focus-width: 2px !default;\n$input-focus-box-shadow: 0 0 0 $input-focus-width #e9aede !default;\n\n$input-placeholder-color: $gray-500 !default;\n$input-plaintext-color: $dark !default;\n\n$input-height-border: $input-border-width * 2 !default;\n\n$input-height-inner: unset !default;\n$input-height-inner-half: 1rem !default;\n$input-height-inner-quarter: .75rem !default;\n\n$input-height: unset !default;\n$input-height-sm: unset !default;\n$input-height-lg: unset !default;\n\n$input-transition: box-shadow .15s ease, border-color .15s ease !default;\n\n\n$form-check-input-width: 1.23em !default;\n$form-check-min-height: $font-size-base * $line-height-base !default;\n$form-check-padding-left: $form-check-input-width + .45em !default;\n$form-check-margin-bottom: .125rem !default;\n$form-check-label-color: null !default;\n$form-check-label-cursor: null !default;\n$form-check-transition: background-color .25s ease, border-color .25s ease, background-position .15s ease-in-out, opacity .15s ease-out, box-shadow .15s ease-in-out !default;\n$form-check-transition-time: .25s !default;\n\n$form-check-input-active-filter: brightness(99%) !default;\n\n$form-check-input-bg: $white !default;\n$form-check-input-border: none !default;\n$form-check-input-border-radius: .35rem !default;\n$form-check-radio-border-radius: 50% !default;\n$form-check-input-focus-border: none !default;\n$form-check-input-focus-box-shadow: none !default;\n\n$form-check-input-checked-color: $white !default;\n$form-check-input-checked-bg-color: transparent !default;\n$form-check-input-checked-border-color: $form-check-input-checked-bg-color !default;\n$form-check-input-checked-bg-image: linear-gradient(310deg, $dark-gradient 0%, $dark-gradient-state 100%) !default;\n$form-check-radio-checked-bg-image: $form-check-input-checked-bg-image !default;\n$form-check-radio-after-width: .4375rem !default;\n\n$form-check-input-indeterminate-color: $component-active-color !default;\n$form-check-input-indeterminate-bg-color: $component-active-bg !default;\n$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default;\n$form-check-input-indeterminate-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-switch-color: rgba(0, 0, 0, 1) !default;\n$form-switch-height: 1.2em !default;\n$form-switch-width: 2.5rem !default;\n$form-switch-check-after-width: 1rem !default;\n$form-switch-padding-start: $form-switch-width + .5rem !default;\n$form-switch-bg-image: none !default;\n$form-switch-border-radius: $form-switch-width !default;\n$form-switch-translate-x-start: 1px !default;\n$form-switch-translate-x-end: 21px !default;\n$form-switch-round-box-shadow: $box-shadow !default;\n$form-switch-transition: $form-check-transition !default;\n\n$form-switch-focus-color: $form-switch-color !default;\n$form-switch-focus-bg-image: $form-switch-bg-image !default;\n$form-switch-checked-color: $white !default;\n$form-switch-checked-bg-image: $form-switch-bg-image !default;\n$form-switch-checked-bg-position: right center !default;\n\n$form-check-inline-margin-right: 1rem !default;\n\n$input-group-addon-padding-y: $input-padding-y !default;\n$input-group-addon-padding-x: $input-padding-x !default;\n$input-group-addon-font-weight: $input-font-weight !default;\n$input-group-addon-color: $dark !default;\n$input-group-addon-bg: $white !default;\n$input-group-addon-border-color: $input-border-color !default;\n\n\n$form-select-padding-y: $input-padding-y !default;\n$form-select-padding-x: $input-padding-x !default;\n$form-select-font-family: $input-font-family !default;\n$form-select-font-size: $input-font-size !default;\n$form-select-height: $input-height !default;\n$form-select-indicator-padding: 1rem !default; // Extra padding to account for the presence of the background-image based indicator\n$form-select-font-weight: $input-font-weight !default;\n$form-select-line-height: $input-line-height !default;\n$form-select-color: $input-color !default;\n$form-select-disabled-color: $gray-600 !default;\n$form-select-bg: $input-bg !default;\n$form-select-disabled-bg: $gray-200 !default;\n$form-select-disabled-border-color: $input-disabled-border-color !default;\n$form-select-bg-position: right $form-select-padding-x center !default;\n$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions\n$form-select-indicator-color: $gray-800 !default;\n$form-select-indicator: url(\"data:image/svg+xml,\") !default;\n\n$form-select-feedback-icon-padding-right: add(1em * .75, (2 * $form-select-padding-y * .75) + $form-select-padding-x + $form-select-indicator-padding) !default;\n$form-select-feedback-icon-position: center right ($form-select-padding-x + $form-select-indicator-padding) !default;\n$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default;\n\n$form-select-border-width: $input-border-width !default;\n$form-select-border-color: $input-border-color !default;\n$form-select-border-radius: $border-radius-md !default;\n$form-select-box-shadow: $box-shadow-inset !default;\n\n$form-select-focus-border-color: $input-focus-border-color !default;\n$form-select-focus-width: $input-focus-width !default;\n$form-select-focus-box-shadow: $input-focus-box-shadow !default;\n\n$form-select-padding-y-sm: $input-padding-y-sm !default;\n$form-select-padding-x-sm: $input-padding-x-sm !default;\n$form-select-font-size-sm: $input-font-size-sm !default;\n$form-select-height-sm: $input-height-sm !default;\n\n$form-select-padding-y-lg: $input-padding-y-lg !default;\n$form-select-padding-x-lg: $input-padding-x-lg !default;\n$form-select-font-size-lg: $input-font-size-lg !default;\n$form-select-height-lg: $input-height-lg !default;\n\n$form-range-track-width: 100% !default;\n$form-range-track-height: .5rem !default;\n$form-range-track-cursor: pointer !default;\n$form-range-track-bg: $gray-300 !default;\n$form-range-track-border-radius: 1rem !default;\n$form-range-track-box-shadow: $box-shadow-inset !default;\n\n$form-range-thumb-width: 1rem !default;\n$form-range-thumb-height: $form-range-thumb-width !default;\n$form-range-thumb-bg: $component-active-bg !default;\n$form-range-thumb-border: 0 !default;\n$form-range-thumb-border-radius: 1rem !default;\n$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default;\n$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default;\n$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in Edge\n$form-range-thumb-active-bg: lighten($component-active-bg, 35%) !default;\n$form-range-thumb-disabled-bg: $gray-500 !default;\n$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$form-file-height: $input-height !default;\n$form-file-focus-border-color: $input-focus-border-color !default;\n$form-file-focus-box-shadow: $input-focus-box-shadow !default;\n$form-file-disabled-bg: $input-disabled-bg !default;\n$form-file-disabled-border-color: $input-disabled-border-color !default;\n\n$form-file-padding-y: $input-padding-y !default;\n$form-file-padding-x: $input-padding-x !default;\n$form-file-line-height: $input-line-height !default;\n$form-file-font-family: $input-font-family !default;\n$form-file-font-weight: $input-font-weight !default;\n$form-file-color: $input-color !default;\n$form-file-bg: $input-bg !default;\n$form-file-border-width: $input-border-width !default;\n$form-file-border-color: $input-border-color !default;\n$form-file-border-radius: $input-border-radius !default;\n$form-file-box-shadow: $input-box-shadow !default;\n$form-file-button-color: $form-file-color !default;\n$form-file-button-bg: $input-group-addon-bg !default;\n\n$form-file-padding-y-sm: $input-padding-y-sm !default;\n$form-file-padding-x-sm: $input-padding-x-sm !default;\n$form-file-font-size-sm: $input-font-size-sm !default;\n$form-file-height-sm: $input-height-sm !default;\n\n$form-file-padding-y-lg: $input-padding-y-lg !default;\n$form-file-padding-x-lg: $input-padding-x-lg !default;\n$form-file-font-size-lg: $input-font-size-lg !default;\n$form-file-height-lg: $input-height-lg !default;\n\n\n// Form validation\n\n$form-feedback-margin-top: $form-text-margin-top !default;\n$form-feedback-font-size: $form-text-font-size !default;\n$form-feedback-font-style: $form-text-font-style !default;\n$form-feedback-valid-color: #66d432 !default;\n$form-feedback-invalid-color: #fd5c70 !default;\n\n$form-feedback-icon-valid-color: $form-feedback-valid-color !default;\n$form-feedback-icon-valid: url(\"data:image/svg+xml,\") !default;\n$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default;\n$form-feedback-icon-invalid: url(\"data:image/svg+xml,\") !default;\n\n// scss-docs-start form-validation-states\n$form-validation-states: (\n \"valid\": (\n \"color\": $form-feedback-valid-color,\n \"icon\": $form-feedback-icon-valid\n ),\n \"invalid\": (\n \"color\": $form-feedback-invalid-color,\n \"icon\": $form-feedback-icon-invalid\n )\n) !default;\n// scss-docs-end form-validation-states\n\n// Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n\n// scss-docs-start zindex-stack\n$zindex-dropdown: 1000 !default;\n$zindex-sticky: 1020 !default;\n$zindex-fixed: 1030 !default;\n$zindex-modal-backdrop: 1040 !default;\n$zindex-modal: 1050 !default;\n$zindex-popover: 1060 !default;\n$zindex-tooltip: 1070 !default;\n// scss-docs-end zindex-stack\n\n\n// Navs\n\n$nav-link-padding-y: .5rem !default;\n$nav-link-padding-x: 1rem !default;\n$nav-link-font-size: null !default;\n$nav-link-font-weight: null !default;\n$nav-link-color: null !default;\n$nav-link-hover-color: null !default;\n$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default;\n$nav-link-disabled-color: $gray-600 !default;\n$nav-link-footer-padding: .25rem !default;\n\n$nav-tabs-border-color: $gray-300 !default;\n$nav-tabs-border-width: $border-width !default;\n$nav-tabs-border-radius: $border-radius-md !default;\n$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default;\n$nav-tabs-link-active-color: $gray-700 !default;\n$nav-tabs-link-active-bg: $body-bg !default;\n$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default;\n\n$nav-pills-border-radius: 0.75rem !default;\n$nav-pills-link-active-color: $dark !default;\n$nav-pills-link-active-bg: $white !default;\n$nav-pills-link-transition: background-color .3s ease !default;\n$nav-pills-background: $gray-100 !default;\n$nav-pills-vertical-background: transparent !default;\n$nav-pills-vertical-radius: 1.1875rem !default;\n$nav-pills-vertical-link-radius: .875rem !default;\n\n\n// Navbar\n\n$navbar-padding-y: $spacer / 2 !default;\n$navbar-padding-x: null !default;\n$navbar-box-shadow: 0 2px 12px 0 rgba(0, 0, 0, .16) !default;\n\n$navbar-nav-link-padding-x: .5rem !default;\n$navbar-nav-link-padding: $navbar-nav-link-padding-x 1rem !default;\n\n$navbar-brand-font-size: $font-size-lg !default;\n// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link\n$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default;\n$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default;\n$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) / 2 !default;\n$navbar-brand-margin-right: 1rem !default;\n\n$navbar-toggler-padding-y: .25rem !default;\n$navbar-toggler-padding-x: .75rem !default;\n$navbar-toggler-font-size: $font-size-lg !default;\n$navbar-toggler-border-radius: $btn-border-radius !default;\n$navbar-toggler-focus-width: $btn-focus-width !default;\n$navbar-toggler-transition: box-shadow .15s ease-in-out !default;\n\n$navbar-blur-bg-color: rgba(255, 255, 255, .8) !default;\n$navbar-blur-dark-bg-color: rgba(2, 5, 22, .8) !default;\n\n$navbar-dark-color: rgba($white, .85) !default;\n$navbar-dark-hover-color: rgba($white, .75) !default;\n$navbar-dark-active-color: $white !default;\n$navbar-dark-disabled-color: rgba($white, .25) !default;\n$navbar-dark-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-dark-toggler-border-color: rgba($white, .1) !default;\n\n$navbar-light-color: $dark !default;\n$navbar-light-hover-color: rgba($dark, .7) !default;\n$navbar-light-active-color: rgba($dark, .9) !default;\n$navbar-light-disabled-color: rgba($dark, .3) !default;\n$navbar-light-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-light-toggler-border-color: rgba($dark, .1) !default;\n\n$navbar-light-brand-color: $navbar-light-active-color !default;\n$navbar-light-brand-hover-color: $navbar-light-active-color !default;\n$navbar-dark-brand-color: $navbar-dark-active-color !default;\n$navbar-dark-brand-hover-color: $navbar-dark-active-color !default;\n\n// Sidenav toggler\n$sidenav-toggler-width: 18px !default;\n$sidenav-toggler-line-transition: all .15s ease !default;\n$sidenav-toggler-line-height: 2px !default;\n$sidenav-toggler-line-margin-bottom: 3px !default;\n$sidenav-toggler-line-active-width: 13px !default;\n$sidenav-toggler-line-transform: translateX(5px) !default;\n\n// Dropdowns\n//\n// Dropdown menu container and contents.\n\n$dropdown-min-width: 11rem !default;\n$dropdown-padding-x: 0 !default;\n$dropdown-padding-y: .5rem !default;\n$dropdown-spacer: 1.625rem !default;\n$dropdown-font-size: $font-size-sm !default;\n$dropdown-color: $body-color !default;\n$dropdown-bg: $white !default;\n$dropdown-border-color: transparent !default;\n$dropdown-border-radius: $border-radius-md !default;\n$dropdown-border-width: 0 !default;\n$dropdown-inner-border-radius: subtract($dropdown-border-radius, $dropdown-border-width) !default;\n$dropdown-transition-time: .3s ease !default;\n$dropdown-divider-bg: $dropdown-border-color !default;\n$dropdown-divider-margin-y: $spacer / 2 !default;\n$dropdown-box-shadow: $box-shadow-lg !default;\n\n$dropdown-link-color: $font-color !default;\n$dropdown-link-hover-color: $h-color !default;\n$dropdown-link-hover-bg: $gray-200 !default;\n\n$dropdown-link-active-color: $font-color !default;\n$dropdown-link-active-bg: transparent !default;\n\n$dropdown-link-disabled-color: $gray-600 !default;\n\n$dropdown-item-padding-y: .3rem !default;\n$dropdown-item-padding-x: $spacer !default;\n\n$dropdown-header-color: $gray-600 !default;\n$dropdown-header-padding: $dropdown-padding-y $dropdown-item-padding-x !default;\n\n$dropdown-dark-color: $gray-300 !default;\n$dropdown-dark-bg: $gray-800 !default;\n$dropdown-dark-border-color: $dropdown-border-color !default;\n$dropdown-dark-divider-bg: $dropdown-divider-bg !default;\n$dropdown-dark-box-shadow: null !default;\n$dropdown-dark-link-color: $dropdown-dark-color !default;\n$dropdown-dark-link-hover-color: $white !default;\n$dropdown-dark-link-hover-bg: rgba($white, .15) !default;\n$dropdown-dark-link-active-color: $dropdown-link-active-color !default;\n$dropdown-dark-link-active-bg: $dropdown-link-active-bg !default;\n$dropdown-dark-link-disabled-color: $gray-500 !default;\n$dropdown-dark-header-color: $gray-500 !default;\n\n\n// Pagination\n\n$pagination-padding-y: .375rem !default;\n$pagination-padding-x: .75rem !default;\n$pagination-padding-y-sm: .25rem !default;\n$pagination-padding-x-sm: .5rem !default;\n$pagination-padding-y-lg: .75rem !default;\n$pagination-padding-x-lg: 1.5rem !default;\n\n$pagination-color: $link-color !default;\n$pagination-bg: $white !default;\n$pagination-border-width: $border-width !default;\n$pagination-border-radius: $border-radius-md !default;\n$pagination-margin-left: -$pagination-border-width !default;\n$pagination-border-color: $gray-300 !default;\n\n$pagination-focus-color: $link-hover-color !default;\n$pagination-focus-bg: $gray-200 !default;\n$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default;\n$pagination-focus-outline: 0 !default;\n\n$pagination-hover-color: $link-hover-color !default;\n$pagination-hover-bg: $gray-200 !default;\n$pagination-hover-border-color: $gray-300 !default;\n\n$pagination-active-color: $component-active-color !default;\n$pagination-active-bg: $component-active-bg !default;\n$pagination-active-border-color: $pagination-active-bg !default;\n\n$pagination-disabled-color: $gray-600 !default;\n$pagination-disabled-bg: $white !default;\n$pagination-disabled-border-color: $gray-300 !default;\n\n$pagination-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n// Cards\n\n$card-spacer-y: $spacer !default;\n$card-spacer-x: $spacer !default;\n$card-title-spacer-y: $spacer / 2 !default;\n$card-border-width: 0 !default;\n$card-border-radius: 1rem !default;\n$card-border-color: rgba($black, .125) !default;\n$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default;\n$card-cap-padding-y: $card-spacer-y / 2 !default;\n$card-cap-padding-x: $card-spacer-x !default;\n$card-cap-bg: $white !default;\n$card-cap-color: null !default;\n$card-height: null !default;\n$card-color: null !default;\n$card-bg: $white !default;\n\n$card-img-overlay-padding: $spacer !default;\n\n$card-group-margin: $grid-gutter-width / 2 !default;\n\n\n// Accordion\n$accordion-padding-y: 1rem !default;\n$accordion-padding-x: 1rem !default;\n$accordion-color: $body-color !default;\n$accordion-bg: transparent !default;\n$accordion-border-width: 0 !default;\n$accordion-border-color: rgba($black, .125) !default;\n$accordion-border-radius: $border-radius-sm !default;\n\n$accordion-body-padding-y: $accordion-padding-y !default;\n$accordion-body-padding-x: $accordion-padding-x !default;\n\n$accordion-button-padding-y: $accordion-padding-y !default;\n$accordion-button-padding-x: $accordion-padding-x !default;\n$accordion-button-color: $accordion-color !default;\n$accordion-button-bg: $accordion-bg !default;\n$accordion-transition: $btn-transition, border-radius .15s ease !default;\n$accordion-button-active-bg: $accordion-bg !default;\n$accordion-button-active-color: $dark !default;\n\n$accordion-button-focus-border-color: $input-focus-border-color !default;\n$accordion-button-focus-box-shadow: none !default;\n\n$accordion-icon-width: 1rem !default;\n$accordion-icon-color: $accordion-color !default;\n$accordion-icon-active-color: $accordion-button-active-color !default;\n$accordion-icon-transition: transform .2s ease-in-out !default;\n$accordion-icon-transform: rotate(180deg) !default;\n\n$accordion-button-icon: none !default;\n$accordion-button-active-icon: none !default;\n\n\n// Tooltips\n\n$tooltip-font-size: $font-size-sm !default;\n$tooltip-max-width: 200px !default;\n$tooltip-color: $white !default;\n$tooltip-bg: $black !default;\n$tooltip-border-radius: $border-radius-md !default;\n$tooltip-opacity: .9 !default;\n$tooltip-padding-y: $spacer / 4 !default;\n$tooltip-padding-x: $spacer / 2 !default;\n$tooltip-margin: 0 !default;\n\n$tooltip-arrow-width: .8rem !default;\n$tooltip-arrow-height: .4rem !default;\n$tooltip-arrow-color: $tooltip-bg !default;\n\n// Form tooltips must come after regular tooltips\n$form-feedback-tooltip-padding-y: $tooltip-padding-y !default;\n$form-feedback-tooltip-padding-x: $tooltip-padding-x !default;\n$form-feedback-tooltip-font-size: $tooltip-font-size !default;\n$form-feedback-tooltip-line-height: null !default;\n$form-feedback-tooltip-opacity: $tooltip-opacity !default;\n$form-feedback-tooltip-border-radius: $tooltip-border-radius !default;\n\n\n// Popovers\n\n$popover-font-size: $font-size-xs !default;\n$popover-bg: $white !default;\n$popover-max-width: 276px !default;\n$popover-border-width: 0px !default;\n$popover-border-color: rgba($black, .2) !default;\n$popover-border-radius: $border-radius-lg !default;\n$popover-inner-border-radius: subtract($popover-border-radius, $popover-border-width) !default;\n$popover-box-shadow: $box-shadow-sm !default;\n\n$popover-header-bg: $gray-200 !default;\n$popover-header-color: $headings-color !default;\n$popover-header-padding-y: .5rem !default;\n$popover-header-padding-x: $spacer !default;\n\n$popover-body-color: $font-color !default;\n$popover-body-padding-y: $spacer !default;\n$popover-body-padding-x: $spacer !default;\n\n$popover-arrow-width: 1rem !default;\n$popover-arrow-height: .5rem !default;\n$popover-arrow-color: $popover-bg !default;\n\n$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default;\n\n\n// Toasts\n\n$toast-max-width: 350px !default;\n$toast-padding-x: .75rem !default;\n$toast-padding-y: .75rem !default;\n$toast-font-size: .875rem !default;\n$toast-color: null !default;\n$toast-background-color: rgba($white, .85) !default;\n$toast-border-width: 0 !default;\n$toast-border-color: transparent !default;\n$toast-border-radius: $border-radius-md !default;\n$toast-box-shadow: $box-shadow !default;\n\n$toast-header-color: $h-color !default;\n$toast-header-background-color: rgba($white, .85) !default;\n$toast-header-border-color: rgba(0, 0, 0, .05) !default;\n\n\n// Badges\n\n$badge-font-size: .75em !default;\n$badge-font-weight: $font-weight-bolder !default;\n$badge-color: $white !default;\n$badge-padding-y: .55em !default;\n$badge-padding-x: .9em !default;\n$badge-border-radius-custom: .45rem !default;\n$badge-border-radius: $badge-border-radius-custom !default;\n\n\n// Modals\n\n// Padding applied to the modal body\n$modal-inner-padding: $spacer !default;\n\n// Margin between elements in footer, must be lower than or equal to 2 * $modal-inner-padding\n$modal-footer-margin-between: .5rem !default;\n\n$modal-dialog-margin: .5rem !default;\n$modal-dialog-margin-y-sm-up: 1.75rem !default;\n\n$modal-title-line-height: $line-height-base !default;\n\n$modal-content-color: null !default;\n$modal-content-bg: $white !default;\n$modal-content-border-color: rgba($black, .2) !default;\n$modal-content-border-width: $border-width !default;\n$modal-content-border-radius: $border-radius-lg !default;\n$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width) !default;\n$modal-content-box-shadow-xs: $box-shadow-sm !default;\n$modal-content-box-shadow-sm-up: $box-shadow !default;\n\n$modal-backdrop-bg: $black !default;\n$modal-backdrop-opacity: .5 !default;\n$modal-header-border-color: $border-color !default;\n$modal-footer-border-color: $modal-header-border-color !default;\n$modal-header-border-width: $modal-content-border-width !default;\n$modal-footer-border-width: $modal-header-border-width !default;\n$modal-header-padding-y: $modal-inner-padding !default;\n$modal-header-padding-x: $modal-inner-padding !default;\n$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility\n\n$modal-sm: 300px !default;\n$modal-md: 500px !default;\n$modal-lg: 800px !default;\n$modal-xl: 1140px !default;\n\n$modal-fade-transform: translate(0, -50px) !default;\n$modal-show-transform: none !default;\n$modal-transition: transform .3s ease-out !default;\n$modal-scale-transform: scale(1.02) !default;\n\n\n// Alerts\n//\n// Define alert colors, border radius, and padding.\n\n$alert-padding-y: $spacer !default;\n$alert-padding-x: $spacer !default;\n$alert-margin-bottom: 1rem !default;\n$alert-border-radius: $border-radius-md !default;\n$alert-link-font-weight: $font-weight-bold !default;\n$alert-border-width: $border-width !default;\n\n$alert-bg-level: -10 !default;\n$alert-border-level: -9 !default;\n$alert-color-level: 6 !default;\n\n$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side\n\n\n// Progress bars\n\n$progress-height: 3px !default;\n$progress-bar-height: 6px !default;\n$progress-height-sm: 4px !default;\n$progress-height-lg: 20px !default;\n$progress-font-size: $font-size-base * .75 !default;\n$progress-bg: $gray-200 !default;\n$progress-border-radius: $border-radius-md !default;\n$progress-box-shadow: $box-shadow-inset !default;\n$progress-bar-color: $white !default;\n$progress-bar-bg: $primary !default;\n$progress-bar-animation-timing: 1s linear infinite !default;\n$progress-bar-transition: width .6s ease !default;\n\n\n// List group\n\n$list-group-color: inherit !default;\n$list-group-bg: $white !default;\n$list-group-border-color: rgba($black, .125) !default;\n$list-group-border-width: $border-width !default;\n$list-group-border-radius: $border-radius-md !default;\n\n$list-group-item-padding-y: $spacer / 2 !default;\n$list-group-item-padding-x: $spacer !default;\n$list-group-item-bg-level: -9 !default;\n$list-group-item-color-level: 6 !default;\n\n$list-group-hover-bg: $gray-100 !default;\n$list-group-active-color: $component-active-color !default;\n$list-group-active-bg: $component-active-bg !default;\n$list-group-active-border-color: $list-group-active-bg !default;\n\n$list-group-disabled-color: $gray-600 !default;\n$list-group-disabled-bg: $list-group-bg !default;\n\n$list-group-action-color: $gray-700 !default;\n$list-group-action-hover-color: $list-group-action-color !default;\n\n$list-group-action-active-color: $body-color !default;\n$list-group-action-active-bg: $gray-200 !default;\n\n\n// Image thumbnails\n\n$thumbnail-padding: .25rem !default;\n$thumbnail-bg: $body-bg !default;\n$thumbnail-border-width: $border-width !default;\n$thumbnail-border-color: $gray-300 !default;\n$thumbnail-border-radius: $border-radius-md !default;\n$thumbnail-box-shadow: $box-shadow-sm !default;\n\n\n// Figures\n\n$figure-caption-font-size: $small-font-size !default;\n$figure-caption-color: $gray-600 !default;\n\n\n// Breadcrumbs\n\n$breadcrumb-font-size: null !default;\n$breadcrumb-padding-y: $spacer / 2 !default;\n$breadcrumb-padding-x: $spacer !default;\n$breadcrumb-item-padding-x: .5rem !default;\n$breadcrumb-margin-bottom: 1rem !default;\n$breadcrumb-bg: $gray-200 !default;\n$breadcrumb-divider-color: $gray-600 !default;\n$breadcrumb-active-color: $gray-600 !default;\n$breadcrumb-divider: quote(\"/\") !default;\n$breadcrumb-border-radius: $border-radius-md !default;\n\n// Carousel\n\n$carousel-control-color: $white !default;\n$carousel-control-width: 15% !default;\n$carousel-control-opacity: .5 !default;\n$carousel-control-hover-opacity: .9 !default;\n$carousel-control-transition: opacity .15s ease !default;\n\n$carousel-indicator-width: 30px !default;\n$carousel-indicator-height: 3px !default;\n$carousel-indicator-hit-area-height: 10px !default;\n$carousel-indicator-spacer: 3px !default;\n$carousel-indicator-opacity: .5 !default;\n$carousel-indicator-active-bg: $white !default;\n$carousel-indicator-active-opacity: 1 !default;\n$carousel-indicator-transition: opacity .6s ease !default;\n\n$carousel-caption-width: 70% !default;\n$carousel-caption-color: $white !default;\n$carousel-caption-padding-y: 1.25rem !default;\n$carousel-caption-spacer: 1.25rem !default;\n\n$carousel-control-icon-width: 2rem !default;\n\n$carousel-control-prev-icon-bg: url(\"data:image/svg+xml,\") !default;\n$carousel-control-next-icon-bg: url(\"data:image/svg+xml,\") !default;\n\n$carousel-transition-duration: .6s !default;\n$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`)\n\n$carousel-dark-indicator-active-bg: $black !default;\n$carousel-dark-caption-color: $black !default;\n$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default;\n\n\n// Spinners\n\n$spinner-width: 2rem !default;\n$spinner-height: $spinner-width !default;\n$spinner-border-width: .25em !default;\n$spinner-animation-speed: .75s !default;\n\n$spinner-width-sm: 1rem !default;\n$spinner-height-sm: $spinner-width-sm !default;\n$spinner-border-width-sm: .2em !default;\n\n\n// Close\n\n$btn-close-width: 1em !default;\n$btn-close-height: $btn-close-width !default;\n$btn-close-padding-x: .25em !default;\n$btn-close-padding-y: $btn-close-padding-x !default;\n$btn-close-color: $white !default;\n$btn-close-bg: url(\"data:image/svg+xml,\") !default;\n$btn-close-focus-shadow: $input-btn-focus-box-shadow !default;\n$btn-close-opacity: .5 !default;\n$btn-close-hover-opacity: .75 !default;\n$btn-close-focus-opacity: 1 !default;\n$btn-close-disabled-opacity: .25 !default;\n$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default;\n\n// Code\n\n$code-font-size: $small-font-size !default;\n$code-color: $pink !default;\n\n$kbd-padding-y: .2rem !default;\n$kbd-padding-x: .4rem !default;\n$kbd-font-size: $code-font-size !default;\n$kbd-color: $white !default;\n$kbd-bg: $gray-900 !default;\n$pre-color: null !default;\n\n// Tilt Animation\n\n$tilt-transform-style: preserve-3d !default;\n$tilt-transform-up-transform: translateZ(50px) scale(0.7) !default;\n$tilt-transform-up-transition: all 0.5s !default;\n\n// Variables for Core\n\n@import \"variables/animations\";\n@import \"variables/avatars\";\n@import \"variables/cards\";\n@import \"variables/dropdowns\";\n@import 'variables/header';\n@import 'variables/info-areas';\n@import 'variables/navbar';\n@import 'variables/navbar-vertical';\n@import 'variables/utilities';\n@import 'variables/utilities-extend';\n@import 'variables/misc';\n@import 'variables/misc-extend';\n@import 'variables/form-switch';\n@import 'variables/fixed-plugin';\n@import 'variables/pagination';\n@import 'variables/badge';\n@import 'variables/rtl';\n@import 'variables/cards-extend';\n@import 'variables/choices';\n@import 'variables/timeline';\n@import 'variables/full-calendar';\n@import 'variables/social-buttons';\n@import 'variables/virtual-reality';\n\n\n// Import Utilities\n@import \"utilities\";\n", + "// Waves Animation & Styling\n\n$waves-position: relative !default;\n$waves-width: 100% !default;\n$waves-height: 16vh !default;\n$waves-min-height: 100px !default;\n$waves-max-height: 150px !default;\n$waves-margin-bottom: -7px !default;\n$waves-height-sm: 50px !default;\n$waves-min-height-sm: $waves-height-sm !default;\n$waves-rotate: rotate(180deg) !default;\n$waves-mobile-height: 40px !default;\n\n$moving-waves-keyframe-0: translate3d(-90px,0,0) !default;\n$moving-waves-keyframe-100: translate3d(85px,0,0) !default;\n$moving-waves-animation: move-forever 40s cubic-bezier(.55,.5,.45,.5) infinite !default;\n$moving-waves-child-1-delay: -2s !default;\n$moving-waves-child-1-duration: 11s !default;\n$moving-waves-child-2-delay: -4s !default;\n$moving-waves-child-2-duration: 13s !default;\n$moving-waves-child-3-delay: -3s !default;\n$moving-waves-child-3-duration: 15s !default;\n$moving-waves-child-4-delay: -4s !default;\n$moving-waves-child-4-duration: 20s !default;\n$moving-waves-child-5-delay: -4s !default;\n$moving-waves-child-5-duration: 25s !default;\n$moving-waves-child-6-delay: -3s !default;\n$moving-waves-child-6-duration: 30s !default;\n\n// Fade In\n\n$fade-in-animation-name: fadeInBottom !default;\n$fade-in-animation-top-name: fadeInTop !default;\n$fade-in-bottom-transform: translateY(100%) !default;\n$fade-in-top-transform: translateY(-100%) !default;\n\n\n$fade-in-1-animation-duration: 1.5s !default;\n$fade-in-2-animation-duration: 1.75s !default;\n$fade-in-3-animation-duration: 2s !default;\n$fade-in-4-animation-duration: 2.25s !default;\n$fade-in-5-animation-duration: 2.5s !default;\n\n\n$floating-man-width: 350px !default;\n", + "// Avatar\n$avatar-height: 48px !default;\n$avatar-width: 48px !default;\n\n$avatar-xs-height: 24px !default;\n$avatar-xs-width: 24px !default;\n\n$avatar-sm-height: 36px !default;\n$avatar-sm-width: 36px !default;\n\n$avatar-lg-height: 58px !default;\n$avatar-lg-width: 58px !default;\n\n$avatar-xl-height: 74px !default;\n$avatar-xl-width: 74px !default;\n\n$avatar-xxl-height: 110px !default;\n$avatar-xxl-width: 110px !default;\n\n$avatar-font-size: 1rem !default;\n$avatar-content-margin: .75rem !default;\n\n\n// Avatar Group\n$avatar-group-border: 2px !default;\n$avatar-group-zindex: 2 !default;\n$avatar-group-zindex-hover: 3 !default;\n$avatar-group-double: -1rem !default;\n", + "$card-box-shadow: 0 20px 27px 0 rgba(0,0,0,0.05) !default;\n$card-background-blur: rgba(255, 255, 255, 0.8) !default;\n\n$card-header-padding: 1.5rem !default;\n\n$card-body-padding: $card-header-padding !default;\n$card-plain-bg-color: transparent !default;\n$card-plain-box-shadow: none !default;\n\n$card-footer-padding: $card-body-padding !default;\n\n$card-title-font-weight: $font-weight-bold !default;\n$card-title-line-height: 1.2 !default;\n\n$card-author-display: flex !default;\n$card-author-name-line-height: 1.571 !default;\n$card-author-name-color: #3A416F !default;\n$card-author-stats-color: #5D6494 !default;\n$card-avatar-width: 30px !default;\n$card-avatar-height: $card-avatar-width !default;\n$card-avatar-overflow: hidden !default;\n$card-avatar-radius: 50% !default;\n$card-avatar-mr: 5px !default;\n$card-stats-name-mt: -4px !default;\n$card-name-ml: .25rem !default;\n\n$card-badge-text-transform: uppercase !default;\n$card-badge-bg-color: #FAFAFF !default;\n\n\n// Card Background\n$card-bg-align-items: center !default;\n$card-bg-body-position: relative !default;\n$card-bg-body-z-index: 2 !default;\n$card-bg-content-min-height: 330px !default;\n$card-bg-content-max-width: 450px !default;\n$card-bg-content-pt: 60px !default;\n$card-bg-content-pb: $card-bg-content-pt !default;\n$card-bg-body-left-width: 90% !default;\n\n$card-bg-description-margin: 24px !default;\n\n$card-bg-filter-position: absolute !default;\n$card-bg-filter-top: 0 !default;\n$card-bg-filter-bottom: $card-bg-filter-top !default;\n$card-bg-filter-left: $card-bg-filter-top !default;\n$card-bg-filter-height: 100% !default;\n$card-bg-filter-width: $card-bg-filter-height !default;\n$card-bg-filter-z-index: 1 !default;\n$card-bg-filter-display: block !default;\n$card-bg-filter-content: \"\" !default;\n$card-bg-filter-bg: rgba(0,0,0,.4) !default;\n$card-bg-filter-mask-bg: rgba(0,0,0,.2) !default;\n$card-bg-filter-radius: 1rem !default;\n\n$card-full-bg-bg-position: 50% !default;\n$card-full-bg-bg-size: cover !default;\n$card-full-bg-mb: 30px !default;\n$card-full-bg-width: 100% !default;\n$card-full-bg-height: $card-full-bg-width !default;\n$card-full-bg-position: absolute !default;\n$card-full-bg-radius: $card-bg-filter-radius !default;\n", + "$dropdown-subitem-position: 101% !default;\n$dropdown-transition: visibility .25s,opacity .25s,transform .25s !default;\n$dropdown-transform-origin: 50% 0 !default;\n$dropdown-transform: perspective(999px) rotateX(-10deg) translateZ(0) translate3d(0px, 37px, 0px) !important !default;\n$dropdown-transform-show: perspective(999px) rotateX(0deg) translateZ(0) translate3d(0, 37px,5px) !important !default;\n\n$dropdown-multilevel-transform: perspective(999px) rotateX(-10deg) translateZ(0) translate3d(0px, 0px, 0px) !important !default;\n$dropdown-multilevel-transform-show: perspective(999px) rotateX(0deg) translateZ(0) translate3d(0, 0px,5px) !important !default;\n\n$dropup-transform-origin: bottom !default;\n$dropup-transform: perspective(999px) rotateX(12deg) translateZ(0) translate3d(0px, 0px, 0px) !important !default;\n$dropup-transform-show: perspective(999px) rotateX(0deg) translateZ(0) translate3d(1px,0px,5px) !important !default;\n\n$dropdown-icon-margin-right: .75rem !default;\n\n$dropdown-toggle-arrow-transform: rotate(180deg) !default;\n$dropdown-toggle-arrow-transition: .3s ease !default;\n\n$dropdown-button-after-margin-top: 3px !default;\n\n$dropdown-animation-arrow-left-position: 28px !default;\n$dropup-animation-arrow-bottom-position: 22px !default;\n$dropdown-animation-arrow-font-size: 22px !default;\n$dropup-animation-arrow-transition: bottom .35s ease !default;\n$dropdown-animation-arrow-transition: top .35s ease !default;\n$dropup-mb: .5rem !default;\n\n$dropdown-mt: 8px !default;\n$dropdown-hover-after-bottom-pos: -24px !default;\n$dropdown-hover-after-bottom-pos: -24px !default;\n$dropdown-hover-arrow-active-top: -20px !default;\n\n$dropdown-subitem-position-right: -197px !default;\n$dropdown-subitem-left-hover: -8px !default;\n$dropdown-subitem-arrow-rotate: rotate(-90deg) !default;\n\n$dropdown-md-min-width: 15rem !default;\n$dropdown-lg-min-width: 23rem !default;\n$dropdown-lg-width-responsive: 19rem !default;\n$dropdown-xl-min-width: 40rem !default;\n\n$dropdown-subitem-position: 101% !default;\n\n\n// Extend\n$dropdown-subitem-position-right: -197px !default;\n$dropdown-subitem-left-hover: -8px !default;\n$dropdown-subitem-arrow-rotate: rotate(-90deg) !default;\n\n$dropdown-md-min-width: 15rem !default;\n$dropdown-lg-min-width: 23rem !default;\n$dropdown-lg-width-responsive: 19rem !default;\n$dropdown-xl-min-width: 40rem !default;\n", + "$page-header-padding: 0 !default;\n$page-header-position: relative !default;\n$page-header-overflow: hidden !default;\n$page-header-display: flex !default;\n$page-header-align-items: center !default;\n$page-header-bg-size: cover !default;\n$page-header-bg-position: 50% !default;\n\n$mask-position: absolute !default;\n$mask-bg-size: cover !default;\n$mask-bg-position: center center !default;\n$mask-top: 0 !default;\n$mask-left: $mask-top !default;\n$mask-width: 100% !default;\n$mask-height: $mask-width !default;\n$mask-opacity: .8 !default;\n\n$page-header-conteiner-index: 1 !default;\n\n$header-oblique-img-width: 60% !default;\n$header-oblique-img-right: -10rem !default;\n$header-oblique-transform: skewX(-10deg) !default;\n$header-oblique-overflow: hidden !default;\n$header-oblique-img-transform: skewX(10deg) !default;\n", + "$icon-shape-bg-image: linear-gradient(310deg,#7928CA,#FF0080) !default;\n$icon-shape-bg-position: center !default;\n\n$icon-striped-bg-md: 85px !default;\n$icon-striped-bg-lg: 111px !default;\n$icon-striped-bg-xl: 80px !default;\n\n$icon-striped-icon-mt: 25% !default;\n$icon-striped-icon-ml: -24% !default;\n\n$icon-shape-icon-opacity: .8 !default;\n$info-icon-top: 11px !default;\n$info-icon-top-xxs: -4px !default;\n$info-icon-top-xs: -4px !default;\n$info-icon-top-sm: 2px !default;\n$info-icon-top-md: 22% !default;\n$info-icon-top-lg: 31% !default;\n$info-icon-top-xl: 37% !default;\n$info-icon-position: relative !default;\n\n$icon-xxs-width: 20px !default;\n$icon-xxs-height: $icon-xxs-width !default;\n$icon-xs-width: 24px !default;\n$icon-xs-height: $icon-xs-width !default;\n$icon-sm-width: 32px !default;\n$icon-sm-height: $icon-sm-width !default;\n$icon-md-width: 48px !default;\n$icon-md-height: $icon-md-width !default;\n$icon-lg-width: 64px !default;\n$icon-lg-height: $icon-lg-width !default;\n$icon-xl-width: 100px !default;\n$icon-xl-height: $icon-xl-width !default;\n", + "// Navbar toggler icon on responsive styling\n\n$navbar-toggler-bar-display: block !default;\n$navbar-toggler-bar-position: relative !default;\n$navbar-toggler-bar-width: 22px !default;\n$navbar-toggler-bar-height: 1px !default;\n$navbar-toggler-bar-radius: 1px !default;\n$navbar-toggler-bar-transition: all 0.2s !default;\n$navbar-toggler-bar-margin-top: 7px !default;\n\n$navbar-toggler-bar-1-transform: rotate(45deg) !default;\n$navbar-toggler-bar-1-transform-origin: 10% 10% !default;\n$navbar-toggler-bar-1-margin-top: 4px !default;\n$navbar-toggler-bar-2-opacity: 0 !default;\n$navbar-toggler-bar-3-transform: rotate(-45deg) !default;\n$navbar-toggler-bar-3-transform-origin: 10% 90% !default;\n$navbar-toggler-bar-3-margin-top: 3px !default;\n", + "$navbar-light-bg: #FBFBFB !default;\n$navbar-light-hover-bg: darken($gray-100, 5%) !default;\n$navbar-light-active-bg: darken($gray-100, 5%) !default;\n$navbar-light-border-color: rgba($black, .05) !default;\n$navbar-light-color: rgba($black, .6) !default;\n$navbar-light-hover-color: rgba($black, .7) !default;\n$navbar-light-active-color: rgba($black, .9) !default;\n$navbar-light-disabled-color: rgba($black, .3) !default;\n$navbar-light-toggler-border-color: transparent !default;\n// Vertical navbar\n$sidenav-header-width: 4.875rem !default;\n$sidenav-card-opacity: .65 !default;\n$navbar-vertical-box-shadow: 0 0 2rem 0 rgba(136, 152, 170, .15) !default;\n$navbar-vertical-border-color: rgba($black, .05) !default;\n$navbar-vertical-width: 3.875rem !default;\n$navbar-vertical-open-width: 15.625rem !default;\n$navbar-vertical-padding-x: 1rem !default;\n$navbar-vertical-nav-link-padding-x: 1rem !default;\n$navbar-vertical-nav-link-padding-y: .675rem !default;\n$navbar-vertical-sidenav-normal-ml: 4.01rem !default;\n$navbar-vertical-m: 1rem !default;\n$navbar-vertical-inner: calc(100vh - 360px) !default;\n$navbar-icon-min-width: 1.8rem !default;\n$navbar-icon-margin-left: 0.15rem !default;\n$navbar-breadcrumb-padding-y: $nav-link-padding-y !default;\n$navbar-breadcrumb-padding-x: 0 !default;\n$navbar-light-border-color: $border-color !default;\n$navbar-dark-bg: transparent !default;\n$navbar-dark-hover-bg: rgba(255, 255, 255, .1) !default;\n$navbar-dark-active-bg: rgba(255, 255, 255, .1) !default;\n$navbar-dark-border-color: rgba(255, 255, 255, .1) !default;\n$navbar-dark-color: rgba($white, .95) !default;\n$navbar-dark-hover-color: rgba($white, .65) !default;\n$navbar-dark-active-color: rgba($white, .65) !default;\n$navbar-dark-disabled-color: rgba($white, .25) !default;\n$navbar-dark-toggler-border-color: transparent !default;\n$navbar-padding-y: 1rem !default;\n$navbar-padding-x: 1rem !default;\n$navbar-nav-link-padding-x: 1rem !default;\n$navbar-nav-link-padding-y: 1rem !default;\n$navbar-nav-link-font-size: .875rem !default;\n$navbar-nav-link-font-weight: 500 !default;\n$navbar-nav-link-text-transform: normal !default;\n$navbar-nav-link-letter-spacing: 0 !default;\n$navbar-nav-link-border-radius: $border-radius-sm !default;\n$font-size-xs: ($font-size-base * .75);\n$transition-base-time: .25s;\n$transition-cubic-bezier: all $transition-base-time cubic-bezier(.68, -0.55, .265, 1.55) !default;\n\n// Navbar collapse\n\n$navbar-vertical-collapse-dot-size: 5px !default;\n$navbar-vertical-collapse-dot-size-active: 8px !default;\n$navbar-vertical-collapse-margin-left: 1.35rem !default;\n$navbar-vertical-collapse-left: -18px !default;\n$navbar-vertical-collapse-top: 50% !default;\n$navbar-vertical-collapse-translate: translate(0,-50%) !default;\n\n$navbar-vertical-hidden-width: 6rem !default;\n\n// RTL Page\n\n$rtl-sidebar-bullet-right: -1.125rem !default;\n$rtl-sidebar-hover-padding-right: 2.5rem !default;\n", + "// on hover transition variables\n$move-transition: .2s ease-out !default;\n$move-overflow: hidden !default;\n$move-transform: perspective(999px) rotateX(0deg) translate3d(0,0,0) !default;\n$move-transform-origin: 50% 0 !default;\n$move-backface-visibility: hidden !default;\n$move-will-change: transform,box-shadow !default;\n$move-hover-transform: perspective(999px) rotateX(7deg) translate3d(0px,-4px,5px) !default;\n\n// Sections Height Utilities\n$section-height-25-min-height: 25vh !default;\n$section-height-35-min-height: 35vh !default;\n$section-height-45-min-height: 45vh !default;\n$section-height-50-min-height: 50vh !default;\n$section-height-55-min-height: 55vh !default;\n$section-height-65-min-height: 65vh !default;\n$section-height-70-min-height: 70vh !default;\n$section-height-75-min-height: 75vh !default;\n$section-height-80-min-height: 80vh !default;\n$section-height-85-min-height: 85vh !default;\n$section-height-90-min-height: 90vh !default;\n$section-height-95-min-height: 95vh !default;\n$section-height-100-min-height: 100vh !default;\n\n// extra padding utilities variables - CT\n$padding-6: 4rem !default;\n$padding-7: 6rem !default;\n$padding-8: 8rem !default;\n$padding-9: 10rem !default;\n$padding-10: 12rem !default;\n$padding-11: 14rem !default;\n$padding-12: 16rem !default;\n\n// extra margins utilities variables - CT\n$margin-6: 4rem !default;\n$margin-7: 6rem !default;\n$margin-8: 8rem !default;\n$margin-9: 10rem !default;\n$margin-10: 12rem !default;\n$margin-11: 14rem !default;\n$margin-12: 16rem !default;\n\n// extra width values variables - CT\n$width-0: 0% !default;\n$width-1: 1% !default;\n$width-2: 2% !default;\n$width-3: 3% !default;\n$width-4: 4% !default;\n$width-5: 5% !default;\n$width-6: 6% !default;\n$width-7: 7% !default;\n$width-8: 8% !default;\n$width-9: 9% !default;\n$width-10: 10% !default;\n$width-15: 15% !default;\n$width-20: 20% !default;\n$width-25: 25% !default;\n$width-30: 30% !default;\n$width-35: 35% !default;\n$width-40: 40% !default;\n$width-45: 45% !default;\n$width-50: 50% !default;\n$width-55: 55% !default;\n$width-60: 60% !default;\n$width-65: 65% !default;\n$width-70: 70% !default;\n$width-75: 75% !default;\n$width-80: 80% !default;\n$width-85: 85% !default;\n$width-90: 90% !default;\n$width-95: 95% !default;\n$width-100: 100% !default;\n\n// extra max width values variables - CT\n$max-width-100: 100px !default;\n$max-width-200: 200px !default;\n$max-width-300: 300px !default;\n$max-width-400: 400px !default;\n$max-width-500: 500px !default;\n\n// extra height values variables - CT\n$height-100: 100px !default;\n$height-200: 200px !default;\n$height-300: 300px !default;\n$height-400: 400px !default;\n$height-500: 500px !default;\n$height-600: 600px !default;\n\n\n// extra min height values variables - CT\n$min-height-100: 100px !default;\n$min-height-150: 150px !default;\n$min-height-160: 160px !default;\n$min-height-200: 200px !default;\n$min-height-250: 250px !default;\n$min-height-300: 300px !default;\n$min-height-400: 400px !default;\n$min-height-500: 500px !default;\n$min-height-600: 600px !default;\n\n// extra min height values variables - CT\n$max-height-100: 100px !default;\n$max-height-150: 150px !default;\n$max-height-160: 160px !default;\n$max-height-200: 200px !default;\n$max-height-250: 250px !default;\n$max-height-300: 300px !default;\n$max-height-400: 400px !default;\n$max-height-500: 500px !default;\n$max-height-600: 600px !default;\n\n// extra min height vh values variables - CT\n$max-height-vh-10: 10vh !default;\n$max-height-vh-20: 20vh !default;\n$max-height-vh-30: 30vh !default;\n$max-height-vh-40: 40vh !default;\n$max-height-vh-50: 50vh !default;\n$max-height-vh-60: 60vh !default;\n$max-height-vh-70: 70vh !default;\n$max-height-vh-80: 80vh !default;\n$max-height-vh-90: 90vh !default;\n$max-height-vh-100: 100vh !default;\n\n// Extra Padding values Map\n$paddings: (\n \"6\": $padding-6,\n \"7\": $padding-7,\n \"8\": $padding-8,\n \"9\": $padding-9,\n \"10\": $padding-10,\n \"11\": $padding-11,\n \"12\": $padding-12\n) !default;\n\n// Extra Margins values Map\n$margins: (\n \"6\": $margin-6,\n \"7\": $margin-7,\n \"8\": $margin-8,\n \"9\": $margin-9,\n \"10\": $margin-10,\n \"11\": $margin-11,\n \"12\": $margin-12\n) !default;\n\n$width: (\n \"0\": $width-0,\n \"1\": $width-1,\n \"2\": $width-2,\n \"3\": $width-3,\n \"4\": $width-4,\n \"5\": $width-5,\n \"6\": $width-6,\n \"7\": $width-7,\n \"8\": $width-8,\n \"9\": $width-9,\n \"10\": $width-10,\n \"15\": $width-15,\n \"20\": $width-20,\n \"25\": $width-25,\n \"30\": $width-30,\n \"35\": $width-35,\n \"40\": $width-40,\n \"45\": $width-45,\n \"50\": $width-50,\n \"55\": $width-55,\n \"60\": $width-60,\n \"65\": $width-65,\n \"70\": $width-70,\n \"75\": $width-75,\n \"80\": $width-80,\n \"85\": $width-85,\n \"90\": $width-90,\n \"95\": $width-95,\n \"100\": $width-100,\n \"auto\": auto\n) !default;\n\n\n// blur effect variables\n$blur-border-radius-rounded: 40px !default;\n$blur-box-shadow: inset 0px 0px 2px #fefefed1 !default;\n$blur-backdrop-filter: saturate(200%) blur(30px) !default;\n$blur-backdrop-filter-less: saturate(20%) blur(30px) !default;\n\n$shadow-blur-box-shadow: inset 0 0px 1px 1px rgba(254, 254, 254, .9), 0 20px 27px 0 rgba(0, 0, 0, .05) !default;\n\n// sidebar variables\n\n$sidebar-width: 80px !default;\n$sidebar-transition: 1s ease !default;\n", + "// Colores Shadow on cards\n$colored-shadow-top: 3.5% !default;\n$colored-shadow-blur: 12px !default;\n$colored-shadow-scale: .94 !default;\n$colored-shadow-scale-avatar: .87 !default;\n\n// Card Projects\n$card-project-transition: .4s cubic-bezier(.215,.61,.355,1) !default;\n$card-project-avatar-transform: scale(.8) translateY(-45px) !default;\n$card-project-hover-transform: translateY(-2px) !default;\n\n// Transform Perspective effect\n$transform-perspective: scale(1) perspective(1040px) rotateY(-11deg) rotateX(2deg) rotate(2deg) !default;\n$transform-perspective-inverse: scale(1) perspective(1040px) rotateY(11deg) rotateX(-2deg) rotate(-2deg) !default;\n\n// Z index\n$z-index2: 2 !default;\n\n// Width in PX\n$width-32-px: 32px !default;\n$width-48-px: 48px !default;\n$width-64-px: 64px !default;\n", + "// Horizontal Faded Line\n$hr-bg: transparent !default;\n$hr-transform: rotate(90deg) !default;\n$hr-bg-image: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1), rgba(255, 255, 255, 0)) !default;\n$hr-bg-dark-image: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, .4), rgba(0, 0, 0, 0)) !default;\n\n\n// Gradient Animation\n$gradient-animation-background: linear-gradient(-45deg, $info-gradient, $danger, $warning, $primary-gradient, $dark) !default;\n$gradient-animation-bg-size: 400% 400% !default;\n\n// Device Wrapper\n$device-wrapper-radius: 3.5rem !default;\n$device-wrapper-box-shadow: 0 12px 15px rgba(140, 152, 164, 0.1) !default;\n$device-wrapper-animation: gradient 10s ease infinite !default;\n\n\n// Nav pills\n$nav-pills-link-border-radius: 0.5rem !default;\n$nav-pills-link-box-shadow: 0px 1px 5px 1px #ddd !default;\n$nav-pills-link-active-padding: 7px 15px !default;\n$nav-pills-link-active-margin: 1px !default;\n$nav-pills-link-active-animation: .2s ease !default;\n\n// Table Progress\n\n$table-progress-width: 120px !default;\n$table-progress-height: 3px !default;\n$table-progress-margin: 0 !default;\n\n// Tooltip Arrow\n\n$tooltip-arrow-left: 1px !default;\n$tooltip-arrow-right: $tooltip-arrow-left !default;\n\n// Footer Link hover animation\n\n$footer-link-animation: opacity .3 ease !default;\n\n// Blur background\n\n$blur-light-background: rgba(255, 255, 255, 0.4) !default;\n$blur-dark-background: rgba(0, 0, 0, 0.3) !default;\n\n// HR w/ opacity\n\n$hr-bg-color: transparent !default;\n$hr-width: 1px !default;\n$hr-margin: .75rem 0 !default;\n$hr-horizontal-bg-image-light: linear-gradient(to right, rgba(255, 255, 255, 0), white, rgba(255, 255, 255, 0)) !default;\n$hr-horizontal-bg-image-gray-light: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, .1), rgba(0, 0, 0, 0)) !default;\n$hr-horizontal-bg-image-dark: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, .4), rgba(0, 0, 0, 0)) !default;\n$hr-vertical-bg-image-light: linear-gradient(to bottom, rgba(255, 255, 255, 0), white, rgba(255, 255, 255, 0)) !default;\n$hr-vertical-bg-image-dark: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, .4), rgba(0, 0, 0, 0)) !default;\n", + "// Text Border\n$text-border-bg-color: rgba($secondary,.5) !default;\n$text-border-bg-color-before: linear-gradient(90deg,transparent,rgba(117,117,117,.4),rgba(117,117,117,.4)) !default;\n$text-border-bg-color-after: linear-gradient(90deg,rgba(117,117,117,.4),rgba(117,117,117,.4),transparent) !default;\n$text-border-display: inline-block !default;\n$text-border-width: 30% !default;\n$text-border-height: 1px !default;\n$text-border-position: relative !default;\n$text-border-vertical-align: middle !default;\n$text-border-before-right: .5em !default;\n$text-border-before-ml: -50% !default;\n$text-border-after-left: $text-border-before-right !default;\n$text-border-after-mr: $text-border-before-ml !default;\n\n\n// Header Shapes\n\n$shape-1-width: 55% !default;\n$shape-1-left: 15% !default;\n$shape-2-width: 35% !default;\n$shape-2-left: 20% !default;\n$shape-3-width: 50% !default;\n$shape-3-left: -28rem !default;\n\n$shape-img-1-right: 7% !default;\n$shape-img-1-width: 36% !default;\n$shape-img-1-margin-top: 12% !default;\n\n$shape-img-2-left: 24% !default;\n$shape-img-2-width: 27% !default;\n$shape-img-2-margin-top: 10% !default;\n\n// Comming Soon page\n\n$coming-rotate-transform: rotate(20deg) !default;\n\n\n// Tilt Animation\n\n$tilt-transform-style: preserve-3d !default;\n$tilt-transform-up-transform: translateZ(50px) scale(0.7) !default;\n$tilt-transform-up-transition: all 0.5s !default;\n\n// Round Slider\n\n$round-slider-m-width: 200px !default;\n$round-slider-scale-m-width: 300px !default;\n$round-slider-transition: all .5s ease-out 0s !default;\n", + "$slider-dim: 15px !default;\n$slider-position: 2px !default;\n$moving-circle: translateX(21px) !default;\n", + "$fixed-plugin-bottom: 30px !default;\n$fixed-plugin-right: $fixed-plugin-bottom !default;\n$fixed-plugin-radius: 50% !default;\n$fixed-plugin-box-shadow: $navbar-box-shadow !default;\n$fixed-plugin-button-z-index: 990 !default;\n$fixed-plugin-card-z-index: 1020 !default;\n$fixed-plugin-card-width: 360px !default;\n", + "// Pagination\n\n$pagination-active-box-shadow: $btn-hover-box-shadow !default;\n\n$page-link-display: flex !default;\n$page-link-align-items: center !default;\n$page-link-justify-content: $page-link-align-items !default;\n$page-link-margin: 0 3px !default;\n$page-link-radius: 50% !default;\n$page-link-width: 36px !default;\n$page-link-height: $page-link-width !default;\n\n$page-link-width-lg: 46px !default;\n$page-link-height-lg: $page-link-width-lg !default;\n$page-link-line-height-lg: $page-link-width-lg !default;\n\n$page-link-width-sm: 30px !default;\n$page-link-height-sm: $page-link-width-sm !default;\n$page-link-line-height-sm: $page-link-width-sm !default;\n", + "// Badge\n$badge-sm-padding: .45em .775em !default;\n$badge-sm-font-size: .65em !default;\n$badge-md-padding: .65em 1em !default;\n$badge-lg-padding: .85em 1.375em !default;\n$badge-inline-margin-right: .625rem !default;\n$badge-inline-span-top: 2px !default;\n$badge-btn-margin: .5rem !default;\n\n// Badge Circle\n$badge-circle-border-radius: 50% !default;\n$badge-circle-width: 1.25rem !default;\n$badge-circle-height: 1.25rem !default;\n$badge-circle-font-size: .75rem !default;\n$badge-circle-font-weight: 600 !default;\n\n$badge-circle-md-width: 1.5rem !default;\n$badge-circle-md-height: 1.5rem !default;\n\n$badge-circle-lg-width: 2rem !default;\n$badge-circle-lg-height: 2rem !default;\n\n//Badge Dot\n$badge-dot-icon-width: .375rem !default;\n$badge-dot-icon-height: .375rem !default;\n$badge-dot-icon-radius: 50% !default;\n$badge-dot-icon-margin-right: .375rem !default;\n\n$badge-dot-md-icon-width: .5rem !default;\n$badge-dot-md-icon-height: .5rem !default;\n\n$badge-dot-lg-icon-width: .625rem !default;\n$badge-dot-lg-icon-height: .625rem !default;\n\n//Badge Floating\n$badge-floating-top: -50% !default;\n$badge-floating-border: 3px !default;\n$badge-floating-transform: translate(147%, 50%) !default;\n", + "$timeline-step-transform-rtl: translateX(50%) !default;\n", + "// Card Profile\n$card-profile-body-text-align: center !default;\n$card-profile-body-padding: 1.25rem 2rem !default;\n$card-profile-avatar-margin: 0 auto !default;\n$card-profile-img-mt: 32px !default;\n$card-profile-img-radius: 50% !default;\n$card-profile-img-width: 130px !default;\n$card-profile-btn-mt: 24px !default;\n$card-profile-p-line-height: 1.778 !default;\n\n// Card Pricing\n$card-pricing-body-padding: 2.25rem !default;\n$card-pricing-line-height: 1.111 !default;\n$card-pricing-title-mb: $card-bg-description-margin !default;\n$card-pricing-td-line-height: 1.429 !default;\n$card-pricing-icon-height: 4rem !default;\n$card-pricing-icon-width: $card-pricing-icon-height !default;\n$card-pricing-icon-position: absolute !default;\n$card-pricing-icon-top: -22px !default;\n$card-pricing-icon-font-size: 1.25rem !default;\n$card-pricing-icon-lg-font-size: 1.75rem !default;\n$card-pricing-i-padding: 18px !default;\n$card-pricing-badge-padding: 5px !default;\n$card-pricing-badge-font-size: 6px !default;\n$card-pricing-badge-position: relative !default;\n$card-pricing-badge-top: -2px !default;\n$card-pricing-border-color: linear-gradient(to right, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));\n$card-pricing-border-color-dark: linear-gradient(to right, rgba(0, 0, 0, 0), rgba(0, 0, 0, .4), rgba(0, 0, 0, 0));\n", + "$choices-box-shadow: $dropdown-box-shadow !default;\n$choices-border-radius: .5rem !default;\n$choices-animation: .3s cubic-bezier(.23,1,.32,1) !default;\n$choices-transition: $dropdown-transition !default;\n$choices-transform: perspective(999px) rotateX(-10deg) translateZ(0) translate3d(0px, 37px, 0px) !important !default;\n$choices-transform-show: perspective(999px) rotateX(0deg) translateZ(0) translate3d(0,37px,5px) !important !default;\n$choices-padding-y: 1rem !default;\n$choices-padding-x: .5rem !default;\n", + "// Timeline\n\n$timeline-axis-width: 2px !default;\n$timeline-axis-color: $border-color !default;\n$timeline-left: 1rem !default;\n\n$timeline-step-bg: $white !default;\n$timeline-step-width: 26px !default;\n$timeline-step-height: $timeline-step-width !default;\n$timeline-step-radius: 50% !default;\n$timeline-step-transform: translateX(-50%) !default;\n$timeline-step-line-height: 1.4 !default;\n\n$timeline-step-border-width: 2px !default;\n$timeline-step-border-color: $timeline-axis-color !default;\n\n$timeline-content-margin-left: 45px !default;\n$timeline-content-padding-top: .35rem !default;\n$timeline-content-top: -6px !default;\n", + "$fc-event-title-padding-y: .2rem !default;\n$fc-event-title-padding-x: .3rem !default;\n\n$fc-daygrid-event-border-radius: .35rem !default;\n", + "// Social Buttons\n\n$facebook: #3b5998 !default;\n$facebook-states: darken($facebook, 5%) !default;\n$twitter: #55acee !default;\n$twitter-states: darken($twitter, 5%) !default;\n$instagram: #125688 !default;\n$instagram-states: darken($instagram, 6%) !default;\n$linkedin: #0077B5 !default;\n$linkedin-states: darken($linkedin, 5%) !default;\n$pinterest: #cc2127 !default;\n$pinterest-states: darken($pinterest, 6%) !default;\n$youtube: #e52d27 !default;\n$youtube-states: darken($youtube, 6%) !default;\n$dribbble: #ea4c89 !default;\n$dribbble-states: darken($dribbble, 6%) !default;\n$github: #24292E !default;\n$github-states: darken($github, 6%) !default;\n$reddit: #ff4500 !default;\n$reddit-states: darken($reddit, 6%) !default;\n$tumblr: #35465c !default;\n$tumblr-states: darken($tumblr, 6%) !default;\n$behance: #1769ff !default;\n$behance-states: darken($behance, 6%) !default;\n$vimeo: #1AB7EA !default;\n$vimeo-states: darken($vimeo, 6%) !default;\n$slack: #3aaf85 !default;\n$slack-states: darken($slack, 6%) !default;\n", + "$animation-name: fadeInBottom !default;\n$animation-mode: both !default;\n$animation-duration: 1.5s !default;\n$transform-scale: scale(0.6) !default;\n$position-left: 18% !default; \n", + "@import \"../bootstrap/functions\";\n@import \"../bootstrap/variables\";\n@import \"../bootstrap/utilities\";\n\n$utilities: (\n // scss-docs-start utils-vertical-align\n \"align\": (\n property: vertical-align,\n class: align,\n values: baseline top middle bottom text-bottom text-top\n ),\n // scss-docs-end utils-vertical-align\n // scss-docs-start utils-float\n \"float\": (\n responsive: true,\n property: float,\n values: (\n start: left,\n end: right,\n none: none,\n )\n ),\n // scss-docs-end utils-float\n // scss-docs-start utils-overflow\n \"overflow\": (\n property: overflow,\n values: auto hidden visible scroll,\n ),\n // scss-docs-end utils-overflow\n // scss-docs-start utils-display\n \"display\": (\n responsive: true,\n print: true,\n property: display,\n class: d,\n values: inline inline-block block grid table table-row table-cell flex inline-flex none\n ),\n // scss-docs-end utils-display\n // scss-docs-start utils-shadow\n \"shadow\": (\n property: box-shadow,\n class: shadow,\n values: (\n null: $box-shadow,\n sm: $box-shadow-sm,\n lg: $box-shadow-lg,\n xl: $box-shadow-xl,\n none: none,\n )\n ),\n // scss-docs-end utils-shadow\n // scss-docs-start utils-position\n \"position\": (\n property: position,\n values: static relative absolute fixed sticky\n ),\n \"top\": (\n property: top,\n values: $position-values\n ),\n \"bottom\": (\n property: bottom,\n values: $position-values\n ),\n \"start\": (\n property: left,\n class: start,\n values: $position-values\n ),\n \"end\": (\n property: right,\n class: end,\n values: $position-values\n ),\n \"translate-middle\": (\n property: transform,\n class: translate-middle,\n values: (\n null: translate(-50%, -50%),\n x: translateX(-50%),\n y: translateY(-50%),\n )\n ),\n //Scale\n \"transform\": (\n property: transform,\n class: transform-scale,\n responsive: true,\n values: (\n 5: scale(.5),\n 6: scale(.6),\n 7: scale(.7),\n 8: scale(.8),\n 9: scale(.9),\n 10: scale(1),\n )\n ),\n // scss-docs-end utils-position\n // scss-docs-start utils-borders\n \"border\": (\n property: border,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-top\": (\n property: border-top,\n responsive: true,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-end\": (\n property: border-right,\n responsive: true,\n class: border-end,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-bottom\": (\n property: border-bottom,\n responsive: true,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-start\": (\n property: border-left,\n responsive: true,\n class: border-start,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-color\": (\n property: border-color,\n class: border,\n values: map-merge($theme-colors, (\"white\": $white))\n ),\n \"border-width\": (\n property: border-width,\n class: border,\n values: $border-widths\n ),\n // scss-docs-end utils-borders\n // Sizing utilities\n // scss-docs-start utils-sizing\n \"width\": (\n property: width,\n responsive: true,\n class: w,\n values: $width\n ),\n \"max-width\": (\n property: max-width,\n class: mw,\n values: (100: 100%)\n ),\n \"viewport-width\": (\n property: width,\n class: vw,\n values: (100: 100vw)\n ),\n \"min-viewport-width\": (\n property: min-width,\n class: min-vw,\n values: (100: 100vw)\n ),\n \"height\": (\n property: height,\n class: h,\n values: (\n 25: 25%,\n 50: 50%,\n 75: 75%,\n 100: 100%,\n auto: auto\n )\n ),\n \"max-height\": (\n property: max-height,\n class: mh,\n values: (100: 100%)\n ),\n \"viewport-height\": (\n property: height,\n class: vh,\n values: (100: 100vh)\n ),\n \"min-viewport-height\": (\n property: min-height,\n class: min-vh,\n values: (\n 25: $section-height-25-min-height,\n 35: $section-height-35-min-height,\n 45: $section-height-45-min-height,\n 50: $section-height-50-min-height,\n 55: $section-height-55-min-height,\n 65: $section-height-65-min-height,\n 70: $section-height-70-min-height,\n 75: $section-height-75-min-height,\n 80: $section-height-80-min-height,\n 85: $section-height-85-min-height,\n 90: $section-height-90-min-height,\n 95: $section-height-95-min-height,\n 100: 100vh\n )\n ),\n // scss-docs-end utils-sizing\n // Flex utilities\n // scss-docs-start utils-flex\n \"flex\": (\n responsive: true,\n property: flex,\n values: (fill: 1 1 auto)\n ),\n \"flex-direction\": (\n responsive: true,\n property: flex-direction,\n class: flex,\n values: row column row-reverse column-reverse\n ),\n \"flex-grow\": (\n responsive: true,\n property: flex-grow,\n class: flex,\n values: (\n grow-0: 0,\n grow-1: 1,\n )\n ),\n \"flex-shrink\": (\n responsive: true,\n property: flex-shrink,\n class: flex,\n values: (\n shrink-0: 0,\n shrink-1: 1,\n )\n ),\n \"flex-wrap\": (\n responsive: true,\n property: flex-wrap,\n class: flex,\n values: wrap nowrap wrap-reverse\n ),\n \"gap\": (\n responsive: true,\n property: gap,\n class: gap,\n values: $spacers\n ),\n \"justify-content\": (\n responsive: true,\n property: justify-content,\n values: (\n start: flex-start,\n end: flex-end,\n center: center,\n between: space-between,\n around: space-around,\n evenly: space-evenly,\n )\n ),\n \"align-items\": (\n responsive: true,\n property: align-items,\n values: (\n start: flex-start,\n end: flex-end,\n center: center,\n baseline: baseline,\n stretch: stretch,\n )\n ),\n \"align-content\": (\n responsive: true,\n property: align-content,\n values: (\n start: flex-start,\n end: flex-end,\n center: center,\n between: space-between,\n around: space-around,\n stretch: stretch,\n )\n ),\n \"align-self\": (\n responsive: true,\n property: align-self,\n values: (\n auto: auto,\n start: flex-start,\n end: flex-end,\n center: center,\n baseline: baseline,\n stretch: stretch,\n )\n ),\n \"order\": (\n responsive: true,\n property: order,\n values: (\n first: -1,\n 0: 0,\n 1: 1,\n 2: 2,\n 3: 3,\n 4: 4,\n 5: 5,\n last: 6,\n ),\n ),\n // scss-docs-end utils-flex\n // Margin utilities\n // scss-docs-start utils-spacing\n \"margin\": (\n responsive: true,\n property: margin,\n class: m,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-x\": (\n responsive: true,\n property: margin-right margin-left,\n class: mx,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-y\": (\n responsive: true,\n property: margin-top margin-bottom,\n class: my,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-top\": (\n responsive: true,\n property: margin-top,\n class: mt,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-end\": (\n responsive: true,\n property: margin-right,\n class: me,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-bottom\": (\n responsive: true,\n property: margin-bottom,\n class: mb,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-start\": (\n responsive: true,\n property: margin-left,\n class: ms,\n values: map-merge($spacers, (auto: auto))\n ),\n // Negative margin utilities\n \"negative-margin\": (\n responsive: true,\n property: margin,\n class: m,\n values: $negative-spacers\n ),\n \"negative-margin-x\": (\n responsive: true,\n property: margin-right margin-left,\n class: mx,\n values: $negative-spacers\n ),\n \"negative-margin-y\": (\n responsive: true,\n property: margin-top margin-bottom,\n class: my,\n values: $negative-spacers\n ),\n \"negative-margin-top\": (\n responsive: true,\n property: margin-top,\n class: mt,\n values: $negative-spacers\n ),\n \"negative-margin-end\": (\n responsive: true,\n property: margin-right,\n class: me,\n values: $negative-spacers\n ),\n \"negative-margin-bottom\": (\n responsive: true,\n property: margin-bottom,\n class: mb,\n values: $negative-spacers\n ),\n \"negative-margin-start\": (\n responsive: true,\n property: margin-left,\n class: ms,\n values: $negative-spacers\n ),\n // Padding utilities\n \"padding\": (\n responsive: true,\n property: padding,\n class: p,\n values: $spacers\n ),\n \"padding-x\": (\n responsive: true,\n property: padding-right padding-left,\n class: px,\n values: $spacers\n ),\n \"padding-y\": (\n responsive: true,\n property: padding-top padding-bottom,\n class: py,\n values: $spacers\n ),\n \"padding-top\": (\n responsive: true,\n property: padding-top,\n class: pt,\n values: $spacers\n ),\n \"padding-end\": (\n responsive: true,\n property: padding-right,\n class: pe,\n values: $spacers\n ),\n \"padding-bottom\": (\n responsive: true,\n property: padding-bottom,\n class: pb,\n values: $spacers\n ),\n \"padding-start\": (\n responsive: true,\n property: padding-left,\n class: ps,\n values: $spacers\n ),\n // scss-docs-end utils-spacing\n // Text\n // scss-docs-start utils-text\n \"font-family\": (\n property: font-family,\n class: font,\n values: (monospace: var(--#{$variable-prefix}font-monospace))\n ),\n \"font-size\": (\n rfs: true,\n property: font-size,\n class: fs,\n values: $font-sizes\n ),\n \"font-style\": (\n property: font-style,\n class: fst,\n values: italic normal\n ),\n \"font-weight\": (\n property: font-weight,\n class: fw,\n values: (\n light: $font-weight-light,\n lighter: $font-weight-lighter,\n normal: $font-weight-normal,\n bold: $font-weight-bold,\n bolder: $font-weight-bolder\n )\n ),\n \"line-height\": (\n property: line-height,\n class: lh,\n values: (\n 1: 1,\n sm: $line-height-sm,\n base: $line-height-base,\n lg: $line-height-lg,\n )\n ),\n \"text-align\": (\n responsive: true,\n property: text-align,\n class: text,\n values: (\n start: left,\n end: right,\n center: center,\n )\n ),\n \"text-decoration\": (\n property: text-decoration,\n values: none underline line-through\n ),\n \"text-transform\": (\n property: text-transform,\n class: text,\n values: lowercase uppercase capitalize\n ),\n \"white-space\": (\n property: white-space,\n class: text,\n values: (\n wrap: normal,\n nowrap: nowrap,\n )\n ),\n \"word-wrap\": (\n property: word-wrap word-break,\n class: text,\n values: (break: break-word),\n rtl: false\n ),\n // scss-docs-end utils-text\n // scss-docs-start utils-color\n \"color\": (\n property: color,\n class: text,\n values: map-merge(\n $theme-colors,\n (\n \"white\": $white,\n \"body\": $body-color,\n \"muted\": $text-muted,\n \"black-50\": rgba($black, .5),\n \"white-50\": rgba($white, .5),\n \"reset\": inherit,\n )\n )\n ),\n // scss-docs-end utils-color\n // scss-docs-start utils-bg-color\n \"background-color\": (\n property: background-color,\n class: bg,\n values: map-merge(\n $theme-colors,\n (\n \"body\": $body-bg,\n \"white\": $white,\n \"transparent\": transparent,\n \"gray-100\": $gray-100,\n \"gray-200\": $gray-200,\n \"gray-300\": $gray-300,\n \"gray-400\": $gray-400,\n \"gray-500\": $gray-500,\n \"gray-600\": $gray-600,\n \"gray-700\": $gray-700,\n \"gray-800\": $gray-800,\n \"gray-900\": $gray-900,\n )\n )\n ),\n // scss-docs-end utils-bg-color\n \"gradient\": (\n property: background-image,\n class: bg,\n values: (gradient: var(--#{$variable-prefix}gradient))\n ),\n // scss-docs-start utils-interaction\n \"user-select\": (\n property: user-select,\n values: all auto none\n ),\n \"pointer-events\": (\n property: pointer-events,\n class: pe,\n values: none auto,\n ),\n // scss-docs-end utils-interaction\n // scss-docs-start utils-border-radius\n \"rounded\": (\n property: border-radius,\n class: rounded,\n values: (\n null: $border-radius,\n 0: 0,\n 1: $border-radius-sm,\n 2: $border-radius,\n 3: $border-radius-lg,\n circle: 50%,\n pill: $border-radius-pill\n )\n ),\n \"rounded-top\": (\n property: border-top-left-radius border-top-right-radius,\n class: rounded-top,\n values: (null: $border-radius)\n ),\n \"rounded-end\": (\n property: border-top-right-radius border-bottom-right-radius,\n class: rounded-end,\n values: (null: $border-radius)\n ),\n \"rounded-bottom\": (\n property: border-bottom-right-radius border-bottom-left-radius,\n class: rounded-bottom,\n values: (null: $border-radius)\n ),\n \"rounded-start\": (\n property: border-bottom-left-radius border-top-left-radius,\n class: rounded-start,\n values: (null: $border-radius)\n ),\n // scss-docs-end utils-border-radius\n // scss-docs-start utils-visibility\n \"visibility\": (\n property: visibility,\n class: null,\n values: (\n visible: visible,\n invisible: hidden,\n )\n ),\n // Opacity utilities\n \"opacity\": (\n property: opacity,\n values: (\n 0: 0,\n 1: .1,\n 2: .2,\n 3: .3,\n 4: .4,\n 5: .5,\n 6: .6,\n 7: .7,\n 8: .8,\n 9: .9,\n 10: 1\n ),\n ),\n // Z-index utilities\n \"z-index\": (\n property: z-index,\n values: (\n 0: 0,\n 1: 1,\n 2: 2,\n 3: 3\n ),\n ),\n // Letter spacing utilities\n \"letter-spacing\": (\n property: letter-spacing,\n values: (\n 1: 1px,\n 2: 2px,\n 3: 3px,\n 4: 4px,\n 5: 5px\n ),\n ),\n// Border radius utilities\n\"border-top-left-radius\": (\n property: border-top-left-radius,\n class: border-radius-top-start,\n responsive: true,\n values: (\n 0: 0\n )\n ),\n \"border-top-right-radius\": (\n property: border-top-right-radius,\n class: border-radius-top-end,\n responsive: true,\n values: (\n 0: 0\n )\n ),\n \"border-bottom-left-radius\": (\n property: border-bottom-left-radius,\n class: border-radius-bottom-start,\n responsive: true,\n values: (\n 0: 0\n )\n ),\n \"border-bottom-right-radius\": (\n property: border-bottom-right-radius,\n class: border-radius-bottom-end,\n responsive: true,\n values: (\n 0: 0\n )\n ),\n // Max Height Values\n \"max-height-px\": (\n property: max-height,\n class: max-height,\n values: (\n 100: $max-height-100,\n 150: $max-height-150,\n 160: $max-height-160,\n 200: $max-height-200,\n 250: $max-height-250,\n 300: $max-height-300,\n 400: $max-height-400,\n 500: $max-height-500,\n 600: $max-height-600\n )\n ),\n // Max Height Values vh\n \"max-height-vh\": (\n property: max-height,\n class: max-height-vh,\n values: (\n 10: $max-height-vh-10,\n 20: $max-height-vh-20,\n 30: $max-height-vh-30,\n 40: $max-height-vh-40,\n 50: $max-height-vh-50,\n 60: $max-height-vh-60,\n 70: $max-height-vh-70,\n 80: $max-height-vh-80,\n 90: $max-height-vh-90,\n 100: $max-height-vh-100,\n )\n ),\n // Min Height Values\n \"min-height-px\": (\n property: min-height,\n class: min-height,\n values: (\n 100: $min-height-100,\n 150: $min-height-150,\n 160: $min-height-160,\n 200: $min-height-200,\n 250: $min-height-250,\n 300: $min-height-300,\n 400: $min-height-400,\n 500: $min-height-500,\n 600: $min-height-600\n )\n ),\n // Height Values\n \"height-px\": (\n property: height,\n class: height,\n values: (\n 100: $height-100,\n 200: $height-200,\n 300: $height-300,\n 400: $height-400,\n 500: $height-500,\n 600: $height-600\n )\n ),\n // Max Width Values\n \"max-width-px\": (\n property: max-width,\n class: max-width,\n values: (\n 100: $max-width-100,\n 200: $max-width-200,\n 300: $max-width-300,\n 400: $max-width-400,\n 500: $max-width-500\n )\n ),\n);\n", + "// Bootstrap functions\n//\n// Utility mixins and functions for evaluating source code across our variables, maps, and mixins.\n\n// Ascending\n// Used to evaluate Sass maps like our grid breakpoints.\n@mixin _assert-ascending($map, $map-name) {\n $prev-key: null;\n $prev-num: null;\n @each $key, $num in $map {\n @if $prev-num == null or unit($num) == \"%\" or unit($prev-num) == \"%\" {\n // Do nothing\n } @else if not comparable($prev-num, $num) {\n @warn \"Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !\";\n } @else if $prev-num >= $num {\n @warn \"Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !\";\n }\n $prev-key: $key;\n $prev-num: $num;\n }\n}\n\n// Starts at zero\n// Used to ensure the min-width of the lowest breakpoint starts at 0.\n@mixin _assert-starts-at-zero($map, $map-name: \"$grid-breakpoints\") {\n @if length($map) > 0 {\n $values: map-values($map);\n $first-value: nth($values, 1);\n @if $first-value != 0 {\n @warn \"First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}.\";\n }\n }\n}\n\n// Colors\n@function to-rgb($value) {\n @return red($value), green($value), blue($value);\n}\n\n@function rgba-css-var($identifier, $target) {\n @return rgba(var(--#{$variable-prefix}#{$identifier}-rgb), var(--#{$variable-prefix}#{$target}-opacity));\n}\n\n// stylelint-disable scss/dollar-variable-pattern\n@function map-loop($map, $func, $args...) {\n $_map: ();\n\n @each $key, $value in $map {\n // allow to pass the $key and $value of the map as an function argument\n $_args: ();\n @each $arg in $args {\n $_args: append($_args, if($arg == \"$key\", $key, if($arg == \"$value\", $value, $arg)));\n }\n\n $_map: map-merge($_map, ($key: call(get-function($func), $_args...)));\n }\n\n @return $_map;\n}\n// stylelint-enable scss/dollar-variable-pattern\n\n@function varify($list) {\n $result: null;\n @each $entry in $list {\n $result: append($result, var(--#{$variable-prefix}#{$entry}), space);\n }\n @return $result;\n}\n\n// Internal Bootstrap function to turn maps into its negative variant.\n// It prefixes the keys with `n` and makes the value negative.\n@function negativify-map($map) {\n $result: ();\n @each $key, $value in $map {\n @if $key != 0 {\n $result: map-merge($result, (\"n\" + $key: (-$value)));\n }\n }\n @return $result;\n}\n\n// Get multiple keys from a sass map\n@function map-get-multiple($map, $values) {\n $result: ();\n @each $key, $value in $map {\n @if (index($values, $key) != null) {\n $result: map-merge($result, ($key: $value));\n }\n }\n @return $result;\n}\n\n// Merge multiple maps\n@function map-merge-multiple($maps...) {\n $merged-maps: ();\n\n @each $map in $maps {\n $merged-maps: map-merge($merged-maps, $map);\n }\n @return $merged-maps;\n}\n\n// Replace `$search` with `$replace` in `$string`\n// Used on our SVG icon backgrounds for custom forms.\n//\n// @author Hugo Giraudel\n// @param {String} $string - Initial string\n// @param {String} $search - Substring to replace\n// @param {String} $replace ('') - New value\n// @return {String} - Updated string\n@function str-replace($string, $search, $replace: \"\") {\n $index: str-index($string, $search);\n\n @if $index {\n @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);\n }\n\n @return $string;\n}\n\n// See https://codepen.io/kevinweber/pen/dXWoRw\n//\n// Requires the use of quotes around data URIs.\n\n@function escape-svg($string) {\n @if str-index($string, \"data:image/svg+xml\") {\n @each $char, $encoded in $escaped-characters {\n // Do not escape the url brackets\n @if str-index($string, \"url(\") == 1 {\n $string: url(\"#{str-replace(str-slice($string, 6, -3), $char, $encoded)}\");\n } @else {\n $string: str-replace($string, $char, $encoded);\n }\n }\n }\n\n @return $string;\n}\n\n// Color contrast\n// See https://github.com/twbs/bootstrap/pull/30168\n\n// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255)\n// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern\n$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1;\n\n@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) {\n $foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black;\n $max-ratio: 0;\n $max-ratio-color: null;\n\n @each $color in $foregrounds {\n $contrast-ratio: contrast-ratio($background, $color);\n @if $contrast-ratio > $min-contrast-ratio {\n @return $color;\n } @else if $contrast-ratio > $max-ratio {\n $max-ratio: $contrast-ratio;\n $max-ratio-color: $color;\n }\n }\n\n @warn \"Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}...\";\n\n @return $max-ratio-color;\n}\n\n@function contrast-ratio($background, $foreground: $color-contrast-light) {\n $l1: luminance($background);\n $l2: luminance(opaque($background, $foreground));\n\n @return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05));\n}\n\n// Return WCAG2.0 relative luminance\n// See https://www.w3.org/WAI/GL/wiki/Relative_luminance\n// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests\n@function luminance($color) {\n $rgb: (\n \"r\": red($color),\n \"g\": green($color),\n \"b\": blue($color)\n );\n\n @each $name, $value in $rgb {\n $value: if(divide($value, 255) < .03928, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));\n $rgb: map-merge($rgb, ($name: $value));\n }\n\n @return (map-get($rgb, \"r\") * .2126) + (map-get($rgb, \"g\") * .7152) + (map-get($rgb, \"b\") * .0722);\n}\n\n// Return opaque color\n// opaque(#fff, rgba(0, 0, 0, .5)) => #808080\n@function opaque($background, $foreground) {\n @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100);\n}\n\n// scss-docs-start color-functions\n// Tint a color: mix a color with white\n@function tint-color($color, $weight) {\n @return mix(white, $color, $weight);\n}\n\n// Shade a color: mix a color with black\n@function shade-color($color, $weight) {\n @return mix(black, $color, $weight);\n}\n\n// Shade the color if the weight is positive, else tint it\n@function shift-color($color, $weight) {\n @return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight));\n}\n// scss-docs-end color-functions\n\n// Return valid calc\n@function add($value1, $value2, $return-calc: true) {\n @if $value1 == null {\n @return $value2;\n }\n\n @if $value2 == null {\n @return $value1;\n }\n\n @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {\n @return $value1 + $value2;\n }\n\n @return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(\" + \") + $value2);\n}\n\n@function subtract($value1, $value2, $return-calc: true) {\n @if $value1 == null and $value2 == null {\n @return null;\n }\n\n @if $value1 == null {\n @return -$value2;\n }\n\n @if $value2 == null {\n @return $value1;\n }\n\n @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {\n @return $value1 - $value2;\n }\n\n @if type-of($value2) != number {\n $value2: unquote(\"(\") + $value2 + unquote(\")\");\n }\n\n @return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(\" - \") + $value2);\n}\n\n@function divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n $remainder: $dividend;\n $result: 0;\n $factor: 10;\n @while ($remainder > 0 and $precision >= 0) {\n $quotient: 0;\n @while ($remainder >= $divisor) {\n $remainder: $remainder - $divisor;\n $quotient: $quotient + 1;\n }\n $result: $result * 10 + $quotient;\n $factor: $factor * .1;\n $remainder: $remainder * 10;\n $precision: $precision - 1;\n @if ($precision < 0 and $remainder >= $divisor * 5) {\n $result: $result + 1;\n }\n }\n $result: $result * $factor * $sign;\n $dividend-unit: unit($dividend);\n $divisor-unit: unit($divisor);\n $unit-map: (\n \"px\": 1px,\n \"rem\": 1rem,\n \"em\": 1em,\n \"%\": 1%\n );\n @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {\n $result: $result * map-get($unit-map, $dividend-unit);\n }\n @return $result;\n}\n", + "// Variables\n//\n// Variables should follow the `$component-state-property-size` formula for\n// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.\n\n// Color system\n\n// scss-docs-start gray-color-variables\n$white: #fff !default;\n$gray-100: #f8f9fa !default;\n$gray-200: #e9ecef !default;\n$gray-300: #dee2e6 !default;\n$gray-400: #ced4da !default;\n$gray-500: #adb5bd !default;\n$gray-600: #6c757d !default;\n$gray-700: #495057 !default;\n$gray-800: #343a40 !default;\n$gray-900: #212529 !default;\n$black: #000 !default;\n// scss-docs-end gray-color-variables\n\n// fusv-disable\n// scss-docs-start gray-colors-map\n$grays: (\n \"100\": $gray-100,\n \"200\": $gray-200,\n \"300\": $gray-300,\n \"400\": $gray-400,\n \"500\": $gray-500,\n \"600\": $gray-600,\n \"700\": $gray-700,\n \"800\": $gray-800,\n \"900\": $gray-900\n) !default;\n// scss-docs-end gray-colors-map\n// fusv-enable\n\n// scss-docs-start color-variables\n$blue: #0d6efd !default;\n$indigo: #6610f2 !default;\n$purple: #6f42c1 !default;\n$pink: #d63384 !default;\n$red: #dc3545 !default;\n$orange: #fd7e14 !default;\n$yellow: #ffc107 !default;\n$green: #198754 !default;\n$teal: #20c997 !default;\n$cyan: #0dcaf0 !default;\n// scss-docs-end color-variables\n\n// scss-docs-start colors-map\n$colors: (\n \"blue\": $blue,\n \"indigo\": $indigo,\n \"purple\": $purple,\n \"pink\": $pink,\n \"red\": $red,\n \"orange\": $orange,\n \"yellow\": $yellow,\n \"green\": $green,\n \"teal\": $teal,\n \"cyan\": $cyan,\n \"white\": $white,\n \"gray\": $gray-600,\n \"gray-dark\": $gray-800\n) !default;\n// scss-docs-end colors-map\n\n// scss-docs-start theme-color-variables\n$primary: $blue !default;\n$secondary: $gray-600 !default;\n$success: $green !default;\n$info: $cyan !default;\n$warning: $yellow !default;\n$danger: $red !default;\n$light: $gray-100 !default;\n$dark: $gray-900 !default;\n// scss-docs-end theme-color-variables\n\n// scss-docs-start theme-colors-map\n$theme-colors: (\n \"primary\": $primary,\n \"secondary\": $secondary,\n \"success\": $success,\n \"info\": $info,\n \"warning\": $warning,\n \"danger\": $danger,\n \"light\": $light,\n \"dark\": $dark\n) !default;\n// scss-docs-end theme-colors-map\n\n// scss-docs-start theme-colors-rgb\n$theme-colors-rgb: map-loop($theme-colors, to-rgb, \"$value\") !default;\n// scss-docs-end theme-colors-rgb\n\n// The contrast ratio to reach against white, to determine if color changes from \"light\" to \"dark\". Acceptable values for WCAG 2.0 are 3, 4.5 and 7.\n// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast\n$min-contrast-ratio: 4.5 !default;\n\n// Customize the light and dark text colors for use in our color contrast function.\n$color-contrast-dark: $black !default;\n$color-contrast-light: $white !default;\n\n// fusv-disable\n$blue-100: tint-color($blue, 80%) !default;\n$blue-200: tint-color($blue, 60%) !default;\n$blue-300: tint-color($blue, 40%) !default;\n$blue-400: tint-color($blue, 20%) !default;\n$blue-500: $blue !default;\n$blue-600: shade-color($blue, 20%) !default;\n$blue-700: shade-color($blue, 40%) !default;\n$blue-800: shade-color($blue, 60%) !default;\n$blue-900: shade-color($blue, 80%) !default;\n\n$indigo-100: tint-color($indigo, 80%) !default;\n$indigo-200: tint-color($indigo, 60%) !default;\n$indigo-300: tint-color($indigo, 40%) !default;\n$indigo-400: tint-color($indigo, 20%) !default;\n$indigo-500: $indigo !default;\n$indigo-600: shade-color($indigo, 20%) !default;\n$indigo-700: shade-color($indigo, 40%) !default;\n$indigo-800: shade-color($indigo, 60%) !default;\n$indigo-900: shade-color($indigo, 80%) !default;\n\n$purple-100: tint-color($purple, 80%) !default;\n$purple-200: tint-color($purple, 60%) !default;\n$purple-300: tint-color($purple, 40%) !default;\n$purple-400: tint-color($purple, 20%) !default;\n$purple-500: $purple !default;\n$purple-600: shade-color($purple, 20%) !default;\n$purple-700: shade-color($purple, 40%) !default;\n$purple-800: shade-color($purple, 60%) !default;\n$purple-900: shade-color($purple, 80%) !default;\n\n$pink-100: tint-color($pink, 80%) !default;\n$pink-200: tint-color($pink, 60%) !default;\n$pink-300: tint-color($pink, 40%) !default;\n$pink-400: tint-color($pink, 20%) !default;\n$pink-500: $pink !default;\n$pink-600: shade-color($pink, 20%) !default;\n$pink-700: shade-color($pink, 40%) !default;\n$pink-800: shade-color($pink, 60%) !default;\n$pink-900: shade-color($pink, 80%) !default;\n\n$red-100: tint-color($red, 80%) !default;\n$red-200: tint-color($red, 60%) !default;\n$red-300: tint-color($red, 40%) !default;\n$red-400: tint-color($red, 20%) !default;\n$red-500: $red !default;\n$red-600: shade-color($red, 20%) !default;\n$red-700: shade-color($red, 40%) !default;\n$red-800: shade-color($red, 60%) !default;\n$red-900: shade-color($red, 80%) !default;\n\n$orange-100: tint-color($orange, 80%) !default;\n$orange-200: tint-color($orange, 60%) !default;\n$orange-300: tint-color($orange, 40%) !default;\n$orange-400: tint-color($orange, 20%) !default;\n$orange-500: $orange !default;\n$orange-600: shade-color($orange, 20%) !default;\n$orange-700: shade-color($orange, 40%) !default;\n$orange-800: shade-color($orange, 60%) !default;\n$orange-900: shade-color($orange, 80%) !default;\n\n$yellow-100: tint-color($yellow, 80%) !default;\n$yellow-200: tint-color($yellow, 60%) !default;\n$yellow-300: tint-color($yellow, 40%) !default;\n$yellow-400: tint-color($yellow, 20%) !default;\n$yellow-500: $yellow !default;\n$yellow-600: shade-color($yellow, 20%) !default;\n$yellow-700: shade-color($yellow, 40%) !default;\n$yellow-800: shade-color($yellow, 60%) !default;\n$yellow-900: shade-color($yellow, 80%) !default;\n\n$green-100: tint-color($green, 80%) !default;\n$green-200: tint-color($green, 60%) !default;\n$green-300: tint-color($green, 40%) !default;\n$green-400: tint-color($green, 20%) !default;\n$green-500: $green !default;\n$green-600: shade-color($green, 20%) !default;\n$green-700: shade-color($green, 40%) !default;\n$green-800: shade-color($green, 60%) !default;\n$green-900: shade-color($green, 80%) !default;\n\n$teal-100: tint-color($teal, 80%) !default;\n$teal-200: tint-color($teal, 60%) !default;\n$teal-300: tint-color($teal, 40%) !default;\n$teal-400: tint-color($teal, 20%) !default;\n$teal-500: $teal !default;\n$teal-600: shade-color($teal, 20%) !default;\n$teal-700: shade-color($teal, 40%) !default;\n$teal-800: shade-color($teal, 60%) !default;\n$teal-900: shade-color($teal, 80%) !default;\n\n$cyan-100: tint-color($cyan, 80%) !default;\n$cyan-200: tint-color($cyan, 60%) !default;\n$cyan-300: tint-color($cyan, 40%) !default;\n$cyan-400: tint-color($cyan, 20%) !default;\n$cyan-500: $cyan !default;\n$cyan-600: shade-color($cyan, 20%) !default;\n$cyan-700: shade-color($cyan, 40%) !default;\n$cyan-800: shade-color($cyan, 60%) !default;\n$cyan-900: shade-color($cyan, 80%) !default;\n\n$blues: (\n \"blue-100\": $blue-100,\n \"blue-200\": $blue-200,\n \"blue-300\": $blue-300,\n \"blue-400\": $blue-400,\n \"blue-500\": $blue-500,\n \"blue-600\": $blue-600,\n \"blue-700\": $blue-700,\n \"blue-800\": $blue-800,\n \"blue-900\": $blue-900\n) !default;\n\n$indigos: (\n \"indigo-100\": $indigo-100,\n \"indigo-200\": $indigo-200,\n \"indigo-300\": $indigo-300,\n \"indigo-400\": $indigo-400,\n \"indigo-500\": $indigo-500,\n \"indigo-600\": $indigo-600,\n \"indigo-700\": $indigo-700,\n \"indigo-800\": $indigo-800,\n \"indigo-900\": $indigo-900\n) !default;\n\n$purples: (\n \"purple-100\": $purple-200,\n \"purple-200\": $purple-100,\n \"purple-300\": $purple-300,\n \"purple-400\": $purple-400,\n \"purple-500\": $purple-500,\n \"purple-600\": $purple-600,\n \"purple-700\": $purple-700,\n \"purple-800\": $purple-800,\n \"purple-900\": $purple-900\n) !default;\n\n$pinks: (\n \"pink-100\": $pink-100,\n \"pink-200\": $pink-200,\n \"pink-300\": $pink-300,\n \"pink-400\": $pink-400,\n \"pink-500\": $pink-500,\n \"pink-600\": $pink-600,\n \"pink-700\": $pink-700,\n \"pink-800\": $pink-800,\n \"pink-900\": $pink-900\n) !default;\n\n$reds: (\n \"red-100\": $red-100,\n \"red-200\": $red-200,\n \"red-300\": $red-300,\n \"red-400\": $red-400,\n \"red-500\": $red-500,\n \"red-600\": $red-600,\n \"red-700\": $red-700,\n \"red-800\": $red-800,\n \"red-900\": $red-900\n) !default;\n\n$oranges: (\n \"orange-100\": $orange-100,\n \"orange-200\": $orange-200,\n \"orange-300\": $orange-300,\n \"orange-400\": $orange-400,\n \"orange-500\": $orange-500,\n \"orange-600\": $orange-600,\n \"orange-700\": $orange-700,\n \"orange-800\": $orange-800,\n \"orange-900\": $orange-900\n) !default;\n\n$yellows: (\n \"yellow-100\": $yellow-100,\n \"yellow-200\": $yellow-200,\n \"yellow-300\": $yellow-300,\n \"yellow-400\": $yellow-400,\n \"yellow-500\": $yellow-500,\n \"yellow-600\": $yellow-600,\n \"yellow-700\": $yellow-700,\n \"yellow-800\": $yellow-800,\n \"yellow-900\": $yellow-900\n) !default;\n\n$greens: (\n \"green-100\": $green-100,\n \"green-200\": $green-200,\n \"green-300\": $green-300,\n \"green-400\": $green-400,\n \"green-500\": $green-500,\n \"green-600\": $green-600,\n \"green-700\": $green-700,\n \"green-800\": $green-800,\n \"green-900\": $green-900\n) !default;\n\n$teals: (\n \"teal-100\": $teal-100,\n \"teal-200\": $teal-200,\n \"teal-300\": $teal-300,\n \"teal-400\": $teal-400,\n \"teal-500\": $teal-500,\n \"teal-600\": $teal-600,\n \"teal-700\": $teal-700,\n \"teal-800\": $teal-800,\n \"teal-900\": $teal-900\n) !default;\n\n$cyans: (\n \"cyan-100\": $cyan-100,\n \"cyan-200\": $cyan-200,\n \"cyan-300\": $cyan-300,\n \"cyan-400\": $cyan-400,\n \"cyan-500\": $cyan-500,\n \"cyan-600\": $cyan-600,\n \"cyan-700\": $cyan-700,\n \"cyan-800\": $cyan-800,\n \"cyan-900\": $cyan-900\n) !default;\n// fusv-enable\n\n// Characters which are escaped by the escape-svg function\n$escaped-characters: (\n (\"<\", \"%3c\"),\n (\">\", \"%3e\"),\n (\"#\", \"%23\"),\n (\"(\", \"%28\"),\n (\")\", \"%29\"),\n) !default;\n\n// Options\n//\n// Quickly modify global styling by enabling or disabling optional features.\n\n$enable-caret: true !default;\n$enable-rounded: true !default;\n$enable-shadows: false !default;\n$enable-gradients: false !default;\n$enable-transitions: true !default;\n$enable-reduced-motion: true !default;\n$enable-smooth-scroll: true !default;\n$enable-grid-classes: true !default;\n$enable-cssgrid: false !default;\n$enable-button-pointers: true !default;\n$enable-rfs: true !default;\n$enable-validation-icons: true !default;\n$enable-negative-margins: false !default;\n$enable-deprecation-messages: true !default;\n$enable-important-utilities: true !default;\n\n// Prefix for :root CSS variables\n\n$variable-prefix: bs- !default;\n\n// Gradient\n//\n// The gradient which is added to components if `$enable-gradients` is `true`\n// This gradient is also added to elements with `.bg-gradient`\n// scss-docs-start variable-gradient\n$gradient: linear-gradient(180deg, rgba($white, .15), rgba($white, 0)) !default;\n// scss-docs-end variable-gradient\n\n// Spacing\n//\n// Control the default styling of most Bootstrap elements by modifying these\n// variables. Mostly focused on spacing.\n// You can add more entries to the $spacers map, should you need more variation.\n\n// scss-docs-start spacer-variables-maps\n$spacer: 1rem !default;\n$spacers: (\n 0: 0,\n 1: $spacer * .25,\n 2: $spacer * .5,\n 3: $spacer,\n 4: $spacer * 1.5,\n 5: $spacer * 3,\n) !default;\n\n$negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default;\n// scss-docs-end spacer-variables-maps\n\n// Position\n//\n// Define the edge positioning anchors of the position utilities.\n\n// scss-docs-start position-map\n$position-values: (\n 0: 0,\n 50: 50%,\n 100: 100%\n) !default;\n// scss-docs-end position-map\n\n// Body\n//\n// Settings for the `` element.\n\n$body-bg: $white !default;\n$body-color: $gray-900 !default;\n$body-text-align: null !default;\n\n// Utilities maps\n//\n// Extends the default `$theme-colors` maps to help create our utilities.\n\n// scss-docs-start utilities-colors\n$utilities-colors: map-merge(\n $theme-colors-rgb,\n (\n \"black\": to-rgb($black),\n \"white\": to-rgb($white),\n \"body\": to-rgb($body-color)\n )\n) !default;\n// scss-docs-end utilities-colors\n\n// scss-docs-start utilities-text-colors\n$utilities-text-colors: map-loop($utilities-colors, rgba-css-var, \"$key\", \"text\") !default;\n// scss-docs-end utilities-text-colors\n\n// scss-docs-start utilities-bg-colors\n$utilities-bg-colors: map-loop($utilities-colors, rgba-css-var, \"$key\", \"bg\") !default;\n// scss-docs-end utilities-bg-colors\n\n// Links\n//\n// Style anchor elements.\n\n$link-color: $primary !default;\n$link-decoration: underline !default;\n$link-shade-percentage: 20% !default;\n$link-hover-color: shift-color($link-color, $link-shade-percentage) !default;\n$link-hover-decoration: null !default;\n\n$stretched-link-pseudo-element: after !default;\n$stretched-link-z-index: 1 !default;\n\n// Paragraphs\n//\n// Style p element.\n\n$paragraph-margin-bottom: 1rem !default;\n\n\n// Grid breakpoints\n//\n// Define the minimum dimensions at which your layout will change,\n// adapting to different screen sizes, for use in media queries.\n\n// scss-docs-start grid-breakpoints\n$grid-breakpoints: (\n xs: 0,\n sm: 576px,\n md: 768px,\n lg: 992px,\n xl: 1200px,\n xxl: 1400px\n) !default;\n// scss-docs-end grid-breakpoints\n\n@include _assert-ascending($grid-breakpoints, \"$grid-breakpoints\");\n@include _assert-starts-at-zero($grid-breakpoints, \"$grid-breakpoints\");\n\n\n// Grid containers\n//\n// Define the maximum width of `.container` for different screen sizes.\n\n// scss-docs-start container-max-widths\n$container-max-widths: (\n sm: 540px,\n md: 720px,\n lg: 960px,\n xl: 1140px,\n xxl: 1320px\n) !default;\n// scss-docs-end container-max-widths\n\n@include _assert-ascending($container-max-widths, \"$container-max-widths\");\n\n\n// Grid columns\n//\n// Set the number of columns and specify the width of the gutters.\n\n$grid-columns: 12 !default;\n$grid-gutter-width: 1.5rem !default;\n$grid-row-columns: 6 !default;\n\n$gutters: $spacers !default;\n\n// Container padding\n\n$container-padding-x: $grid-gutter-width * .5 !default;\n\n\n// Components\n//\n// Define common padding and border radius sizes and more.\n\n// scss-docs-start border-variables\n$border-width: 1px !default;\n$border-widths: (\n 1: 1px,\n 2: 2px,\n 3: 3px,\n 4: 4px,\n 5: 5px\n) !default;\n\n$border-color: $gray-300 !default;\n// scss-docs-end border-variables\n\n// scss-docs-start border-radius-variables\n$border-radius: .25rem !default;\n$border-radius-sm: .2rem !default;\n$border-radius-lg: .3rem !default;\n$border-radius-pill: 50rem !default;\n// scss-docs-end border-radius-variables\n\n// scss-docs-start box-shadow-variables\n$box-shadow: 0 .5rem 1rem rgba($black, .15) !default;\n$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default;\n$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default;\n$box-shadow-inset: inset 0 1px 2px rgba($black, .075) !default;\n// scss-docs-end box-shadow-variables\n\n$component-active-color: $white !default;\n$component-active-bg: $primary !default;\n\n// scss-docs-start caret-variables\n$caret-width: .3em !default;\n$caret-vertical-align: $caret-width * .85 !default;\n$caret-spacing: $caret-width * .85 !default;\n// scss-docs-end caret-variables\n\n$transition-base: all .2s ease-in-out !default;\n$transition-fade: opacity .15s linear !default;\n// scss-docs-start collapse-transition\n$transition-collapse: height .35s ease !default;\n$transition-collapse-width: width .35s ease !default;\n// scss-docs-end collapse-transition\n\n// stylelint-disable function-disallowed-list\n// scss-docs-start aspect-ratios\n$aspect-ratios: (\n \"1x1\": 100%,\n \"4x3\": calc(3 / 4 * 100%),\n \"16x9\": calc(9 / 16 * 100%),\n \"21x9\": calc(9 / 21 * 100%)\n) !default;\n// scss-docs-end aspect-ratios\n// stylelint-enable function-disallowed-list\n\n// Typography\n//\n// Font, line-height, and color for body text, headings, and more.\n\n// scss-docs-start font-variables\n// stylelint-disable value-keyword-case\n$font-family-sans-serif: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", \"Liberation Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\" !default;\n$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace !default;\n// stylelint-enable value-keyword-case\n$font-family-base: var(--#{$variable-prefix}font-sans-serif) !default;\n$font-family-code: var(--#{$variable-prefix}font-monospace) !default;\n\n// $font-size-root affects the value of `rem`, which is used for as well font sizes, paddings, and margins\n// $font-size-base affects the font size of the body text\n$font-size-root: null !default;\n$font-size-base: 1rem !default; // Assumes the browser default, typically `16px`\n$font-size-sm: $font-size-base * .875 !default;\n$font-size-lg: $font-size-base * 1.25 !default;\n\n$font-weight-lighter: lighter !default;\n$font-weight-light: 300 !default;\n$font-weight-normal: 400 !default;\n$font-weight-bold: 700 !default;\n$font-weight-bolder: bolder !default;\n\n$font-weight-base: $font-weight-normal !default;\n\n$line-height-base: 1.5 !default;\n$line-height-sm: 1.25 !default;\n$line-height-lg: 2 !default;\n\n$h1-font-size: $font-size-base * 2.5 !default;\n$h2-font-size: $font-size-base * 2 !default;\n$h3-font-size: $font-size-base * 1.75 !default;\n$h4-font-size: $font-size-base * 1.5 !default;\n$h5-font-size: $font-size-base * 1.25 !default;\n$h6-font-size: $font-size-base !default;\n// scss-docs-end font-variables\n\n// scss-docs-start font-sizes\n$font-sizes: (\n 1: $h1-font-size,\n 2: $h2-font-size,\n 3: $h3-font-size,\n 4: $h4-font-size,\n 5: $h5-font-size,\n 6: $h6-font-size\n) !default;\n// scss-docs-end font-sizes\n\n// scss-docs-start headings-variables\n$headings-margin-bottom: $spacer * .5 !default;\n$headings-font-family: null !default;\n$headings-font-style: null !default;\n$headings-font-weight: 500 !default;\n$headings-line-height: 1.2 !default;\n$headings-color: null !default;\n// scss-docs-end headings-variables\n\n// scss-docs-start display-headings\n$display-font-sizes: (\n 1: 5rem,\n 2: 4.5rem,\n 3: 4rem,\n 4: 3.5rem,\n 5: 3rem,\n 6: 2.5rem\n) !default;\n\n$display-font-weight: 300 !default;\n$display-line-height: $headings-line-height !default;\n// scss-docs-end display-headings\n\n// scss-docs-start type-variables\n$lead-font-size: $font-size-base * 1.25 !default;\n$lead-font-weight: 300 !default;\n\n$small-font-size: .875em !default;\n\n$sub-sup-font-size: .75em !default;\n\n$text-muted: $gray-600 !default;\n\n$initialism-font-size: $small-font-size !default;\n\n$blockquote-margin-y: $spacer !default;\n$blockquote-font-size: $font-size-base * 1.25 !default;\n$blockquote-footer-color: $gray-600 !default;\n$blockquote-footer-font-size: $small-font-size !default;\n\n$hr-margin-y: $spacer !default;\n$hr-color: inherit !default;\n$hr-height: $border-width !default;\n$hr-opacity: .25 !default;\n\n$legend-margin-bottom: .5rem !default;\n$legend-font-size: 1.5rem !default;\n$legend-font-weight: null !default;\n\n$mark-padding: .2em !default;\n\n$dt-font-weight: $font-weight-bold !default;\n\n$nested-kbd-font-weight: $font-weight-bold !default;\n\n$list-inline-padding: .5rem !default;\n\n$mark-bg: #fcf8e3 !default;\n// scss-docs-end type-variables\n\n\n// Tables\n//\n// Customizes the `.table` component with basic values, each used across all table variations.\n\n// scss-docs-start table-variables\n$table-cell-padding-y: .5rem !default;\n$table-cell-padding-x: .5rem !default;\n$table-cell-padding-y-sm: .25rem !default;\n$table-cell-padding-x-sm: .25rem !default;\n\n$table-cell-vertical-align: top !default;\n\n$table-color: $body-color !default;\n$table-bg: transparent !default;\n$table-accent-bg: transparent !default;\n\n$table-th-font-weight: null !default;\n\n$table-striped-color: $table-color !default;\n$table-striped-bg-factor: .05 !default;\n$table-striped-bg: rgba($black, $table-striped-bg-factor) !default;\n\n$table-active-color: $table-color !default;\n$table-active-bg-factor: .1 !default;\n$table-active-bg: rgba($black, $table-active-bg-factor) !default;\n\n$table-hover-color: $table-color !default;\n$table-hover-bg-factor: .075 !default;\n$table-hover-bg: rgba($black, $table-hover-bg-factor) !default;\n\n$table-border-factor: .1 !default;\n$table-border-width: $border-width !default;\n$table-border-color: $border-color !default;\n\n$table-striped-order: odd !default;\n\n$table-group-separator-color: currentColor !default;\n\n$table-caption-color: $text-muted !default;\n\n$table-bg-scale: -80% !default;\n// scss-docs-end table-variables\n\n// scss-docs-start table-loop\n$table-variants: (\n \"primary\": shift-color($primary, $table-bg-scale),\n \"secondary\": shift-color($secondary, $table-bg-scale),\n \"success\": shift-color($success, $table-bg-scale),\n \"info\": shift-color($info, $table-bg-scale),\n \"warning\": shift-color($warning, $table-bg-scale),\n \"danger\": shift-color($danger, $table-bg-scale),\n \"light\": $light,\n \"dark\": $dark,\n) !default;\n// scss-docs-end table-loop\n\n\n// Buttons + Forms\n//\n// Shared variables that are reassigned to `$input-` and `$btn-` specific variables.\n\n// scss-docs-start input-btn-variables\n$input-btn-padding-y: .375rem !default;\n$input-btn-padding-x: .75rem !default;\n$input-btn-font-family: null !default;\n$input-btn-font-size: $font-size-base !default;\n$input-btn-line-height: $line-height-base !default;\n\n$input-btn-focus-width: .25rem !default;\n$input-btn-focus-color-opacity: .25 !default;\n$input-btn-focus-color: rgba($component-active-bg, $input-btn-focus-color-opacity) !default;\n$input-btn-focus-blur: 0 !default;\n$input-btn-focus-box-shadow: 0 0 $input-btn-focus-blur $input-btn-focus-width $input-btn-focus-color !default;\n\n$input-btn-padding-y-sm: .25rem !default;\n$input-btn-padding-x-sm: .5rem !default;\n$input-btn-font-size-sm: $font-size-sm !default;\n\n$input-btn-padding-y-lg: .5rem !default;\n$input-btn-padding-x-lg: 1rem !default;\n$input-btn-font-size-lg: $font-size-lg !default;\n\n$input-btn-border-width: $border-width !default;\n// scss-docs-end input-btn-variables\n\n\n// Buttons\n//\n// For each of Bootstrap's buttons, define text, background, and border color.\n\n// scss-docs-start btn-variables\n$btn-padding-y: $input-btn-padding-y !default;\n$btn-padding-x: $input-btn-padding-x !default;\n$btn-font-family: $input-btn-font-family !default;\n$btn-font-size: $input-btn-font-size !default;\n$btn-line-height: $input-btn-line-height !default;\n$btn-white-space: null !default; // Set to `nowrap` to prevent text wrapping\n\n$btn-padding-y-sm: $input-btn-padding-y-sm !default;\n$btn-padding-x-sm: $input-btn-padding-x-sm !default;\n$btn-font-size-sm: $input-btn-font-size-sm !default;\n\n$btn-padding-y-lg: $input-btn-padding-y-lg !default;\n$btn-padding-x-lg: $input-btn-padding-x-lg !default;\n$btn-font-size-lg: $input-btn-font-size-lg !default;\n\n$btn-border-width: $input-btn-border-width !default;\n\n$btn-font-weight: $font-weight-normal !default;\n$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default;\n$btn-focus-width: $input-btn-focus-width !default;\n$btn-focus-box-shadow: $input-btn-focus-box-shadow !default;\n$btn-disabled-opacity: .65 !default;\n$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default;\n\n$btn-link-color: $link-color !default;\n$btn-link-hover-color: $link-hover-color !default;\n$btn-link-disabled-color: $gray-600 !default;\n\n// Allows for customizing button radius independently from global border radius\n$btn-border-radius: $border-radius !default;\n$btn-border-radius-sm: $border-radius-sm !default;\n$btn-border-radius-lg: $border-radius-lg !default;\n\n$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$btn-hover-bg-shade-amount: 15% !default;\n$btn-hover-bg-tint-amount: 15% !default;\n$btn-hover-border-shade-amount: 20% !default;\n$btn-hover-border-tint-amount: 10% !default;\n$btn-active-bg-shade-amount: 20% !default;\n$btn-active-bg-tint-amount: 20% !default;\n$btn-active-border-shade-amount: 25% !default;\n$btn-active-border-tint-amount: 10% !default;\n// scss-docs-end btn-variables\n\n\n// Forms\n\n// scss-docs-start form-text-variables\n$form-text-margin-top: .25rem !default;\n$form-text-font-size: $small-font-size !default;\n$form-text-font-style: null !default;\n$form-text-font-weight: null !default;\n$form-text-color: $text-muted !default;\n// scss-docs-end form-text-variables\n\n// scss-docs-start form-label-variables\n$form-label-margin-bottom: .5rem !default;\n$form-label-font-size: null !default;\n$form-label-font-style: null !default;\n$form-label-font-weight: null !default;\n$form-label-color: null !default;\n// scss-docs-end form-label-variables\n\n// scss-docs-start form-input-variables\n$input-padding-y: $input-btn-padding-y !default;\n$input-padding-x: $input-btn-padding-x !default;\n$input-font-family: $input-btn-font-family !default;\n$input-font-size: $input-btn-font-size !default;\n$input-font-weight: $font-weight-base !default;\n$input-line-height: $input-btn-line-height !default;\n\n$input-padding-y-sm: $input-btn-padding-y-sm !default;\n$input-padding-x-sm: $input-btn-padding-x-sm !default;\n$input-font-size-sm: $input-btn-font-size-sm !default;\n\n$input-padding-y-lg: $input-btn-padding-y-lg !default;\n$input-padding-x-lg: $input-btn-padding-x-lg !default;\n$input-font-size-lg: $input-btn-font-size-lg !default;\n\n$input-bg: $body-bg !default;\n$input-disabled-bg: $gray-200 !default;\n$input-disabled-border-color: null !default;\n\n$input-color: $body-color !default;\n$input-border-color: $gray-400 !default;\n$input-border-width: $input-btn-border-width !default;\n$input-box-shadow: $box-shadow-inset !default;\n\n$input-border-radius: $border-radius !default;\n$input-border-radius-sm: $border-radius-sm !default;\n$input-border-radius-lg: $border-radius-lg !default;\n\n$input-focus-bg: $input-bg !default;\n$input-focus-border-color: tint-color($component-active-bg, 50%) !default;\n$input-focus-color: $input-color !default;\n$input-focus-width: $input-btn-focus-width !default;\n$input-focus-box-shadow: $input-btn-focus-box-shadow !default;\n\n$input-placeholder-color: $gray-600 !default;\n$input-plaintext-color: $body-color !default;\n\n$input-height-border: $input-border-width * 2 !default;\n\n$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2) !default;\n$input-height-inner-half: add($input-line-height * .5em, $input-padding-y) !default;\n$input-height-inner-quarter: add($input-line-height * .25em, $input-padding-y * .5) !default;\n\n$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default;\n$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default;\n$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default;\n\n$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$form-color-width: 3rem !default;\n// scss-docs-end form-input-variables\n\n// scss-docs-start form-check-variables\n$form-check-input-width: 1em !default;\n$form-check-min-height: $font-size-base * $line-height-base !default;\n$form-check-padding-start: $form-check-input-width + .5em !default;\n$form-check-margin-bottom: .125rem !default;\n$form-check-label-color: null !default;\n$form-check-label-cursor: null !default;\n$form-check-transition: null !default;\n\n$form-check-input-active-filter: brightness(90%) !default;\n\n$form-check-input-bg: $input-bg !default;\n$form-check-input-border: 1px solid rgba($black, .25) !default;\n$form-check-input-border-radius: .25em !default;\n$form-check-radio-border-radius: 50% !default;\n$form-check-input-focus-border: $input-focus-border-color !default;\n$form-check-input-focus-box-shadow: $input-btn-focus-box-shadow !default;\n\n$form-check-input-checked-color: $component-active-color !default;\n$form-check-input-checked-bg-color: $component-active-bg !default;\n$form-check-input-checked-border-color: $form-check-input-checked-bg-color !default;\n$form-check-input-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-check-radio-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-check-input-indeterminate-color: $component-active-color !default;\n$form-check-input-indeterminate-bg-color: $component-active-bg !default;\n$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default;\n$form-check-input-indeterminate-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-check-input-disabled-opacity: .5 !default;\n$form-check-label-disabled-opacity: $form-check-input-disabled-opacity !default;\n$form-check-btn-check-disabled-opacity: $btn-disabled-opacity !default;\n\n$form-check-inline-margin-end: 1rem !default;\n// scss-docs-end form-check-variables\n\n// scss-docs-start form-switch-variables\n$form-switch-color: rgba(0, 0, 0, .25) !default;\n$form-switch-width: 2em !default;\n$form-switch-padding-start: $form-switch-width + .5em !default;\n$form-switch-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-switch-border-radius: $form-switch-width !default;\n$form-switch-transition: background-position .15s ease-in-out !default;\n\n$form-switch-focus-color: $input-focus-border-color !default;\n$form-switch-focus-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-switch-checked-color: $component-active-color !default;\n$form-switch-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-switch-checked-bg-position: right center !default;\n// scss-docs-end form-switch-variables\n\n// scss-docs-start input-group-variables\n$input-group-addon-padding-y: $input-padding-y !default;\n$input-group-addon-padding-x: $input-padding-x !default;\n$input-group-addon-font-weight: $input-font-weight !default;\n$input-group-addon-color: $input-color !default;\n$input-group-addon-bg: $gray-200 !default;\n$input-group-addon-border-color: $input-border-color !default;\n// scss-docs-end input-group-variables\n\n// scss-docs-start form-select-variables\n$form-select-padding-y: $input-padding-y !default;\n$form-select-padding-x: $input-padding-x !default;\n$form-select-font-family: $input-font-family !default;\n$form-select-font-size: $input-font-size !default;\n$form-select-indicator-padding: $form-select-padding-x * 3 !default; // Extra padding for background-image\n$form-select-font-weight: $input-font-weight !default;\n$form-select-line-height: $input-line-height !default;\n$form-select-color: $input-color !default;\n$form-select-bg: $input-bg !default;\n$form-select-disabled-color: null !default;\n$form-select-disabled-bg: $gray-200 !default;\n$form-select-disabled-border-color: $input-disabled-border-color !default;\n$form-select-bg-position: right $form-select-padding-x center !default;\n$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions\n$form-select-indicator-color: $gray-800 !default;\n$form-select-indicator: url(\"data:image/svg+xml,\") !default;\n\n$form-select-feedback-icon-padding-end: $form-select-padding-x * 2.5 + $form-select-indicator-padding !default;\n$form-select-feedback-icon-position: center right $form-select-indicator-padding !default;\n$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default;\n\n$form-select-border-width: $input-border-width !default;\n$form-select-border-color: $input-border-color !default;\n$form-select-border-radius: $border-radius !default;\n$form-select-box-shadow: $box-shadow-inset !default;\n\n$form-select-focus-border-color: $input-focus-border-color !default;\n$form-select-focus-width: $input-focus-width !default;\n$form-select-focus-box-shadow: 0 0 0 $form-select-focus-width $input-btn-focus-color !default;\n\n$form-select-padding-y-sm: $input-padding-y-sm !default;\n$form-select-padding-x-sm: $input-padding-x-sm !default;\n$form-select-font-size-sm: $input-font-size-sm !default;\n\n$form-select-padding-y-lg: $input-padding-y-lg !default;\n$form-select-padding-x-lg: $input-padding-x-lg !default;\n$form-select-font-size-lg: $input-font-size-lg !default;\n\n$form-select-transition: $input-transition !default;\n// scss-docs-end form-select-variables\n\n// scss-docs-start form-range-variables\n$form-range-track-width: 100% !default;\n$form-range-track-height: .5rem !default;\n$form-range-track-cursor: pointer !default;\n$form-range-track-bg: $gray-300 !default;\n$form-range-track-border-radius: 1rem !default;\n$form-range-track-box-shadow: $box-shadow-inset !default;\n\n$form-range-thumb-width: 1rem !default;\n$form-range-thumb-height: $form-range-thumb-width !default;\n$form-range-thumb-bg: $component-active-bg !default;\n$form-range-thumb-border: 0 !default;\n$form-range-thumb-border-radius: 1rem !default;\n$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default;\n$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default;\n$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in Edge\n$form-range-thumb-active-bg: tint-color($component-active-bg, 70%) !default;\n$form-range-thumb-disabled-bg: $gray-500 !default;\n$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n// scss-docs-end form-range-variables\n\n// scss-docs-start form-file-variables\n$form-file-button-color: $input-color !default;\n$form-file-button-bg: $input-group-addon-bg !default;\n$form-file-button-hover-bg: shade-color($form-file-button-bg, 5%) !default;\n// scss-docs-end form-file-variables\n\n// scss-docs-start form-floating-variables\n$form-floating-height: add(3.5rem, $input-height-border) !default;\n$form-floating-line-height: 1.25 !default;\n$form-floating-padding-x: $input-padding-x !default;\n$form-floating-padding-y: 1rem !default;\n$form-floating-input-padding-t: 1.625rem !default;\n$form-floating-input-padding-b: .625rem !default;\n$form-floating-label-opacity: .65 !default;\n$form-floating-label-transform: scale(.85) translateY(-.5rem) translateX(.15rem) !default;\n$form-floating-transition: opacity .1s ease-in-out, transform .1s ease-in-out !default;\n// scss-docs-end form-floating-variables\n\n// Form validation\n\n// scss-docs-start form-feedback-variables\n$form-feedback-margin-top: $form-text-margin-top !default;\n$form-feedback-font-size: $form-text-font-size !default;\n$form-feedback-font-style: $form-text-font-style !default;\n$form-feedback-valid-color: $success !default;\n$form-feedback-invalid-color: $danger !default;\n\n$form-feedback-icon-valid-color: $form-feedback-valid-color !default;\n$form-feedback-icon-valid: url(\"data:image/svg+xml,\") !default;\n$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default;\n$form-feedback-icon-invalid: url(\"data:image/svg+xml,\") !default;\n// scss-docs-end form-feedback-variables\n\n// scss-docs-start form-validation-states\n$form-validation-states: (\n \"valid\": (\n \"color\": $form-feedback-valid-color,\n \"icon\": $form-feedback-icon-valid\n ),\n \"invalid\": (\n \"color\": $form-feedback-invalid-color,\n \"icon\": $form-feedback-icon-invalid\n )\n) !default;\n// scss-docs-end form-validation-states\n\n// Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n\n// scss-docs-start zindex-stack\n$zindex-dropdown: 1000 !default;\n$zindex-sticky: 1020 !default;\n$zindex-fixed: 1030 !default;\n$zindex-offcanvas-backdrop: 1040 !default;\n$zindex-offcanvas: 1045 !default;\n$zindex-modal-backdrop: 1050 !default;\n$zindex-modal: 1055 !default;\n$zindex-popover: 1070 !default;\n$zindex-tooltip: 1080 !default;\n// scss-docs-end zindex-stack\n\n\n// Navs\n\n// scss-docs-start nav-variables\n$nav-link-padding-y: .5rem !default;\n$nav-link-padding-x: 1rem !default;\n$nav-link-font-size: null !default;\n$nav-link-font-weight: null !default;\n$nav-link-color: $link-color !default;\n$nav-link-hover-color: $link-hover-color !default;\n$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default;\n$nav-link-disabled-color: $gray-600 !default;\n\n$nav-tabs-border-color: $gray-300 !default;\n$nav-tabs-border-width: $border-width !default;\n$nav-tabs-border-radius: $border-radius !default;\n$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default;\n$nav-tabs-link-active-color: $gray-700 !default;\n$nav-tabs-link-active-bg: $body-bg !default;\n$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default;\n\n$nav-pills-border-radius: $border-radius !default;\n$nav-pills-link-active-color: $component-active-color !default;\n$nav-pills-link-active-bg: $component-active-bg !default;\n// scss-docs-end nav-variables\n\n\n// Navbar\n\n// scss-docs-start navbar-variables\n$navbar-padding-y: $spacer * .5 !default;\n$navbar-padding-x: null !default;\n\n$navbar-nav-link-padding-x: .5rem !default;\n\n$navbar-brand-font-size: $font-size-lg !default;\n// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link\n$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default;\n$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default;\n$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * .5 !default;\n$navbar-brand-margin-end: 1rem !default;\n\n$navbar-toggler-padding-y: .25rem !default;\n$navbar-toggler-padding-x: .75rem !default;\n$navbar-toggler-font-size: $font-size-lg !default;\n$navbar-toggler-border-radius: $btn-border-radius !default;\n$navbar-toggler-focus-width: $btn-focus-width !default;\n$navbar-toggler-transition: box-shadow .15s ease-in-out !default;\n// scss-docs-end navbar-variables\n\n// scss-docs-start navbar-theme-variables\n$navbar-dark-color: rgba($white, .55) !default;\n$navbar-dark-hover-color: rgba($white, .75) !default;\n$navbar-dark-active-color: $white !default;\n$navbar-dark-disabled-color: rgba($white, .25) !default;\n$navbar-dark-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-dark-toggler-border-color: rgba($white, .1) !default;\n\n$navbar-light-color: rgba($black, .55) !default;\n$navbar-light-hover-color: rgba($black, .7) !default;\n$navbar-light-active-color: rgba($black, .9) !default;\n$navbar-light-disabled-color: rgba($black, .3) !default;\n$navbar-light-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-light-toggler-border-color: rgba($black, .1) !default;\n\n$navbar-light-brand-color: $navbar-light-active-color !default;\n$navbar-light-brand-hover-color: $navbar-light-active-color !default;\n$navbar-dark-brand-color: $navbar-dark-active-color !default;\n$navbar-dark-brand-hover-color: $navbar-dark-active-color !default;\n// scss-docs-end navbar-theme-variables\n\n\n// Dropdowns\n//\n// Dropdown menu container and contents.\n\n// scss-docs-start dropdown-variables\n$dropdown-min-width: 10rem !default;\n$dropdown-padding-x: 0 !default;\n$dropdown-padding-y: .5rem !default;\n$dropdown-spacer: .125rem !default;\n$dropdown-font-size: $font-size-base !default;\n$dropdown-color: $body-color !default;\n$dropdown-bg: $white !default;\n$dropdown-border-color: rgba($black, .15) !default;\n$dropdown-border-radius: $border-radius !default;\n$dropdown-border-width: $border-width !default;\n$dropdown-inner-border-radius: subtract($dropdown-border-radius, $dropdown-border-width) !default;\n$dropdown-divider-bg: $dropdown-border-color !default;\n$dropdown-divider-margin-y: $spacer * .5 !default;\n$dropdown-box-shadow: $box-shadow !default;\n\n$dropdown-link-color: $gray-900 !default;\n$dropdown-link-hover-color: shade-color($gray-900, 10%) !default;\n$dropdown-link-hover-bg: $gray-200 !default;\n\n$dropdown-link-active-color: $component-active-color !default;\n$dropdown-link-active-bg: $component-active-bg !default;\n\n$dropdown-link-disabled-color: $gray-500 !default;\n\n$dropdown-item-padding-y: $spacer * .25 !default;\n$dropdown-item-padding-x: $spacer !default;\n\n$dropdown-header-color: $gray-600 !default;\n$dropdown-header-padding: $dropdown-padding-y $dropdown-item-padding-x !default;\n// scss-docs-end dropdown-variables\n\n// scss-docs-start dropdown-dark-variables\n$dropdown-dark-color: $gray-300 !default;\n$dropdown-dark-bg: $gray-800 !default;\n$dropdown-dark-border-color: $dropdown-border-color !default;\n$dropdown-dark-divider-bg: $dropdown-divider-bg !default;\n$dropdown-dark-box-shadow: null !default;\n$dropdown-dark-link-color: $dropdown-dark-color !default;\n$dropdown-dark-link-hover-color: $white !default;\n$dropdown-dark-link-hover-bg: rgba($white, .15) !default;\n$dropdown-dark-link-active-color: $dropdown-link-active-color !default;\n$dropdown-dark-link-active-bg: $dropdown-link-active-bg !default;\n$dropdown-dark-link-disabled-color: $gray-500 !default;\n$dropdown-dark-header-color: $gray-500 !default;\n// scss-docs-end dropdown-dark-variables\n\n\n// Pagination\n\n// scss-docs-start pagination-variables\n$pagination-padding-y: .375rem !default;\n$pagination-padding-x: .75rem !default;\n$pagination-padding-y-sm: .25rem !default;\n$pagination-padding-x-sm: .5rem !default;\n$pagination-padding-y-lg: .75rem !default;\n$pagination-padding-x-lg: 1.5rem !default;\n\n$pagination-color: $link-color !default;\n$pagination-bg: $white !default;\n$pagination-border-width: $border-width !default;\n$pagination-border-radius: $border-radius !default;\n$pagination-margin-start: -$pagination-border-width !default;\n$pagination-border-color: $gray-300 !default;\n\n$pagination-focus-color: $link-hover-color !default;\n$pagination-focus-bg: $gray-200 !default;\n$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default;\n$pagination-focus-outline: 0 !default;\n\n$pagination-hover-color: $link-hover-color !default;\n$pagination-hover-bg: $gray-200 !default;\n$pagination-hover-border-color: $gray-300 !default;\n\n$pagination-active-color: $component-active-color !default;\n$pagination-active-bg: $component-active-bg !default;\n$pagination-active-border-color: $pagination-active-bg !default;\n\n$pagination-disabled-color: $gray-600 !default;\n$pagination-disabled-bg: $white !default;\n$pagination-disabled-border-color: $gray-300 !default;\n\n$pagination-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$pagination-border-radius-sm: $border-radius-sm !default;\n$pagination-border-radius-lg: $border-radius-lg !default;\n// scss-docs-end pagination-variables\n\n\n// Placeholders\n\n// scss-docs-start placeholders\n$placeholder-opacity-max: .5 !default;\n$placeholder-opacity-min: .2 !default;\n// scss-docs-end placeholders\n\n// Cards\n\n// scss-docs-start card-variables\n$card-spacer-y: $spacer !default;\n$card-spacer-x: $spacer !default;\n$card-title-spacer-y: $spacer * .5 !default;\n$card-border-width: $border-width !default;\n$card-border-color: rgba($black, .125) !default;\n$card-border-radius: $border-radius !default;\n$card-box-shadow: null !default;\n$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default;\n$card-cap-padding-y: $card-spacer-y * .5 !default;\n$card-cap-padding-x: $card-spacer-x !default;\n$card-cap-bg: rgba($black, .03) !default;\n$card-cap-color: null !default;\n$card-height: null !default;\n$card-color: null !default;\n$card-bg: $white !default;\n$card-img-overlay-padding: $spacer !default;\n$card-group-margin: $grid-gutter-width * .5 !default;\n// scss-docs-end card-variables\n\n// Accordion\n\n// scss-docs-start accordion-variables\n$accordion-padding-y: 1rem !default;\n$accordion-padding-x: 1.25rem !default;\n$accordion-color: $body-color !default;\n$accordion-bg: $body-bg !default;\n$accordion-border-width: $border-width !default;\n$accordion-border-color: rgba($black, .125) !default;\n$accordion-border-radius: $border-radius !default;\n$accordion-inner-border-radius: subtract($accordion-border-radius, $accordion-border-width) !default;\n\n$accordion-body-padding-y: $accordion-padding-y !default;\n$accordion-body-padding-x: $accordion-padding-x !default;\n\n$accordion-button-padding-y: $accordion-padding-y !default;\n$accordion-button-padding-x: $accordion-padding-x !default;\n$accordion-button-color: $accordion-color !default;\n$accordion-button-bg: $accordion-bg !default;\n$accordion-transition: $btn-transition, border-radius .15s ease !default;\n$accordion-button-active-bg: tint-color($component-active-bg, 90%) !default;\n$accordion-button-active-color: shade-color($primary, 10%) !default;\n\n$accordion-button-focus-border-color: $input-focus-border-color !default;\n$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default;\n\n$accordion-icon-width: 1.25rem !default;\n$accordion-icon-color: $accordion-button-color !default;\n$accordion-icon-active-color: $accordion-button-active-color !default;\n$accordion-icon-transition: transform .2s ease-in-out !default;\n$accordion-icon-transform: rotate(-180deg) !default;\n\n$accordion-button-icon: url(\"data:image/svg+xml,\") !default;\n$accordion-button-active-icon: url(\"data:image/svg+xml,\") !default;\n// scss-docs-end accordion-variables\n\n// Tooltips\n\n// scss-docs-start tooltip-variables\n$tooltip-font-size: $font-size-sm !default;\n$tooltip-max-width: 200px !default;\n$tooltip-color: $white !default;\n$tooltip-bg: $black !default;\n$tooltip-border-radius: $border-radius !default;\n$tooltip-opacity: .9 !default;\n$tooltip-padding-y: $spacer * .25 !default;\n$tooltip-padding-x: $spacer * .5 !default;\n$tooltip-margin: 0 !default;\n\n$tooltip-arrow-width: .8rem !default;\n$tooltip-arrow-height: .4rem !default;\n$tooltip-arrow-color: $tooltip-bg !default;\n// scss-docs-end tooltip-variables\n\n// Form tooltips must come after regular tooltips\n// scss-docs-start tooltip-feedback-variables\n$form-feedback-tooltip-padding-y: $tooltip-padding-y !default;\n$form-feedback-tooltip-padding-x: $tooltip-padding-x !default;\n$form-feedback-tooltip-font-size: $tooltip-font-size !default;\n$form-feedback-tooltip-line-height: null !default;\n$form-feedback-tooltip-opacity: $tooltip-opacity !default;\n$form-feedback-tooltip-border-radius: $tooltip-border-radius !default;\n// scss-docs-end tooltip-feedback-variables\n\n\n// Popovers\n\n// scss-docs-start popover-variables\n$popover-font-size: $font-size-sm !default;\n$popover-bg: $white !default;\n$popover-max-width: 276px !default;\n$popover-border-width: $border-width !default;\n$popover-border-color: rgba($black, .2) !default;\n$popover-border-radius: $border-radius-lg !default;\n$popover-inner-border-radius: subtract($popover-border-radius, $popover-border-width) !default;\n$popover-box-shadow: $box-shadow !default;\n\n$popover-header-bg: shade-color($popover-bg, 6%) !default;\n$popover-header-color: $headings-color !default;\n$popover-header-padding-y: .5rem !default;\n$popover-header-padding-x: $spacer !default;\n\n$popover-body-color: $body-color !default;\n$popover-body-padding-y: $spacer !default;\n$popover-body-padding-x: $spacer !default;\n\n$popover-arrow-width: 1rem !default;\n$popover-arrow-height: .5rem !default;\n$popover-arrow-color: $popover-bg !default;\n\n$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default;\n// scss-docs-end popover-variables\n\n\n// Toasts\n\n// scss-docs-start toast-variables\n$toast-max-width: 350px !default;\n$toast-padding-x: .75rem !default;\n$toast-padding-y: .5rem !default;\n$toast-font-size: .875rem !default;\n$toast-color: null !default;\n$toast-background-color: rgba($white, .85) !default;\n$toast-border-width: 1px !default;\n$toast-border-color: rgba(0, 0, 0, .1) !default;\n$toast-border-radius: $border-radius !default;\n$toast-box-shadow: $box-shadow !default;\n$toast-spacing: $container-padding-x !default;\n\n$toast-header-color: $gray-600 !default;\n$toast-header-background-color: rgba($white, .85) !default;\n$toast-header-border-color: rgba(0, 0, 0, .05) !default;\n// scss-docs-end toast-variables\n\n\n// Badges\n\n// scss-docs-start badge-variables\n$badge-font-size: .75em !default;\n$badge-font-weight: $font-weight-bold !default;\n$badge-color: $white !default;\n$badge-padding-y: .35em !default;\n$badge-padding-x: .65em !default;\n$badge-border-radius: $border-radius !default;\n// scss-docs-end badge-variables\n\n\n// Modals\n\n// scss-docs-start modal-variables\n$modal-inner-padding: $spacer !default;\n\n$modal-footer-margin-between: .5rem !default;\n\n$modal-dialog-margin: .5rem !default;\n$modal-dialog-margin-y-sm-up: 1.75rem !default;\n\n$modal-title-line-height: $line-height-base !default;\n\n$modal-content-color: null !default;\n$modal-content-bg: $white !default;\n$modal-content-border-color: rgba($black, .2) !default;\n$modal-content-border-width: $border-width !default;\n$modal-content-border-radius: $border-radius-lg !default;\n$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width) !default;\n$modal-content-box-shadow-xs: $box-shadow-sm !default;\n$modal-content-box-shadow-sm-up: $box-shadow !default;\n\n$modal-backdrop-bg: $black !default;\n$modal-backdrop-opacity: .5 !default;\n$modal-header-border-color: $border-color !default;\n$modal-footer-border-color: $modal-header-border-color !default;\n$modal-header-border-width: $modal-content-border-width !default;\n$modal-footer-border-width: $modal-header-border-width !default;\n$modal-header-padding-y: $modal-inner-padding !default;\n$modal-header-padding-x: $modal-inner-padding !default;\n$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility\n\n$modal-sm: 300px !default;\n$modal-md: 500px !default;\n$modal-lg: 800px !default;\n$modal-xl: 1140px !default;\n\n$modal-fade-transform: translate(0, -50px) !default;\n$modal-show-transform: none !default;\n$modal-transition: transform .3s ease-out !default;\n$modal-scale-transform: scale(1.02) !default;\n// scss-docs-end modal-variables\n\n\n// Alerts\n//\n// Define alert colors, border radius, and padding.\n\n// scss-docs-start alert-variables\n$alert-padding-y: $spacer !default;\n$alert-padding-x: $spacer !default;\n$alert-margin-bottom: 1rem !default;\n$alert-border-radius: $border-radius !default;\n$alert-link-font-weight: $font-weight-bold !default;\n$alert-border-width: $border-width !default;\n$alert-bg-scale: -80% !default;\n$alert-border-scale: -70% !default;\n$alert-color-scale: 40% !default;\n$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side\n// scss-docs-end alert-variables\n\n\n// Progress bars\n\n// scss-docs-start progress-variables\n$progress-height: 1rem !default;\n$progress-font-size: $font-size-base * .75 !default;\n$progress-bg: $gray-200 !default;\n$progress-border-radius: $border-radius !default;\n$progress-box-shadow: $box-shadow-inset !default;\n$progress-bar-color: $white !default;\n$progress-bar-bg: $primary !default;\n$progress-bar-animation-timing: 1s linear infinite !default;\n$progress-bar-transition: width .6s ease !default;\n// scss-docs-end progress-variables\n\n\n// List group\n\n// scss-docs-start list-group-variables\n$list-group-color: $gray-900 !default;\n$list-group-bg: $white !default;\n$list-group-border-color: rgba($black, .125) !default;\n$list-group-border-width: $border-width !default;\n$list-group-border-radius: $border-radius !default;\n\n$list-group-item-padding-y: $spacer * .5 !default;\n$list-group-item-padding-x: $spacer !default;\n$list-group-item-bg-scale: -80% !default;\n$list-group-item-color-scale: 40% !default;\n\n$list-group-hover-bg: $gray-100 !default;\n$list-group-active-color: $component-active-color !default;\n$list-group-active-bg: $component-active-bg !default;\n$list-group-active-border-color: $list-group-active-bg !default;\n\n$list-group-disabled-color: $gray-600 !default;\n$list-group-disabled-bg: $list-group-bg !default;\n\n$list-group-action-color: $gray-700 !default;\n$list-group-action-hover-color: $list-group-action-color !default;\n\n$list-group-action-active-color: $body-color !default;\n$list-group-action-active-bg: $gray-200 !default;\n// scss-docs-end list-group-variables\n\n\n// Image thumbnails\n\n// scss-docs-start thumbnail-variables\n$thumbnail-padding: .25rem !default;\n$thumbnail-bg: $body-bg !default;\n$thumbnail-border-width: $border-width !default;\n$thumbnail-border-color: $gray-300 !default;\n$thumbnail-border-radius: $border-radius !default;\n$thumbnail-box-shadow: $box-shadow-sm !default;\n// scss-docs-end thumbnail-variables\n\n\n// Figures\n\n// scss-docs-start figure-variables\n$figure-caption-font-size: $small-font-size !default;\n$figure-caption-color: $gray-600 !default;\n// scss-docs-end figure-variables\n\n\n// Breadcrumbs\n\n// scss-docs-start breadcrumb-variables\n$breadcrumb-font-size: null !default;\n$breadcrumb-padding-y: 0 !default;\n$breadcrumb-padding-x: 0 !default;\n$breadcrumb-item-padding-x: .5rem !default;\n$breadcrumb-margin-bottom: 1rem !default;\n$breadcrumb-bg: null !default;\n$breadcrumb-divider-color: $gray-600 !default;\n$breadcrumb-active-color: $gray-600 !default;\n$breadcrumb-divider: quote(\"/\") !default;\n$breadcrumb-divider-flipped: $breadcrumb-divider !default;\n$breadcrumb-border-radius: null !default;\n// scss-docs-end breadcrumb-variables\n\n// Carousel\n\n// scss-docs-start carousel-variables\n$carousel-control-color: $white !default;\n$carousel-control-width: 15% !default;\n$carousel-control-opacity: .5 !default;\n$carousel-control-hover-opacity: .9 !default;\n$carousel-control-transition: opacity .15s ease !default;\n\n$carousel-indicator-width: 30px !default;\n$carousel-indicator-height: 3px !default;\n$carousel-indicator-hit-area-height: 10px !default;\n$carousel-indicator-spacer: 3px !default;\n$carousel-indicator-opacity: .5 !default;\n$carousel-indicator-active-bg: $white !default;\n$carousel-indicator-active-opacity: 1 !default;\n$carousel-indicator-transition: opacity .6s ease !default;\n\n$carousel-caption-width: 70% !default;\n$carousel-caption-color: $white !default;\n$carousel-caption-padding-y: 1.25rem !default;\n$carousel-caption-spacer: 1.25rem !default;\n\n$carousel-control-icon-width: 2rem !default;\n\n$carousel-control-prev-icon-bg: url(\"data:image/svg+xml,\") !default;\n$carousel-control-next-icon-bg: url(\"data:image/svg+xml,\") !default;\n\n$carousel-transition-duration: .6s !default;\n$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`)\n\n$carousel-dark-indicator-active-bg: $black !default;\n$carousel-dark-caption-color: $black !default;\n$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default;\n// scss-docs-end carousel-variables\n\n\n// Spinners\n\n// scss-docs-start spinner-variables\n$spinner-width: 2rem !default;\n$spinner-height: $spinner-width !default;\n$spinner-vertical-align: -.125em !default;\n$spinner-border-width: .25em !default;\n$spinner-animation-speed: .75s !default;\n\n$spinner-width-sm: 1rem !default;\n$spinner-height-sm: $spinner-width-sm !default;\n$spinner-border-width-sm: .2em !default;\n// scss-docs-end spinner-variables\n\n\n// Close\n\n// scss-docs-start close-variables\n$btn-close-width: 1em !default;\n$btn-close-height: $btn-close-width !default;\n$btn-close-padding-x: .25em !default;\n$btn-close-padding-y: $btn-close-padding-x !default;\n$btn-close-color: $black !default;\n$btn-close-bg: url(\"data:image/svg+xml,\") !default;\n$btn-close-focus-shadow: $input-btn-focus-box-shadow !default;\n$btn-close-opacity: .5 !default;\n$btn-close-hover-opacity: .75 !default;\n$btn-close-focus-opacity: 1 !default;\n$btn-close-disabled-opacity: .25 !default;\n$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default;\n// scss-docs-end close-variables\n\n\n// Offcanvas\n\n// scss-docs-start offcanvas-variables\n$offcanvas-padding-y: $modal-inner-padding !default;\n$offcanvas-padding-x: $modal-inner-padding !default;\n$offcanvas-horizontal-width: 400px !default;\n$offcanvas-vertical-height: 30vh !default;\n$offcanvas-transition-duration: .3s !default;\n$offcanvas-border-color: $modal-content-border-color !default;\n$offcanvas-border-width: $modal-content-border-width !default;\n$offcanvas-title-line-height: $modal-title-line-height !default;\n$offcanvas-bg-color: $modal-content-bg !default;\n$offcanvas-color: $modal-content-color !default;\n$offcanvas-box-shadow: $modal-content-box-shadow-xs !default;\n$offcanvas-backdrop-bg: $modal-backdrop-bg !default;\n$offcanvas-backdrop-opacity: $modal-backdrop-opacity !default;\n// scss-docs-end offcanvas-variables\n\n// Code\n\n$code-font-size: $small-font-size !default;\n$code-color: $pink !default;\n\n$kbd-padding-y: .2rem !default;\n$kbd-padding-x: .4rem !default;\n$kbd-font-size: $code-font-size !default;\n$kbd-color: $white !default;\n$kbd-bg: $gray-900 !default;\n\n$pre-color: null !default;\n", + "// stylelint-disable indentation\n\n// Utilities\n\n$utilities: () !default;\n// stylelint-disable-next-line scss/dollar-variable-default\n$utilities: map-merge(\n (\n // scss-docs-start utils-vertical-align\n \"align\": (\n property: vertical-align,\n class: align,\n values: baseline top middle bottom text-bottom text-top\n ),\n // scss-docs-end utils-vertical-align\n // scss-docs-start utils-float\n \"float\": (\n responsive: true,\n property: float,\n values: (\n start: left,\n end: right,\n none: none,\n )\n ),\n // scss-docs-end utils-float\n // Opacity utilities\n // scss-docs-start utils-opacity\n \"opacity\": (\n property: opacity,\n values: (\n 0: 0,\n 25: .25,\n 50: .5,\n 75: .75,\n 100: 1,\n )\n ),\n // scss-docs-end utils-opacity\n // scss-docs-start utils-overflow\n \"overflow\": (\n property: overflow,\n values: auto hidden visible scroll,\n ),\n // scss-docs-end utils-overflow\n // scss-docs-start utils-display\n \"display\": (\n responsive: true,\n print: true,\n property: display,\n class: d,\n values: inline inline-block block grid table table-row table-cell flex inline-flex none\n ),\n // scss-docs-end utils-display\n // scss-docs-start utils-shadow\n \"shadow\": (\n property: box-shadow,\n class: shadow,\n values: (\n null: $box-shadow,\n sm: $box-shadow-sm,\n lg: $box-shadow-lg,\n none: none,\n )\n ),\n // scss-docs-end utils-shadow\n // scss-docs-start utils-position\n \"position\": (\n property: position,\n values: static relative absolute fixed sticky\n ),\n \"top\": (\n property: top,\n values: $position-values\n ),\n \"bottom\": (\n property: bottom,\n values: $position-values\n ),\n \"start\": (\n property: left,\n class: start,\n values: $position-values\n ),\n \"end\": (\n property: right,\n class: end,\n values: $position-values\n ),\n \"translate-middle\": (\n property: transform,\n class: translate-middle,\n values: (\n null: translate(-50%, -50%),\n x: translateX(-50%),\n y: translateY(-50%),\n )\n ),\n // scss-docs-end utils-position\n // scss-docs-start utils-borders\n \"border\": (\n property: border,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-top\": (\n property: border-top,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-end\": (\n property: border-right,\n class: border-end,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-bottom\": (\n property: border-bottom,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-start\": (\n property: border-left,\n class: border-start,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-color\": (\n property: border-color,\n class: border,\n values: map-merge($theme-colors, (\"white\": $white))\n ),\n \"border-width\": (\n property: border-width,\n class: border,\n values: $border-widths\n ),\n // scss-docs-end utils-borders\n // Sizing utilities\n // scss-docs-start utils-sizing\n \"width\": (\n property: width,\n class: w,\n values: (\n 25: 25%,\n 50: 50%,\n 75: 75%,\n 100: 100%,\n auto: auto\n )\n ),\n \"max-width\": (\n property: max-width,\n class: mw,\n values: (100: 100%)\n ),\n \"viewport-width\": (\n property: width,\n class: vw,\n values: (100: 100vw)\n ),\n \"min-viewport-width\": (\n property: min-width,\n class: min-vw,\n values: (100: 100vw)\n ),\n \"height\": (\n property: height,\n class: h,\n values: (\n 25: 25%,\n 50: 50%,\n 75: 75%,\n 100: 100%,\n auto: auto\n )\n ),\n \"max-height\": (\n property: max-height,\n class: mh,\n values: (100: 100%)\n ),\n \"viewport-height\": (\n property: height,\n class: vh,\n values: (100: 100vh)\n ),\n \"min-viewport-height\": (\n property: min-height,\n class: min-vh,\n values: (100: 100vh)\n ),\n // scss-docs-end utils-sizing\n // Flex utilities\n // scss-docs-start utils-flex\n \"flex\": (\n responsive: true,\n property: flex,\n values: (fill: 1 1 auto)\n ),\n \"flex-direction\": (\n responsive: true,\n property: flex-direction,\n class: flex,\n values: row column row-reverse column-reverse\n ),\n \"flex-grow\": (\n responsive: true,\n property: flex-grow,\n class: flex,\n values: (\n grow-0: 0,\n grow-1: 1,\n )\n ),\n \"flex-shrink\": (\n responsive: true,\n property: flex-shrink,\n class: flex,\n values: (\n shrink-0: 0,\n shrink-1: 1,\n )\n ),\n \"flex-wrap\": (\n responsive: true,\n property: flex-wrap,\n class: flex,\n values: wrap nowrap wrap-reverse\n ),\n \"gap\": (\n responsive: true,\n property: gap,\n class: gap,\n values: $spacers\n ),\n \"justify-content\": (\n responsive: true,\n property: justify-content,\n values: (\n start: flex-start,\n end: flex-end,\n center: center,\n between: space-between,\n around: space-around,\n evenly: space-evenly,\n )\n ),\n \"align-items\": (\n responsive: true,\n property: align-items,\n values: (\n start: flex-start,\n end: flex-end,\n center: center,\n baseline: baseline,\n stretch: stretch,\n )\n ),\n \"align-content\": (\n responsive: true,\n property: align-content,\n values: (\n start: flex-start,\n end: flex-end,\n center: center,\n between: space-between,\n around: space-around,\n stretch: stretch,\n )\n ),\n \"align-self\": (\n responsive: true,\n property: align-self,\n values: (\n auto: auto,\n start: flex-start,\n end: flex-end,\n center: center,\n baseline: baseline,\n stretch: stretch,\n )\n ),\n \"order\": (\n responsive: true,\n property: order,\n values: (\n first: -1,\n 0: 0,\n 1: 1,\n 2: 2,\n 3: 3,\n 4: 4,\n 5: 5,\n last: 6,\n ),\n ),\n // scss-docs-end utils-flex\n // Margin utilities\n // scss-docs-start utils-spacing\n \"margin\": (\n responsive: true,\n property: margin,\n class: m,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-x\": (\n responsive: true,\n property: margin-right margin-left,\n class: mx,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-y\": (\n responsive: true,\n property: margin-top margin-bottom,\n class: my,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-top\": (\n responsive: true,\n property: margin-top,\n class: mt,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-end\": (\n responsive: true,\n property: margin-right,\n class: me,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-bottom\": (\n responsive: true,\n property: margin-bottom,\n class: mb,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-start\": (\n responsive: true,\n property: margin-left,\n class: ms,\n values: map-merge($spacers, (auto: auto))\n ),\n // Negative margin utilities\n \"negative-margin\": (\n responsive: true,\n property: margin,\n class: m,\n values: $negative-spacers\n ),\n \"negative-margin-x\": (\n responsive: true,\n property: margin-right margin-left,\n class: mx,\n values: $negative-spacers\n ),\n \"negative-margin-y\": (\n responsive: true,\n property: margin-top margin-bottom,\n class: my,\n values: $negative-spacers\n ),\n \"negative-margin-top\": (\n responsive: true,\n property: margin-top,\n class: mt,\n values: $negative-spacers\n ),\n \"negative-margin-end\": (\n responsive: true,\n property: margin-right,\n class: me,\n values: $negative-spacers\n ),\n \"negative-margin-bottom\": (\n responsive: true,\n property: margin-bottom,\n class: mb,\n values: $negative-spacers\n ),\n \"negative-margin-start\": (\n responsive: true,\n property: margin-left,\n class: ms,\n values: $negative-spacers\n ),\n // Padding utilities\n \"padding\": (\n responsive: true,\n property: padding,\n class: p,\n values: $spacers\n ),\n \"padding-x\": (\n responsive: true,\n property: padding-right padding-left,\n class: px,\n values: $spacers\n ),\n \"padding-y\": (\n responsive: true,\n property: padding-top padding-bottom,\n class: py,\n values: $spacers\n ),\n \"padding-top\": (\n responsive: true,\n property: padding-top,\n class: pt,\n values: $spacers\n ),\n \"padding-end\": (\n responsive: true,\n property: padding-right,\n class: pe,\n values: $spacers\n ),\n \"padding-bottom\": (\n responsive: true,\n property: padding-bottom,\n class: pb,\n values: $spacers\n ),\n \"padding-start\": (\n responsive: true,\n property: padding-left,\n class: ps,\n values: $spacers\n ),\n // scss-docs-end utils-spacing\n // Text\n // scss-docs-start utils-text\n \"font-family\": (\n property: font-family,\n class: font,\n values: (monospace: var(--#{$variable-prefix}font-monospace))\n ),\n \"font-size\": (\n rfs: true,\n property: font-size,\n class: fs,\n values: $font-sizes\n ),\n \"font-style\": (\n property: font-style,\n class: fst,\n values: italic normal\n ),\n \"font-weight\": (\n property: font-weight,\n class: fw,\n values: (\n light: $font-weight-light,\n lighter: $font-weight-lighter,\n normal: $font-weight-normal,\n bold: $font-weight-bold,\n bolder: $font-weight-bolder\n )\n ),\n \"line-height\": (\n property: line-height,\n class: lh,\n values: (\n 1: 1,\n sm: $line-height-sm,\n base: $line-height-base,\n lg: $line-height-lg,\n )\n ),\n \"text-align\": (\n responsive: true,\n property: text-align,\n class: text,\n values: (\n start: left,\n end: right,\n center: center,\n )\n ),\n \"text-decoration\": (\n property: text-decoration,\n values: none underline line-through\n ),\n \"text-transform\": (\n property: text-transform,\n class: text,\n values: lowercase uppercase capitalize\n ),\n \"white-space\": (\n property: white-space,\n class: text,\n values: (\n wrap: normal,\n nowrap: nowrap,\n )\n ),\n \"word-wrap\": (\n property: word-wrap word-break,\n class: text,\n values: (break: break-word),\n rtl: false\n ),\n // scss-docs-end utils-text\n // scss-docs-start utils-color\n \"color\": (\n property: color,\n class: text,\n local-vars: (\n \"text-opacity\": 1\n ),\n values: map-merge(\n $utilities-text-colors,\n (\n \"muted\": $text-muted,\n \"black-50\": rgba($black, .5), // deprecated\n \"white-50\": rgba($white, .5), // deprecated\n \"reset\": inherit,\n )\n )\n ),\n \"text-opacity\": (\n css-var: true,\n class: text-opacity,\n values: (\n 25: .25,\n 50: .5,\n 75: .75,\n 100: 1\n )\n ),\n // scss-docs-end utils-color\n // scss-docs-start utils-bg-color\n \"background-color\": (\n property: background-color,\n class: bg,\n local-vars: (\n \"bg-opacity\": 1\n ),\n values: map-merge(\n $utilities-bg-colors,\n (\n \"transparent\": transparent\n )\n )\n ),\n \"bg-opacity\": (\n css-var: true,\n class: bg-opacity,\n values: (\n 10: .1,\n 25: .25,\n 50: .5,\n 75: .75,\n 100: 1\n )\n ),\n // scss-docs-end utils-bg-color\n \"gradient\": (\n property: background-image,\n class: bg,\n values: (gradient: var(--#{$variable-prefix}gradient))\n ),\n // scss-docs-start utils-interaction\n \"user-select\": (\n property: user-select,\n values: all auto none\n ),\n \"pointer-events\": (\n property: pointer-events,\n class: pe,\n values: none auto,\n ),\n // scss-docs-end utils-interaction\n // scss-docs-start utils-border-radius\n \"rounded\": (\n property: border-radius,\n class: rounded,\n values: (\n null: $border-radius,\n 0: 0,\n 1: $border-radius-sm,\n 2: $border-radius,\n 3: $border-radius-lg,\n circle: 50%,\n pill: $border-radius-pill\n )\n ),\n \"rounded-top\": (\n property: border-top-left-radius border-top-right-radius,\n class: rounded-top,\n values: (null: $border-radius)\n ),\n \"rounded-end\": (\n property: border-top-right-radius border-bottom-right-radius,\n class: rounded-end,\n values: (null: $border-radius)\n ),\n \"rounded-bottom\": (\n property: border-bottom-right-radius border-bottom-left-radius,\n class: rounded-bottom,\n values: (null: $border-radius)\n ),\n \"rounded-start\": (\n property: border-bottom-left-radius border-top-left-radius,\n class: rounded-start,\n values: (null: $border-radius)\n ),\n // scss-docs-end utils-border-radius\n // scss-docs-start utils-visibility\n \"visibility\": (\n property: visibility,\n class: null,\n values: (\n visible: visible,\n invisible: hidden,\n )\n )\n // scss-docs-end utils-visibility\n ),\n $utilities\n);\n", + "/*!\n * Bootstrap v5.1.0 (https://getbootstrap.com/)\n * Copyright 2011-2021 The Bootstrap Authors\n * Copyright 2011-2021 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)\n */\n\n// scss-docs-start import-stack\n// Configuration\n@import \"functions\";\n@import \"variables\";\n@import \"mixins\";\n@import \"utilities\";\n\n// Layout & components\n@import \"root\";\n@import \"reboot\";\n@import \"type\";\n@import \"images\";\n@import \"containers\";\n@import \"grid\";\n@import \"tables\";\n@import \"forms\";\n@import \"buttons\";\n@import \"transitions\";\n@import \"dropdown\";\n@import \"button-group\";\n@import \"nav\";\n@import \"navbar\";\n@import \"card\";\n@import \"accordion\";\n@import \"breadcrumb\";\n@import \"pagination\";\n@import \"badge\";\n@import \"alert\";\n@import \"progress\";\n@import \"list-group\";\n@import \"close\";\n@import \"toasts\";\n@import \"modal\";\n@import \"tooltip\";\n@import \"popover\";\n@import \"carousel\";\n@import \"spinners\";\n@import \"offcanvas\";\n@import \"placeholders\";\n\n// Helpers\n@import \"helpers\";\n\n// Utilities\n@import \"utilities/api\";\n// scss-docs-end import-stack\n", + "// Bootstrap functions\n//\n// Utility mixins and functions for evaluating source code across our variables, maps, and mixins.\n\n// Ascending\n// Used to evaluate Sass maps like our grid breakpoints.\n@mixin _assert-ascending($map, $map-name) {\n $prev-key: null;\n $prev-num: null;\n @each $key, $num in $map {\n @if $prev-num == null or unit($num) == \"%\" or unit($prev-num) == \"%\" {\n // Do nothing\n } @else if not comparable($prev-num, $num) {\n @warn \"Potentially invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} whose unit makes it incomparable to #{$prev-num}, the value of the previous key '#{$prev-key}' !\";\n } @else if $prev-num >= $num {\n @warn \"Invalid value for #{$map-name}: This map must be in ascending order, but key '#{$key}' has value #{$num} which isn't greater than #{$prev-num}, the value of the previous key '#{$prev-key}' !\";\n }\n $prev-key: $key;\n $prev-num: $num;\n }\n}\n\n// Starts at zero\n// Used to ensure the min-width of the lowest breakpoint starts at 0.\n@mixin _assert-starts-at-zero($map, $map-name: \"$grid-breakpoints\") {\n @if length($map) > 0 {\n $values: map-values($map);\n $first-value: nth($values, 1);\n @if $first-value != 0 {\n @warn \"First breakpoint in #{$map-name} must start at 0, but starts at #{$first-value}.\";\n }\n }\n}\n\n// Colors\n@function to-rgb($value) {\n @return red($value), green($value), blue($value);\n}\n\n@function rgba-css-var($identifier, $target) {\n @return rgba(var(--#{$variable-prefix}#{$identifier}-rgb), var(--#{$variable-prefix}#{$target}-opacity));\n}\n\n// stylelint-disable scss/dollar-variable-pattern\n@function map-loop($map, $func, $args...) {\n $_map: ();\n\n @each $key, $value in $map {\n // allow to pass the $key and $value of the map as an function argument\n $_args: ();\n @each $arg in $args {\n $_args: append($_args, if($arg == \"$key\", $key, if($arg == \"$value\", $value, $arg)));\n }\n\n $_map: map-merge($_map, ($key: call(get-function($func), $_args...)));\n }\n\n @return $_map;\n}\n// stylelint-enable scss/dollar-variable-pattern\n\n@function varify($list) {\n $result: null;\n @each $entry in $list {\n $result: append($result, var(--#{$variable-prefix}#{$entry}), space);\n }\n @return $result;\n}\n\n// Internal Bootstrap function to turn maps into its negative variant.\n// It prefixes the keys with `n` and makes the value negative.\n@function negativify-map($map) {\n $result: ();\n @each $key, $value in $map {\n @if $key != 0 {\n $result: map-merge($result, (\"n\" + $key: (-$value)));\n }\n }\n @return $result;\n}\n\n// Get multiple keys from a sass map\n@function map-get-multiple($map, $values) {\n $result: ();\n @each $key, $value in $map {\n @if (index($values, $key) != null) {\n $result: map-merge($result, ($key: $value));\n }\n }\n @return $result;\n}\n\n// Merge multiple maps\n@function map-merge-multiple($maps...) {\n $merged-maps: ();\n\n @each $map in $maps {\n $merged-maps: map-merge($merged-maps, $map);\n }\n @return $merged-maps;\n}\n\n// Replace `$search` with `$replace` in `$string`\n// Used on our SVG icon backgrounds for custom forms.\n//\n// @author Hugo Giraudel\n// @param {String} $string - Initial string\n// @param {String} $search - Substring to replace\n// @param {String} $replace ('') - New value\n// @return {String} - Updated string\n@function str-replace($string, $search, $replace: \"\") {\n $index: str-index($string, $search);\n\n @if $index {\n @return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);\n }\n\n @return $string;\n}\n\n// See https://codepen.io/kevinweber/pen/dXWoRw\n//\n// Requires the use of quotes around data URIs.\n\n@function escape-svg($string) {\n @if str-index($string, \"data:image/svg+xml\") {\n @each $char, $encoded in $escaped-characters {\n // Do not escape the url brackets\n @if str-index($string, \"url(\") == 1 {\n $string: url(\"#{str-replace(str-slice($string, 6, -3), $char, $encoded)}\");\n } @else {\n $string: str-replace($string, $char, $encoded);\n }\n }\n }\n\n @return $string;\n}\n\n// Color contrast\n// See https://github.com/twbs/bootstrap/pull/30168\n\n// A list of pre-calculated numbers of pow(divide((divide($value, 255) + .055), 1.055), 2.4). (from 0 to 255)\n// stylelint-disable-next-line scss/dollar-variable-default, scss/dollar-variable-pattern\n$_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003 .0033 .0037 .004 .0044 .0048 .0052 .0056 .006 .0065 .007 .0075 .008 .0086 .0091 .0097 .0103 .011 .0116 .0 .013 .0137 .0144 .0152 .016 .0168 .0176 .0185 .0194 .0203 .0212 .0222 .0232 .0242 .0252 .0262 .0273 .0284 .0296 .0307 .0319 .0331 .0343 .0356 .0369 .0382 .0395 .0409 .0423 .0437 .0452 .0467 .0482 .0497 .0513 .0529 .0545 .0561 .0578 .0595 .0612 .063 .0648 .0666 .0685 .0704 .0723 .0742 .0762 .0782 .0802 .0823 .0844 .0865 .0887 .0908 .0931 .0953 .0976 .0999 .1022 .1046 .107 .1095 .1119 .1144 .117 .1195 .1221 .1248 .1274 .1301 .1329 .1356 .1384 .1413 .1441 .147 .15 .1529 .1559 .159 .162 .1651 .1683 .1714 .1746 .1779 .1812 .1845 .1878 .1912 .1946 .1981 .2016 .2051 .2086 .2122 .2159 .2195 .2232 .227 .2307 .2346 .2384 .2423 .2462 .2502 .2542 .2582 .2623 .2664 .2705 .2747 .2789 .2831 .2874 .2918 .2961 .3005 .305 .3095 .314 .3185 .3231 .3278 .3325 .3372 .3419 .3467 .3515 .3564 .3613 .3663 .3712 .3763 .3813 .3864 .3916 .3968 .402 .4072 .4125 .4179 .4233 .4287 .4342 .4397 .4452 .4508 .4564 .4621 .4678 .4735 .4793 .4851 .491 .4969 .5029 .5089 .5149 .521 .5271 .5333 .5395 .5457 .552 .5583 .5647 .5711 .5776 .5841 .5906 .5972 .6038 .6105 .6172 .624 .6308 .6376 .6445 .6514 .6584 .6654 .6724 .6795 .6867 .6939 .7011 .7084 .7157 .7231 .7305 .7379 .7454 .7529 .7605 .7682 .7758 .7835 .7913 .7991 .807 .8148 .8228 .8308 .8388 .8469 .855 .8632 .8714 .8796 .8879 .8963 .9047 .9131 .9216 .9301 .9387 .9473 .956 .9647 .9734 .9823 .9911 1;\n\n@function color-contrast($background, $color-contrast-dark: $color-contrast-dark, $color-contrast-light: $color-contrast-light, $min-contrast-ratio: $min-contrast-ratio) {\n $foregrounds: $color-contrast-light, $color-contrast-dark, $white, $black;\n $max-ratio: 0;\n $max-ratio-color: null;\n\n @each $color in $foregrounds {\n $contrast-ratio: contrast-ratio($background, $color);\n @if $contrast-ratio > $min-contrast-ratio {\n @return $color;\n } @else if $contrast-ratio > $max-ratio {\n $max-ratio: $contrast-ratio;\n $max-ratio-color: $color;\n }\n }\n\n @warn \"Found no color leading to #{$min-contrast-ratio}:1 contrast ratio against #{$background}...\";\n\n @return $max-ratio-color;\n}\n\n@function contrast-ratio($background, $foreground: $color-contrast-light) {\n $l1: luminance($background);\n $l2: luminance(opaque($background, $foreground));\n\n @return if($l1 > $l2, divide($l1 + .05, $l2 + .05), divide($l2 + .05, $l1 + .05));\n}\n\n// Return WCAG2.0 relative luminance\n// See https://www.w3.org/WAI/GL/wiki/Relative_luminance\n// See https://www.w3.org/TR/WCAG20-TECHS/G17.html#G17-tests\n@function luminance($color) {\n $rgb: (\n \"r\": red($color),\n \"g\": green($color),\n \"b\": blue($color)\n );\n\n @each $name, $value in $rgb {\n $value: if(divide($value, 255) < .03928, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));\n $rgb: map-merge($rgb, ($name: $value));\n }\n\n @return (map-get($rgb, \"r\") * .2126) + (map-get($rgb, \"g\") * .7152) + (map-get($rgb, \"b\") * .0722);\n}\n\n// Return opaque color\n// opaque(#fff, rgba(0, 0, 0, .5)) => #808080\n@function opaque($background, $foreground) {\n @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100);\n}\n\n// scss-docs-start color-functions\n// Tint a color: mix a color with white\n@function tint-color($color, $weight) {\n @return mix(white, $color, $weight);\n}\n\n// Shade a color: mix a color with black\n@function shade-color($color, $weight) {\n @return mix(black, $color, $weight);\n}\n\n// Shade the color if the weight is positive, else tint it\n@function shift-color($color, $weight) {\n @return if($weight > 0, shade-color($color, $weight), tint-color($color, -$weight));\n}\n// scss-docs-end color-functions\n\n// Return valid calc\n@function add($value1, $value2, $return-calc: true) {\n @if $value1 == null {\n @return $value2;\n }\n\n @if $value2 == null {\n @return $value1;\n }\n\n @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {\n @return $value1 + $value2;\n }\n\n @return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(\" + \") + $value2);\n}\n\n@function subtract($value1, $value2, $return-calc: true) {\n @if $value1 == null and $value2 == null {\n @return null;\n }\n\n @if $value1 == null {\n @return -$value2;\n }\n\n @if $value2 == null {\n @return $value1;\n }\n\n @if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {\n @return $value1 - $value2;\n }\n\n @if type-of($value2) != number {\n $value2: unquote(\"(\") + $value2 + unquote(\")\");\n }\n\n @return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(\" - \") + $value2);\n}\n\n@function divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n $remainder: $dividend;\n $result: 0;\n $factor: 10;\n @while ($remainder > 0 and $precision >= 0) {\n $quotient: 0;\n @while ($remainder >= $divisor) {\n $remainder: $remainder - $divisor;\n $quotient: $quotient + 1;\n }\n $result: $result * 10 + $quotient;\n $factor: $factor * .1;\n $remainder: $remainder * 10;\n $precision: $precision - 1;\n @if ($precision < 0 and $remainder >= $divisor * 5) {\n $result: $result + 1;\n }\n }\n $result: $result * $factor * $sign;\n $dividend-unit: unit($dividend);\n $divisor-unit: unit($divisor);\n $unit-map: (\n \"px\": 1px,\n \"rem\": 1rem,\n \"em\": 1em,\n \"%\": 1%\n );\n @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {\n $result: $result * map-get($unit-map, $dividend-unit);\n }\n @return $result;\n}\n", + "// Variables\n//\n// Variables should follow the `$component-state-property-size` formula for\n// consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.\n\n// Color system\n\n// scss-docs-start gray-color-variables\n$white: #fff !default;\n$gray-100: #f8f9fa !default;\n$gray-200: #e9ecef !default;\n$gray-300: #dee2e6 !default;\n$gray-400: #ced4da !default;\n$gray-500: #adb5bd !default;\n$gray-600: #6c757d !default;\n$gray-700: #495057 !default;\n$gray-800: #343a40 !default;\n$gray-900: #212529 !default;\n$black: #000 !default;\n// scss-docs-end gray-color-variables\n\n// fusv-disable\n// scss-docs-start gray-colors-map\n$grays: (\n \"100\": $gray-100,\n \"200\": $gray-200,\n \"300\": $gray-300,\n \"400\": $gray-400,\n \"500\": $gray-500,\n \"600\": $gray-600,\n \"700\": $gray-700,\n \"800\": $gray-800,\n \"900\": $gray-900\n) !default;\n// scss-docs-end gray-colors-map\n// fusv-enable\n\n// scss-docs-start color-variables\n$blue: #0d6efd !default;\n$indigo: #6610f2 !default;\n$purple: #6f42c1 !default;\n$pink: #d63384 !default;\n$red: #dc3545 !default;\n$orange: #fd7e14 !default;\n$yellow: #ffc107 !default;\n$green: #198754 !default;\n$teal: #20c997 !default;\n$cyan: #0dcaf0 !default;\n// scss-docs-end color-variables\n\n// scss-docs-start colors-map\n$colors: (\n \"blue\": $blue,\n \"indigo\": $indigo,\n \"purple\": $purple,\n \"pink\": $pink,\n \"red\": $red,\n \"orange\": $orange,\n \"yellow\": $yellow,\n \"green\": $green,\n \"teal\": $teal,\n \"cyan\": $cyan,\n \"white\": $white,\n \"gray\": $gray-600,\n \"gray-dark\": $gray-800\n) !default;\n// scss-docs-end colors-map\n\n// scss-docs-start theme-color-variables\n$primary: $blue !default;\n$secondary: $gray-600 !default;\n$success: $green !default;\n$info: $cyan !default;\n$warning: $yellow !default;\n$danger: $red !default;\n$light: $gray-100 !default;\n$dark: $gray-900 !default;\n// scss-docs-end theme-color-variables\n\n// scss-docs-start theme-colors-map\n$theme-colors: (\n \"primary\": $primary,\n \"secondary\": $secondary,\n \"success\": $success,\n \"info\": $info,\n \"warning\": $warning,\n \"danger\": $danger,\n \"light\": $light,\n \"dark\": $dark\n) !default;\n// scss-docs-end theme-colors-map\n\n// scss-docs-start theme-colors-rgb\n$theme-colors-rgb: map-loop($theme-colors, to-rgb, \"$value\") !default;\n// scss-docs-end theme-colors-rgb\n\n// The contrast ratio to reach against white, to determine if color changes from \"light\" to \"dark\". Acceptable values for WCAG 2.0 are 3, 4.5 and 7.\n// See https://www.w3.org/TR/WCAG20/#visual-audio-contrast-contrast\n$min-contrast-ratio: 4.5 !default;\n\n// Customize the light and dark text colors for use in our color contrast function.\n$color-contrast-dark: $black !default;\n$color-contrast-light: $white !default;\n\n// fusv-disable\n$blue-100: tint-color($blue, 80%) !default;\n$blue-200: tint-color($blue, 60%) !default;\n$blue-300: tint-color($blue, 40%) !default;\n$blue-400: tint-color($blue, 20%) !default;\n$blue-500: $blue !default;\n$blue-600: shade-color($blue, 20%) !default;\n$blue-700: shade-color($blue, 40%) !default;\n$blue-800: shade-color($blue, 60%) !default;\n$blue-900: shade-color($blue, 80%) !default;\n\n$indigo-100: tint-color($indigo, 80%) !default;\n$indigo-200: tint-color($indigo, 60%) !default;\n$indigo-300: tint-color($indigo, 40%) !default;\n$indigo-400: tint-color($indigo, 20%) !default;\n$indigo-500: $indigo !default;\n$indigo-600: shade-color($indigo, 20%) !default;\n$indigo-700: shade-color($indigo, 40%) !default;\n$indigo-800: shade-color($indigo, 60%) !default;\n$indigo-900: shade-color($indigo, 80%) !default;\n\n$purple-100: tint-color($purple, 80%) !default;\n$purple-200: tint-color($purple, 60%) !default;\n$purple-300: tint-color($purple, 40%) !default;\n$purple-400: tint-color($purple, 20%) !default;\n$purple-500: $purple !default;\n$purple-600: shade-color($purple, 20%) !default;\n$purple-700: shade-color($purple, 40%) !default;\n$purple-800: shade-color($purple, 60%) !default;\n$purple-900: shade-color($purple, 80%) !default;\n\n$pink-100: tint-color($pink, 80%) !default;\n$pink-200: tint-color($pink, 60%) !default;\n$pink-300: tint-color($pink, 40%) !default;\n$pink-400: tint-color($pink, 20%) !default;\n$pink-500: $pink !default;\n$pink-600: shade-color($pink, 20%) !default;\n$pink-700: shade-color($pink, 40%) !default;\n$pink-800: shade-color($pink, 60%) !default;\n$pink-900: shade-color($pink, 80%) !default;\n\n$red-100: tint-color($red, 80%) !default;\n$red-200: tint-color($red, 60%) !default;\n$red-300: tint-color($red, 40%) !default;\n$red-400: tint-color($red, 20%) !default;\n$red-500: $red !default;\n$red-600: shade-color($red, 20%) !default;\n$red-700: shade-color($red, 40%) !default;\n$red-800: shade-color($red, 60%) !default;\n$red-900: shade-color($red, 80%) !default;\n\n$orange-100: tint-color($orange, 80%) !default;\n$orange-200: tint-color($orange, 60%) !default;\n$orange-300: tint-color($orange, 40%) !default;\n$orange-400: tint-color($orange, 20%) !default;\n$orange-500: $orange !default;\n$orange-600: shade-color($orange, 20%) !default;\n$orange-700: shade-color($orange, 40%) !default;\n$orange-800: shade-color($orange, 60%) !default;\n$orange-900: shade-color($orange, 80%) !default;\n\n$yellow-100: tint-color($yellow, 80%) !default;\n$yellow-200: tint-color($yellow, 60%) !default;\n$yellow-300: tint-color($yellow, 40%) !default;\n$yellow-400: tint-color($yellow, 20%) !default;\n$yellow-500: $yellow !default;\n$yellow-600: shade-color($yellow, 20%) !default;\n$yellow-700: shade-color($yellow, 40%) !default;\n$yellow-800: shade-color($yellow, 60%) !default;\n$yellow-900: shade-color($yellow, 80%) !default;\n\n$green-100: tint-color($green, 80%) !default;\n$green-200: tint-color($green, 60%) !default;\n$green-300: tint-color($green, 40%) !default;\n$green-400: tint-color($green, 20%) !default;\n$green-500: $green !default;\n$green-600: shade-color($green, 20%) !default;\n$green-700: shade-color($green, 40%) !default;\n$green-800: shade-color($green, 60%) !default;\n$green-900: shade-color($green, 80%) !default;\n\n$teal-100: tint-color($teal, 80%) !default;\n$teal-200: tint-color($teal, 60%) !default;\n$teal-300: tint-color($teal, 40%) !default;\n$teal-400: tint-color($teal, 20%) !default;\n$teal-500: $teal !default;\n$teal-600: shade-color($teal, 20%) !default;\n$teal-700: shade-color($teal, 40%) !default;\n$teal-800: shade-color($teal, 60%) !default;\n$teal-900: shade-color($teal, 80%) !default;\n\n$cyan-100: tint-color($cyan, 80%) !default;\n$cyan-200: tint-color($cyan, 60%) !default;\n$cyan-300: tint-color($cyan, 40%) !default;\n$cyan-400: tint-color($cyan, 20%) !default;\n$cyan-500: $cyan !default;\n$cyan-600: shade-color($cyan, 20%) !default;\n$cyan-700: shade-color($cyan, 40%) !default;\n$cyan-800: shade-color($cyan, 60%) !default;\n$cyan-900: shade-color($cyan, 80%) !default;\n\n$blues: (\n \"blue-100\": $blue-100,\n \"blue-200\": $blue-200,\n \"blue-300\": $blue-300,\n \"blue-400\": $blue-400,\n \"blue-500\": $blue-500,\n \"blue-600\": $blue-600,\n \"blue-700\": $blue-700,\n \"blue-800\": $blue-800,\n \"blue-900\": $blue-900\n) !default;\n\n$indigos: (\n \"indigo-100\": $indigo-100,\n \"indigo-200\": $indigo-200,\n \"indigo-300\": $indigo-300,\n \"indigo-400\": $indigo-400,\n \"indigo-500\": $indigo-500,\n \"indigo-600\": $indigo-600,\n \"indigo-700\": $indigo-700,\n \"indigo-800\": $indigo-800,\n \"indigo-900\": $indigo-900\n) !default;\n\n$purples: (\n \"purple-100\": $purple-200,\n \"purple-200\": $purple-100,\n \"purple-300\": $purple-300,\n \"purple-400\": $purple-400,\n \"purple-500\": $purple-500,\n \"purple-600\": $purple-600,\n \"purple-700\": $purple-700,\n \"purple-800\": $purple-800,\n \"purple-900\": $purple-900\n) !default;\n\n$pinks: (\n \"pink-100\": $pink-100,\n \"pink-200\": $pink-200,\n \"pink-300\": $pink-300,\n \"pink-400\": $pink-400,\n \"pink-500\": $pink-500,\n \"pink-600\": $pink-600,\n \"pink-700\": $pink-700,\n \"pink-800\": $pink-800,\n \"pink-900\": $pink-900\n) !default;\n\n$reds: (\n \"red-100\": $red-100,\n \"red-200\": $red-200,\n \"red-300\": $red-300,\n \"red-400\": $red-400,\n \"red-500\": $red-500,\n \"red-600\": $red-600,\n \"red-700\": $red-700,\n \"red-800\": $red-800,\n \"red-900\": $red-900\n) !default;\n\n$oranges: (\n \"orange-100\": $orange-100,\n \"orange-200\": $orange-200,\n \"orange-300\": $orange-300,\n \"orange-400\": $orange-400,\n \"orange-500\": $orange-500,\n \"orange-600\": $orange-600,\n \"orange-700\": $orange-700,\n \"orange-800\": $orange-800,\n \"orange-900\": $orange-900\n) !default;\n\n$yellows: (\n \"yellow-100\": $yellow-100,\n \"yellow-200\": $yellow-200,\n \"yellow-300\": $yellow-300,\n \"yellow-400\": $yellow-400,\n \"yellow-500\": $yellow-500,\n \"yellow-600\": $yellow-600,\n \"yellow-700\": $yellow-700,\n \"yellow-800\": $yellow-800,\n \"yellow-900\": $yellow-900\n) !default;\n\n$greens: (\n \"green-100\": $green-100,\n \"green-200\": $green-200,\n \"green-300\": $green-300,\n \"green-400\": $green-400,\n \"green-500\": $green-500,\n \"green-600\": $green-600,\n \"green-700\": $green-700,\n \"green-800\": $green-800,\n \"green-900\": $green-900\n) !default;\n\n$teals: (\n \"teal-100\": $teal-100,\n \"teal-200\": $teal-200,\n \"teal-300\": $teal-300,\n \"teal-400\": $teal-400,\n \"teal-500\": $teal-500,\n \"teal-600\": $teal-600,\n \"teal-700\": $teal-700,\n \"teal-800\": $teal-800,\n \"teal-900\": $teal-900\n) !default;\n\n$cyans: (\n \"cyan-100\": $cyan-100,\n \"cyan-200\": $cyan-200,\n \"cyan-300\": $cyan-300,\n \"cyan-400\": $cyan-400,\n \"cyan-500\": $cyan-500,\n \"cyan-600\": $cyan-600,\n \"cyan-700\": $cyan-700,\n \"cyan-800\": $cyan-800,\n \"cyan-900\": $cyan-900\n) !default;\n// fusv-enable\n\n// Characters which are escaped by the escape-svg function\n$escaped-characters: (\n (\"<\", \"%3c\"),\n (\">\", \"%3e\"),\n (\"#\", \"%23\"),\n (\"(\", \"%28\"),\n (\")\", \"%29\"),\n) !default;\n\n// Options\n//\n// Quickly modify global styling by enabling or disabling optional features.\n\n$enable-caret: true !default;\n$enable-rounded: true !default;\n$enable-shadows: false !default;\n$enable-gradients: false !default;\n$enable-transitions: true !default;\n$enable-reduced-motion: true !default;\n$enable-smooth-scroll: true !default;\n$enable-grid-classes: true !default;\n$enable-cssgrid: false !default;\n$enable-button-pointers: true !default;\n$enable-rfs: true !default;\n$enable-validation-icons: true !default;\n$enable-negative-margins: false !default;\n$enable-deprecation-messages: true !default;\n$enable-important-utilities: true !default;\n\n// Prefix for :root CSS variables\n\n$variable-prefix: bs- !default;\n\n// Gradient\n//\n// The gradient which is added to components if `$enable-gradients` is `true`\n// This gradient is also added to elements with `.bg-gradient`\n// scss-docs-start variable-gradient\n$gradient: linear-gradient(180deg, rgba($white, .15), rgba($white, 0)) !default;\n// scss-docs-end variable-gradient\n\n// Spacing\n//\n// Control the default styling of most Bootstrap elements by modifying these\n// variables. Mostly focused on spacing.\n// You can add more entries to the $spacers map, should you need more variation.\n\n// scss-docs-start spacer-variables-maps\n$spacer: 1rem !default;\n$spacers: (\n 0: 0,\n 1: $spacer * .25,\n 2: $spacer * .5,\n 3: $spacer,\n 4: $spacer * 1.5,\n 5: $spacer * 3,\n) !default;\n\n$negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default;\n// scss-docs-end spacer-variables-maps\n\n// Position\n//\n// Define the edge positioning anchors of the position utilities.\n\n// scss-docs-start position-map\n$position-values: (\n 0: 0,\n 50: 50%,\n 100: 100%\n) !default;\n// scss-docs-end position-map\n\n// Body\n//\n// Settings for the `` element.\n\n$body-bg: $white !default;\n$body-color: $gray-900 !default;\n$body-text-align: null !default;\n\n// Utilities maps\n//\n// Extends the default `$theme-colors` maps to help create our utilities.\n\n// scss-docs-start utilities-colors\n$utilities-colors: map-merge(\n $theme-colors-rgb,\n (\n \"black\": to-rgb($black),\n \"white\": to-rgb($white),\n \"body\": to-rgb($body-color)\n )\n) !default;\n// scss-docs-end utilities-colors\n\n// scss-docs-start utilities-text-colors\n$utilities-text-colors: map-loop($utilities-colors, rgba-css-var, \"$key\", \"text\") !default;\n// scss-docs-end utilities-text-colors\n\n// scss-docs-start utilities-bg-colors\n$utilities-bg-colors: map-loop($utilities-colors, rgba-css-var, \"$key\", \"bg\") !default;\n// scss-docs-end utilities-bg-colors\n\n// Links\n//\n// Style anchor elements.\n\n$link-color: $primary !default;\n$link-decoration: underline !default;\n$link-shade-percentage: 20% !default;\n$link-hover-color: shift-color($link-color, $link-shade-percentage) !default;\n$link-hover-decoration: null !default;\n\n$stretched-link-pseudo-element: after !default;\n$stretched-link-z-index: 1 !default;\n\n// Paragraphs\n//\n// Style p element.\n\n$paragraph-margin-bottom: 1rem !default;\n\n\n// Grid breakpoints\n//\n// Define the minimum dimensions at which your layout will change,\n// adapting to different screen sizes, for use in media queries.\n\n// scss-docs-start grid-breakpoints\n$grid-breakpoints: (\n xs: 0,\n sm: 576px,\n md: 768px,\n lg: 992px,\n xl: 1200px,\n xxl: 1400px\n) !default;\n// scss-docs-end grid-breakpoints\n\n@include _assert-ascending($grid-breakpoints, \"$grid-breakpoints\");\n@include _assert-starts-at-zero($grid-breakpoints, \"$grid-breakpoints\");\n\n\n// Grid containers\n//\n// Define the maximum width of `.container` for different screen sizes.\n\n// scss-docs-start container-max-widths\n$container-max-widths: (\n sm: 540px,\n md: 720px,\n lg: 960px,\n xl: 1140px,\n xxl: 1320px\n) !default;\n// scss-docs-end container-max-widths\n\n@include _assert-ascending($container-max-widths, \"$container-max-widths\");\n\n\n// Grid columns\n//\n// Set the number of columns and specify the width of the gutters.\n\n$grid-columns: 12 !default;\n$grid-gutter-width: 1.5rem !default;\n$grid-row-columns: 6 !default;\n\n$gutters: $spacers !default;\n\n// Container padding\n\n$container-padding-x: $grid-gutter-width * .5 !default;\n\n\n// Components\n//\n// Define common padding and border radius sizes and more.\n\n// scss-docs-start border-variables\n$border-width: 1px !default;\n$border-widths: (\n 1: 1px,\n 2: 2px,\n 3: 3px,\n 4: 4px,\n 5: 5px\n) !default;\n\n$border-color: $gray-300 !default;\n// scss-docs-end border-variables\n\n// scss-docs-start border-radius-variables\n$border-radius: .25rem !default;\n$border-radius-sm: .2rem !default;\n$border-radius-lg: .3rem !default;\n$border-radius-pill: 50rem !default;\n// scss-docs-end border-radius-variables\n\n// scss-docs-start box-shadow-variables\n$box-shadow: 0 .5rem 1rem rgba($black, .15) !default;\n$box-shadow-sm: 0 .125rem .25rem rgba($black, .075) !default;\n$box-shadow-lg: 0 1rem 3rem rgba($black, .175) !default;\n$box-shadow-inset: inset 0 1px 2px rgba($black, .075) !default;\n// scss-docs-end box-shadow-variables\n\n$component-active-color: $white !default;\n$component-active-bg: $primary !default;\n\n// scss-docs-start caret-variables\n$caret-width: .3em !default;\n$caret-vertical-align: $caret-width * .85 !default;\n$caret-spacing: $caret-width * .85 !default;\n// scss-docs-end caret-variables\n\n$transition-base: all .2s ease-in-out !default;\n$transition-fade: opacity .15s linear !default;\n// scss-docs-start collapse-transition\n$transition-collapse: height .35s ease !default;\n$transition-collapse-width: width .35s ease !default;\n// scss-docs-end collapse-transition\n\n// stylelint-disable function-disallowed-list\n// scss-docs-start aspect-ratios\n$aspect-ratios: (\n \"1x1\": 100%,\n \"4x3\": calc(3 / 4 * 100%),\n \"16x9\": calc(9 / 16 * 100%),\n \"21x9\": calc(9 / 21 * 100%)\n) !default;\n// scss-docs-end aspect-ratios\n// stylelint-enable function-disallowed-list\n\n// Typography\n//\n// Font, line-height, and color for body text, headings, and more.\n\n// scss-docs-start font-variables\n// stylelint-disable value-keyword-case\n$font-family-sans-serif: system-ui, -apple-system, \"Segoe UI\", Roboto, \"Helvetica Neue\", Arial, \"Noto Sans\", \"Liberation Sans\", sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\" !default;\n$font-family-monospace: SFMono-Regular, Menlo, Monaco, Consolas, \"Liberation Mono\", \"Courier New\", monospace !default;\n// stylelint-enable value-keyword-case\n$font-family-base: var(--#{$variable-prefix}font-sans-serif) !default;\n$font-family-code: var(--#{$variable-prefix}font-monospace) !default;\n\n// $font-size-root affects the value of `rem`, which is used for as well font sizes, paddings, and margins\n// $font-size-base affects the font size of the body text\n$font-size-root: null !default;\n$font-size-base: 1rem !default; // Assumes the browser default, typically `16px`\n$font-size-sm: $font-size-base * .875 !default;\n$font-size-lg: $font-size-base * 1.25 !default;\n\n$font-weight-lighter: lighter !default;\n$font-weight-light: 300 !default;\n$font-weight-normal: 400 !default;\n$font-weight-bold: 700 !default;\n$font-weight-bolder: bolder !default;\n\n$font-weight-base: $font-weight-normal !default;\n\n$line-height-base: 1.5 !default;\n$line-height-sm: 1.25 !default;\n$line-height-lg: 2 !default;\n\n$h1-font-size: $font-size-base * 2.5 !default;\n$h2-font-size: $font-size-base * 2 !default;\n$h3-font-size: $font-size-base * 1.75 !default;\n$h4-font-size: $font-size-base * 1.5 !default;\n$h5-font-size: $font-size-base * 1.25 !default;\n$h6-font-size: $font-size-base !default;\n// scss-docs-end font-variables\n\n// scss-docs-start font-sizes\n$font-sizes: (\n 1: $h1-font-size,\n 2: $h2-font-size,\n 3: $h3-font-size,\n 4: $h4-font-size,\n 5: $h5-font-size,\n 6: $h6-font-size\n) !default;\n// scss-docs-end font-sizes\n\n// scss-docs-start headings-variables\n$headings-margin-bottom: $spacer * .5 !default;\n$headings-font-family: null !default;\n$headings-font-style: null !default;\n$headings-font-weight: 500 !default;\n$headings-line-height: 1.2 !default;\n$headings-color: null !default;\n// scss-docs-end headings-variables\n\n// scss-docs-start display-headings\n$display-font-sizes: (\n 1: 5rem,\n 2: 4.5rem,\n 3: 4rem,\n 4: 3.5rem,\n 5: 3rem,\n 6: 2.5rem\n) !default;\n\n$display-font-weight: 300 !default;\n$display-line-height: $headings-line-height !default;\n// scss-docs-end display-headings\n\n// scss-docs-start type-variables\n$lead-font-size: $font-size-base * 1.25 !default;\n$lead-font-weight: 300 !default;\n\n$small-font-size: .875em !default;\n\n$sub-sup-font-size: .75em !default;\n\n$text-muted: $gray-600 !default;\n\n$initialism-font-size: $small-font-size !default;\n\n$blockquote-margin-y: $spacer !default;\n$blockquote-font-size: $font-size-base * 1.25 !default;\n$blockquote-footer-color: $gray-600 !default;\n$blockquote-footer-font-size: $small-font-size !default;\n\n$hr-margin-y: $spacer !default;\n$hr-color: inherit !default;\n$hr-height: $border-width !default;\n$hr-opacity: .25 !default;\n\n$legend-margin-bottom: .5rem !default;\n$legend-font-size: 1.5rem !default;\n$legend-font-weight: null !default;\n\n$mark-padding: .2em !default;\n\n$dt-font-weight: $font-weight-bold !default;\n\n$nested-kbd-font-weight: $font-weight-bold !default;\n\n$list-inline-padding: .5rem !default;\n\n$mark-bg: #fcf8e3 !default;\n// scss-docs-end type-variables\n\n\n// Tables\n//\n// Customizes the `.table` component with basic values, each used across all table variations.\n\n// scss-docs-start table-variables\n$table-cell-padding-y: .5rem !default;\n$table-cell-padding-x: .5rem !default;\n$table-cell-padding-y-sm: .25rem !default;\n$table-cell-padding-x-sm: .25rem !default;\n\n$table-cell-vertical-align: top !default;\n\n$table-color: $body-color !default;\n$table-bg: transparent !default;\n$table-accent-bg: transparent !default;\n\n$table-th-font-weight: null !default;\n\n$table-striped-color: $table-color !default;\n$table-striped-bg-factor: .05 !default;\n$table-striped-bg: rgba($black, $table-striped-bg-factor) !default;\n\n$table-active-color: $table-color !default;\n$table-active-bg-factor: .1 !default;\n$table-active-bg: rgba($black, $table-active-bg-factor) !default;\n\n$table-hover-color: $table-color !default;\n$table-hover-bg-factor: .075 !default;\n$table-hover-bg: rgba($black, $table-hover-bg-factor) !default;\n\n$table-border-factor: .1 !default;\n$table-border-width: $border-width !default;\n$table-border-color: $border-color !default;\n\n$table-striped-order: odd !default;\n\n$table-group-separator-color: currentColor !default;\n\n$table-caption-color: $text-muted !default;\n\n$table-bg-scale: -80% !default;\n// scss-docs-end table-variables\n\n// scss-docs-start table-loop\n$table-variants: (\n \"primary\": shift-color($primary, $table-bg-scale),\n \"secondary\": shift-color($secondary, $table-bg-scale),\n \"success\": shift-color($success, $table-bg-scale),\n \"info\": shift-color($info, $table-bg-scale),\n \"warning\": shift-color($warning, $table-bg-scale),\n \"danger\": shift-color($danger, $table-bg-scale),\n \"light\": $light,\n \"dark\": $dark,\n) !default;\n// scss-docs-end table-loop\n\n\n// Buttons + Forms\n//\n// Shared variables that are reassigned to `$input-` and `$btn-` specific variables.\n\n// scss-docs-start input-btn-variables\n$input-btn-padding-y: .375rem !default;\n$input-btn-padding-x: .75rem !default;\n$input-btn-font-family: null !default;\n$input-btn-font-size: $font-size-base !default;\n$input-btn-line-height: $line-height-base !default;\n\n$input-btn-focus-width: .25rem !default;\n$input-btn-focus-color-opacity: .25 !default;\n$input-btn-focus-color: rgba($component-active-bg, $input-btn-focus-color-opacity) !default;\n$input-btn-focus-blur: 0 !default;\n$input-btn-focus-box-shadow: 0 0 $input-btn-focus-blur $input-btn-focus-width $input-btn-focus-color !default;\n\n$input-btn-padding-y-sm: .25rem !default;\n$input-btn-padding-x-sm: .5rem !default;\n$input-btn-font-size-sm: $font-size-sm !default;\n\n$input-btn-padding-y-lg: .5rem !default;\n$input-btn-padding-x-lg: 1rem !default;\n$input-btn-font-size-lg: $font-size-lg !default;\n\n$input-btn-border-width: $border-width !default;\n// scss-docs-end input-btn-variables\n\n\n// Buttons\n//\n// For each of Bootstrap's buttons, define text, background, and border color.\n\n// scss-docs-start btn-variables\n$btn-padding-y: $input-btn-padding-y !default;\n$btn-padding-x: $input-btn-padding-x !default;\n$btn-font-family: $input-btn-font-family !default;\n$btn-font-size: $input-btn-font-size !default;\n$btn-line-height: $input-btn-line-height !default;\n$btn-white-space: null !default; // Set to `nowrap` to prevent text wrapping\n\n$btn-padding-y-sm: $input-btn-padding-y-sm !default;\n$btn-padding-x-sm: $input-btn-padding-x-sm !default;\n$btn-font-size-sm: $input-btn-font-size-sm !default;\n\n$btn-padding-y-lg: $input-btn-padding-y-lg !default;\n$btn-padding-x-lg: $input-btn-padding-x-lg !default;\n$btn-font-size-lg: $input-btn-font-size-lg !default;\n\n$btn-border-width: $input-btn-border-width !default;\n\n$btn-font-weight: $font-weight-normal !default;\n$btn-box-shadow: inset 0 1px 0 rgba($white, .15), 0 1px 1px rgba($black, .075) !default;\n$btn-focus-width: $input-btn-focus-width !default;\n$btn-focus-box-shadow: $input-btn-focus-box-shadow !default;\n$btn-disabled-opacity: .65 !default;\n$btn-active-box-shadow: inset 0 3px 5px rgba($black, .125) !default;\n\n$btn-link-color: $link-color !default;\n$btn-link-hover-color: $link-hover-color !default;\n$btn-link-disabled-color: $gray-600 !default;\n\n// Allows for customizing button radius independently from global border radius\n$btn-border-radius: $border-radius !default;\n$btn-border-radius-sm: $border-radius-sm !default;\n$btn-border-radius-lg: $border-radius-lg !default;\n\n$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$btn-hover-bg-shade-amount: 15% !default;\n$btn-hover-bg-tint-amount: 15% !default;\n$btn-hover-border-shade-amount: 20% !default;\n$btn-hover-border-tint-amount: 10% !default;\n$btn-active-bg-shade-amount: 20% !default;\n$btn-active-bg-tint-amount: 20% !default;\n$btn-active-border-shade-amount: 25% !default;\n$btn-active-border-tint-amount: 10% !default;\n// scss-docs-end btn-variables\n\n\n// Forms\n\n// scss-docs-start form-text-variables\n$form-text-margin-top: .25rem !default;\n$form-text-font-size: $small-font-size !default;\n$form-text-font-style: null !default;\n$form-text-font-weight: null !default;\n$form-text-color: $text-muted !default;\n// scss-docs-end form-text-variables\n\n// scss-docs-start form-label-variables\n$form-label-margin-bottom: .5rem !default;\n$form-label-font-size: null !default;\n$form-label-font-style: null !default;\n$form-label-font-weight: null !default;\n$form-label-color: null !default;\n// scss-docs-end form-label-variables\n\n// scss-docs-start form-input-variables\n$input-padding-y: $input-btn-padding-y !default;\n$input-padding-x: $input-btn-padding-x !default;\n$input-font-family: $input-btn-font-family !default;\n$input-font-size: $input-btn-font-size !default;\n$input-font-weight: $font-weight-base !default;\n$input-line-height: $input-btn-line-height !default;\n\n$input-padding-y-sm: $input-btn-padding-y-sm !default;\n$input-padding-x-sm: $input-btn-padding-x-sm !default;\n$input-font-size-sm: $input-btn-font-size-sm !default;\n\n$input-padding-y-lg: $input-btn-padding-y-lg !default;\n$input-padding-x-lg: $input-btn-padding-x-lg !default;\n$input-font-size-lg: $input-btn-font-size-lg !default;\n\n$input-bg: $body-bg !default;\n$input-disabled-bg: $gray-200 !default;\n$input-disabled-border-color: null !default;\n\n$input-color: $body-color !default;\n$input-border-color: $gray-400 !default;\n$input-border-width: $input-btn-border-width !default;\n$input-box-shadow: $box-shadow-inset !default;\n\n$input-border-radius: $border-radius !default;\n$input-border-radius-sm: $border-radius-sm !default;\n$input-border-radius-lg: $border-radius-lg !default;\n\n$input-focus-bg: $input-bg !default;\n$input-focus-border-color: tint-color($component-active-bg, 50%) !default;\n$input-focus-color: $input-color !default;\n$input-focus-width: $input-btn-focus-width !default;\n$input-focus-box-shadow: $input-btn-focus-box-shadow !default;\n\n$input-placeholder-color: $gray-600 !default;\n$input-plaintext-color: $body-color !default;\n\n$input-height-border: $input-border-width * 2 !default;\n\n$input-height-inner: add($input-line-height * 1em, $input-padding-y * 2) !default;\n$input-height-inner-half: add($input-line-height * .5em, $input-padding-y) !default;\n$input-height-inner-quarter: add($input-line-height * .25em, $input-padding-y * .5) !default;\n\n$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-height-border, false)) !default;\n$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-height-border, false)) !default;\n$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-height-border, false)) !default;\n\n$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$form-color-width: 3rem !default;\n// scss-docs-end form-input-variables\n\n// scss-docs-start form-check-variables\n$form-check-input-width: 1em !default;\n$form-check-min-height: $font-size-base * $line-height-base !default;\n$form-check-padding-start: $form-check-input-width + .5em !default;\n$form-check-margin-bottom: .125rem !default;\n$form-check-label-color: null !default;\n$form-check-label-cursor: null !default;\n$form-check-transition: null !default;\n\n$form-check-input-active-filter: brightness(90%) !default;\n\n$form-check-input-bg: $input-bg !default;\n$form-check-input-border: 1px solid rgba($black, .25) !default;\n$form-check-input-border-radius: .25em !default;\n$form-check-radio-border-radius: 50% !default;\n$form-check-input-focus-border: $input-focus-border-color !default;\n$form-check-input-focus-box-shadow: $input-btn-focus-box-shadow !default;\n\n$form-check-input-checked-color: $component-active-color !default;\n$form-check-input-checked-bg-color: $component-active-bg !default;\n$form-check-input-checked-border-color: $form-check-input-checked-bg-color !default;\n$form-check-input-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-check-radio-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-check-input-indeterminate-color: $component-active-color !default;\n$form-check-input-indeterminate-bg-color: $component-active-bg !default;\n$form-check-input-indeterminate-border-color: $form-check-input-indeterminate-bg-color !default;\n$form-check-input-indeterminate-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-check-input-disabled-opacity: .5 !default;\n$form-check-label-disabled-opacity: $form-check-input-disabled-opacity !default;\n$form-check-btn-check-disabled-opacity: $btn-disabled-opacity !default;\n\n$form-check-inline-margin-end: 1rem !default;\n// scss-docs-end form-check-variables\n\n// scss-docs-start form-switch-variables\n$form-switch-color: rgba(0, 0, 0, .25) !default;\n$form-switch-width: 2em !default;\n$form-switch-padding-start: $form-switch-width + .5em !default;\n$form-switch-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-switch-border-radius: $form-switch-width !default;\n$form-switch-transition: background-position .15s ease-in-out !default;\n\n$form-switch-focus-color: $input-focus-border-color !default;\n$form-switch-focus-bg-image: url(\"data:image/svg+xml,\") !default;\n\n$form-switch-checked-color: $component-active-color !default;\n$form-switch-checked-bg-image: url(\"data:image/svg+xml,\") !default;\n$form-switch-checked-bg-position: right center !default;\n// scss-docs-end form-switch-variables\n\n// scss-docs-start input-group-variables\n$input-group-addon-padding-y: $input-padding-y !default;\n$input-group-addon-padding-x: $input-padding-x !default;\n$input-group-addon-font-weight: $input-font-weight !default;\n$input-group-addon-color: $input-color !default;\n$input-group-addon-bg: $gray-200 !default;\n$input-group-addon-border-color: $input-border-color !default;\n// scss-docs-end input-group-variables\n\n// scss-docs-start form-select-variables\n$form-select-padding-y: $input-padding-y !default;\n$form-select-padding-x: $input-padding-x !default;\n$form-select-font-family: $input-font-family !default;\n$form-select-font-size: $input-font-size !default;\n$form-select-indicator-padding: $form-select-padding-x * 3 !default; // Extra padding for background-image\n$form-select-font-weight: $input-font-weight !default;\n$form-select-line-height: $input-line-height !default;\n$form-select-color: $input-color !default;\n$form-select-bg: $input-bg !default;\n$form-select-disabled-color: null !default;\n$form-select-disabled-bg: $gray-200 !default;\n$form-select-disabled-border-color: $input-disabled-border-color !default;\n$form-select-bg-position: right $form-select-padding-x center !default;\n$form-select-bg-size: 16px 12px !default; // In pixels because image dimensions\n$form-select-indicator-color: $gray-800 !default;\n$form-select-indicator: url(\"data:image/svg+xml,\") !default;\n\n$form-select-feedback-icon-padding-end: $form-select-padding-x * 2.5 + $form-select-indicator-padding !default;\n$form-select-feedback-icon-position: center right $form-select-indicator-padding !default;\n$form-select-feedback-icon-size: $input-height-inner-half $input-height-inner-half !default;\n\n$form-select-border-width: $input-border-width !default;\n$form-select-border-color: $input-border-color !default;\n$form-select-border-radius: $border-radius !default;\n$form-select-box-shadow: $box-shadow-inset !default;\n\n$form-select-focus-border-color: $input-focus-border-color !default;\n$form-select-focus-width: $input-focus-width !default;\n$form-select-focus-box-shadow: 0 0 0 $form-select-focus-width $input-btn-focus-color !default;\n\n$form-select-padding-y-sm: $input-padding-y-sm !default;\n$form-select-padding-x-sm: $input-padding-x-sm !default;\n$form-select-font-size-sm: $input-font-size-sm !default;\n\n$form-select-padding-y-lg: $input-padding-y-lg !default;\n$form-select-padding-x-lg: $input-padding-x-lg !default;\n$form-select-font-size-lg: $input-font-size-lg !default;\n\n$form-select-transition: $input-transition !default;\n// scss-docs-end form-select-variables\n\n// scss-docs-start form-range-variables\n$form-range-track-width: 100% !default;\n$form-range-track-height: .5rem !default;\n$form-range-track-cursor: pointer !default;\n$form-range-track-bg: $gray-300 !default;\n$form-range-track-border-radius: 1rem !default;\n$form-range-track-box-shadow: $box-shadow-inset !default;\n\n$form-range-thumb-width: 1rem !default;\n$form-range-thumb-height: $form-range-thumb-width !default;\n$form-range-thumb-bg: $component-active-bg !default;\n$form-range-thumb-border: 0 !default;\n$form-range-thumb-border-radius: 1rem !default;\n$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default;\n$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default;\n$form-range-thumb-focus-box-shadow-width: $input-focus-width !default; // For focus box shadow issue in Edge\n$form-range-thumb-active-bg: tint-color($component-active-bg, 70%) !default;\n$form-range-thumb-disabled-bg: $gray-500 !default;\n$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n// scss-docs-end form-range-variables\n\n// scss-docs-start form-file-variables\n$form-file-button-color: $input-color !default;\n$form-file-button-bg: $input-group-addon-bg !default;\n$form-file-button-hover-bg: shade-color($form-file-button-bg, 5%) !default;\n// scss-docs-end form-file-variables\n\n// scss-docs-start form-floating-variables\n$form-floating-height: add(3.5rem, $input-height-border) !default;\n$form-floating-line-height: 1.25 !default;\n$form-floating-padding-x: $input-padding-x !default;\n$form-floating-padding-y: 1rem !default;\n$form-floating-input-padding-t: 1.625rem !default;\n$form-floating-input-padding-b: .625rem !default;\n$form-floating-label-opacity: .65 !default;\n$form-floating-label-transform: scale(.85) translateY(-.5rem) translateX(.15rem) !default;\n$form-floating-transition: opacity .1s ease-in-out, transform .1s ease-in-out !default;\n// scss-docs-end form-floating-variables\n\n// Form validation\n\n// scss-docs-start form-feedback-variables\n$form-feedback-margin-top: $form-text-margin-top !default;\n$form-feedback-font-size: $form-text-font-size !default;\n$form-feedback-font-style: $form-text-font-style !default;\n$form-feedback-valid-color: $success !default;\n$form-feedback-invalid-color: $danger !default;\n\n$form-feedback-icon-valid-color: $form-feedback-valid-color !default;\n$form-feedback-icon-valid: url(\"data:image/svg+xml,\") !default;\n$form-feedback-icon-invalid-color: $form-feedback-invalid-color !default;\n$form-feedback-icon-invalid: url(\"data:image/svg+xml,\") !default;\n// scss-docs-end form-feedback-variables\n\n// scss-docs-start form-validation-states\n$form-validation-states: (\n \"valid\": (\n \"color\": $form-feedback-valid-color,\n \"icon\": $form-feedback-icon-valid\n ),\n \"invalid\": (\n \"color\": $form-feedback-invalid-color,\n \"icon\": $form-feedback-icon-invalid\n )\n) !default;\n// scss-docs-end form-validation-states\n\n// Z-index master list\n//\n// Warning: Avoid customizing these values. They're used for a bird's eye view\n// of components dependent on the z-axis and are designed to all work together.\n\n// scss-docs-start zindex-stack\n$zindex-dropdown: 1000 !default;\n$zindex-sticky: 1020 !default;\n$zindex-fixed: 1030 !default;\n$zindex-offcanvas-backdrop: 1040 !default;\n$zindex-offcanvas: 1045 !default;\n$zindex-modal-backdrop: 1050 !default;\n$zindex-modal: 1055 !default;\n$zindex-popover: 1070 !default;\n$zindex-tooltip: 1080 !default;\n// scss-docs-end zindex-stack\n\n\n// Navs\n\n// scss-docs-start nav-variables\n$nav-link-padding-y: .5rem !default;\n$nav-link-padding-x: 1rem !default;\n$nav-link-font-size: null !default;\n$nav-link-font-weight: null !default;\n$nav-link-color: $link-color !default;\n$nav-link-hover-color: $link-hover-color !default;\n$nav-link-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out !default;\n$nav-link-disabled-color: $gray-600 !default;\n\n$nav-tabs-border-color: $gray-300 !default;\n$nav-tabs-border-width: $border-width !default;\n$nav-tabs-border-radius: $border-radius !default;\n$nav-tabs-link-hover-border-color: $gray-200 $gray-200 $nav-tabs-border-color !default;\n$nav-tabs-link-active-color: $gray-700 !default;\n$nav-tabs-link-active-bg: $body-bg !default;\n$nav-tabs-link-active-border-color: $gray-300 $gray-300 $nav-tabs-link-active-bg !default;\n\n$nav-pills-border-radius: $border-radius !default;\n$nav-pills-link-active-color: $component-active-color !default;\n$nav-pills-link-active-bg: $component-active-bg !default;\n// scss-docs-end nav-variables\n\n\n// Navbar\n\n// scss-docs-start navbar-variables\n$navbar-padding-y: $spacer * .5 !default;\n$navbar-padding-x: null !default;\n\n$navbar-nav-link-padding-x: .5rem !default;\n\n$navbar-brand-font-size: $font-size-lg !default;\n// Compute the navbar-brand padding-y so the navbar-brand will have the same height as navbar-text and nav-link\n$nav-link-height: $font-size-base * $line-height-base + $nav-link-padding-y * 2 !default;\n$navbar-brand-height: $navbar-brand-font-size * $line-height-base !default;\n$navbar-brand-padding-y: ($nav-link-height - $navbar-brand-height) * .5 !default;\n$navbar-brand-margin-end: 1rem !default;\n\n$navbar-toggler-padding-y: .25rem !default;\n$navbar-toggler-padding-x: .75rem !default;\n$navbar-toggler-font-size: $font-size-lg !default;\n$navbar-toggler-border-radius: $btn-border-radius !default;\n$navbar-toggler-focus-width: $btn-focus-width !default;\n$navbar-toggler-transition: box-shadow .15s ease-in-out !default;\n// scss-docs-end navbar-variables\n\n// scss-docs-start navbar-theme-variables\n$navbar-dark-color: rgba($white, .55) !default;\n$navbar-dark-hover-color: rgba($white, .75) !default;\n$navbar-dark-active-color: $white !default;\n$navbar-dark-disabled-color: rgba($white, .25) !default;\n$navbar-dark-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-dark-toggler-border-color: rgba($white, .1) !default;\n\n$navbar-light-color: rgba($black, .55) !default;\n$navbar-light-hover-color: rgba($black, .7) !default;\n$navbar-light-active-color: rgba($black, .9) !default;\n$navbar-light-disabled-color: rgba($black, .3) !default;\n$navbar-light-toggler-icon-bg: url(\"data:image/svg+xml,\") !default;\n$navbar-light-toggler-border-color: rgba($black, .1) !default;\n\n$navbar-light-brand-color: $navbar-light-active-color !default;\n$navbar-light-brand-hover-color: $navbar-light-active-color !default;\n$navbar-dark-brand-color: $navbar-dark-active-color !default;\n$navbar-dark-brand-hover-color: $navbar-dark-active-color !default;\n// scss-docs-end navbar-theme-variables\n\n\n// Dropdowns\n//\n// Dropdown menu container and contents.\n\n// scss-docs-start dropdown-variables\n$dropdown-min-width: 10rem !default;\n$dropdown-padding-x: 0 !default;\n$dropdown-padding-y: .5rem !default;\n$dropdown-spacer: .125rem !default;\n$dropdown-font-size: $font-size-base !default;\n$dropdown-color: $body-color !default;\n$dropdown-bg: $white !default;\n$dropdown-border-color: rgba($black, .15) !default;\n$dropdown-border-radius: $border-radius !default;\n$dropdown-border-width: $border-width !default;\n$dropdown-inner-border-radius: subtract($dropdown-border-radius, $dropdown-border-width) !default;\n$dropdown-divider-bg: $dropdown-border-color !default;\n$dropdown-divider-margin-y: $spacer * .5 !default;\n$dropdown-box-shadow: $box-shadow !default;\n\n$dropdown-link-color: $gray-900 !default;\n$dropdown-link-hover-color: shade-color($gray-900, 10%) !default;\n$dropdown-link-hover-bg: $gray-200 !default;\n\n$dropdown-link-active-color: $component-active-color !default;\n$dropdown-link-active-bg: $component-active-bg !default;\n\n$dropdown-link-disabled-color: $gray-500 !default;\n\n$dropdown-item-padding-y: $spacer * .25 !default;\n$dropdown-item-padding-x: $spacer !default;\n\n$dropdown-header-color: $gray-600 !default;\n$dropdown-header-padding: $dropdown-padding-y $dropdown-item-padding-x !default;\n// scss-docs-end dropdown-variables\n\n// scss-docs-start dropdown-dark-variables\n$dropdown-dark-color: $gray-300 !default;\n$dropdown-dark-bg: $gray-800 !default;\n$dropdown-dark-border-color: $dropdown-border-color !default;\n$dropdown-dark-divider-bg: $dropdown-divider-bg !default;\n$dropdown-dark-box-shadow: null !default;\n$dropdown-dark-link-color: $dropdown-dark-color !default;\n$dropdown-dark-link-hover-color: $white !default;\n$dropdown-dark-link-hover-bg: rgba($white, .15) !default;\n$dropdown-dark-link-active-color: $dropdown-link-active-color !default;\n$dropdown-dark-link-active-bg: $dropdown-link-active-bg !default;\n$dropdown-dark-link-disabled-color: $gray-500 !default;\n$dropdown-dark-header-color: $gray-500 !default;\n// scss-docs-end dropdown-dark-variables\n\n\n// Pagination\n\n// scss-docs-start pagination-variables\n$pagination-padding-y: .375rem !default;\n$pagination-padding-x: .75rem !default;\n$pagination-padding-y-sm: .25rem !default;\n$pagination-padding-x-sm: .5rem !default;\n$pagination-padding-y-lg: .75rem !default;\n$pagination-padding-x-lg: 1.5rem !default;\n\n$pagination-color: $link-color !default;\n$pagination-bg: $white !default;\n$pagination-border-width: $border-width !default;\n$pagination-border-radius: $border-radius !default;\n$pagination-margin-start: -$pagination-border-width !default;\n$pagination-border-color: $gray-300 !default;\n\n$pagination-focus-color: $link-hover-color !default;\n$pagination-focus-bg: $gray-200 !default;\n$pagination-focus-box-shadow: $input-btn-focus-box-shadow !default;\n$pagination-focus-outline: 0 !default;\n\n$pagination-hover-color: $link-hover-color !default;\n$pagination-hover-bg: $gray-200 !default;\n$pagination-hover-border-color: $gray-300 !default;\n\n$pagination-active-color: $component-active-color !default;\n$pagination-active-bg: $component-active-bg !default;\n$pagination-active-border-color: $pagination-active-bg !default;\n\n$pagination-disabled-color: $gray-600 !default;\n$pagination-disabled-bg: $white !default;\n$pagination-disabled-border-color: $gray-300 !default;\n\n$pagination-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;\n\n$pagination-border-radius-sm: $border-radius-sm !default;\n$pagination-border-radius-lg: $border-radius-lg !default;\n// scss-docs-end pagination-variables\n\n\n// Placeholders\n\n// scss-docs-start placeholders\n$placeholder-opacity-max: .5 !default;\n$placeholder-opacity-min: .2 !default;\n// scss-docs-end placeholders\n\n// Cards\n\n// scss-docs-start card-variables\n$card-spacer-y: $spacer !default;\n$card-spacer-x: $spacer !default;\n$card-title-spacer-y: $spacer * .5 !default;\n$card-border-width: $border-width !default;\n$card-border-color: rgba($black, .125) !default;\n$card-border-radius: $border-radius !default;\n$card-box-shadow: null !default;\n$card-inner-border-radius: subtract($card-border-radius, $card-border-width) !default;\n$card-cap-padding-y: $card-spacer-y * .5 !default;\n$card-cap-padding-x: $card-spacer-x !default;\n$card-cap-bg: rgba($black, .03) !default;\n$card-cap-color: null !default;\n$card-height: null !default;\n$card-color: null !default;\n$card-bg: $white !default;\n$card-img-overlay-padding: $spacer !default;\n$card-group-margin: $grid-gutter-width * .5 !default;\n// scss-docs-end card-variables\n\n// Accordion\n\n// scss-docs-start accordion-variables\n$accordion-padding-y: 1rem !default;\n$accordion-padding-x: 1.25rem !default;\n$accordion-color: $body-color !default;\n$accordion-bg: $body-bg !default;\n$accordion-border-width: $border-width !default;\n$accordion-border-color: rgba($black, .125) !default;\n$accordion-border-radius: $border-radius !default;\n$accordion-inner-border-radius: subtract($accordion-border-radius, $accordion-border-width) !default;\n\n$accordion-body-padding-y: $accordion-padding-y !default;\n$accordion-body-padding-x: $accordion-padding-x !default;\n\n$accordion-button-padding-y: $accordion-padding-y !default;\n$accordion-button-padding-x: $accordion-padding-x !default;\n$accordion-button-color: $accordion-color !default;\n$accordion-button-bg: $accordion-bg !default;\n$accordion-transition: $btn-transition, border-radius .15s ease !default;\n$accordion-button-active-bg: tint-color($component-active-bg, 90%) !default;\n$accordion-button-active-color: shade-color($primary, 10%) !default;\n\n$accordion-button-focus-border-color: $input-focus-border-color !default;\n$accordion-button-focus-box-shadow: $btn-focus-box-shadow !default;\n\n$accordion-icon-width: 1.25rem !default;\n$accordion-icon-color: $accordion-button-color !default;\n$accordion-icon-active-color: $accordion-button-active-color !default;\n$accordion-icon-transition: transform .2s ease-in-out !default;\n$accordion-icon-transform: rotate(-180deg) !default;\n\n$accordion-button-icon: url(\"data:image/svg+xml,\") !default;\n$accordion-button-active-icon: url(\"data:image/svg+xml,\") !default;\n// scss-docs-end accordion-variables\n\n// Tooltips\n\n// scss-docs-start tooltip-variables\n$tooltip-font-size: $font-size-sm !default;\n$tooltip-max-width: 200px !default;\n$tooltip-color: $white !default;\n$tooltip-bg: $black !default;\n$tooltip-border-radius: $border-radius !default;\n$tooltip-opacity: .9 !default;\n$tooltip-padding-y: $spacer * .25 !default;\n$tooltip-padding-x: $spacer * .5 !default;\n$tooltip-margin: 0 !default;\n\n$tooltip-arrow-width: .8rem !default;\n$tooltip-arrow-height: .4rem !default;\n$tooltip-arrow-color: $tooltip-bg !default;\n// scss-docs-end tooltip-variables\n\n// Form tooltips must come after regular tooltips\n// scss-docs-start tooltip-feedback-variables\n$form-feedback-tooltip-padding-y: $tooltip-padding-y !default;\n$form-feedback-tooltip-padding-x: $tooltip-padding-x !default;\n$form-feedback-tooltip-font-size: $tooltip-font-size !default;\n$form-feedback-tooltip-line-height: null !default;\n$form-feedback-tooltip-opacity: $tooltip-opacity !default;\n$form-feedback-tooltip-border-radius: $tooltip-border-radius !default;\n// scss-docs-end tooltip-feedback-variables\n\n\n// Popovers\n\n// scss-docs-start popover-variables\n$popover-font-size: $font-size-sm !default;\n$popover-bg: $white !default;\n$popover-max-width: 276px !default;\n$popover-border-width: $border-width !default;\n$popover-border-color: rgba($black, .2) !default;\n$popover-border-radius: $border-radius-lg !default;\n$popover-inner-border-radius: subtract($popover-border-radius, $popover-border-width) !default;\n$popover-box-shadow: $box-shadow !default;\n\n$popover-header-bg: shade-color($popover-bg, 6%) !default;\n$popover-header-color: $headings-color !default;\n$popover-header-padding-y: .5rem !default;\n$popover-header-padding-x: $spacer !default;\n\n$popover-body-color: $body-color !default;\n$popover-body-padding-y: $spacer !default;\n$popover-body-padding-x: $spacer !default;\n\n$popover-arrow-width: 1rem !default;\n$popover-arrow-height: .5rem !default;\n$popover-arrow-color: $popover-bg !default;\n\n$popover-arrow-outer-color: fade-in($popover-border-color, .05) !default;\n// scss-docs-end popover-variables\n\n\n// Toasts\n\n// scss-docs-start toast-variables\n$toast-max-width: 350px !default;\n$toast-padding-x: .75rem !default;\n$toast-padding-y: .5rem !default;\n$toast-font-size: .875rem !default;\n$toast-color: null !default;\n$toast-background-color: rgba($white, .85) !default;\n$toast-border-width: 1px !default;\n$toast-border-color: rgba(0, 0, 0, .1) !default;\n$toast-border-radius: $border-radius !default;\n$toast-box-shadow: $box-shadow !default;\n$toast-spacing: $container-padding-x !default;\n\n$toast-header-color: $gray-600 !default;\n$toast-header-background-color: rgba($white, .85) !default;\n$toast-header-border-color: rgba(0, 0, 0, .05) !default;\n// scss-docs-end toast-variables\n\n\n// Badges\n\n// scss-docs-start badge-variables\n$badge-font-size: .75em !default;\n$badge-font-weight: $font-weight-bold !default;\n$badge-color: $white !default;\n$badge-padding-y: .35em !default;\n$badge-padding-x: .65em !default;\n$badge-border-radius: $border-radius !default;\n// scss-docs-end badge-variables\n\n\n// Modals\n\n// scss-docs-start modal-variables\n$modal-inner-padding: $spacer !default;\n\n$modal-footer-margin-between: .5rem !default;\n\n$modal-dialog-margin: .5rem !default;\n$modal-dialog-margin-y-sm-up: 1.75rem !default;\n\n$modal-title-line-height: $line-height-base !default;\n\n$modal-content-color: null !default;\n$modal-content-bg: $white !default;\n$modal-content-border-color: rgba($black, .2) !default;\n$modal-content-border-width: $border-width !default;\n$modal-content-border-radius: $border-radius-lg !default;\n$modal-content-inner-border-radius: subtract($modal-content-border-radius, $modal-content-border-width) !default;\n$modal-content-box-shadow-xs: $box-shadow-sm !default;\n$modal-content-box-shadow-sm-up: $box-shadow !default;\n\n$modal-backdrop-bg: $black !default;\n$modal-backdrop-opacity: .5 !default;\n$modal-header-border-color: $border-color !default;\n$modal-footer-border-color: $modal-header-border-color !default;\n$modal-header-border-width: $modal-content-border-width !default;\n$modal-footer-border-width: $modal-header-border-width !default;\n$modal-header-padding-y: $modal-inner-padding !default;\n$modal-header-padding-x: $modal-inner-padding !default;\n$modal-header-padding: $modal-header-padding-y $modal-header-padding-x !default; // Keep this for backwards compatibility\n\n$modal-sm: 300px !default;\n$modal-md: 500px !default;\n$modal-lg: 800px !default;\n$modal-xl: 1140px !default;\n\n$modal-fade-transform: translate(0, -50px) !default;\n$modal-show-transform: none !default;\n$modal-transition: transform .3s ease-out !default;\n$modal-scale-transform: scale(1.02) !default;\n// scss-docs-end modal-variables\n\n\n// Alerts\n//\n// Define alert colors, border radius, and padding.\n\n// scss-docs-start alert-variables\n$alert-padding-y: $spacer !default;\n$alert-padding-x: $spacer !default;\n$alert-margin-bottom: 1rem !default;\n$alert-border-radius: $border-radius !default;\n$alert-link-font-weight: $font-weight-bold !default;\n$alert-border-width: $border-width !default;\n$alert-bg-scale: -80% !default;\n$alert-border-scale: -70% !default;\n$alert-color-scale: 40% !default;\n$alert-dismissible-padding-r: $alert-padding-x * 3 !default; // 3x covers width of x plus default padding on either side\n// scss-docs-end alert-variables\n\n\n// Progress bars\n\n// scss-docs-start progress-variables\n$progress-height: 1rem !default;\n$progress-font-size: $font-size-base * .75 !default;\n$progress-bg: $gray-200 !default;\n$progress-border-radius: $border-radius !default;\n$progress-box-shadow: $box-shadow-inset !default;\n$progress-bar-color: $white !default;\n$progress-bar-bg: $primary !default;\n$progress-bar-animation-timing: 1s linear infinite !default;\n$progress-bar-transition: width .6s ease !default;\n// scss-docs-end progress-variables\n\n\n// List group\n\n// scss-docs-start list-group-variables\n$list-group-color: $gray-900 !default;\n$list-group-bg: $white !default;\n$list-group-border-color: rgba($black, .125) !default;\n$list-group-border-width: $border-width !default;\n$list-group-border-radius: $border-radius !default;\n\n$list-group-item-padding-y: $spacer * .5 !default;\n$list-group-item-padding-x: $spacer !default;\n$list-group-item-bg-scale: -80% !default;\n$list-group-item-color-scale: 40% !default;\n\n$list-group-hover-bg: $gray-100 !default;\n$list-group-active-color: $component-active-color !default;\n$list-group-active-bg: $component-active-bg !default;\n$list-group-active-border-color: $list-group-active-bg !default;\n\n$list-group-disabled-color: $gray-600 !default;\n$list-group-disabled-bg: $list-group-bg !default;\n\n$list-group-action-color: $gray-700 !default;\n$list-group-action-hover-color: $list-group-action-color !default;\n\n$list-group-action-active-color: $body-color !default;\n$list-group-action-active-bg: $gray-200 !default;\n// scss-docs-end list-group-variables\n\n\n// Image thumbnails\n\n// scss-docs-start thumbnail-variables\n$thumbnail-padding: .25rem !default;\n$thumbnail-bg: $body-bg !default;\n$thumbnail-border-width: $border-width !default;\n$thumbnail-border-color: $gray-300 !default;\n$thumbnail-border-radius: $border-radius !default;\n$thumbnail-box-shadow: $box-shadow-sm !default;\n// scss-docs-end thumbnail-variables\n\n\n// Figures\n\n// scss-docs-start figure-variables\n$figure-caption-font-size: $small-font-size !default;\n$figure-caption-color: $gray-600 !default;\n// scss-docs-end figure-variables\n\n\n// Breadcrumbs\n\n// scss-docs-start breadcrumb-variables\n$breadcrumb-font-size: null !default;\n$breadcrumb-padding-y: 0 !default;\n$breadcrumb-padding-x: 0 !default;\n$breadcrumb-item-padding-x: .5rem !default;\n$breadcrumb-margin-bottom: 1rem !default;\n$breadcrumb-bg: null !default;\n$breadcrumb-divider-color: $gray-600 !default;\n$breadcrumb-active-color: $gray-600 !default;\n$breadcrumb-divider: quote(\"/\") !default;\n$breadcrumb-divider-flipped: $breadcrumb-divider !default;\n$breadcrumb-border-radius: null !default;\n// scss-docs-end breadcrumb-variables\n\n// Carousel\n\n// scss-docs-start carousel-variables\n$carousel-control-color: $white !default;\n$carousel-control-width: 15% !default;\n$carousel-control-opacity: .5 !default;\n$carousel-control-hover-opacity: .9 !default;\n$carousel-control-transition: opacity .15s ease !default;\n\n$carousel-indicator-width: 30px !default;\n$carousel-indicator-height: 3px !default;\n$carousel-indicator-hit-area-height: 10px !default;\n$carousel-indicator-spacer: 3px !default;\n$carousel-indicator-opacity: .5 !default;\n$carousel-indicator-active-bg: $white !default;\n$carousel-indicator-active-opacity: 1 !default;\n$carousel-indicator-transition: opacity .6s ease !default;\n\n$carousel-caption-width: 70% !default;\n$carousel-caption-color: $white !default;\n$carousel-caption-padding-y: 1.25rem !default;\n$carousel-caption-spacer: 1.25rem !default;\n\n$carousel-control-icon-width: 2rem !default;\n\n$carousel-control-prev-icon-bg: url(\"data:image/svg+xml,\") !default;\n$carousel-control-next-icon-bg: url(\"data:image/svg+xml,\") !default;\n\n$carousel-transition-duration: .6s !default;\n$carousel-transition: transform $carousel-transition-duration ease-in-out !default; // Define transform transition first if using multiple transitions (e.g., `transform 2s ease, opacity .5s ease-out`)\n\n$carousel-dark-indicator-active-bg: $black !default;\n$carousel-dark-caption-color: $black !default;\n$carousel-dark-control-icon-filter: invert(1) grayscale(100) !default;\n// scss-docs-end carousel-variables\n\n\n// Spinners\n\n// scss-docs-start spinner-variables\n$spinner-width: 2rem !default;\n$spinner-height: $spinner-width !default;\n$spinner-vertical-align: -.125em !default;\n$spinner-border-width: .25em !default;\n$spinner-animation-speed: .75s !default;\n\n$spinner-width-sm: 1rem !default;\n$spinner-height-sm: $spinner-width-sm !default;\n$spinner-border-width-sm: .2em !default;\n// scss-docs-end spinner-variables\n\n\n// Close\n\n// scss-docs-start close-variables\n$btn-close-width: 1em !default;\n$btn-close-height: $btn-close-width !default;\n$btn-close-padding-x: .25em !default;\n$btn-close-padding-y: $btn-close-padding-x !default;\n$btn-close-color: $black !default;\n$btn-close-bg: url(\"data:image/svg+xml,\") !default;\n$btn-close-focus-shadow: $input-btn-focus-box-shadow !default;\n$btn-close-opacity: .5 !default;\n$btn-close-hover-opacity: .75 !default;\n$btn-close-focus-opacity: 1 !default;\n$btn-close-disabled-opacity: .25 !default;\n$btn-close-white-filter: invert(1) grayscale(100%) brightness(200%) !default;\n// scss-docs-end close-variables\n\n\n// Offcanvas\n\n// scss-docs-start offcanvas-variables\n$offcanvas-padding-y: $modal-inner-padding !default;\n$offcanvas-padding-x: $modal-inner-padding !default;\n$offcanvas-horizontal-width: 400px !default;\n$offcanvas-vertical-height: 30vh !default;\n$offcanvas-transition-duration: .3s !default;\n$offcanvas-border-color: $modal-content-border-color !default;\n$offcanvas-border-width: $modal-content-border-width !default;\n$offcanvas-title-line-height: $modal-title-line-height !default;\n$offcanvas-bg-color: $modal-content-bg !default;\n$offcanvas-color: $modal-content-color !default;\n$offcanvas-box-shadow: $modal-content-box-shadow-xs !default;\n$offcanvas-backdrop-bg: $modal-backdrop-bg !default;\n$offcanvas-backdrop-opacity: $modal-backdrop-opacity !default;\n// scss-docs-end offcanvas-variables\n\n// Code\n\n$code-font-size: $small-font-size !default;\n$code-color: $pink !default;\n\n$kbd-padding-y: .2rem !default;\n$kbd-padding-x: .4rem !default;\n$kbd-font-size: $code-font-size !default;\n$kbd-color: $white !default;\n$kbd-bg: $gray-900 !default;\n\n$pre-color: null !default;\n", + "// Toggles\n//\n// Used in conjunction with global variables to enable certain theme features.\n\n// Vendor\n@import \"vendor/rfs\";\n\n// Deprecate\n@import \"mixins/deprecate\";\n\n// Helpers\n@import \"mixins/breakpoints\";\n@import \"mixins/color-scheme\";\n@import \"mixins/image\";\n@import \"mixins/resize\";\n@import \"mixins/visually-hidden\";\n@import \"mixins/reset-text\";\n@import \"mixins/text-truncate\";\n\n// Utilities\n@import \"mixins/utilities\";\n\n// Components\n@import \"mixins/alert\";\n@import \"mixins/backdrop\";\n@import \"mixins/buttons\";\n@import \"mixins/caret\";\n@import \"mixins/pagination\";\n@import \"mixins/lists\";\n@import \"mixins/list-group\";\n@import \"mixins/forms\";\n@import \"mixins/table-variants\";\n\n// Skins\n@import \"mixins/border-radius\";\n@import \"mixins/box-shadow\";\n@import \"mixins/gradients\";\n@import \"mixins/transition\";\n\n// Layout\n@import \"mixins/clearfix\";\n@import \"mixins/container\";\n@import \"mixins/grid\";\n", + "// stylelint-disable property-blacklist, scss/dollar-variable-default\n\n// SCSS RFS mixin\n//\n// Automated responsive values for font sizes, paddings, margins and much more\n//\n// Licensed under MIT (https://github.com/twbs/rfs/blob/main/LICENSE)\n\n// Configuration\n\n// Base value\n$rfs-base-value: 1.25rem !default;\n$rfs-unit: rem !default;\n\n@if $rfs-unit != rem and $rfs-unit != px {\n @error \"`#{$rfs-unit}` is not a valid unit for $rfs-unit. Use `px` or `rem`.\";\n}\n\n// Breakpoint at where values start decreasing if screen width is smaller\n$rfs-breakpoint: 1200px !default;\n$rfs-breakpoint-unit: px !default;\n\n@if $rfs-breakpoint-unit != px and $rfs-breakpoint-unit != em and $rfs-breakpoint-unit != rem {\n @error \"`#{$rfs-breakpoint-unit}` is not a valid unit for $rfs-breakpoint-unit. Use `px`, `em` or `rem`.\";\n}\n\n// Resize values based on screen height and width\n$rfs-two-dimensional: false !default;\n\n// Factor of decrease\n$rfs-factor: 10 !default;\n\n@if type-of($rfs-factor) != number or $rfs-factor <= 1 {\n @error \"`#{$rfs-factor}` is not a valid $rfs-factor, it must be greater than 1.\";\n}\n\n// Mode. Possibilities: \"min-media-query\", \"max-media-query\"\n$rfs-mode: min-media-query !default;\n\n// Generate enable or disable classes. Possibilities: false, \"enable\" or \"disable\"\n$rfs-class: false !default;\n\n// 1 rem = $rfs-rem-value px\n$rfs-rem-value: 16 !default;\n\n// Safari iframe resize bug: https://github.com/twbs/rfs/issues/14\n$rfs-safari-iframe-resize-bug-fix: false !default;\n\n// Disable RFS by setting $enable-rfs to false\n$enable-rfs: true !default;\n\n// Cache $rfs-base-value unit\n$rfs-base-value-unit: unit($rfs-base-value);\n\n@function divide($dividend, $divisor, $precision: 10) {\n $sign: if($dividend > 0 and $divisor > 0 or $dividend < 0 and $divisor < 0, 1, -1);\n $dividend: abs($dividend);\n $divisor: abs($divisor);\n @if $dividend == 0 {\n @return 0;\n }\n @if $divisor == 0 {\n @error \"Cannot divide by 0\";\n }\n $remainder: $dividend;\n $result: 0;\n $factor: 10;\n @while ($remainder > 0 and $precision >= 0) {\n $quotient: 0;\n @while ($remainder >= $divisor) {\n $remainder: $remainder - $divisor;\n $quotient: $quotient + 1;\n }\n $result: $result * 10 + $quotient;\n $factor: $factor * .1;\n $remainder: $remainder * 10;\n $precision: $precision - 1;\n @if ($precision < 0 and $remainder >= $divisor * 5) {\n $result: $result + 1;\n }\n }\n $result: $result * $factor * $sign;\n $dividend-unit: unit($dividend);\n $divisor-unit: unit($divisor);\n $unit-map: (\n \"px\": 1px,\n \"rem\": 1rem,\n \"em\": 1em,\n \"%\": 1%\n );\n @if ($dividend-unit != $divisor-unit and map-has-key($unit-map, $dividend-unit)) {\n $result: $result * map-get($unit-map, $dividend-unit);\n }\n @return $result;\n}\n\n// Remove px-unit from $rfs-base-value for calculations\n@if $rfs-base-value-unit == px {\n $rfs-base-value: divide($rfs-base-value, $rfs-base-value * 0 + 1);\n}\n@else if $rfs-base-value-unit == rem {\n $rfs-base-value: divide($rfs-base-value, divide($rfs-base-value * 0 + 1, $rfs-rem-value));\n}\n\n// Cache $rfs-breakpoint unit to prevent multiple calls\n$rfs-breakpoint-unit-cache: unit($rfs-breakpoint);\n\n// Remove unit from $rfs-breakpoint for calculations\n@if $rfs-breakpoint-unit-cache == px {\n $rfs-breakpoint: divide($rfs-breakpoint, $rfs-breakpoint * 0 + 1);\n}\n@else if $rfs-breakpoint-unit-cache == rem or $rfs-breakpoint-unit-cache == \"em\" {\n $rfs-breakpoint: divide($rfs-breakpoint, divide($rfs-breakpoint * 0 + 1, $rfs-rem-value));\n}\n\n// Calculate the media query value\n$rfs-mq-value: if($rfs-breakpoint-unit == px, #{$rfs-breakpoint}px, #{divide($rfs-breakpoint, $rfs-rem-value)}#{$rfs-breakpoint-unit});\n$rfs-mq-property-width: if($rfs-mode == max-media-query, max-width, min-width);\n$rfs-mq-property-height: if($rfs-mode == max-media-query, max-height, min-height);\n\n// Internal mixin used to determine which media query needs to be used\n@mixin _rfs-media-query {\n @if $rfs-two-dimensional {\n @if $rfs-mode == max-media-query {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}), (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) and (#{$rfs-mq-property-height}: #{$rfs-mq-value}) {\n @content;\n }\n }\n }\n @else {\n @media (#{$rfs-mq-property-width}: #{$rfs-mq-value}) {\n @content;\n }\n }\n}\n\n// Internal mixin that adds disable classes to the selector if needed.\n@mixin _rfs-rule {\n @if $rfs-class == disable and $rfs-mode == max-media-query {\n // Adding an extra class increases specificity, which prevents the media query to override the property\n &,\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @else if $rfs-class == enable and $rfs-mode == min-media-query {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n }\n @else {\n @content;\n }\n}\n\n// Internal mixin that adds enable classes to the selector if needed.\n@mixin _rfs-media-query-rule {\n\n @if $rfs-class == enable {\n @if $rfs-mode == min-media-query {\n @content;\n }\n\n @include _rfs-media-query {\n .enable-rfs &,\n &.enable-rfs {\n @content;\n }\n }\n }\n @else {\n @if $rfs-class == disable and $rfs-mode == min-media-query {\n .disable-rfs &,\n &.disable-rfs {\n @content;\n }\n }\n @include _rfs-media-query {\n @content;\n }\n }\n}\n\n// Helper function to get the formatted non-responsive value\n@function rfs-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: '';\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + ' 0';\n }\n @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n @if $unit == px {\n // Convert to rem if needed\n $val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $value * 0 + $rfs-rem-value)}rem, $value);\n }\n @else if $unit == rem {\n // Convert to px if needed\n $val: $val + ' ' + if($rfs-unit == px, #{divide($value, $value * 0 + 1) * $rfs-rem-value}px, $value);\n }\n @else {\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n $val: $val + ' ' + $value;\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// Helper function to get the responsive value calculated by RFS\n@function rfs-fluid-value($values) {\n // Convert to list\n $values: if(type-of($values) != list, ($values,), $values);\n\n $val: '';\n\n // Loop over each value and calculate value\n @each $value in $values {\n @if $value == 0 {\n $val: $val + ' 0';\n }\n\n @else {\n // Cache $value unit\n $unit: if(type-of($value) == \"number\", unit($value), false);\n\n // If $value isn't a number (like inherit) or $value has a unit (not px or rem, like 1.5em) or $ is 0, just print the value\n @if not $unit or $unit != px and $unit != rem {\n $val: $val + ' ' + $value;\n }\n\n @else {\n // Remove unit from $value for calculations\n $value: divide($value, $value * 0 + if($unit == px, 1, divide(1, $rfs-rem-value)));\n\n // Only add the media query if the value is greater than the minimum value\n @if abs($value) <= $rfs-base-value or not $enable-rfs {\n $val: $val + ' ' + if($rfs-unit == rem, #{divide($value, $rfs-rem-value)}rem, #{$value}px);\n }\n @else {\n // Calculate the minimum value\n $value-min: $rfs-base-value + divide(abs($value) - $rfs-base-value, $rfs-factor);\n\n // Calculate difference between $value and the minimum value\n $value-diff: abs($value) - $value-min;\n\n // Base value formatting\n $min-width: if($rfs-unit == rem, #{divide($value-min, $rfs-rem-value)}rem, #{$value-min}px);\n\n // Use negative value if needed\n $min-width: if($value < 0, -$min-width, $min-width);\n\n // Use `vmin` if two-dimensional is enabled\n $variable-unit: if($rfs-two-dimensional, vmin, vw);\n\n // Calculate the variable width between 0 and $rfs-breakpoint\n $variable-width: #{divide($value-diff * 100, $rfs-breakpoint)}#{$variable-unit};\n\n // Return the calculated value\n $val: $val + ' calc(' + $min-width + if($value < 0, ' - ', ' + ') + $variable-width + ')';\n }\n }\n }\n }\n\n // Remove first space\n @return unquote(str-slice($val, 2));\n}\n\n// RFS mixin\n@mixin rfs($values, $property: font-size) {\n @if $values != null {\n $val: rfs-value($values);\n $fluidVal: rfs-fluid-value($values);\n\n // Do not print the media query if responsive & non-responsive values are the same\n @if $val == $fluidVal {\n #{$property}: $val;\n }\n @else {\n @include _rfs-rule {\n #{$property}: if($rfs-mode == max-media-query, $val, $fluidVal);\n\n // Include safari iframe resize fix if needed\n min-width: if($rfs-safari-iframe-resize-bug-fix, (0 * 1vw), null);\n }\n\n @include _rfs-media-query-rule {\n #{$property}: if($rfs-mode == max-media-query, $fluidVal, $val);\n }\n }\n }\n}\n\n// Shorthand helper mixins\n@mixin font-size($value) {\n @include rfs($value);\n}\n\n@mixin padding($value) {\n @include rfs($value, padding);\n}\n\n@mixin padding-top($value) {\n @include rfs($value, padding-top);\n}\n\n@mixin padding-right($value) {\n @include rfs($value, padding-right);\n}\n\n@mixin padding-bottom($value) {\n @include rfs($value, padding-bottom);\n}\n\n@mixin padding-left($value) {\n @include rfs($value, padding-left);\n}\n\n@mixin margin($value) {\n @include rfs($value, margin);\n}\n\n@mixin margin-top($value) {\n @include rfs($value, margin-top);\n}\n\n@mixin margin-right($value) {\n @include rfs($value, margin-right);\n}\n\n@mixin margin-bottom($value) {\n @include rfs($value, margin-bottom);\n}\n\n@mixin margin-left($value) {\n @include rfs($value, margin-left);\n}\n", + "// Deprecate mixin\n//\n// This mixin can be used to deprecate mixins or functions.\n// `$enable-deprecation-messages` is a global variable, `$ignore-warning` is a variable that can be passed to\n// some deprecated mixins to suppress the warning (for example if the mixin is still be used in the current version of Bootstrap)\n@mixin deprecate($name, $deprecate-version, $remove-version, $ignore-warning: false) {\n @if ($enable-deprecation-messages != false and $ignore-warning != true) {\n @warn \"#{$name} has been deprecated as of #{$deprecate-version}. It will be removed entirely in #{$remove-version}.\";\n }\n}\n", + "// Breakpoint viewport sizes and media queries.\n//\n// Breakpoints are defined as a map of (name: minimum width), order from small to large:\n//\n// (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px)\n//\n// The map defined in the `$grid-breakpoints` global variable is used as the `$breakpoints` argument by default.\n\n// Name of the next breakpoint, or null for the last breakpoint.\n//\n// >> breakpoint-next(sm)\n// md\n// >> breakpoint-next(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// md\n// >> breakpoint-next(sm, $breakpoint-names: (xs sm md lg xl))\n// md\n@function breakpoint-next($name, $breakpoints: $grid-breakpoints, $breakpoint-names: map-keys($breakpoints)) {\n $n: index($breakpoint-names, $name);\n @if not $n {\n @error \"breakpoint `#{$name}` not found in `#{$breakpoints}`\";\n }\n @return if($n < length($breakpoint-names), nth($breakpoint-names, $n + 1), null);\n}\n\n// Minimum breakpoint width. Null for the smallest (first) breakpoint.\n//\n// >> breakpoint-min(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// 576px\n@function breakpoint-min($name, $breakpoints: $grid-breakpoints) {\n $min: map-get($breakpoints, $name);\n @return if($min != 0, $min, null);\n}\n\n// Maximum breakpoint width.\n// The maximum value is reduced by 0.02px to work around the limitations of\n// `min-` and `max-` prefixes and viewports with fractional widths.\n// See https://www.w3.org/TR/mediaqueries-4/#mq-min-max\n// Uses 0.02px rather than 0.01px to work around a current rounding bug in Safari.\n// See https://bugs.webkit.org/show_bug.cgi?id=178261\n//\n// >> breakpoint-max(md, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// 767.98px\n@function breakpoint-max($name, $breakpoints: $grid-breakpoints) {\n $max: map-get($breakpoints, $name);\n @return if($max and $max > 0, $max - .02, null);\n}\n\n// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.\n// Useful for making responsive utilities.\n//\n// >> breakpoint-infix(xs, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// \"\" (Returns a blank string)\n// >> breakpoint-infix(sm, (xs: 0, sm: 576px, md: 768px, lg: 992px, xl: 1200px))\n// \"-sm\"\n@function breakpoint-infix($name, $breakpoints: $grid-breakpoints) {\n @return if(breakpoint-min($name, $breakpoints) == null, \"\", \"-#{$name}\");\n}\n\n// Media of at least the minimum breakpoint width. No query for the smallest breakpoint.\n// Makes the @content apply to the given breakpoint and wider.\n@mixin media-breakpoint-up($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n @if $min {\n @media (min-width: $min) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media of at most the maximum breakpoint width. No query for the largest breakpoint.\n// Makes the @content apply to the given breakpoint and narrower.\n@mixin media-breakpoint-down($name, $breakpoints: $grid-breakpoints) {\n $max: breakpoint-max($name, $breakpoints);\n @if $max {\n @media (max-width: $max) {\n @content;\n }\n } @else {\n @content;\n }\n}\n\n// Media that spans multiple breakpoint widths.\n// Makes the @content apply between the min and max breakpoints\n@mixin media-breakpoint-between($lower, $upper, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($lower, $breakpoints);\n $max: breakpoint-max($upper, $breakpoints);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($lower, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($upper, $breakpoints) {\n @content;\n }\n }\n}\n\n// Media between the breakpoint's minimum and maximum widths.\n// No minimum for the smallest breakpoint, and no maximum for the largest one.\n// Makes the @content apply only to the given breakpoint, not viewports any wider or narrower.\n@mixin media-breakpoint-only($name, $breakpoints: $grid-breakpoints) {\n $min: breakpoint-min($name, $breakpoints);\n $next: breakpoint-next($name, $breakpoints);\n $max: breakpoint-max($next);\n\n @if $min != null and $max != null {\n @media (min-width: $min) and (max-width: $max) {\n @content;\n }\n } @else if $max == null {\n @include media-breakpoint-up($name, $breakpoints) {\n @content;\n }\n } @else if $min == null {\n @include media-breakpoint-down($next, $breakpoints) {\n @content;\n }\n }\n}\n", + "// scss-docs-start mixin-color-scheme\n@mixin color-scheme($name) {\n @media (prefers-color-scheme: #{$name}) {\n @content;\n }\n}\n// scss-docs-end mixin-color-scheme\n", + "// Image Mixins\n// - Responsive image\n// - Retina image\n\n\n// Responsive image\n//\n// Keep images from scaling beyond the width of their parents.\n\n@mixin img-fluid {\n // Part 1: Set a maximum relative to the parent\n max-width: 100%;\n // Part 2: Override the height to auto, otherwise images will be stretched\n // when setting a width and height attribute on the img element.\n height: auto;\n}\n", + "// Resize anything\n\n@mixin resizable($direction) {\n overflow: auto; // Per CSS3 UI, `resize` only applies when `overflow` isn't `visible`\n resize: $direction; // Options: horizontal, vertical, both\n}\n", + "// stylelint-disable declaration-no-important\n\n// Hide content visually while keeping it accessible to assistive technologies\n//\n// See: https://www.a11yproject.com/posts/2013-01-11-how-to-hide-content/\n// See: https://hugogiraudel.com/2016/10/13/css-hide-and-seek/\n\n@mixin visually-hidden() {\n position: absolute !important;\n width: 1px !important;\n height: 1px !important;\n padding: 0 !important;\n margin: -1px !important; // Fix for https://github.com/twbs/bootstrap/issues/25686\n overflow: hidden !important;\n clip: rect(0, 0, 0, 0) !important;\n white-space: nowrap !important;\n border: 0 !important;\n}\n\n// Use to only display content when it's focused, or one of its child elements is focused\n// (i.e. when focus is within the element/container that the class was applied to)\n//\n// Useful for \"Skip to main content\" links; see https://www.w3.org/TR/2013/NOTE-WCAG20-TECHS-20130905/G1\n\n@mixin visually-hidden-focusable() {\n &:not(:focus):not(:focus-within) {\n @include visually-hidden();\n }\n}\n", + "@mixin reset-text {\n font-family: $font-family-base;\n // We deliberately do NOT reset font-size or overflow-wrap / word-wrap.\n font-style: normal;\n font-weight: $font-weight-normal;\n line-height: $line-height-base;\n text-align: left; // Fallback for where `start` is not supported\n text-align: start;\n text-decoration: none;\n text-shadow: none;\n text-transform: none;\n letter-spacing: normal;\n word-break: normal;\n word-spacing: normal;\n white-space: normal;\n line-break: auto;\n}\n", + "// Text truncate\n// Requires inline-block or block for proper styling\n\n@mixin text-truncate() {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n", + "// Utility generator\n// Used to generate utilities & print utilities\n@mixin generate-utility($utility, $infix, $is-rfs-media-query: false) {\n $values: map-get($utility, values);\n\n // If the values are a list or string, convert it into a map\n @if type-of($values) == \"string\" or type-of(nth($values, 1)) != \"list\" {\n $values: zip($values, $values);\n }\n\n @each $key, $value in $values {\n $properties: map-get($utility, property);\n\n // Multiple properties are possible, for example with vertical or horizontal margins or paddings\n @if type-of($properties) == \"string\" {\n $properties: append((), $properties);\n }\n\n // Use custom class if present\n $property-class: if(map-has-key($utility, class), map-get($utility, class), nth($properties, 1));\n $property-class: if($property-class == null, \"\", $property-class);\n\n // State params to generate pseudo-classes\n $state: if(map-has-key($utility, state), map-get($utility, state), ());\n\n $infix: if($property-class == \"\" and str-slice($infix, 1, 1) == \"-\", str-slice($infix, 2), $infix);\n\n // Don't prefix if value key is null (eg. with shadow class)\n $property-class-modifier: if($key, if($property-class == \"\" and $infix == \"\", \"\", \"-\") + $key, \"\");\n\n @if map-get($utility, rfs) {\n // Inside the media query\n @if $is-rfs-media-query {\n $val: rfs-value($value);\n\n // Do not render anything if fluid and non fluid values are the same\n $value: if($val == rfs-fluid-value($value), null, $val);\n }\n @else {\n $value: rfs-fluid-value($value);\n }\n }\n\n $is-css-var: map-get($utility, css-var);\n $is-local-vars: map-get($utility, local-vars);\n $is-rtl: map-get($utility, rtl);\n\n @if $value != null {\n @if $is-rtl == false {\n /* rtl:begin:remove */\n }\n\n @if $is-css-var {\n .#{$property-class + $infix + $property-class-modifier} {\n --#{$variable-prefix}#{$property-class}: #{$value};\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n --#{$variable-prefix}#{$property-class}: #{$value};\n }\n }\n } @else {\n .#{$property-class + $infix + $property-class-modifier} {\n @each $property in $properties {\n @if $is-local-vars {\n @each $local-var, $value in $is-local-vars {\n --#{$variable-prefix}#{$local-var}: #{$value};\n }\n }\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n\n @each $pseudo in $state {\n .#{$property-class + $infix + $property-class-modifier}-#{$pseudo}:#{$pseudo} {\n @each $property in $properties {\n #{$property}: $value if($enable-important-utilities, !important, null);\n }\n }\n }\n }\n\n @if $is-rtl == false {\n /* rtl:end:remove */\n }\n }\n }\n}\n", + "// scss-docs-start alert-variant-mixin\n@mixin alert-variant($background, $border, $color) {\n color: $color;\n @include gradient-bg($background);\n border-color: $border;\n\n .alert-link {\n color: shade-color($color, 20%);\n }\n}\n// scss-docs-end alert-variant-mixin\n", + "// Shared between modals and offcanvases\n@mixin overlay-backdrop($zindex, $backdrop-bg, $backdrop-opacity) {\n position: fixed;\n top: 0;\n left: 0;\n z-index: $zindex;\n width: 100vw;\n height: 100vh;\n background-color: $backdrop-bg;\n\n // Fade for backdrop\n &.fade { opacity: 0; }\n &.show { opacity: $backdrop-opacity; }\n}\n", + "// Button variants\n//\n// Easily pump out default styles, as well as :hover, :focus, :active,\n// and disabled options for all buttons\n\n// scss-docs-start btn-variant-mixin\n@mixin button-variant(\n $background,\n $border,\n $color: color-contrast($background),\n $hover-background: if($color == $color-contrast-light, shade-color($background, $btn-hover-bg-shade-amount), tint-color($background, $btn-hover-bg-tint-amount)),\n $hover-border: if($color == $color-contrast-light, shade-color($border, $btn-hover-border-shade-amount), tint-color($border, $btn-hover-border-tint-amount)),\n $hover-color: color-contrast($hover-background),\n $active-background: if($color == $color-contrast-light, shade-color($background, $btn-active-bg-shade-amount), tint-color($background, $btn-active-bg-tint-amount)),\n $active-border: if($color == $color-contrast-light, shade-color($border, $btn-active-border-shade-amount), tint-color($border, $btn-active-border-tint-amount)),\n $active-color: color-contrast($active-background),\n $disabled-background: $background,\n $disabled-border: $border,\n $disabled-color: color-contrast($disabled-background)\n) {\n color: $color;\n @include gradient-bg($background);\n border-color: $border;\n @include box-shadow($btn-box-shadow);\n\n &:hover {\n color: $hover-color;\n @include gradient-bg($hover-background);\n border-color: $hover-border;\n }\n\n .btn-check:focus + &,\n &:focus {\n color: $hover-color;\n @include gradient-bg($hover-background);\n border-color: $hover-border;\n @if $enable-shadows {\n @include box-shadow($btn-box-shadow, 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5));\n } @else {\n // Avoid using mixin so we can pass custom focus shadow properly\n box-shadow: 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5);\n }\n }\n\n .btn-check:checked + &,\n .btn-check:active + &,\n &:active,\n &.active,\n .show > &.dropdown-toggle {\n color: $active-color;\n background-color: $active-background;\n // Remove CSS gradients if they're enabled\n background-image: if($enable-gradients, none, null);\n border-color: $active-border;\n\n &:focus {\n @if $enable-shadows {\n @include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5));\n } @else {\n // Avoid using mixin so we can pass custom focus shadow properly\n box-shadow: 0 0 0 $btn-focus-width rgba(mix($color, $border, 15%), .5);\n }\n }\n }\n\n &:disabled,\n &.disabled {\n color: $disabled-color;\n background-color: $disabled-background;\n // Remove CSS gradients if they're enabled\n background-image: if($enable-gradients, none, null);\n border-color: $disabled-border;\n }\n}\n// scss-docs-end btn-variant-mixin\n\n// scss-docs-start btn-outline-variant-mixin\n@mixin button-outline-variant(\n $color,\n $color-hover: color-contrast($color),\n $active-background: $color,\n $active-border: $color,\n $active-color: color-contrast($active-background)\n) {\n color: $color;\n border-color: $color;\n\n &:hover {\n color: $color-hover;\n background-color: $active-background;\n border-color: $active-border;\n }\n\n .btn-check:focus + &,\n &:focus {\n box-shadow: 0 0 0 $btn-focus-width rgba($color, .5);\n }\n\n .btn-check:checked + &,\n .btn-check:active + &,\n &:active,\n &.active,\n &.dropdown-toggle.show {\n color: $active-color;\n background-color: $active-background;\n border-color: $active-border;\n\n &:focus {\n @if $enable-shadows {\n @include box-shadow($btn-active-box-shadow, 0 0 0 $btn-focus-width rgba($color, .5));\n } @else {\n // Avoid using mixin so we can pass custom focus shadow properly\n box-shadow: 0 0 0 $btn-focus-width rgba($color, .5);\n }\n }\n }\n\n &:disabled,\n &.disabled {\n color: $color;\n background-color: transparent;\n }\n}\n// scss-docs-end btn-outline-variant-mixin\n\n// scss-docs-start btn-size-mixin\n@mixin button-size($padding-y, $padding-x, $font-size, $border-radius) {\n padding: $padding-y $padding-x;\n @include font-size($font-size);\n // Manually declare to provide an override to the browser default\n @include border-radius($border-radius, 0);\n}\n// scss-docs-end btn-size-mixin\n", + "// scss-docs-start caret-mixins\n@mixin caret-down {\n border-top: $caret-width solid;\n border-right: $caret-width solid transparent;\n border-bottom: 0;\n border-left: $caret-width solid transparent;\n}\n\n@mixin caret-up {\n border-top: 0;\n border-right: $caret-width solid transparent;\n border-bottom: $caret-width solid;\n border-left: $caret-width solid transparent;\n}\n\n@mixin caret-end {\n border-top: $caret-width solid transparent;\n border-right: 0;\n border-bottom: $caret-width solid transparent;\n border-left: $caret-width solid;\n}\n\n@mixin caret-start {\n border-top: $caret-width solid transparent;\n border-right: $caret-width solid;\n border-bottom: $caret-width solid transparent;\n}\n\n@mixin caret($direction: down) {\n @if $enable-caret {\n &::after {\n display: inline-block;\n margin-left: $caret-spacing;\n vertical-align: $caret-vertical-align;\n content: \"\";\n @if $direction == down {\n @include caret-down();\n } @else if $direction == up {\n @include caret-up();\n } @else if $direction == end {\n @include caret-end();\n }\n }\n\n @if $direction == start {\n &::after {\n display: none;\n }\n\n &::before {\n display: inline-block;\n margin-right: $caret-spacing;\n vertical-align: $caret-vertical-align;\n content: \"\";\n @include caret-start();\n }\n }\n\n &:empty::after {\n margin-left: 0;\n }\n }\n}\n// scss-docs-end caret-mixins\n", + "// Pagination\n\n// scss-docs-start pagination-mixin\n@mixin pagination-size($padding-y, $padding-x, $font-size, $border-radius) {\n .page-link {\n padding: $padding-y $padding-x;\n @include font-size($font-size);\n }\n\n .page-item {\n @if $pagination-margin-start == (-$pagination-border-width) {\n &:first-child {\n .page-link {\n @include border-start-radius($border-radius);\n }\n }\n\n &:last-child {\n .page-link {\n @include border-end-radius($border-radius);\n }\n }\n } @else {\n //Add border-radius to all pageLinks in case they have left margin\n .page-link {\n @include border-radius($border-radius);\n }\n }\n }\n}\n// scss-docs-end pagination-mixin\n", + "// Lists\n\n// Unstyled keeps list items block level, just removes default browser padding and list-style\n@mixin list-unstyled {\n padding-left: 0;\n list-style: none;\n}\n", + "// List Groups\n\n// scss-docs-start list-group-mixin\n@mixin list-group-item-variant($state, $background, $color) {\n .list-group-item-#{$state} {\n color: $color;\n background-color: $background;\n\n &.list-group-item-action {\n &:hover,\n &:focus {\n color: $color;\n background-color: shade-color($background, 10%);\n }\n\n &.active {\n color: $white;\n background-color: $color;\n border-color: $color;\n }\n }\n }\n}\n// scss-docs-end list-group-mixin\n", + "// This mixin uses an `if()` technique to be compatible with Dart Sass\n// See https://github.com/sass/sass/issues/1873#issuecomment-152293725 for more details\n\n// scss-docs-start form-validation-mixins\n@mixin form-validation-state-selector($state) {\n @if ($state == \"valid\" or $state == \"invalid\") {\n .was-validated #{if(&, \"&\", \"\")}:#{$state},\n #{if(&, \"&\", \"\")}.is-#{$state} {\n @content;\n }\n } @else {\n #{if(&, \"&\", \"\")}.is-#{$state} {\n @content;\n }\n }\n}\n\n@mixin form-validation-state(\n $state,\n $color,\n $icon,\n $tooltip-color: color-contrast($color),\n $tooltip-bg-color: rgba($color, $form-feedback-tooltip-opacity),\n $focus-box-shadow: 0 0 $input-btn-focus-blur $input-focus-width rgba($color, $input-btn-focus-color-opacity)\n) {\n .#{$state}-feedback {\n display: none;\n width: 100%;\n margin-top: $form-feedback-margin-top;\n @include font-size($form-feedback-font-size);\n font-style: $form-feedback-font-style;\n color: $color;\n }\n\n .#{$state}-tooltip {\n position: absolute;\n top: 100%;\n z-index: 5;\n display: none;\n max-width: 100%; // Contain to parent when possible\n padding: $form-feedback-tooltip-padding-y $form-feedback-tooltip-padding-x;\n margin-top: .1rem;\n @include font-size($form-feedback-tooltip-font-size);\n line-height: $form-feedback-tooltip-line-height;\n color: $tooltip-color;\n background-color: $tooltip-bg-color;\n @include border-radius($form-feedback-tooltip-border-radius);\n }\n\n @include form-validation-state-selector($state) {\n ~ .#{$state}-feedback,\n ~ .#{$state}-tooltip {\n display: block;\n }\n }\n\n .form-control {\n @include form-validation-state-selector($state) {\n border-color: $color;\n\n @if $enable-validation-icons {\n padding-right: $input-height-inner;\n background-image: escape-svg($icon);\n background-repeat: no-repeat;\n background-position: right $input-height-inner-quarter center;\n background-size: $input-height-inner-half $input-height-inner-half;\n }\n\n &:focus {\n border-color: $color;\n box-shadow: $focus-box-shadow;\n }\n }\n }\n\n // stylelint-disable-next-line selector-no-qualifying-type\n textarea.form-control {\n @include form-validation-state-selector($state) {\n @if $enable-validation-icons {\n padding-right: $input-height-inner;\n background-position: top $input-height-inner-quarter right $input-height-inner-quarter;\n }\n }\n }\n\n .form-select {\n @include form-validation-state-selector($state) {\n border-color: $color;\n\n @if $enable-validation-icons {\n &:not([multiple]):not([size]),\n &:not([multiple])[size=\"1\"] {\n padding-right: $form-select-feedback-icon-padding-end;\n background-image: escape-svg($form-select-indicator), escape-svg($icon);\n background-position: $form-select-bg-position, $form-select-feedback-icon-position;\n background-size: $form-select-bg-size, $form-select-feedback-icon-size;\n }\n }\n\n &:focus {\n border-color: $color;\n box-shadow: $focus-box-shadow;\n }\n }\n }\n\n .form-check-input {\n @include form-validation-state-selector($state) {\n border-color: $color;\n\n &:checked {\n background-color: $color;\n }\n\n &:focus {\n box-shadow: $focus-box-shadow;\n }\n\n ~ .form-check-label {\n color: $color;\n }\n }\n }\n .form-check-inline .form-check-input {\n ~ .#{$state}-feedback {\n margin-left: .5em;\n }\n }\n\n .input-group .form-control,\n .input-group .form-select {\n @include form-validation-state-selector($state) {\n @if $state == \"valid\" {\n z-index: 1;\n } @else if $state == \"invalid\" {\n z-index: 2;\n }\n &:focus {\n z-index: 3;\n }\n }\n }\n}\n// scss-docs-end form-validation-mixins\n", + "// scss-docs-start table-variant\n@mixin table-variant($state, $background) {\n .table-#{$state} {\n $color: color-contrast(opaque($body-bg, $background));\n $hover-bg: mix($color, $background, percentage($table-hover-bg-factor));\n $striped-bg: mix($color, $background, percentage($table-striped-bg-factor));\n $active-bg: mix($color, $background, percentage($table-active-bg-factor));\n\n --#{$variable-prefix}table-bg: #{$background};\n --#{$variable-prefix}table-striped-bg: #{$striped-bg};\n --#{$variable-prefix}table-striped-color: #{color-contrast($striped-bg)};\n --#{$variable-prefix}table-active-bg: #{$active-bg};\n --#{$variable-prefix}table-active-color: #{color-contrast($active-bg)};\n --#{$variable-prefix}table-hover-bg: #{$hover-bg};\n --#{$variable-prefix}table-hover-color: #{color-contrast($hover-bg)};\n\n color: $color;\n border-color: mix($color, $background, percentage($table-border-factor));\n }\n}\n// scss-docs-end table-variant\n", + "// stylelint-disable property-disallowed-list\n// Single side border-radius\n\n// Helper function to replace negative values with 0\n@function valid-radius($radius) {\n $return: ();\n @each $value in $radius {\n @if type-of($value) == number {\n $return: append($return, max($value, 0));\n } @else {\n $return: append($return, $value);\n }\n }\n @return $return;\n}\n\n// scss-docs-start border-radius-mixins\n@mixin border-radius($radius: $border-radius, $fallback-border-radius: false) {\n @if $enable-rounded {\n border-radius: valid-radius($radius);\n }\n @else if $fallback-border-radius != false {\n border-radius: $fallback-border-radius;\n }\n}\n\n@mixin border-top-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-left-radius: valid-radius($radius);\n border-top-right-radius: valid-radius($radius);\n }\n}\n\n@mixin border-end-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-right-radius: valid-radius($radius);\n border-bottom-right-radius: valid-radius($radius);\n }\n}\n\n@mixin border-bottom-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-bottom-right-radius: valid-radius($radius);\n border-bottom-left-radius: valid-radius($radius);\n }\n}\n\n@mixin border-start-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-left-radius: valid-radius($radius);\n border-bottom-left-radius: valid-radius($radius);\n }\n}\n\n@mixin border-top-start-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-left-radius: valid-radius($radius);\n }\n}\n\n@mixin border-top-end-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-top-right-radius: valid-radius($radius);\n }\n}\n\n@mixin border-bottom-end-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-bottom-right-radius: valid-radius($radius);\n }\n}\n\n@mixin border-bottom-start-radius($radius: $border-radius) {\n @if $enable-rounded {\n border-bottom-left-radius: valid-radius($radius);\n }\n}\n// scss-docs-end border-radius-mixins\n", + "@mixin box-shadow($shadow...) {\n @if $enable-shadows {\n $result: ();\n\n @each $value in $shadow {\n @if $value != null {\n $result: append($result, $value, \"comma\");\n }\n @if $value == none and length($shadow) > 1 {\n @warn \"The keyword 'none' must be used as a single argument.\";\n }\n }\n\n @if (length($result) > 0) {\n box-shadow: $result;\n }\n }\n}\n", + "// Gradients\n\n// scss-docs-start gradient-bg-mixin\n@mixin gradient-bg($color: null) {\n background-color: $color;\n\n @if $enable-gradients {\n background-image: var(--#{$variable-prefix}gradient);\n }\n}\n// scss-docs-end gradient-bg-mixin\n\n// scss-docs-start gradient-mixins\n// Horizontal gradient, from left to right\n//\n// Creates two color stops, start and end, by specifying a color and position for each color stop.\n@mixin gradient-x($start-color: $gray-700, $end-color: $gray-800, $start-percent: 0%, $end-percent: 100%) {\n background-image: linear-gradient(to right, $start-color $start-percent, $end-color $end-percent);\n}\n\n// Vertical gradient, from top to bottom\n//\n// Creates two color stops, start and end, by specifying a color and position for each color stop.\n@mixin gradient-y($start-color: $gray-700, $end-color: $gray-800, $start-percent: null, $end-percent: null) {\n background-image: linear-gradient(to bottom, $start-color $start-percent, $end-color $end-percent);\n}\n\n@mixin gradient-directional($start-color: $gray-700, $end-color: $gray-800, $deg: 45deg) {\n background-image: linear-gradient($deg, $start-color, $end-color);\n}\n\n@mixin gradient-x-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) {\n background-image: linear-gradient(to right, $start-color, $mid-color $color-stop, $end-color);\n}\n\n@mixin gradient-y-three-colors($start-color: $blue, $mid-color: $purple, $color-stop: 50%, $end-color: $red) {\n background-image: linear-gradient($start-color, $mid-color $color-stop, $end-color);\n}\n\n@mixin gradient-radial($inner-color: $gray-700, $outer-color: $gray-800) {\n background-image: radial-gradient(circle, $inner-color, $outer-color);\n}\n\n@mixin gradient-striped($color: rgba($white, .15), $angle: 45deg) {\n background-image: linear-gradient($angle, $color 25%, transparent 25%, transparent 50%, $color 50%, $color 75%, transparent 75%, transparent);\n}\n// scss-docs-end gradient-mixins\n", + "// stylelint-disable property-disallowed-list\n@mixin transition($transition...) {\n @if length($transition) == 0 {\n $transition: $transition-base;\n }\n\n @if length($transition) > 1 {\n @each $value in $transition {\n @if $value == null or $value == none {\n @warn \"The keyword 'none' or 'null' must be used as a single argument.\";\n }\n }\n }\n\n @if $enable-transitions {\n @if nth($transition, 1) != null {\n transition: $transition;\n }\n\n @if $enable-reduced-motion and nth($transition, 1) != null and nth($transition, 1) != none {\n @media (prefers-reduced-motion: reduce) {\n transition: none;\n }\n }\n }\n}\n", + "// scss-docs-start clearfix\n@mixin clearfix() {\n &::after {\n display: block;\n clear: both;\n content: \"\";\n }\n}\n// scss-docs-end clearfix\n", + "// Container mixins\n\n@mixin make-container($gutter: $container-padding-x) {\n width: 100%;\n padding-right: var(--#{$variable-prefix}gutter-x, #{$gutter});\n padding-left: var(--#{$variable-prefix}gutter-x, #{$gutter});\n margin-right: auto;\n margin-left: auto;\n}\n", + "// Grid system\n//\n// Generate semantic grid columns with these mixins.\n\n@mixin make-row($gutter: $grid-gutter-width) {\n --#{$variable-prefix}gutter-x: #{$gutter};\n --#{$variable-prefix}gutter-y: 0;\n display: flex;\n flex-wrap: wrap;\n margin-top: calc(var(--#{$variable-prefix}gutter-y) * -1); // stylelint-disable-line function-disallowed-list\n margin-right: calc(var(--#{$variable-prefix}gutter-x) * -.5); // stylelint-disable-line function-disallowed-list\n margin-left: calc(var(--#{$variable-prefix}gutter-x) * -.5); // stylelint-disable-line function-disallowed-list\n}\n\n@mixin make-col-ready($gutter: $grid-gutter-width) {\n // Add box sizing if only the grid is loaded\n box-sizing: if(variable-exists(include-column-box-sizing) and $include-column-box-sizing, border-box, null);\n // Prevent columns from becoming too narrow when at smaller grid tiers by\n // always setting `width: 100%;`. This works because we set the width\n // later on to override this initial width.\n flex-shrink: 0;\n width: 100%;\n max-width: 100%; // Prevent `.col-auto`, `.col` (& responsive variants) from breaking out the grid\n padding-right: calc(var(--#{$variable-prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n padding-left: calc(var(--#{$variable-prefix}gutter-x) * .5); // stylelint-disable-line function-disallowed-list\n margin-top: var(--#{$variable-prefix}gutter-y);\n}\n\n@mixin make-col($size: false, $columns: $grid-columns) {\n @if $size {\n flex: 0 0 auto;\n width: percentage(divide($size, $columns));\n\n } @else {\n flex: 1 1 0;\n max-width: 100%;\n }\n}\n\n@mixin make-col-auto() {\n flex: 0 0 auto;\n width: auto;\n}\n\n@mixin make-col-offset($size, $columns: $grid-columns) {\n $num: divide($size, $columns);\n margin-left: if($num == 0, 0, percentage($num));\n}\n\n// Row columns\n//\n// Specify on a parent element(e.g., .row) to force immediate children into NN\n// numberof columns. Supports wrapping to new lines, but does not do a Masonry\n// style grid.\n@mixin row-cols($count) {\n > * {\n flex: 0 0 auto;\n width: divide(100%, $count);\n }\n}\n\n// Framework grid generation\n//\n// Used only by Bootstrap to generate the correct number of grid classes given\n// any value of `$grid-columns`.\n\n@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n // Provide basic `.col-{bp}` classes for equal-width flexbox columns\n .col#{$infix} {\n flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4\n }\n\n .row-cols#{$infix}-auto > * {\n @include make-col-auto();\n }\n\n @if $grid-row-columns > 0 {\n @for $i from 1 through $grid-row-columns {\n .row-cols#{$infix}-#{$i} {\n @include row-cols($i);\n }\n }\n }\n\n .col#{$infix}-auto {\n @include make-col-auto();\n }\n\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .col#{$infix}-#{$i} {\n @include make-col($i, $columns);\n }\n }\n\n // `$columns - 1` because offsetting by the width of an entire row isn't possible\n @for $i from 0 through ($columns - 1) {\n @if not ($infix == \"\" and $i == 0) { // Avoid emitting useless .offset-0\n .offset#{$infix}-#{$i} {\n @include make-col-offset($i, $columns);\n }\n }\n }\n }\n\n // Gutters\n //\n // Make use of `.g-*`, `.gx-*` or `.gy-*` utilities to change spacing between the columns.\n @each $key, $value in $gutters {\n .g#{$infix}-#{$key},\n .gx#{$infix}-#{$key} {\n --#{$variable-prefix}gutter-x: #{$value};\n }\n\n .g#{$infix}-#{$key},\n .gy#{$infix}-#{$key} {\n --#{$variable-prefix}gutter-y: #{$value};\n }\n }\n }\n }\n}\n\n@mixin make-cssgrid($columns: $grid-columns, $breakpoints: $grid-breakpoints) {\n @each $breakpoint in map-keys($breakpoints) {\n $infix: breakpoint-infix($breakpoint, $breakpoints);\n\n @include media-breakpoint-up($breakpoint, $breakpoints) {\n @if $columns > 0 {\n @for $i from 1 through $columns {\n .g-col#{$infix}-#{$i} {\n grid-column: auto / span $i;\n }\n }\n\n // Start with `1` because `0` is and invalid value.\n // Ends with `$columns - 1` because offsetting by the width of an entire row isn't possible.\n @for $i from 1 through ($columns - 1) {\n .g-start#{$infix}-#{$i} {\n grid-column-start: $i;\n }\n }\n }\n }\n }\n}\n", + "// stylelint-disable indentation\n\n// Utilities\n\n$utilities: () !default;\n// stylelint-disable-next-line scss/dollar-variable-default\n$utilities: map-merge(\n (\n // scss-docs-start utils-vertical-align\n \"align\": (\n property: vertical-align,\n class: align,\n values: baseline top middle bottom text-bottom text-top\n ),\n // scss-docs-end utils-vertical-align\n // scss-docs-start utils-float\n \"float\": (\n responsive: true,\n property: float,\n values: (\n start: left,\n end: right,\n none: none,\n )\n ),\n // scss-docs-end utils-float\n // Opacity utilities\n // scss-docs-start utils-opacity\n \"opacity\": (\n property: opacity,\n values: (\n 0: 0,\n 25: .25,\n 50: .5,\n 75: .75,\n 100: 1,\n )\n ),\n // scss-docs-end utils-opacity\n // scss-docs-start utils-overflow\n \"overflow\": (\n property: overflow,\n values: auto hidden visible scroll,\n ),\n // scss-docs-end utils-overflow\n // scss-docs-start utils-display\n \"display\": (\n responsive: true,\n print: true,\n property: display,\n class: d,\n values: inline inline-block block grid table table-row table-cell flex inline-flex none\n ),\n // scss-docs-end utils-display\n // scss-docs-start utils-shadow\n \"shadow\": (\n property: box-shadow,\n class: shadow,\n values: (\n null: $box-shadow,\n sm: $box-shadow-sm,\n lg: $box-shadow-lg,\n none: none,\n )\n ),\n // scss-docs-end utils-shadow\n // scss-docs-start utils-position\n \"position\": (\n property: position,\n values: static relative absolute fixed sticky\n ),\n \"top\": (\n property: top,\n values: $position-values\n ),\n \"bottom\": (\n property: bottom,\n values: $position-values\n ),\n \"start\": (\n property: left,\n class: start,\n values: $position-values\n ),\n \"end\": (\n property: right,\n class: end,\n values: $position-values\n ),\n \"translate-middle\": (\n property: transform,\n class: translate-middle,\n values: (\n null: translate(-50%, -50%),\n x: translateX(-50%),\n y: translateY(-50%),\n )\n ),\n // scss-docs-end utils-position\n // scss-docs-start utils-borders\n \"border\": (\n property: border,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-top\": (\n property: border-top,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-end\": (\n property: border-right,\n class: border-end,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-bottom\": (\n property: border-bottom,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-start\": (\n property: border-left,\n class: border-start,\n values: (\n null: $border-width solid $border-color,\n 0: 0,\n )\n ),\n \"border-color\": (\n property: border-color,\n class: border,\n values: map-merge($theme-colors, (\"white\": $white))\n ),\n \"border-width\": (\n property: border-width,\n class: border,\n values: $border-widths\n ),\n // scss-docs-end utils-borders\n // Sizing utilities\n // scss-docs-start utils-sizing\n \"width\": (\n property: width,\n class: w,\n values: (\n 25: 25%,\n 50: 50%,\n 75: 75%,\n 100: 100%,\n auto: auto\n )\n ),\n \"max-width\": (\n property: max-width,\n class: mw,\n values: (100: 100%)\n ),\n \"viewport-width\": (\n property: width,\n class: vw,\n values: (100: 100vw)\n ),\n \"min-viewport-width\": (\n property: min-width,\n class: min-vw,\n values: (100: 100vw)\n ),\n \"height\": (\n property: height,\n class: h,\n values: (\n 25: 25%,\n 50: 50%,\n 75: 75%,\n 100: 100%,\n auto: auto\n )\n ),\n \"max-height\": (\n property: max-height,\n class: mh,\n values: (100: 100%)\n ),\n \"viewport-height\": (\n property: height,\n class: vh,\n values: (100: 100vh)\n ),\n \"min-viewport-height\": (\n property: min-height,\n class: min-vh,\n values: (100: 100vh)\n ),\n // scss-docs-end utils-sizing\n // Flex utilities\n // scss-docs-start utils-flex\n \"flex\": (\n responsive: true,\n property: flex,\n values: (fill: 1 1 auto)\n ),\n \"flex-direction\": (\n responsive: true,\n property: flex-direction,\n class: flex,\n values: row column row-reverse column-reverse\n ),\n \"flex-grow\": (\n responsive: true,\n property: flex-grow,\n class: flex,\n values: (\n grow-0: 0,\n grow-1: 1,\n )\n ),\n \"flex-shrink\": (\n responsive: true,\n property: flex-shrink,\n class: flex,\n values: (\n shrink-0: 0,\n shrink-1: 1,\n )\n ),\n \"flex-wrap\": (\n responsive: true,\n property: flex-wrap,\n class: flex,\n values: wrap nowrap wrap-reverse\n ),\n \"gap\": (\n responsive: true,\n property: gap,\n class: gap,\n values: $spacers\n ),\n \"justify-content\": (\n responsive: true,\n property: justify-content,\n values: (\n start: flex-start,\n end: flex-end,\n center: center,\n between: space-between,\n around: space-around,\n evenly: space-evenly,\n )\n ),\n \"align-items\": (\n responsive: true,\n property: align-items,\n values: (\n start: flex-start,\n end: flex-end,\n center: center,\n baseline: baseline,\n stretch: stretch,\n )\n ),\n \"align-content\": (\n responsive: true,\n property: align-content,\n values: (\n start: flex-start,\n end: flex-end,\n center: center,\n between: space-between,\n around: space-around,\n stretch: stretch,\n )\n ),\n \"align-self\": (\n responsive: true,\n property: align-self,\n values: (\n auto: auto,\n start: flex-start,\n end: flex-end,\n center: center,\n baseline: baseline,\n stretch: stretch,\n )\n ),\n \"order\": (\n responsive: true,\n property: order,\n values: (\n first: -1,\n 0: 0,\n 1: 1,\n 2: 2,\n 3: 3,\n 4: 4,\n 5: 5,\n last: 6,\n ),\n ),\n // scss-docs-end utils-flex\n // Margin utilities\n // scss-docs-start utils-spacing\n \"margin\": (\n responsive: true,\n property: margin,\n class: m,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-x\": (\n responsive: true,\n property: margin-right margin-left,\n class: mx,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-y\": (\n responsive: true,\n property: margin-top margin-bottom,\n class: my,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-top\": (\n responsive: true,\n property: margin-top,\n class: mt,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-end\": (\n responsive: true,\n property: margin-right,\n class: me,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-bottom\": (\n responsive: true,\n property: margin-bottom,\n class: mb,\n values: map-merge($spacers, (auto: auto))\n ),\n \"margin-start\": (\n responsive: true,\n property: margin-left,\n class: ms,\n values: map-merge($spacers, (auto: auto))\n ),\n // Negative margin utilities\n \"negative-margin\": (\n responsive: true,\n property: margin,\n class: m,\n values: $negative-spacers\n ),\n \"negative-margin-x\": (\n responsive: true,\n property: margin-right margin-left,\n class: mx,\n values: $negative-spacers\n ),\n \"negative-margin-y\": (\n responsive: true,\n property: margin-top margin-bottom,\n class: my,\n values: $negative-spacers\n ),\n \"negative-margin-top\": (\n responsive: true,\n property: margin-top,\n class: mt,\n values: $negative-spacers\n ),\n \"negative-margin-end\": (\n responsive: true,\n property: margin-right,\n class: me,\n values: $negative-spacers\n ),\n \"negative-margin-bottom\": (\n responsive: true,\n property: margin-bottom,\n class: mb,\n values: $negative-spacers\n ),\n \"negative-margin-start\": (\n responsive: true,\n property: margin-left,\n class: ms,\n values: $negative-spacers\n ),\n // Padding utilities\n \"padding\": (\n responsive: true,\n property: padding,\n class: p,\n values: $spacers\n ),\n \"padding-x\": (\n responsive: true,\n property: padding-right padding-left,\n class: px,\n values: $spacers\n ),\n \"padding-y\": (\n responsive: true,\n property: padding-top padding-bottom,\n class: py,\n values: $spacers\n ),\n \"padding-top\": (\n responsive: true,\n property: padding-top,\n class: pt,\n values: $spacers\n ),\n \"padding-end\": (\n responsive: true,\n property: padding-right,\n class: pe,\n values: $spacers\n ),\n \"padding-bottom\": (\n responsive: true,\n property: padding-bottom,\n class: pb,\n values: $spacers\n ),\n \"padding-start\": (\n responsive: true,\n property: padding-left,\n class: ps,\n values: $spacers\n ),\n // scss-docs-end utils-spacing\n // Text\n // scss-docs-start utils-text\n \"font-family\": (\n property: font-family,\n class: font,\n values: (monospace: var(--#{$variable-prefix}font-monospace))\n ),\n \"font-size\": (\n rfs: true,\n property: font-size,\n class: fs,\n values: $font-sizes\n ),\n \"font-style\": (\n property: font-style,\n class: fst,\n values: italic normal\n ),\n \"font-weight\": (\n property: font-weight,\n class: fw,\n values: (\n light: $font-weight-light,\n lighter: $font-weight-lighter,\n normal: $font-weight-normal,\n bold: $font-weight-bold,\n bolder: $font-weight-bolder\n )\n ),\n \"line-height\": (\n property: line-height,\n class: lh,\n values: (\n 1: 1,\n sm: $line-height-sm,\n base: $line-height-base,\n lg: $line-height-lg,\n )\n ),\n \"text-align\": (\n responsive: true,\n property: text-align,\n class: text,\n values: (\n start: left,\n end: right,\n center: center,\n )\n ),\n \"text-decoration\": (\n property: text-decoration,\n values: none underline line-through\n ),\n \"text-transform\": (\n property: text-transform,\n class: text,\n values: lowercase uppercase capitalize\n ),\n \"white-space\": (\n property: white-space,\n class: text,\n values: (\n wrap: normal,\n nowrap: nowrap,\n )\n ),\n \"word-wrap\": (\n property: word-wrap word-break,\n class: text,\n values: (break: break-word),\n rtl: false\n ),\n // scss-docs-end utils-text\n // scss-docs-start utils-color\n \"color\": (\n property: color,\n class: text,\n local-vars: (\n \"text-opacity\": 1\n ),\n values: map-merge(\n $utilities-text-colors,\n (\n \"muted\": $text-muted,\n \"black-50\": rgba($black, .5), // deprecated\n \"white-50\": rgba($white, .5), // deprecated\n \"reset\": inherit,\n )\n )\n ),\n \"text-opacity\": (\n css-var: true,\n class: text-opacity,\n values: (\n 25: .25,\n 50: .5,\n 75: .75,\n 100: 1\n )\n ),\n // scss-docs-end utils-color\n // scss-docs-start utils-bg-color\n \"background-color\": (\n property: background-color,\n class: bg,\n local-vars: (\n \"bg-opacity\": 1\n ),\n values: map-merge(\n $utilities-bg-colors,\n (\n \"transparent\": transparent\n )\n )\n ),\n \"bg-opacity\": (\n css-var: true,\n class: bg-opacity,\n values: (\n 10: .1,\n 25: .25,\n 50: .5,\n 75: .75,\n 100: 1\n )\n ),\n // scss-docs-end utils-bg-color\n \"gradient\": (\n property: background-image,\n class: bg,\n values: (gradient: var(--#{$variable-prefix}gradient))\n ),\n // scss-docs-start utils-interaction\n \"user-select\": (\n property: user-select,\n values: all auto none\n ),\n \"pointer-events\": (\n property: pointer-events,\n class: pe,\n values: none auto,\n ),\n // scss-docs-end utils-interaction\n // scss-docs-start utils-border-radius\n \"rounded\": (\n property: border-radius,\n class: rounded,\n values: (\n null: $border-radius,\n 0: 0,\n 1: $border-radius-sm,\n 2: $border-radius,\n 3: $border-radius-lg,\n circle: 50%,\n pill: $border-radius-pill\n )\n ),\n \"rounded-top\": (\n property: border-top-left-radius border-top-right-radius,\n class: rounded-top,\n values: (null: $border-radius)\n ),\n \"rounded-end\": (\n property: border-top-right-radius border-bottom-right-radius,\n class: rounded-end,\n values: (null: $border-radius)\n ),\n \"rounded-bottom\": (\n property: border-bottom-right-radius border-bottom-left-radius,\n class: rounded-bottom,\n values: (null: $border-radius)\n ),\n \"rounded-start\": (\n property: border-bottom-left-radius border-top-left-radius,\n class: rounded-start,\n values: (null: $border-radius)\n ),\n // scss-docs-end utils-border-radius\n // scss-docs-start utils-visibility\n \"visibility\": (\n property: visibility,\n class: null,\n values: (\n visible: visible,\n invisible: hidden,\n )\n )\n // scss-docs-end utils-visibility\n ),\n $utilities\n);\n", + ":root {\n // Note: Custom variable values only support SassScript inside `#{}`.\n\n // Colors\n //\n // Generate palettes for full colors, grays, and theme colors.\n\n @each $color, $value in $colors {\n --#{$variable-prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $grays {\n --#{$variable-prefix}gray-#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors {\n --#{$variable-prefix}#{$color}: #{$value};\n }\n\n @each $color, $value in $theme-colors-rgb {\n --#{$variable-prefix}#{$color}-rgb: #{$value};\n }\n\n --#{$variable-prefix}white-rgb: #{to-rgb($white)};\n --#{$variable-prefix}black-rgb: #{to-rgb($black)};\n --#{$variable-prefix}body-rgb: #{to-rgb($body-color)};\n\n // Fonts\n\n // Note: Use `inspect` for lists so that quoted items keep the quotes.\n // See https://github.com/sass/sass/issues/2383#issuecomment-336349172\n --#{$variable-prefix}font-sans-serif: #{inspect($font-family-sans-serif)};\n --#{$variable-prefix}font-monospace: #{inspect($font-family-monospace)};\n --#{$variable-prefix}gradient: #{$gradient};\n\n // Root and body\n // stylelint-disable custom-property-empty-line-before\n // scss-docs-start root-body-variables\n @if $font-size-root != null {\n --#{$variable-prefix}root-font-size: #{$font-size-root};\n }\n --#{$variable-prefix}body-font-family: #{$font-family-base};\n --#{$variable-prefix}body-font-size: #{$font-size-base};\n --#{$variable-prefix}body-font-weight: #{$font-weight-base};\n --#{$variable-prefix}body-line-height: #{$line-height-base};\n --#{$variable-prefix}body-color: #{$body-color};\n @if $body-text-align != null {\n --#{$variable-prefix}body-text-align: #{$body-text-align};\n }\n --#{$variable-prefix}body-bg: #{$body-bg};\n // scss-docs-end root-body-variables\n // stylelint-enable custom-property-empty-line-before\n}\n", + "// stylelint-disable declaration-no-important, selector-no-qualifying-type, property-no-vendor-prefix\n\n\n// Reboot\n//\n// Normalization of HTML elements, manually forked from Normalize.css to remove\n// styles targeting irrelevant browsers while applying new styles.\n//\n// Normalize is licensed MIT. https://github.com/necolas/normalize.css\n\n\n// Document\n//\n// Change from `box-sizing: content-box` so that `width` is not affected by `padding` or `border`.\n\n*,\n*::before,\n*::after {\n box-sizing: border-box;\n}\n\n\n// Root\n//\n// Ability to the value of the root font sizes, affecting the value of `rem`.\n// null by default, thus nothing is generated.\n\n:root {\n @if $font-size-root != null {\n font-size: var(--#{$variable-prefix}-root-font-size);\n }\n\n @if $enable-smooth-scroll {\n @media (prefers-reduced-motion: no-preference) {\n scroll-behavior: smooth;\n }\n }\n}\n\n\n// Body\n//\n// 1. Remove the margin in all browsers.\n// 2. As a best practice, apply a default `background-color`.\n// 3. Prevent adjustments of font size after orientation changes in iOS.\n// 4. Change the default tap highlight to be completely transparent in iOS.\n\n// scss-docs-start reboot-body-rules\nbody {\n margin: 0; // 1\n font-family: var(--#{$variable-prefix}body-font-family);\n @include font-size(var(--#{$variable-prefix}body-font-size));\n font-weight: var(--#{$variable-prefix}body-font-weight);\n line-height: var(--#{$variable-prefix}body-line-height);\n color: var(--#{$variable-prefix}body-color);\n text-align: var(--#{$variable-prefix}body-text-align);\n background-color: var(--#{$variable-prefix}body-bg); // 2\n -webkit-text-size-adjust: 100%; // 3\n -webkit-tap-highlight-color: rgba($black, 0); // 4\n}\n// scss-docs-end reboot-body-rules\n\n\n// Content grouping\n//\n// 1. Reset Firefox's gray color\n// 2. Set correct height and prevent the `size` attribute to make the `hr` look like an input field\n\nhr {\n margin: $hr-margin-y 0;\n color: $hr-color; // 1\n background-color: currentColor;\n border: 0;\n opacity: $hr-opacity;\n}\n\nhr:not([size]) {\n height: $hr-height; // 2\n}\n\n\n// Typography\n//\n// 1. Remove top margins from headings\n// By default, `

`-`

` all receive top and bottom margins. We nuke the top\n// margin for easier control within type scales as it avoids margin collapsing.\n\n%heading {\n margin-top: 0; // 1\n margin-bottom: $headings-margin-bottom;\n font-family: $headings-font-family;\n font-style: $headings-font-style;\n font-weight: $headings-font-weight;\n line-height: $headings-line-height;\n color: $headings-color;\n}\n\nh1 {\n @extend %heading;\n @include font-size($h1-font-size);\n}\n\nh2 {\n @extend %heading;\n @include font-size($h2-font-size);\n}\n\nh3 {\n @extend %heading;\n @include font-size($h3-font-size);\n}\n\nh4 {\n @extend %heading;\n @include font-size($h4-font-size);\n}\n\nh5 {\n @extend %heading;\n @include font-size($h5-font-size);\n}\n\nh6 {\n @extend %heading;\n @include font-size($h6-font-size);\n}\n\n\n// Reset margins on paragraphs\n//\n// Similarly, the top margin on `

`s get reset. However, we also reset the\n// bottom margin to use `rem` units instead of `em`.\n\np {\n margin-top: 0;\n margin-bottom: $paragraph-margin-bottom;\n}\n\n\n// Abbreviations\n//\n// 1. Duplicate behavior to the data-bs-* attribute for our tooltip plugin\n// 2. Add the correct text decoration in Chrome, Edge, Opera, and Safari.\n// 3. Add explicit cursor to indicate changed behavior.\n// 4. Prevent the text-decoration to be skipped.\n\nabbr[title],\nabbr[data-bs-original-title] { // 1\n text-decoration: underline dotted; // 2\n cursor: help; // 3\n text-decoration-skip-ink: none; // 4\n}\n\n\n// Address\n\naddress {\n margin-bottom: 1rem;\n font-style: normal;\n line-height: inherit;\n}\n\n\n// Lists\n\nol,\nul {\n padding-left: 2rem;\n}\n\nol,\nul,\ndl {\n margin-top: 0;\n margin-bottom: 1rem;\n}\n\nol ol,\nul ul,\nol ul,\nul ol {\n margin-bottom: 0;\n}\n\ndt {\n font-weight: $dt-font-weight;\n}\n\n// 1. Undo browser default\n\ndd {\n margin-bottom: .5rem;\n margin-left: 0; // 1\n}\n\n\n// Blockquote\n\nblockquote {\n margin: 0 0 1rem;\n}\n\n\n// Strong\n//\n// Add the correct font weight in Chrome, Edge, and Safari\n\nb,\nstrong {\n font-weight: $font-weight-bolder;\n}\n\n\n// Small\n//\n// Add the correct font size in all browsers\n\nsmall {\n @include font-size($small-font-size);\n}\n\n\n// Mark\n\nmark {\n padding: $mark-padding;\n background-color: $mark-bg;\n}\n\n\n// Sub and Sup\n//\n// Prevent `sub` and `sup` elements from affecting the line height in\n// all browsers.\n\nsub,\nsup {\n position: relative;\n @include font-size($sub-sup-font-size);\n line-height: 0;\n vertical-align: baseline;\n}\n\nsub { bottom: -.25em; }\nsup { top: -.5em; }\n\n\n// Links\n\na {\n color: $link-color;\n text-decoration: $link-decoration;\n\n &:hover {\n color: $link-hover-color;\n text-decoration: $link-hover-decoration;\n }\n}\n\n// And undo these styles for placeholder links/named anchors (without href).\n// It would be more straightforward to just use a[href] in previous block, but that\n// causes specificity issues in many other styles that are too complex to fix.\n// See https://github.com/twbs/bootstrap/issues/19402\n\na:not([href]):not([class]) {\n &,\n &:hover {\n color: inherit;\n text-decoration: none;\n }\n}\n\n\n// Code\n\npre,\ncode,\nkbd,\nsamp {\n font-family: $font-family-code;\n @include font-size(1em); // Correct the odd `em` font sizing in all browsers.\n direction: ltr #{\"/* rtl:ignore */\"};\n unicode-bidi: bidi-override;\n}\n\n// 1. Remove browser default top margin\n// 2. Reset browser default of `1em` to use `rem`s\n// 3. Don't allow content to break outside\n\npre {\n display: block;\n margin-top: 0; // 1\n margin-bottom: 1rem; // 2\n overflow: auto; // 3\n @include font-size($code-font-size);\n color: $pre-color;\n\n // Account for some code outputs that place code tags in pre tags\n code {\n @include font-size(inherit);\n color: inherit;\n word-break: normal;\n }\n}\n\ncode {\n @include font-size($code-font-size);\n color: $code-color;\n word-wrap: break-word;\n\n // Streamline the style when inside anchors to avoid broken underline and more\n a > & {\n color: inherit;\n }\n}\n\nkbd {\n padding: $kbd-padding-y $kbd-padding-x;\n @include font-size($kbd-font-size);\n color: $kbd-color;\n background-color: $kbd-bg;\n @include border-radius($border-radius-sm);\n\n kbd {\n padding: 0;\n @include font-size(1em);\n font-weight: $nested-kbd-font-weight;\n }\n}\n\n\n// Figures\n//\n// Apply a consistent margin strategy (matches our type styles).\n\nfigure {\n margin: 0 0 1rem;\n}\n\n\n// Images and content\n\nimg,\nsvg {\n vertical-align: middle;\n}\n\n\n// Tables\n//\n// Prevent double borders\n\ntable {\n caption-side: bottom;\n border-collapse: collapse;\n}\n\ncaption {\n padding-top: $table-cell-padding-y;\n padding-bottom: $table-cell-padding-y;\n color: $table-caption-color;\n text-align: left;\n}\n\n// 1. Removes font-weight bold by inheriting\n// 2. Matches default `` alignment by inheriting `text-align`.\n// 3. Fix alignment for Safari\n\nth {\n font-weight: $table-th-font-weight; // 1\n text-align: inherit; // 2\n text-align: -webkit-match-parent; // 3\n}\n\nthead,\ntbody,\ntfoot,\ntr,\ntd,\nth {\n border-color: inherit;\n border-style: solid;\n border-width: 0;\n}\n\n\n// Forms\n//\n// 1. Allow labels to use `margin` for spacing.\n\nlabel {\n display: inline-block; // 1\n}\n\n// Remove the default `border-radius` that macOS Chrome adds.\n// See https://github.com/twbs/bootstrap/issues/24093\n\nbutton {\n // stylelint-disable-next-line property-disallowed-list\n border-radius: 0;\n}\n\n// Explicitly remove focus outline in Chromium when it shouldn't be\n// visible (e.g. as result of mouse click or touch tap). It already\n// should be doing this automatically, but seems to currently be\n// confused and applies its very visible two-tone outline anyway.\n\nbutton:focus:not(:focus-visible) {\n outline: 0;\n}\n\n// 1. Remove the margin in Firefox and Safari\n\ninput,\nbutton,\nselect,\noptgroup,\ntextarea {\n margin: 0; // 1\n font-family: inherit;\n @include font-size(inherit);\n line-height: inherit;\n}\n\n// Remove the inheritance of text transform in Firefox\nbutton,\nselect {\n text-transform: none;\n}\n// Set the cursor for non-` + + + Kembali + + + + + + + + \ No newline at end of file diff --git a/website/resources/views/absensis/index.blade.php b/website/resources/views/absensis/index.blade.php new file mode 100644 index 0000000..9e8a572 --- /dev/null +++ b/website/resources/views/absensis/index.blade.php @@ -0,0 +1,138 @@ + + +

+ {{ __('Daftar absensi') }} +

+ + +
+
+
+
+ +
+

Rekap Absensi

+

Kelola dan pantau kehadiran santri dengan mudah

+
+ + +
+
+
+ + +
+
+ + +
+
+ +
+ +
+
+ + + @if($santris->count()) +
+
+ + + + + + + + + + + + @foreach($santris as $i => $santri) + + + + + + + + @endforeach + +
NoNama SantriStatusKeteranganAksi
{{ $i+1 }} +
+
+ {{ substr($santri->nama, 0, 1) }} +
+ {{ $santri->nama }} +
+
+ @if(isset($absensis[$santri->id])) + @php + $status = $absensis[$santri->id]->status; + $statusColors = [ + 'hadir' => 'bg-green-100 text-green-800', + 'izin' => 'bg-yellow-100 text-yellow-800', + 'sakit' => 'bg-orange-100 text-orange-800', + 'alfa' => 'bg-red-100 text-red-800' + ]; + $color = $statusColors[$status] ?? 'bg-gray-100 text-gray-800'; + @endphp + + {{ ucfirst($status) }} + + @else + - + @endif + + {{ $absensis[$santri->id]->keterangan ?? '-' }} + + @if(isset($absensis[$santri->id])) +
+ + + Edit + +
+ @csrf + @method('DELETE') + +
+
+ @else + Belum ada data + @endif +
+
+
+ @elseif($kelasId) +
+
+ +
+

Tidak ada data santri

+

Tidak ada data santri di kelas yang dipilih.

+
+ @endif +
+
+
+
+ diff --git a/website/resources/views/absensis/show.blade.php b/website/resources/views/absensis/show.blade.php new file mode 100644 index 0000000..5956df3 --- /dev/null +++ b/website/resources/views/absensis/show.blade.php @@ -0,0 +1,45 @@ + + +

+ {{ __('Detail absensi') }} +

+
+ +
+
+
+
+ + +
+

Rekap Absensi: {{ $santri->nama }}

+
+ + + + + + + + + + + @foreach($absensis as $i => $absen) + + + + + + + @endforeach + +
NoTanggalStatusKeterangan
{{ $i+1 }}{{ $absen->tanggal }}{{ ucfirst($absen->status) }}{{ $absen->keterangan }}
+
+ +
+ diff --git a/website/resources/views/admin/dashboard.blade.php b/website/resources/views/admin/dashboard.blade.php new file mode 100644 index 0000000..4809eb6 --- /dev/null +++ b/website/resources/views/admin/dashboard.blade.php @@ -0,0 +1,101 @@ + + +

+ {{ __('Dashboard Admin') }} +

+
+ +
+
+
+
+ +
+
{{ $jumlahSantri ?? '...' }}
+
Santri
+
+
+
+ +
+
{{ $jumlahGuru ?? '...' }}
+
Guru
+
+
+
+ +
+
{{ $jumlahKelas ?? '...' }}
+
Kelas
+
+
+
+ +
+
{{ $jumlahUser ?? '...' }}
+
User
+
+
+
+
+
+ +
+
{{ $absensiHariIni ?? '...' }}
+
Absensi Hari Ini
+
+
+
+ +
+
{{ $jumlahPrestasi ?? '...' }}
+
Prestasi
+
+
+
+ +
+
{{ $pelanggaranBulanIni ?? '...' }}
+
Pelanggaran Bulan Ini
+
+
+
+ +
+
{{ $pembayaranBulanIni ?? '...' }}
+
Pembayaran Bulan Ini
+
+
+
+ +
+
+
\ No newline at end of file diff --git a/website/resources/views/alumnis/create.blade.php b/website/resources/views/alumnis/create.blade.php new file mode 100644 index 0000000..680922f --- /dev/null +++ b/website/resources/views/alumnis/create.blade.php @@ -0,0 +1,87 @@ + + +

+ {{ __('Tambah Alumni') }} +

+
+ +
+
+
+
+

Tambah Alumni Baru

+ +
+ @csrf + + +
+ + + @error('nama_santri') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('tahun_lulus') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('aktivitas_setelah_lulus') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('kontak') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('keterangan') +
{{ $message }}
+ @enderror +
+ + +
+ + Batal + + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/alumnis/edit.blade.php b/website/resources/views/alumnis/edit.blade.php new file mode 100644 index 0000000..340d112 --- /dev/null +++ b/website/resources/views/alumnis/edit.blade.php @@ -0,0 +1,52 @@ + + +

+ {{ __('Edit alumni') }} +

+
+ +
+
+
+
+ + + +
+

Edit Alumni

+
+ @csrf + @method('PUT') +
+ + + @error('nama_santri')
{{ $message }}
@enderror +
+
+ + + @error('tahun_lulus')
{{ $message }}
@enderror +
+
+ + + @error('aktivitas_setelah_lulus')
{{ $message }}
@enderror +
+
+ + + @error('kontak')
{{ $message }}
@enderror +
+
+ + + @error('keterangan')
{{ $message }}
@enderror +
+
+ + Batal +
+
+ + + diff --git a/website/resources/views/alumnis/index.blade.php b/website/resources/views/alumnis/index.blade.php new file mode 100644 index 0000000..7b663d4 --- /dev/null +++ b/website/resources/views/alumnis/index.blade.php @@ -0,0 +1,62 @@ + + +

+ {{ __('Daftar Alumni') }} +

+
+ +
+
+
+
+
+

Daftar Alumni

+ Tambah Alumni +
+ + @if(session('success')) +
{{ session('success') }}
+ @endif + +
+ + + + + + + + + + + + + + @foreach($alumnis as $alumni) + + + + + + + + + + @endforeach + +
NoSantriTahun LulusAktivitasKontakKeteranganAksi
{{ $loop->iteration + ($alumnis->currentPage()-1)*$alumnis->perPage() }}{{ $alumni->nama_santri }}{{ $alumni->tahun_lulus }}{{ $alumni->aktivitas_setelah_lulus }}{{ $alumni->kontak }}{{ $alumni->keterangan }} + Detail + Edit +
+ @csrf + @method('DELETE') + +
+
+
+ {{ $alumnis->links() }} +
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/alumnis/show.blade.php b/website/resources/views/alumnis/show.blade.php new file mode 100644 index 0000000..fb0e82d --- /dev/null +++ b/website/resources/views/alumnis/show.blade.php @@ -0,0 +1,28 @@ + + +

+ {{ __('Detail alumni') }} +

+
+ +
+
+
+
+ + + +
+

Detail Alumni

+
Santri: {{ $alumni->nama_santri }}
+
Tahun Lulus: {{ $alumni->tahun_lulus }}
+
Aktivitas Setelah Lulus: {{ $alumni->aktivitas_setelah_lulus }}
+
Kontak: {{ $alumni->kontak }}
+
Keterangan: {{ $alumni->keterangan }}
+
+ Kembali + + + +
+ diff --git a/website/resources/views/auth/confirm-password.blade.php b/website/resources/views/auth/confirm-password.blade.php new file mode 100644 index 0000000..3d38186 --- /dev/null +++ b/website/resources/views/auth/confirm-password.blade.php @@ -0,0 +1,27 @@ + +
+ {{ __('This is a secure area of the application. Please confirm your password before continuing.') }} +
+ +
+ @csrf + + +
+ + + + + +
+ +
+ + {{ __('Confirm') }} + +
+
+
diff --git a/website/resources/views/auth/forgot-password.blade.php b/website/resources/views/auth/forgot-password.blade.php new file mode 100644 index 0000000..c3e032b --- /dev/null +++ b/website/resources/views/auth/forgot-password.blade.php @@ -0,0 +1,25 @@ + +
+ {{ __('Forgot your password? No problem. Just let us know your email address and we will email you a password reset link that will allow you to choose a new one.') }} +
+ + + + +
+ @csrf + + +
+ + + +
+ +
+ + {{ __('Email Password Reset Link') }} + +
+
+
diff --git a/website/resources/views/auth/login.blade.php b/website/resources/views/auth/login.blade.php new file mode 100644 index 0000000..919300a --- /dev/null +++ b/website/resources/views/auth/login.blade.php @@ -0,0 +1,58 @@ + + + + +
+ @csrf + + +
+ + + +
+ + +
+ + + + + +
+ + +
+ + + +
+ + +
+ +
+ +
+ @if (Route::has('password.request')) + + {{ __('Forgot your password?') }} + + @endif + + + {{ __('Log in') }} + +
+
+
diff --git a/website/resources/views/auth/register.blade.php b/website/resources/views/auth/register.blade.php new file mode 100644 index 0000000..225ea5a --- /dev/null +++ b/website/resources/views/auth/register.blade.php @@ -0,0 +1,52 @@ + +
+ @csrf + + +
+ + + +
+ + +
+ + + +
+ + +
+ + + + + +
+ + +
+ + + + + +
+ +
+ + {{ __('Already registered?') }} + + + + {{ __('Register') }} + +
+
+
diff --git a/website/resources/views/auth/reset-password.blade.php b/website/resources/views/auth/reset-password.blade.php new file mode 100644 index 0000000..7a94b17 --- /dev/null +++ b/website/resources/views/auth/reset-password.blade.php @@ -0,0 +1,39 @@ + +
+ @csrf + + + + + +
+ + + +
+ + +
+ + + +
+ + +
+ + + + + +
+ +
+ + {{ __('Reset Password') }} + +
+
+
diff --git a/website/resources/views/auth/verify-email.blade.php b/website/resources/views/auth/verify-email.blade.php new file mode 100644 index 0000000..70804d5 --- /dev/null +++ b/website/resources/views/auth/verify-email.blade.php @@ -0,0 +1,5 @@ + +
+ {{ __('Akun Anda berhasil dibuat. Silakan login menggunakan username dan password.') }} +
+
diff --git a/website/resources/views/beritas/create.blade.php b/website/resources/views/beritas/create.blade.php new file mode 100644 index 0000000..da36cca --- /dev/null +++ b/website/resources/views/beritas/create.blade.php @@ -0,0 +1,121 @@ + + +

+ {{ __('Tambah berita') }} +

+
+ +
+
+
+
+ +
+

Tambah Berita Baru

+

Buat berita baru untuk informasi sekolah

+
+ +
+ @csrf + + +
+

Informasi Berita

+
+
+ + + @error('judul') +
{{ $message }}
+ @enderror +
+
+ + + @error('kategori') +
{{ $message }}
+ @enderror +
+
+
+ + + @error('ringkasan') +
{{ $message }}
+ @enderror +
+
+ + +
+

Konten Berita

+
+ + + @error('isi') +
{{ $message }}
+ @enderror +
+
+ + +
+

Media

+
+ + +

Format: JPG, PNG, GIF. Maksimal 5MB.

+ @error('gambar') +
{{ $message }}
+ @enderror +
+
+ + +
+

Informasi Publikasi

+
+
+ + + @error('penulis') +
{{ $message }}
+ @enderror +
+
+ + + @error('status') +
{{ $message }}
+ @enderror +
+
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+
diff --git a/website/resources/views/beritas/edit.blade.php b/website/resources/views/beritas/edit.blade.php new file mode 100644 index 0000000..a79ca4c --- /dev/null +++ b/website/resources/views/beritas/edit.blade.php @@ -0,0 +1,141 @@ + + +

+ {{ __('Edit Berita') }} +

+
+ +
+
+
+
+ +
+

Edit Berita

+

Perbarui informasi berita

+
+ +
+ @csrf + @method('PUT') + + +
+

Informasi Berita

+
+
+ + + @error('judul') +
{{ $message }}
+ @enderror +
+
+ + + @error('kategori') +
{{ $message }}
+ @enderror +
+
+
+ + + @error('ringkasan') +
{{ $message }}
+ @enderror +
+
+ + +
+

Konten Berita

+
+ + + @error('isi') +
{{ $message }}
+ @enderror +
+
+ + +
+

Media

+ + + @if($berita->gambar) +
+ +
+ Current Image +
+

File: {{ basename($berita->gambar) }}

+

Upload: {{ $berita->updated_at->format('d M Y H:i') }}

+
+
+
+ @endif + +
+ + +

Format: JPG, PNG, GIF. Maksimal 5MB. {{ $berita->gambar ? 'Kosongkan jika tidak ingin mengubah gambar.' : '' }}

+ @error('gambar') +
{{ $message }}
+ @enderror +
+
+ + +
+

Informasi Publikasi

+
+
+ + + @error('penulis') +
{{ $message }}
+ @enderror +
+
+ + + @error('status') +
{{ $message }}
+ @enderror +
+
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+
diff --git a/website/resources/views/beritas/index.blade.php b/website/resources/views/beritas/index.blade.php new file mode 100644 index 0000000..ff94903 --- /dev/null +++ b/website/resources/views/beritas/index.blade.php @@ -0,0 +1,151 @@ + + +
+

+ {{ __('Berita') }} +

+ + + Tambah Berita + +
+
+ +
+
+ @if(session('success')) +
+ {{ session('success') }} +
+ @endif + +
+ @forelse($beritas as $berita) +
+ + @if($berita->gambar) +
+ {{ $berita->judul }} +
+ @else +
+ +
+ @endif + + +
+ +
+ @if($berita->status === 'published') + + + Published + + @else + + + Draft + + @endif +
+ + +
+ + {{ $berita->kategori }} + +
+ + +

+ {{ $berita->judul }} +

+ + +

+ {{ $berita->ringkasan }} +

+ + +
+ + + {{ $berita->penulis }} + + + + {{ $berita->created_at->format('d M Y') }} + +
+ + +
+ + +
+ @csrf + @method('DELETE') + +
+
+
+
+ @empty +
+
+ +

Belum ada berita

+

Mulai dengan menambahkan berita pertama Anda.

+ + + Tambah Berita Pertama + +
+
+ @endforelse +
+ + + @if($beritas->hasPages()) +
+ {{ $beritas->links() }} +
+ @endif +
+
+ + +
diff --git a/website/resources/views/beritas/show.blade.php b/website/resources/views/beritas/show.blade.php new file mode 100644 index 0000000..4711c2f --- /dev/null +++ b/website/resources/views/beritas/show.blade.php @@ -0,0 +1,147 @@ + + +
+

+ {{ __('Detail Berita') }} +

+ +
+
+ +
+
+
+ + @if($berita->gambar) +
+ {{ $berita->judul }} +
+
+
+ @if($berita->status === 'published') + + + Published + + @else + + + Draft + + @endif + + {{ $berita->kategori }} + +
+

{{ $berita->judul }}

+
+
+ @else +
+
+ @if($berita->status === 'published') + + + Published + + @else + + + Draft + + @endif + + {{ $berita->kategori }} + +
+

{{ $berita->judul }}

+
+ @endif + + +
+ +
+
+ + + {{ $berita->penulis }} + + + + {{ $berita->created_at->format('d F Y') }} + + + + {{ $berita->created_at->format('H:i') }} + +
+
+ + Dibuat {{ $berita->created_at->diffForHumans() }} +
+
+ + +
+
+
+ +
+
+

Ringkasan

+
+

{{ $berita->ringkasan }}

+
+
+
+
+ + +
+
+ {{ $berita->isi }} +
+
+ + +
+
+
+ Terakhir diperbarui: {{ $berita->updated_at->format('d F Y H:i') }} +
+
+ + + Edit Berita + +
+ @csrf + @method('DELETE') + +
+
+
+
+
+
+
+
+
diff --git a/website/resources/views/catatan_kesehatans/create.blade.php b/website/resources/views/catatan_kesehatans/create.blade.php new file mode 100644 index 0000000..606db44 --- /dev/null +++ b/website/resources/views/catatan_kesehatans/create.blade.php @@ -0,0 +1,72 @@ + + +

+ {{ __('Tambah Catatan Kesehatan') }} +

+
+ +
+
+
+
+

Form Catatan Kesehatan

+ +
+ @csrf + + {{-- Santri --}} +
+ + + @error('santri_id') {{ $message }} @enderror +
+ + {{-- Kelas --}} +
+ + + @error('kelas_id') {{ $message }} @enderror +
+ + {{-- Keluhan --}} +
+ + + @error('keluhan') {{ $message }} @enderror +
+ + {{-- Diagnosis --}} +
+ + + @error('diagnosis') {{ $message }} @enderror +
+ + {{-- Saran (optional) --}} +
+ + + @error('saran') {{ $message }} @enderror +
+ + {{-- Tombol --}} +
+ Kembali + +
+
+
+
+
+
+
diff --git a/website/resources/views/catatan_kesehatans/edit.blade.php b/website/resources/views/catatan_kesehatans/edit.blade.php new file mode 100644 index 0000000..bfdc156 --- /dev/null +++ b/website/resources/views/catatan_kesehatans/edit.blade.php @@ -0,0 +1,63 @@ + + +

+ {{ __('Edit catatan kesehatan') }} +

+
+ +
+
+
+
+ + +
+

Edit Catatan Kesehatan

+
+ @csrf + @method('PUT') +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + + + Batal + +
+
+ +
+
+ diff --git a/website/resources/views/catatan_kesehatans/index.blade.php b/website/resources/views/catatan_kesehatans/index.blade.php new file mode 100644 index 0000000..8121a81 --- /dev/null +++ b/website/resources/views/catatan_kesehatans/index.blade.php @@ -0,0 +1,69 @@ + + +

+ {{ __('Daftar catatan kesehatan') }} +

+
+ +
+
+
+
+ +
+ + +
+ +

Catatan Kesehatan

+ + @if(session('success')) +
{{ session('success') }}
+ @endif +
+ + + + + + + + + + + + + + @foreach($catatanKesehatans as $catatan) + + + + + + + + + + @endforeach + +
NoSantriKelasKeluhanDiagnosisSaranAksi
+ {{ $loop->iteration + ($catatanKesehatans->currentPage() - 1) * $catatanKesehatans->perPage() }} + {{ $catatan->santri->nama ?? '-' }}{{ $catatan->kelas->nama_kelas ?? '-' }}{{ $catatan->keluhan }}{{ $catatan->diagnosis }}{{ $catatan->saran }} + Detail + Edit +
+ @csrf + @method('DELETE') + +
+
+
+ {{ $catatanKesehatans->links() }} + + + \ No newline at end of file diff --git a/website/resources/views/catatan_kesehatans/show.blade.php b/website/resources/views/catatan_kesehatans/show.blade.php new file mode 100644 index 0000000..254cba5 --- /dev/null +++ b/website/resources/views/catatan_kesehatans/show.blade.php @@ -0,0 +1,29 @@ + + +

+ {{ __('Detail catatan kesehatan') }} +

+
+ +
+
+
+
+ + +
+

Detail Catatan Kesehatan

+
Santri: {{ $catatanKesehatan->santri->nama ?? '-' }}
+
Kelas: {{ $catatanKesehatan->kelas->nama_kelas ?? '-' }}
+
Keluhan: {{ $catatanKesehatan->keluhan }}
+
Diagnosis: {{ $catatanKesehatan->diagnosis }}
+
Saran: {{ $catatanKesehatan->saran }}
+ + + Kembali + +
+ + +
+ diff --git a/website/resources/views/components/application-logo.blade.php b/website/resources/views/components/application-logo.blade.php new file mode 100644 index 0000000..34c230d --- /dev/null +++ b/website/resources/views/components/application-logo.blade.php @@ -0,0 +1 @@ +Logomerge(['class' => 'w-20 h-20 object-contain rounded-full']) }} /> diff --git a/website/resources/views/components/auth-session-status.blade.php b/website/resources/views/components/auth-session-status.blade.php new file mode 100644 index 0000000..c4bd6e2 --- /dev/null +++ b/website/resources/views/components/auth-session-status.blade.php @@ -0,0 +1,7 @@ +@props(['status']) + +@if ($status) +
merge(['class' => 'font-medium text-sm text-green-600']) }}> + {{ $status }} +
+@endif diff --git a/website/resources/views/components/danger-button.blade.php b/website/resources/views/components/danger-button.blade.php new file mode 100644 index 0000000..d17d288 --- /dev/null +++ b/website/resources/views/components/danger-button.blade.php @@ -0,0 +1,3 @@ + diff --git a/website/resources/views/components/dropdown-link.blade.php b/website/resources/views/components/dropdown-link.blade.php new file mode 100644 index 0000000..e0f8ce1 --- /dev/null +++ b/website/resources/views/components/dropdown-link.blade.php @@ -0,0 +1 @@ +merge(['class' => 'block w-full px-4 py-2 text-start text-sm leading-5 text-gray-700 hover:bg-gray-100 focus:outline-none focus:bg-gray-100 transition duration-150 ease-in-out']) }}>{{ $slot }} diff --git a/website/resources/views/components/dropdown.blade.php b/website/resources/views/components/dropdown.blade.php new file mode 100644 index 0000000..a46f7c8 --- /dev/null +++ b/website/resources/views/components/dropdown.blade.php @@ -0,0 +1,35 @@ +@props(['align' => 'right', 'width' => '48', 'contentClasses' => 'py-1 bg-white']) + +@php +$alignmentClasses = match ($align) { + 'left' => 'ltr:origin-top-left rtl:origin-top-right start-0', + 'top' => 'origin-top', + default => 'ltr:origin-top-right rtl:origin-top-left end-0', +}; + +$width = match ($width) { + '48' => 'w-48', + default => $width, +}; +@endphp + +
+
+ {{ $trigger }} +
+ + +
diff --git a/website/resources/views/components/input-error.blade.php b/website/resources/views/components/input-error.blade.php new file mode 100644 index 0000000..9e6da21 --- /dev/null +++ b/website/resources/views/components/input-error.blade.php @@ -0,0 +1,9 @@ +@props(['messages']) + +@if ($messages) +
    merge(['class' => 'text-sm text-red-600 space-y-1']) }}> + @foreach ((array) $messages as $message) +
  • {{ $message }}
  • + @endforeach +
+@endif diff --git a/website/resources/views/components/input-label.blade.php b/website/resources/views/components/input-label.blade.php new file mode 100644 index 0000000..1cc65e2 --- /dev/null +++ b/website/resources/views/components/input-label.blade.php @@ -0,0 +1,5 @@ +@props(['value']) + + diff --git a/website/resources/views/components/modal.blade.php b/website/resources/views/components/modal.blade.php new file mode 100644 index 0000000..70704c1 --- /dev/null +++ b/website/resources/views/components/modal.blade.php @@ -0,0 +1,78 @@ +@props([ + 'name', + 'show' => false, + 'maxWidth' => '2xl' +]) + +@php +$maxWidth = [ + 'sm' => 'sm:max-w-sm', + 'md' => 'sm:max-w-md', + 'lg' => 'sm:max-w-lg', + 'xl' => 'sm:max-w-xl', + '2xl' => 'sm:max-w-2xl', +][$maxWidth]; +@endphp + +
+
+
+
+ +
+ {{ $slot }} +
+
diff --git a/website/resources/views/components/nav-link.blade.php b/website/resources/views/components/nav-link.blade.php new file mode 100644 index 0000000..5c101a2 --- /dev/null +++ b/website/resources/views/components/nav-link.blade.php @@ -0,0 +1,11 @@ +@props(['active']) + +@php +$classes = ($active ?? false) + ? 'inline-flex items-center px-1 pt-1 border-b-2 border-indigo-400 text-sm font-medium leading-5 text-gray-900 focus:outline-none focus:border-indigo-700 transition duration-150 ease-in-out' + : 'inline-flex items-center px-1 pt-1 border-b-2 border-transparent text-sm font-medium leading-5 text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out'; +@endphp + +merge(['class' => $classes]) }}> + {{ $slot }} + diff --git a/website/resources/views/components/primary-button.blade.php b/website/resources/views/components/primary-button.blade.php new file mode 100644 index 0000000..f512536 --- /dev/null +++ b/website/resources/views/components/primary-button.blade.php @@ -0,0 +1,3 @@ + diff --git a/website/resources/views/components/responsive-nav-link.blade.php b/website/resources/views/components/responsive-nav-link.blade.php new file mode 100644 index 0000000..43b91e7 --- /dev/null +++ b/website/resources/views/components/responsive-nav-link.blade.php @@ -0,0 +1,11 @@ +@props(['active']) + +@php +$classes = ($active ?? false) + ? 'block w-full ps-3 pe-4 py-2 border-l-4 border-indigo-400 text-start text-base font-medium text-indigo-700 bg-indigo-50 focus:outline-none focus:text-indigo-800 focus:bg-indigo-100 focus:border-indigo-700 transition duration-150 ease-in-out' + : 'block w-full ps-3 pe-4 py-2 border-l-4 border-transparent text-start text-base font-medium text-gray-600 hover:text-gray-800 hover:bg-gray-50 hover:border-gray-300 focus:outline-none focus:text-gray-800 focus:bg-gray-50 focus:border-gray-300 transition duration-150 ease-in-out'; +@endphp + +merge(['class' => $classes]) }}> + {{ $slot }} + diff --git a/website/resources/views/components/secondary-button.blade.php b/website/resources/views/components/secondary-button.blade.php new file mode 100644 index 0000000..b32b69f --- /dev/null +++ b/website/resources/views/components/secondary-button.blade.php @@ -0,0 +1,3 @@ + diff --git a/website/resources/views/components/text-input.blade.php b/website/resources/views/components/text-input.blade.php new file mode 100644 index 0000000..663dc8d --- /dev/null +++ b/website/resources/views/components/text-input.blade.php @@ -0,0 +1,3 @@ +@props(['disabled' => false]) + +merge(['class' => 'border-gray-300 focus:border-primary focus:ring-primary rounded-lg shadow-sm transition duration-200']) }}> diff --git a/website/resources/views/dashboard.blade.php b/website/resources/views/dashboard.blade.php new file mode 100644 index 0000000..d016616 --- /dev/null +++ b/website/resources/views/dashboard.blade.php @@ -0,0 +1,18 @@ + + +

+ {{ __('Dashboard') }} +

+
+ +
+
+
+
+ {{ __("You're logged in!") }} +
+
+
Anda akan diarahkan ke dashboard sesuai role...
+
+
+
diff --git a/website/resources/views/guru/absensis/create.blade.php b/website/resources/views/guru/absensis/create.blade.php new file mode 100644 index 0000000..04d06ea --- /dev/null +++ b/website/resources/views/guru/absensis/create.blade.php @@ -0,0 +1,117 @@ + + +

Input Absensi

+

Masukkan data kehadiran santri untuk tanggal yang dipilih

+
+
+ @csrf + +
+
+ + + @error('tanggal') +
{{ $message }}
+ @enderror +
+
+ + + @error('kelas_id') +
{{ $message }}
+ @enderror +
+
+ + + @if(isset($santris) && $santris->count()) +
+

Data Santri

+
+
+ + + + + + + + + + @foreach($santris as $i => $s) + + + + + + @endforeach + +
Nama SantriStatusKeterangan
+
+
+ {{ substr($s->nama, 0, 1) }} +
+ {{ $s->nama }} +
+ +
+ + + +
+
+
+
+ @else +
+
+ +
+

Pilih Kelas

+

Pilih kelas terlebih dahulu untuk menampilkan daftar santri.

+
+ @endif + + +
+ + + Kembali + + @if(isset($santris) && $santris->count()) + + @endif +
+
+
+
+
+
+ \ No newline at end of file diff --git a/website/resources/views/guru/absensis/create_modern.blade.php b/website/resources/views/guru/absensis/create_modern.blade.php new file mode 100644 index 0000000..2f17558 --- /dev/null +++ b/website/resources/views/guru/absensis/create_modern.blade.php @@ -0,0 +1,242 @@ + + + + + + + {{ config('app.name', 'Laravel') }} + + + + + + + + +
+ + + + +
+ + + + +
+
+
+ +
+
+

Input Absensi Santri

+

Kelola kehadiran santri dengan mudah dan efisien

+
+
+ + +
+
+

Form Input Absensi

+

Pilih tanggal dan kelas untuk mengisi absensi

+
+ +
+
+ @csrf + + +
+
+ + +
+
+ + +
+
+ + +
+
+

Daftar Kehadiran Santri

+

Pilih status kehadiran untuk setiap santri

+
+ +
+ + + + + + + + + + + @foreach($santris as $index => $santri) + + + + + + + @endforeach + +
NoNama SantriStatusKeterangan
{{ $index + 1 }} +
+
+ {{ strtoupper(substr($santri->nama, 0, 1)) }} +
+ {{ $santri->nama }} +
+
+ + + + id}.keterangan") }}" + placeholder="Keterangan (opsional)"> +
+
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+
+
+
+ + + + \ No newline at end of file diff --git a/website/resources/views/guru/absensis/create_new.blade.php b/website/resources/views/guru/absensis/create_new.blade.php new file mode 100644 index 0000000..5e72d83 --- /dev/null +++ b/website/resources/views/guru/absensis/create_new.blade.php @@ -0,0 +1,95 @@ +@extends('layouts.guru') +@section('content') +
+
+
+
+ +
+

Input Absensi

+

Masukkan data kehadiran santri untuk tanggal yang dipilih

+
+ +
+ @csrf + + +
+

Pilih Tanggal

+
+
+ + + @error('tanggal') +
{{ $message }}
+ @enderror +
+
+ + + @error('kelas_id') +
{{ $message }}
+ @enderror +
+
+
+ + +
+

Daftar Kehadiran Santri

+
+ + + + + + + + + + + @foreach($santris as $index => $santri) + + + + + + + @endforeach + +
NoNama SantriStatusKeterangan
{{ $index + 1 }}{{ $santri->nama }} + + + id}") }}" placeholder="Keterangan (opsional)"> +
+
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/website/resources/views/guru/absensis/edit.blade.php b/website/resources/views/guru/absensis/edit.blade.php new file mode 100644 index 0000000..013d4b1 --- /dev/null +++ b/website/resources/views/guru/absensis/edit.blade.php @@ -0,0 +1,40 @@ + +
+

Edit Absensi Santri

+

Perbarui data kehadiran santri

+
+
+ @csrf + @method('PUT') +
+ + +
+
+ + + @error('status')
{{ $message }}
@enderror +
+
+ + + @error('keterangan')
{{ $message }}
@enderror +
+
+ + + + Kembali + +
+
+
\ No newline at end of file diff --git a/website/resources/views/guru/absensis/index.blade.php b/website/resources/views/guru/absensis/index.blade.php new file mode 100644 index 0000000..bdbe8a6 --- /dev/null +++ b/website/resources/views/guru/absensis/index.blade.php @@ -0,0 +1,118 @@ + + +

+ {{ __('Rekap Absensi') }} +

+
+ +
+
+
+ + +
+
+ + +
+
+ +
+
+ @if($kelasId) + + + Input Absensi Massal + + @endif +
+
+
+ @if($santris->count()) +
+ + + + + + + + + + + @foreach($santris as $i => $santri) + + + + + + + + @endforeach + +
NoNama SantriStatusKeterangan
{{ $i+1 }} +
+
+ {{ substr($santri->nama, 0, 1) }} +
+ {{ $santri->nama }} +
+
+ @if(isset($absensis[$santri->id])) + @php + $status = $absensis[$santri->id]->status; + $statusColors = [ + 'hadir' => 'bg-green-100 text-green-800', + 'izin' => 'bg-yellow-100 text-yellow-800', + 'sakit' => 'bg-orange-100 text-orange-800', + 'alfa' => 'bg-red-100 text-red-800' + ]; + $color = $statusColors[$status] ?? 'bg-gray-100 text-gray-800'; + @endphp + + {{ ucfirst($status) }} + + @else + - + @endif + + {{ $absensis[$santri->id]->keterangan ?? '-' }} +
+
+ @elseif($kelasId) +
+
+ +
+

Tidak ada data santri

+

Tidak ada data santri di kelas yang dipilih.

+
+ @endif +
\ No newline at end of file diff --git a/website/resources/views/guru/absensis/show.blade.php b/website/resources/views/guru/absensis/show.blade.php new file mode 100644 index 0000000..70c52f4 --- /dev/null +++ b/website/resources/views/guru/absensis/show.blade.php @@ -0,0 +1,4 @@ +@extends('layouts.guru') +@section('content') + +@endsection \ No newline at end of file diff --git a/website/resources/views/guru/catatan_kesehatans/create.blade.php b/website/resources/views/guru/catatan_kesehatans/create.blade.php new file mode 100644 index 0000000..fdbfec8 --- /dev/null +++ b/website/resources/views/guru/catatan_kesehatans/create.blade.php @@ -0,0 +1,63 @@ +@extends('layouts.guru') +@section('content') + +

+ {{ __('Tambah catatan kesehatan') }} +

+
+ +
+
+
+
+ + + +
+

Tambah Catatan Kesehatan

+
+ @csrf +
+ + + @error('santri_id')
{{ $message }}
@enderror +
+
+ + + @error('kelas_id')
{{ $message }}
@enderror +
+
+ + + @error('keluhan')
{{ $message }}
@enderror +
+
+ + + @error('diagnosis')
{{ $message }}
@enderror +
+
+ + + @error('saran')
{{ $message }}
@enderror +
+
+ + Kembali +
+
+ + +
+@endsection diff --git a/website/resources/views/guru/catatan_kesehatans/edit.blade.php b/website/resources/views/guru/catatan_kesehatans/edit.blade.php new file mode 100644 index 0000000..83a91b0 --- /dev/null +++ b/website/resources/views/guru/catatan_kesehatans/edit.blade.php @@ -0,0 +1,57 @@ +@extends('layouts.guru') +@section('content') + +

+ {{ __('Edit catatan kesehatan') }} +

+
+ +
+
+
+
+ +
+

Edit Catatan Kesehatan

+
+ @csrf + @method('PUT') +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ + Batal +
+ +
+
+
+
+@endsection diff --git a/website/resources/views/guru/catatan_kesehatans/index.blade.php b/website/resources/views/guru/catatan_kesehatans/index.blade.php new file mode 100644 index 0000000..315f938 --- /dev/null +++ b/website/resources/views/guru/catatan_kesehatans/index.blade.php @@ -0,0 +1,57 @@ + + +

+ {{ __('Catatan Kesehatan Santri') }} +

+
+ +
+
+
+
+

Catatan Kesehatan

+ Tambah Catatan + @if(session('success')) +
{{ session('success') }}
+ @endif +
+ + + + + + + + + + + + + + @foreach($catatanKesehatans as $catatan) + + + + + + + + + + @endforeach + +
NoSantriKelasKeluhanDiagnosisSaranAksi
{{ $loop->iteration + ($catatanKesehatans->currentPage()-1)*$catatanKesehatans->perPage() }}{{ $catatan->santri->nama ?? '-' }}{{ $catatan->kelas->nama_kelas ?? '-' }}{{ $catatan->keluhan }}{{ $catatan->diagnosis }}{{ $catatan->saran }} + Detail + +
+
+ {{ $catatanKesehatans->links() }} +
+
+
+ \ No newline at end of file diff --git a/website/resources/views/guru/catatan_kesehatans/show.blade.php b/website/resources/views/guru/catatan_kesehatans/show.blade.php new file mode 100644 index 0000000..1a73763 --- /dev/null +++ b/website/resources/views/guru/catatan_kesehatans/show.blade.php @@ -0,0 +1,30 @@ +@extends('layouts.guru') +@section('content') + +

+ {{ __('Detail catatan kesehatan') }} +

+
+ +
+
+
+
+ + +
+

Detail Catatan Kesehatan

+ +
+
Santri: {{ $catatanKesehatan->santri->nama ?? '-' }}
+
Kelas: {{ $catatanKesehatan->kelas->nama_kelas ?? '-' }}
+

Keluhan: {{ $catatanKesehatan->keluhan }}

+

Diagnosis: {{ $catatanKesehatan->diagnosis }}

+

Saran: {{ $catatanKesehatan->saran }}

+ Kembali + + + +
+
+@endsection diff --git a/website/resources/views/guru/dashboard.blade.php b/website/resources/views/guru/dashboard.blade.php new file mode 100644 index 0000000..e35d1b2 --- /dev/null +++ b/website/resources/views/guru/dashboard.blade.php @@ -0,0 +1,70 @@ + + +

+ {{ __('Dashboard Guru') }} +

+
+ +
+
+
+
+ @php + $guru = \App\Models\Guru::where('user_id', auth()->id())->first(); + @endphp + + @if($guru) +
+ @if($guru->foto) + Foto Profil Guru + @endif + + + + + + + + + + + + + + + + + + + + + + + + +
Nama{{ $guru->nama }}
NIP{{ $guru->code_guru }}
Alamat{{ $guru->alamat }}
Tanggal Lahir{{ \Carbon\Carbon::parse($guru->tanggal_lahir)->translatedFormat('d F Y') }}
Jenis Kelamin + {{ $guru->jenis_kelamin == 'L' ? 'Laki-laki' : 'Perempuan' }} +
+ + {{-- Tombol Edit (aktifkan jika diperlukan) --}} + {{-- + + Edit Profil + + --}} +
+ @else +
+ Data guru tidak ditemukan. +
+ @endif +
+
+
+
+
diff --git a/website/resources/views/guru/edit_profile.blade.php b/website/resources/views/guru/edit_profile.blade.php new file mode 100644 index 0000000..ac3f1ad --- /dev/null +++ b/website/resources/views/guru/edit_profile.blade.php @@ -0,0 +1,78 @@ + + +

+ {{ __('Edit Profile') }} +

+
+ +
+ @csrf + +
+
+ + + @error('nama')

{{ $message }}

@enderror +
+ +
+ + +

Kode guru tidak dapat diubah.

+ @error('code_guru')

{{ $message }}

@enderror +
+ +
+ + + @error('alamat')

{{ $message }}

@enderror +
+ +
+ + + @error('tanggal_lahir')

{{ $message }}

@enderror +
+ +
+ + + @error('jenis_kelamin')

{{ $message }}

@enderror +
+ +
+ + + @if($guru->foto) + Foto Guru + @endif + @error('foto')

{{ $message }}

@enderror +
+
+ +
+ + Batal + + +
+
+
diff --git a/website/resources/views/guru/jadwals/create.blade.php b/website/resources/views/guru/jadwals/create.blade.php new file mode 100644 index 0000000..b71cef2 --- /dev/null +++ b/website/resources/views/guru/jadwals/create.blade.php @@ -0,0 +1,57 @@ +@extends('layouts.guru') +@section('content') + +

+ {{ __('Tambah jadwal') }} +

+
+ +
+
+
+
+ + +
+

Tambah Jadwal

+
+ @csrf +
+ + + @error('kelas_id')
{{ $message }}
@enderror +
+
+ + + @error('hari')
{{ $message }}
@enderror +
+
+ + + @error('jam_pelajaran')
{{ $message }}
@enderror +
+
+ + + @error('mata_pelajaran_id')
{{ $message }}
@enderror +
+
+ + Kembali +
+
+ + +
+@endsection diff --git a/website/resources/views/guru/jadwals/edit.blade.php b/website/resources/views/guru/jadwals/edit.blade.php new file mode 100644 index 0000000..a2cc541 --- /dev/null +++ b/website/resources/views/guru/jadwals/edit.blade.php @@ -0,0 +1,58 @@ +@extends('layouts.guru') +@section('content') + +

+ {{ __('Edit jadwal') }} +

+
+ +
+
+
+
+ + +
+

Edit Jadwal

+
+ @csrf + @method('PUT') +
+ + + @error('kelas_id')
{{ $message }}
@enderror +
+
+ + + @error('hari')
{{ $message }}
@enderror +
+
+ + + @error('jam_pelajaran')
{{ $message }}
@enderror +
+
+ + + @error('mata_pelajaran_id')
{{ $message }}
@enderror +
+
+ + Kembali +
+
+ + +
+@endsection diff --git a/website/resources/views/guru/jadwals/index.blade.php b/website/resources/views/guru/jadwals/index.blade.php new file mode 100644 index 0000000..fc72868 --- /dev/null +++ b/website/resources/views/guru/jadwals/index.blade.php @@ -0,0 +1,52 @@ + + +

+ {{ __('Jadwal Mata Pelajaran') }} +

+
+ +
+
+
+
+ +

Daftar Jadwal

+ {{-- Tambah Jadwal --}} + @if(session('success')) +
{{ session('success') }}
+ @endif +
+ + + + + + + + + + + + + @foreach($jadwals as $i => $jadwal) + + + + + + + + + @endforeach + +
NoKelasHariJamMata Pelajaran
{{ $i+1 }}{{ $jadwal->kelas ? $jadwal->kelas->nama_kelas : '-' }}{{ $jadwal->hari }}{{ $jadwal->jam_pelajaran }}{{ $jadwal->mataPelajaran ? $jadwal->mataPelajaran->nama_mapel : '-' }}
+
+
+ \ No newline at end of file diff --git a/website/resources/views/guru/nilai_santris/create.blade.php b/website/resources/views/guru/nilai_santris/create.blade.php new file mode 100644 index 0000000..335c741 --- /dev/null +++ b/website/resources/views/guru/nilai_santris/create.blade.php @@ -0,0 +1,148 @@ + + +

+ {{ __('Tambah nilai santri') }} +

+
+ +
+ @csrf +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+

Nilai Santri

+
+ + + + + + + + + + + @foreach($santris as $index => $santri) + + + + + + + @endforeach + +
NoNama Santri + NilaiKeterangan
{{ $index + 1 }}{{ $santri->nama }} + + + + +
+
+
+

Nilai dapat berupa angka 0-100 dengan maksimal 2 desimal

+
+
+
+ + + Kembali + + +
+
+
+ + \ No newline at end of file diff --git a/website/resources/views/guru/nilai_santris/edit.blade.php b/website/resources/views/guru/nilai_santris/edit.blade.php new file mode 100644 index 0000000..02bc79a --- /dev/null +++ b/website/resources/views/guru/nilai_santris/edit.blade.php @@ -0,0 +1,63 @@ +@extends('layouts.guru') +@section('content') + +

+ {{ __('Edit Nilai Santri') }} +

+
+ +
+
+
+
+

Edit Nilai Santri

+
+ @csrf + @method('PUT') +
+ + +
+
+ + + @error('nilai')
{{ $message }}
@enderror +
+
+ + + @error('keterangan')
{{ $message }}
@enderror +
+
+ + + @error('semester_id')
{{ $message }}
@enderror +
+
+ + + @error('jenis_nilai')
{{ $message }}
@enderror +
+
+ + Kembali +
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/website/resources/views/guru/nilai_santris/index.blade.php b/website/resources/views/guru/nilai_santris/index.blade.php new file mode 100644 index 0000000..f1e6151 --- /dev/null +++ b/website/resources/views/guru/nilai_santris/index.blade.php @@ -0,0 +1,118 @@ + + +

+ {{ __('Nilai Santri') }} +

+
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + @if($kelasId && $mapelId) + + + Input Nilai Massal + + @endif +
+
+
+ @if($santris->count()) +
+ + + + + + + + + + + + + + @foreach($santris as $i => $santri) + + + + + + + + + + @endforeach + +
NoNama SantriSemesterJenis NilaiNilaiKeterangan
{{ $i+1 }} +
+
+ {{ substr($santri->nama, 0, 1) }} +
+ {{ $santri->nama }} +
+
+ @if(isset($nilaiSantris[$santri->id])) + {{ $nilaiSantris[$santri->id]->semester ? $nilaiSantris[$santri->id]->semester->semester : '-' }} + @else + - + @endif + + {{ $nilaiSantris[$santri->id]->jenis_nilai ?? '-' }} + {{ $nilaiSantris[$santri->id]->nilai ?? '-' }}{{ $nilaiSantris[$santri->id]->keterangan ?? '-' }}
+
+ @elseif($kelasId && $mapelId) +
+
+ +
+

Tidak ada data santri

+

Tidak ada data santri di kelas yang dipilih.

+
+ @endif +
diff --git a/website/resources/views/guru/nilai_santris/show.blade.php b/website/resources/views/guru/nilai_santris/show.blade.php new file mode 100644 index 0000000..2ae8e0e --- /dev/null +++ b/website/resources/views/guru/nilai_santris/show.blade.php @@ -0,0 +1,43 @@ + + +

+ {{ __('Detail Nilai') }} +

+
+ +
+
+
+
+ + +

Rekap Nilai: {{ $santri->nama }}

+ Kembali + + + + + + + + + + + + @foreach($nilaiList as $i => $nilai) + + + + + + + + @endforeach + +
NoTanggalMata PelajaranNilaiKeterangan
{{ $i+1 }}{{ $nilai->tanggal }}{{ $nilai->mapel->nama_mapel ?? '-' }}{{ $nilai->nilai }}{{ $nilai->keterangan }}
+ +
+
+
+
+@endsection diff --git a/website/resources/views/guru/pelanggarans/create.blade.php b/website/resources/views/guru/pelanggarans/create.blade.php new file mode 100644 index 0000000..d22c43f --- /dev/null +++ b/website/resources/views/guru/pelanggarans/create.blade.php @@ -0,0 +1,86 @@ + + +

+ {{ __('Tambah pelanggaran') }} +

+
+ +
+
+
+
+ @csrf + + {{-- Santri --}} +
+ + + @error('santri_id')

{{ $message }}

@enderror +
+ + {{-- Kelas --}} +
+ + + @error('kelas_id')

{{ $message }}

@enderror +
+ + {{-- Jenis Pelanggaran --}} +
+ + + @error('jenis_pelanggaran')

{{ $message }}

@enderror +
+ + {{-- Hukuman --}} +
+ + + @error('hukuman')

{{ $message }}

@enderror +
+ + {{-- Keterangan Hukuman --}} +
+ + + @error('keterangan_hukuman')

{{ $message }}

@enderror +
+ + {{-- Hukuman Selesai --}} + + + + {{-- Tombol --}} +
+ Kembali + +
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/guru/pelanggarans/edit.blade.php b/website/resources/views/guru/pelanggarans/edit.blade.php new file mode 100644 index 0000000..f31b82a --- /dev/null +++ b/website/resources/views/guru/pelanggarans/edit.blade.php @@ -0,0 +1,63 @@ +@extends('layouts.guru') +@section('content') + +

+ {{ __('Edit Pelanggaran') }} +

+
+ +
+
+
+
+ @csrf + @method('PUT') + +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
+
+
+@endsection diff --git a/website/resources/views/guru/pelanggarans/index.blade.php b/website/resources/views/guru/pelanggarans/index.blade.php new file mode 100644 index 0000000..e0479a7 --- /dev/null +++ b/website/resources/views/guru/pelanggarans/index.blade.php @@ -0,0 +1,95 @@ + + +

+ {{ __('Pelanggaran Santri') }} +

+
+ +
+
+
+
+ +
+ + +
+ + {{-- Judul dan tombol tambah --}} +
+

Daftar Pelanggaran Santri

+ + + Tambah Pelanggaran + +
+ + {{-- Alert sukses --}} + @if(session('success')) +
+ {{ session('success') }} +
+ @endif + + {{-- Tabel daftar pelanggaran --}} +
+ + + + + + + + + + + + + + @forelse($pelanggarans as $i => $p) + + + + + + + + + + @empty + + + + @endforelse + +
NoSantriKelasJenis PelanggaranKeteranganStatus HukumanAksi
{{ $i + 1 }}{{ $p->santri->nama }}{{ $p->kelas->nama_kelas }}{{ $p->jenis_pelanggaran }}{{ $p->keterangan_hukuman }} + @if($p->hukuman_selesai === 'selesai') + Selesai + @else + Belum + @endif +
+ Tidak ada data pelanggaran +
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/guru/prestasis/create.blade.php b/website/resources/views/guru/prestasis/create.blade.php new file mode 100644 index 0000000..6863c38 --- /dev/null +++ b/website/resources/views/guru/prestasis/create.blade.php @@ -0,0 +1,86 @@ + + +

+ {{ __('Tambah prestasi') }} +

+
+ +
+
+
+
+ @csrf + + {{-- Santri --}} +
+ + + @error('santri_id')

{{ $message }}

@enderror +
+ + {{-- Kelas --}} +
+ + + @error('kelas_id')

{{ $message }}

@enderror +
+ + {{-- Jenis Pelanggaran --}} +
+ + + @error('jenis_pelanggaran')

{{ $message }}

@enderror +
+ + {{-- Hukuman --}} +
+ + + @error('hukuman')

{{ $message }}

@enderror +
+ + {{-- Keterangan Hukuman --}} +
+ + + @error('keterangan_hukuman')

{{ $message }}

@enderror +
+ + {{-- Hukuman Selesai --}} + + + + {{-- Tombol --}} +
+ Kembali + +
+
+
+
+
+ \ No newline at end of file diff --git a/website/resources/views/guru/prestasis/edit.blade.php b/website/resources/views/guru/prestasis/edit.blade.php new file mode 100644 index 0000000..84655a3 --- /dev/null +++ b/website/resources/views/guru/prestasis/edit.blade.php @@ -0,0 +1,56 @@ +@extends('layouts.guru') +@section('content') + +

+ {{ __('Edit Prestasi') }} +

+
+ +
+
+
+
+

Edit Data Prestasi

+
+ @csrf + @method('PUT') +
+ + + @error('santri_id')
{{ $message }}
@enderror +
+
+ + + @error('kelas_id')
{{ $message }}
@enderror +
+
+ + + @error('nama_perlombaan')
{{ $message }}
@enderror +
+
+ + + @error('keterangan')
{{ $message }}
@enderror +
+
+ + Kembali +
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/website/resources/views/guru/prestasis/index.blade.php b/website/resources/views/guru/prestasis/index.blade.php new file mode 100644 index 0000000..db9e165 --- /dev/null +++ b/website/resources/views/guru/prestasis/index.blade.php @@ -0,0 +1,101 @@ + + +

+ {{ __('Prestasi Santri') }} +

+
+ +
+
+
+
+ +
+ + +
+ +
+

Data Prestasi Santri

+ + + Tambah Prestasi + +
+ + @if(session('success')) +
+ {{ session('success') }} +
+ @endif + +
+ + + + + + + + + + + + + + + + + @foreach($prestasis as $i => $p) + + + + + + + + + + + + + @endforeach + @if($prestasis->isEmpty()) + + + + @endif + +
NoSantriKelasNama PrestasiJenisTingkatPeringkatTanggalSertifikat
{{ $i + 1 }}{{ $p->santri->nama ?? '-' }}{{ $p->kelas->nama_kelas ?? '-' }}{{ $p->nama_prestasi }}{{ $p->jenis_prestasi }}{{ $p->tingkat }}{{ $p->peringkat }} + {{ \Carbon\Carbon::parse($p->tanggal_prestasi)->format('d M Y') }} + @if ($p->sertifikat) + Lihat + @else + - + @endif +
+ Belum ada data prestasi. +
+
+ +
+ {{ $prestasis->links() }} +
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/guru/profile.blade.php b/website/resources/views/guru/profile.blade.php new file mode 100644 index 0000000..c4ca0c4 --- /dev/null +++ b/website/resources/views/guru/profile.blade.php @@ -0,0 +1,49 @@ + + +

+ {{ __('Profile ') }}{{ auth()->user()->name }} +

+
+ +
+
+
+
+ @if(session('success')) +
{{ session('success') }}
+ @endif + @if($guru->foto) +
+ Foto Profil Guru +
+ @endif + + + + + + + + + + + + + + + + + + + + + +
Nama{{ $guru->nama }}
NIP{{ $guru->code_guru }}
Alamat{{ $guru->alamat }}
Tanggal Lahir{{ $guru->tanggal_lahir }}
Jenis Kelamin{{ $guru->jenis_kelamin == 'L' ? 'Laki-laki' : 'Perempuan' }}
+ +
+
+
+ diff --git a/website/resources/views/guru/santris/create.blade.php b/website/resources/views/guru/santris/create.blade.php new file mode 100644 index 0000000..9ebb2d8 --- /dev/null +++ b/website/resources/views/guru/santris/create.blade.php @@ -0,0 +1,96 @@ +@extends('layouts.guru') +@section('content') + +

+ {{ __('Tambah Santri') }} +

+
+ +
+
+
+
+
+ @csrf +
+
+ + + @error('nama')
{{ $message }}
@enderror +
+ +
+

Informasi Akun

+ +
+ + + @error('username')
{{ $message }}
@enderror +
+ +
+ + + @error('password')
{{ $message }}
@enderror +
+ +
+ + +
+ +
+

Detail Informasi Santri

+ +
+ + + @error('nis')
{{ $message }}
@enderror +
+
+ + + @error('kelas_id')
{{ $message }}
@enderror +
+
+ + + @error('alamat')
{{ $message }}
@enderror +
+
+ + + @error('tanggal_lahir')
{{ $message }}
@enderror +
+
+ + + @error('jenis_kelamin')
{{ $message }}
@enderror +
+
+ + + @error('foto') +
{{ $message }}
+ @enderror +
+
+ Kembali + +
+
+
+
+
+
+
+@endsection \ No newline at end of file diff --git a/website/resources/views/guru/santris/edit.blade.php b/website/resources/views/guru/santris/edit.blade.php new file mode 100644 index 0000000..e423b5a --- /dev/null +++ b/website/resources/views/guru/santris/edit.blade.php @@ -0,0 +1,74 @@ + + +

+ {{ __('Edit Santri') }} +

+
+ +
+
+
+
+
+ @csrf + @method('PUT') +
+
+ + + @error('nama')
{{ $message }}
@enderror +
+
+ + + @error('nis')
{{ $message }}
@enderror +
+
+
+
+ + + @error('alamat')
{{ $message }}
@enderror +
+
+ + + @error('tanggal_lahir')
{{ $message }}
@enderror +
+
+ + + @error('jenis_kelamin')
{{ $message }}
@enderror +
+
+ + @if($santri->foto) + Foto Santri + @endif + + @error('foto') +
{{ $message }}
+ @enderror +
+
+ Kembali + +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/guru/santris/index.blade.php b/website/resources/views/guru/santris/index.blade.php new file mode 100644 index 0000000..d8d3331 --- /dev/null +++ b/website/resources/views/guru/santris/index.blade.php @@ -0,0 +1,60 @@ + + +

+ {{ __('Data Seluruh Santri') }} +

+
+ +
+
+
+
+ {{-- Tambah Santri --}} + @if(session('success')) +
{{ session('success') }}
+ @endif +
+ + + + + + + + + + + + + @foreach($santris as $i => $santri) + + + + + + + + + @endforeach + +
NoFotoNamaNISKelas
{{ $i + 1 }} + @if($santri->foto) + Foto + @else + - + @endif + {{ $santri->nama }}{{ $santri->nis }}{{ $santri->kelas->nama_kelas }}
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/guru/test.blade.php b/website/resources/views/guru/test.blade.php new file mode 100644 index 0000000..56a1e6c --- /dev/null +++ b/website/resources/views/guru/test.blade.php @@ -0,0 +1,12 @@ +@extends('layouts.guru') +@section('content') +
+
+
+

TEST HALAMAN

+

Jika kamu melihat ini, berarti perubahan sudah terlihat!

+

Waktu: {{ now() }}

+
+
+
+@endsection \ No newline at end of file diff --git a/website/resources/views/gurus/create.blade.php b/website/resources/views/gurus/create.blade.php new file mode 100644 index 0000000..7f73568 --- /dev/null +++ b/website/resources/views/gurus/create.blade.php @@ -0,0 +1,130 @@ + + +

+ {{ __('Tambah Guru') }} +

+
+ +
+
+
+
+ +
+ @csrf + + +
+ + + @error('nama') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('code_guru') +
{{ $message }}
+ @enderror +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + +
+ + + @error('username') +
{{ $message }}
+ @enderror +
+ + +
+

Informasi Password

+
+
+ + + + + + + @error('password') +
{{ $message }}
+ @enderror +
+
+ + +
+
+
+

Password minimal 8 karakter dengan kombinasi huruf dan + angka

+
+
+ + +
+ +
+ +
+ +
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/gurus/edit.blade.php b/website/resources/views/gurus/edit.blade.php new file mode 100644 index 0000000..f55bb48 --- /dev/null +++ b/website/resources/views/gurus/edit.blade.php @@ -0,0 +1,44 @@ +@extends('layouts.app') +@section('content') +
+
+

Edit Guru

+
+ @csrf + @method('PUT') +
+ + + @error('nama')
{{ $message }}
@enderror +
+
+ + + @error('code_guru')
{{ $message }}
@enderror +
+
+ + + @error('alamat')
{{ $message }}
@enderror +
+
+ + + @error('tanggal_lahir')
{{ $message }}
@enderror +
+
+ + + @error('jenis_kelamin')
{{ $message }}
@enderror +
+
+ + Kembali +
+
+
+
+@endsection \ No newline at end of file diff --git a/website/resources/views/gurus/index.blade.php b/website/resources/views/gurus/index.blade.php new file mode 100644 index 0000000..519df91 --- /dev/null +++ b/website/resources/views/gurus/index.blade.php @@ -0,0 +1,76 @@ + + +

+ {{ __('Daftar Guru') }} +

+
+ +
+
+
+
+ Tambah Guru + @if(session('success')) +
{{ session('success') }}
+ @endif + +
+ + +
+ +
+ + + + + + + + + + + + + + + @foreach($gurus as $i => $guru) + + + + + + + + + + + @endforeach + + +
NoFotoNamaCODE GURUAlamatTanggal LahirJenis KelaminAction
{{ $i + 1 }} + @if($guru->foto) + Foto + @else + Tidak ada + @endif + {{ $guru->nama }}{{ $guru->code_guru }}{{ $guru->alamat }} + {{ \Carbon\Carbon::parse($guru->tanggal_lahir)->format('d-m-Y') }}{{ $guru->jenis_kelamin == 'L' ? 'Laki-laki' : 'Perempuan' }} + + +
+ @csrf + @method('DELETE') + +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/jadwals/create.blade.php b/website/resources/views/jadwals/create.blade.php new file mode 100644 index 0000000..6afc2da --- /dev/null +++ b/website/resources/views/jadwals/create.blade.php @@ -0,0 +1,141 @@ + + +

+ {{ __('Tambah Jadwal') }} +

+
+ +
+
+
+
+ +
+

Tambah Jadwal Baru

+

Silakan lengkapi form berikut untuk membuat jadwal baru.

+
+ +
+ @csrf + +
+

Informasi Jadwal

+
+ +
+ + + @error('kelas_id') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('mata_pelajaran_id') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('guru_id') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('hari') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('jam_mulai') +
{{ $message }}
+ @enderror +
+ + +
+ + + @error('jam_selesai') +
{{ $message }}
+ @enderror +
+
+ + +
+ + + @error('ruangan') +
{{ $message }}
+ @enderror +
+
+ + +
+ + Kembali + + +
+
+
+
+
+
+
diff --git a/website/resources/views/jadwals/edit.blade.php b/website/resources/views/jadwals/edit.blade.php new file mode 100644 index 0000000..080eaea --- /dev/null +++ b/website/resources/views/jadwals/edit.blade.php @@ -0,0 +1,103 @@ + + +

+ {{ __('Edit Jadwal') }} +

+
+ +
+
+
+
+ +
+

Edit Jadwal

+

Ubah informasi jadwal pelajaran

+
+ +
+ @csrf + @method('PUT') + +
+

Informasi Jadwal

+
+
+ + + @error('kelas_id')
{{ $message }}
@enderror +
+ +
+ + + @error('mapel_id')
{{ $message }}
@enderror +
+ +
+ + + @error('guru_id')
{{ $message }}
@enderror +
+ +
+ + + @error('hari')
{{ $message }}
@enderror +
+ +
+ + + @error('jam_mulai')
{{ $message }}
@enderror +
+ +
+ + + @error('jam_selesai')
{{ $message }}
@enderror +
+
+ +
+ + + @error('ruangan')
{{ $message }}
@enderror +
+
+ +
+ Kembali + +
+
+
+
+
+
+
diff --git a/website/resources/views/jadwals/index.blade.php b/website/resources/views/jadwals/index.blade.php new file mode 100644 index 0000000..9ee8ab0 --- /dev/null +++ b/website/resources/views/jadwals/index.blade.php @@ -0,0 +1,60 @@ + + +

+ {{ __('Daftar Jadwal') }} +

+
+ +
+
+
+
+

Jadwal Kelas

+ Tambah Jadwal +
+ + @if(session('success')) +
+ {{ session('success') }} +
+ @endif + +
+ + + + + + + + + + + + + + @foreach($jadwals as $i => $jadwal) + + + + + + + + + + @endforeach + +
NoKelasHariJamMapelRuanganAksi
{{ $i + 1 }}{{ $jadwal->kelas->nama_kelas ?? '-' }}{{ $jadwal->hari }}{{ $jadwal->jam_mulai }} - {{ $jadwal->jam_selesai }}{{ $jadwal->mataPelajaran->nama_mapel ?? '-' }}{{ $jadwal->ruangan ?? '-' }} + Edit +
+ @csrf + @method('DELETE') + +
+
+
+
+
+
+
diff --git a/website/resources/views/kelas/create.blade.php b/website/resources/views/kelas/create.blade.php new file mode 100644 index 0000000..5b507d1 --- /dev/null +++ b/website/resources/views/kelas/create.blade.php @@ -0,0 +1,84 @@ + + +

+ {{ __('Tambah kelas') }} +

+
+ +
+
+
+
+ +
+

Tambah Kelas Baru

+

Buat kelas baru untuk mengelompokkan santri

+
+ +
+ @csrf + + +
+

Informasi Kelas

+
+
+ + + @error('nama_kelas') +
{{ $message }}
+ @enderror +
+
+ + + @error('kapasitas') +
{{ $message }}
+ @enderror +
+
+ + + @error('guru_id') +
{{ $message }}
+ @enderror +
+
+ + + @error('tahun_ajaran') +
{{ $message }}
+ @enderror +
+
+
+ + + @error('deskripsi') +
{{ $message }}
+ @enderror +
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+
diff --git a/website/resources/views/kelas/edit.blade.php b/website/resources/views/kelas/edit.blade.php new file mode 100644 index 0000000..b807080 --- /dev/null +++ b/website/resources/views/kelas/edit.blade.php @@ -0,0 +1,41 @@ + + +

+ {{ __('Edit kela') }} +

+
+ +
+
+
+
+ + +
+

Edit Kelas

+
+ @csrf + @method('PUT') +
+ + + @error('nama_kelas')
{{ $message }}
@enderror +
+
+ + + @error('wali_kelas_id')
{{ $message }}
@enderror +
+
+ + Kembali +
+
+ + + diff --git a/website/resources/views/kelas/index.blade.php b/website/resources/views/kelas/index.blade.php new file mode 100644 index 0000000..7d09dd0 --- /dev/null +++ b/website/resources/views/kelas/index.blade.php @@ -0,0 +1,54 @@ + + +

+ {{ __('Daftar Kelas') }} +

+
+ +
+
+
+
+
+

Daftar Kelas

+ Tambah Kelas +
+ + @if(session('success')) +
{{ session('success') }}
+ @endif + +
+ + + + + + + + + + + @foreach($kelas as $i => $kela) + + + + + + + @endforeach + +
NoNama KelasWali KelasAction
{{ $i+1 }}{{ $kela->nama_kelas }}{{ $kela->waliKelas ? $kela->waliKelas->nama : '-' }} + Edit +
+ @csrf + @method('DELETE') + +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/layouts/app.blade.php b/website/resources/views/layouts/app.blade.php new file mode 100644 index 0000000..ecc8443 --- /dev/null +++ b/website/resources/views/layouts/app.blade.php @@ -0,0 +1,89 @@ + + + + + + + + {{ config('app.name', 'Laravel') }} + + + + + + + + + + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + + +
+ @hasSection('sidebar') + @yield('sidebar') + @else + @include('layouts.navigation') + @endif + +
+ + + + +
+ @hasSection('content') + @yield('content') + @else + {{ $slot ?? '' }} + @endif +
+
+ +
+ + diff --git a/website/resources/views/layouts/guest.blade.php b/website/resources/views/layouts/guest.blade.php new file mode 100644 index 0000000..990e90f --- /dev/null +++ b/website/resources/views/layouts/guest.blade.php @@ -0,0 +1,59 @@ + + + + + + + + {{ config('app.name', 'Laravel') }} + + + + + + + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + + +
+ +
+ +
+ +
+ + Logo + +

Sistem Monitoring Santri

+

Pondok Pesantren

+
+ + +
+
+ {{ $slot }} +
+
+ + +
+

+ © {{ date('Y') }} Sistem Monitoring Santri. All rights reserved. +

+
+
+
+ + + + diff --git a/website/resources/views/layouts/guru.blade.php b/website/resources/views/layouts/guru.blade.php new file mode 100644 index 0000000..16a7af1 --- /dev/null +++ b/website/resources/views/layouts/guru.blade.php @@ -0,0 +1,130 @@ + + + + + + + {{ config('app.name', 'Laravel') }} + + + + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + +
+ + + + +
+ + + + +
+ @yield('content') +
+
+
+ + + + \ No newline at end of file diff --git a/website/resources/views/layouts/guru_modern.blade.php b/website/resources/views/layouts/guru_modern.blade.php new file mode 100644 index 0000000..caf437a --- /dev/null +++ b/website/resources/views/layouts/guru_modern.blade.php @@ -0,0 +1,128 @@ + + + + + + + {{ config('app.name', 'Laravel') }} + + + + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + +
+ + + + +
+ + + + +
+ {{ $slot }} +
+
+
+ + + + \ No newline at end of file diff --git a/website/resources/views/layouts/guru_new.blade.php b/website/resources/views/layouts/guru_new.blade.php new file mode 100644 index 0000000..16a7af1 --- /dev/null +++ b/website/resources/views/layouts/guru_new.blade.php @@ -0,0 +1,130 @@ + + + + + + + {{ config('app.name', 'Laravel') }} + + + + @vite(['resources/css/app.css', 'resources/js/app.js']) + + + +
+ + + + +
+ + + + +
+ @yield('content') +
+
+
+ + + + \ No newline at end of file diff --git a/website/resources/views/layouts/navigation.blade.php b/website/resources/views/layouts/navigation.blade.php new file mode 100644 index 0000000..b898e23 --- /dev/null +++ b/website/resources/views/layouts/navigation.blade.php @@ -0,0 +1,62 @@ + + \ No newline at end of file diff --git a/website/resources/views/mata_pelajarans/create.blade.php b/website/resources/views/mata_pelajarans/create.blade.php new file mode 100644 index 0000000..aa22082 --- /dev/null +++ b/website/resources/views/mata_pelajarans/create.blade.php @@ -0,0 +1,87 @@ + + +

+ {{ __('Tambah mata pelajaran') }} +

+
+ +
+
+
+
+ +
+

Tambah Mata Pelajaran

+

Buat mata pelajaran baru untuk kurikulum sekolah

+
+ +
+ @csrf + + +
+

Informasi Mata Pelajaran

+
+
+ + + @error('nama_mapel') +
{{ $message }}
+ @enderror +
+
+ + + @error('kode_mapel') +
{{ $message }}
+ @enderror +
+
+ + + @error('jumlah_jam') +
{{ $message }}
+ @enderror +
+
+ + + @error('semester') +
{{ $message }}
+ @enderror +
+
+
+ + + @error('deskripsi') +
{{ $message }}
+ @enderror +
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+
diff --git a/website/resources/views/mata_pelajarans/edit.blade.php b/website/resources/views/mata_pelajarans/edit.blade.php new file mode 100644 index 0000000..a05bd66 --- /dev/null +++ b/website/resources/views/mata_pelajarans/edit.blade.php @@ -0,0 +1,34 @@ + + +

+ {{ __('Edit mata pelajaran') }} +

+
+ +
+
+
+
+ + +

Edit Mata Pelajaran

+
+ @csrf + @method('PUT') +
+ + + @error('kode_mapel')
{{ $message }}
@enderror +
+
+ + + @error('nama_mapel')
{{ $message }}
@enderror +
+ + Kembali +
+ +
+
+ diff --git a/website/resources/views/mata_pelajarans/index.blade.php b/website/resources/views/mata_pelajarans/index.blade.php new file mode 100644 index 0000000..2d24da9 --- /dev/null +++ b/website/resources/views/mata_pelajarans/index.blade.php @@ -0,0 +1,52 @@ + + +

+ {{ __('Daftar mata pelajaran') }} +

+
+ +
+
+
+
+ + + +

Daftar Mata Pelajaran

+ Tambah Mata Pelajaran + @if(session('success')) +
{{ session('success') }}
+ @endif +
+ + + + + + + + + + + @foreach($mataPelajarans as $i => $mapel) + + + + + + + @endforeach + +
NoKode MapelNama MapelAction
{{ $i+1 }}{{ $mapel->kode_mapel }}{{ $mapel->nama_mapel }} + Edit +
+ @csrf + @method('DELETE') + +
+
+ + + +
+ diff --git a/website/resources/views/nilai_santris/create.blade.php b/website/resources/views/nilai_santris/create.blade.php new file mode 100644 index 0000000..1571f94 --- /dev/null +++ b/website/resources/views/nilai_santris/create.blade.php @@ -0,0 +1,150 @@ + + +

+ {{ __('Tambah nilai santri') }} +

+
+ +
+

Input Nilai Santri

+

Masukkan nilai akademik santri untuk mata pelajaran yang dipilih

+
+
+ @csrf +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+

Nilai Santri

+
+ + + + + + + + + + + @foreach($santris as $index => $santri) + + + + + + + @endforeach + +
NoNama Santri + NilaiKeterangan
{{ $index + 1 }}{{ $santri->nama }} + + + + +
+
+
+

Nilai dapat berupa angka 0-100 dengan maksimal 2 desimal

+
+
+
+ + + Kembali + + +
+
+
+ + \ No newline at end of file diff --git a/website/resources/views/nilai_santris/edit.blade.php b/website/resources/views/nilai_santris/edit.blade.php new file mode 100644 index 0000000..c758d8a --- /dev/null +++ b/website/resources/views/nilai_santris/edit.blade.php @@ -0,0 +1,62 @@ + + +

+ {{ __('Edit Nilai Santri') }} +

+
+ +
+
+
+
+

Edit Nilai Santri

+
+ @csrf + @method('PUT') +
+ + +
+
+ + + @error('nilai')
{{ $message }}
@enderror +
+
+ + + @error('keterangan')
{{ $message }}
@enderror +
+
+ + + @error('semester_id')
{{ $message }}
@enderror +
+
+ + + @error('jenis_nilai')
{{ $message }}
@enderror +
+
+ + Kembali +
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/nilai_santris/index.blade.php b/website/resources/views/nilai_santris/index.blade.php new file mode 100644 index 0000000..e9db061 --- /dev/null +++ b/website/resources/views/nilai_santris/index.blade.php @@ -0,0 +1,164 @@ + + +

+ {{ __('Daftar nilai santri') }} +

+
+ +
+
+
+
+ +
+

Rekap Nilai Santri

+

Kelola dan pantau nilai akademik santri dengan mudah

+
+ + +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ +
+
+ + + @if($santris->count()) +
+
+ + + + + + + + + + + + + + @foreach($santris as $i => $santri) + + + + + + + + + + @endforeach + +
NoNama SantriNilaiKeteranganSemesterJenis NilaiAksi
{{ $i+1 }} +
+
+ {{ substr($santri->nama, 0, 1) }} +
+ {{ $santri->nama }} +
+
+ @if(isset($nilaiSantris[$santri->id])) + @php + $nilai = $nilaiSantris[$santri->id]->nilai; + $nilaiColors = [ + 'A' => 'bg-green-100 text-green-800', + 'B' => 'bg-yellow-100 text-yellow-800', + 'C' => 'bg-yellow-200 text-yellow-900', + 'D' => 'bg-orange-100 text-orange-800', + 'E' => 'bg-red-100 text-red-800' + ]; + $grade = $nilai >= 90 ? 'A' : ($nilai >= 80 ? 'B' : ($nilai >= 70 ? 'C' : ($nilai >= 60 ? 'D' : 'E'))); + $color = $nilaiColors[$grade]; + @endphp +
+ {{ $nilai }} + + {{ $grade }} + +
+ @else + - + @endif +
+ {{ $nilaiSantris[$santri->id]->keterangan ?? '-' }} + + @if(isset($nilaiSantris[$santri->id])) + {{ $nilaiSantris[$santri->id]->semester ? $nilaiSantris[$santri->id]->semester->semester : '-' }} + @else + - + @endif + + {{ $nilaiSantris[$santri->id]->jenis_nilai ?? '-' }} + + @if(isset($nilaiSantris[$santri->id])) +
+ + + Edit + +
+ @csrf + @method('DELETE') + +
+
+ @else + Belum ada data + @endif +
+
+
+ @elseif($kelasId && $mapelId) +
+
+ +
+

Tidak ada data santri

+

Tidak ada data santri di kelas yang dipilih.

+
+ @endif +
+
+
+
+
diff --git a/website/resources/views/nilai_santris/show.blade.php b/website/resources/views/nilai_santris/show.blade.php new file mode 100644 index 0000000..d2bb23b --- /dev/null +++ b/website/resources/views/nilai_santris/show.blade.php @@ -0,0 +1,44 @@ + + +

+ {{ __('Detail nilai santri') }} +

+
+ +
+
+
+
+ + +

Rekap Nilai: {{ $santri->nama }}

+ + + Kembali + + + + + + + + + + + + + @foreach($nilaiList as $i => $nilai) + + + + + + + + @endforeach + +
NoTanggalMata PelajaranNilaiKeterangan
{{ $i+1 }}{{ $nilai->tanggal }}{{ $nilai->mapel->nama_mapel ?? '-' }}{{ $nilai->nilai }}{{ $nilai->keterangan }}
+ +
+
+ diff --git a/website/resources/views/pelanggarans/create.blade.php b/website/resources/views/pelanggarans/create.blade.php new file mode 100644 index 0000000..40736e3 --- /dev/null +++ b/website/resources/views/pelanggarans/create.blade.php @@ -0,0 +1,86 @@ + + +

+ {{ __('Tambah Pelanggaran') }} +

+
+ +
+
+
+
+ @csrf + + {{-- Santri --}} +
+ + + @error('santri_id')

{{ $message }}

@enderror +
+ + {{-- Kelas --}} +
+ + + @error('kelas_id')

{{ $message }}

@enderror +
+ + {{-- Jenis Pelanggaran --}} +
+ + + @error('jenis_pelanggaran')

{{ $message }}

@enderror +
+ + {{-- Hukuman --}} +
+ + + @error('hukuman')

{{ $message }}

@enderror +
+ + {{-- Keterangan Hukuman --}} +
+ + + @error('keterangan_hukuman')

{{ $message }}

@enderror +
+ + {{-- Hukuman Selesai --}} + + + + {{-- Tombol --}} +
+ Kembali + +
+
+
+
+
+
diff --git a/website/resources/views/pelanggarans/edit.blade.php b/website/resources/views/pelanggarans/edit.blade.php new file mode 100644 index 0000000..5eba99d --- /dev/null +++ b/website/resources/views/pelanggarans/edit.blade.php @@ -0,0 +1,97 @@ + + +

+ {{ __('Edit Pelanggaran') }} +

+
+ +
+
+
+
+ @csrf + @method('PUT') + + {{-- Santri --}} +
+ + + @error('santri_id')

{{ $message }}

@enderror +
+ + {{-- Kelas --}} +
+ + + @error('kelas_id')

{{ $message }}

@enderror +
+ + {{-- Jenis Pelanggaran --}} +
+ + + @error('jenis_pelanggaran')

{{ $message }}

@enderror +
+ + {{-- Hukuman --}} +
+ + + @error('hukuman')

{{ $message }}

@enderror +
+ + {{-- Keterangan Hukuman --}} +
+ + + @error('keterangan_hukuman')

{{ $message }}

@enderror +
+ + {{-- Hukuman Selesai --}} + hukuman_selesai) === 'selesai' ? 'checked' : '' }} + class="h-4 w-4 text-green-600 focus:ring-green-500 border-green-400 rounded"> + + + {{-- Tombol --}} +
+ + Kembali + + +
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/pelanggarans/index.blade.php b/website/resources/views/pelanggarans/index.blade.php new file mode 100644 index 0000000..5aacb5c --- /dev/null +++ b/website/resources/views/pelanggarans/index.blade.php @@ -0,0 +1,95 @@ + + +

+ {{ __('Daftar Pelanggaran') }} +

+
+ +
+
+
+
+ +
+ + +
+ + {{-- Judul dan tombol tambah --}} +
+

Daftar Pelanggaran Santri

+ +
+ + {{-- Alert sukses --}} + @if(session('success')) +
+ {{ session('success') }} +
+ @endif + + {{-- Tabel daftar pelanggaran --}} +
+ + + + + + + + + + + + + + @forelse($pelanggarans as $i => $p) + + + + + + + + + + @empty + + + + @endforelse + +
NoSantriKelasJenis PelanggaranKeteranganStatus HukumanAksi
{{ $i + 1 }}{{ $p->santri->nama }}{{ $p->kelas->nama_kelas }}{{ $p->jenis_pelanggaran }}{{ $p->keterangan_hukuman }} + @if($p->hukuman_selesai === 'selesai') + Selesai + @else + Belum + @endif + + + Edit + +
+ @csrf @method('DELETE') + +
+
+ Tidak ada data pelanggaran +
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/pembayarans/create.blade.php b/website/resources/views/pembayarans/create.blade.php new file mode 100644 index 0000000..4dc2c28 --- /dev/null +++ b/website/resources/views/pembayarans/create.blade.php @@ -0,0 +1,200 @@ + + +

+ {{ __('Tambah pembayaran') }} +

+
+ +
+
+
+
+ +
+

Tambah Pembayaran

+

Catat pembayaran yang dilakukan oleh santri

+
+ +
+ @csrf + + +
+

Informasi Pembayaran

+
+
+ + + @error('santri_id') +
{{ $message }}
+ @enderror +
+
+ + + @error('jenis_pembayaran') +
{{ $message }}
+ @enderror +
+
+ + + @error('jumlah_pembayaran') +
{{ $message }}
+ @enderror +
+
+ + + @error('tanggal_pembayaran') +
{{ $message }}
+ @enderror +
+
+ + + @error('bulan') +
{{ $message }}
+ @enderror +
+
+ + + @error('tahun') +
{{ $message }}
+ @enderror +
+
+
+ + +
+

Detail Pembayaran

+
+
+ + + @error('metode_pembayaran') +
{{ $message }}
+ @enderror +
+
+ + + @error('status_pembayaran') +
{{ $message }}
+ @enderror +
+
+
+ + + @error('keterangan') +
{{ $message }}
+ @enderror +
+
+ + +
+

Bukti Pembayaran

+
+ + + @error('bukti_pembayaran') +
{{ $message }}
+ @enderror +
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/pembayarans/edit.blade.php b/website/resources/views/pembayarans/edit.blade.php new file mode 100644 index 0000000..7fbb941 --- /dev/null +++ b/website/resources/views/pembayarans/edit.blade.php @@ -0,0 +1,101 @@ + + +

+ {{ __('Edit pembayaran') }} +

+
+ +
+
+
+
+ + +
+

Edit Pembayaran

+
+ @csrf + @method('PUT') +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + @if($pembayaran->bukti_pembayaran) + @php + $ext = pathinfo($pembayaran->bukti_pembayaran, PATHINFO_EXTENSION); + $buktiUrl = asset('storage/' . str_replace('\\', '/', $pembayaran->bukti_pembayaran)); + @endphp + + @endif + + @error('bukti_pembayaran')
{{ $message }}
@enderror +
+ + Batal +
+ +
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/pembayarans/index.blade.php b/website/resources/views/pembayarans/index.blade.php new file mode 100644 index 0000000..11d31f1 --- /dev/null +++ b/website/resources/views/pembayarans/index.blade.php @@ -0,0 +1,133 @@ + + +

+ {{ __('Daftar pembayaran') }} +

+
+ +
+
+
+
+

Daftar Pembayaran

+ +
+ + +
+ + + @if(session('success')) +
{{ session('success') }}
+ @endif +
+ + + + + + + + + + + + + + + + @foreach($pembayarans as $pembayaran) + + + + + + + + + + + + @endforeach + +
NoSantriKelasTanggalJenis PembayaranJumlahStatusBuktiAksi
+ {{ $loop->iteration + ($pembayarans->currentPage() - 1) * $pembayarans->perPage() }} + {{ $pembayaran->santri->nama ?? '-' }}{{ $pembayaran->kelas->nama_kelas ?? '-' }}{{ $pembayaran->tanggal }}{{ $pembayaran->jenis_pembayaran }}{{ number_format($pembayaran->jumlah, 0, ',', '.') }} + @php + $badge = match ($pembayaran->status) { + 'menunggu' => 'bg-yellow-100 text-yellow-800', + 'diterima' => 'bg-green-100 text-green-800', + 'ditolak' => 'bg-red-100 text-red-800', + default => 'bg-gray-100 text-gray-800', + }; + @endphp + + {{ ucfirst($pembayaran->status) }} + + + @if($pembayaran->bukti_pembayaran) + @php + $ext = pathinfo($pembayaran->bukti_pembayaran, PATHINFO_EXTENSION); + $buktiUrl = asset('storage/' . str_replace('\\', '/', $pembayaran->bukti_pembayaran)); + @endphp + @if(in_array(strtolower($ext), ['jpg', 'jpeg', 'png', 'gif', 'webp'])) + + Bukti + + @else + Lihat File + @endif + @else + - + @endif + + Detail + Edit +
+ @csrf + @method('DELETE') + +
+
+
+ {{ $pembayarans->links() }} + + + + + + \ No newline at end of file diff --git a/website/resources/views/pembayarans/show.blade.php b/website/resources/views/pembayarans/show.blade.php new file mode 100644 index 0000000..abe6dc1 --- /dev/null +++ b/website/resources/views/pembayarans/show.blade.php @@ -0,0 +1,47 @@ + + +

+ {{ __('Detail pembayaran') }} +

+
+ +
+
+
+
+ + + +
+

Detail Pembayaran

+
Santri: {{ $pembayaran->santri->nama ?? '-' }}
+
Kelas: {{ $pembayaran->kelas->nama ?? '-' }}
+
Tanggal: {{ $pembayaran->tanggal }}
+
Jenis Pembayaran: {{ $pembayaran->jenis_pembayaran }}
+
Jumlah: {{ number_format($pembayaran->jumlah,0,',','.') }}
+
Keterangan: {{ $pembayaran->keterangan }}
+
Status: {{ ucfirst($pembayaran->status) }}
+
Bukti Pembayaran: + @if($pembayaran->bukti_pembayaran) + @php + $ext = pathinfo($pembayaran->bukti_pembayaran, PATHINFO_EXTENSION); + $buktiUrl = asset('storage/' . str_replace('\\', '/', $pembayaran->bukti_pembayaran)); + @endphp + + @if(in_array(strtolower($ext), ['jpg','jpeg','png','gif','webp'])) + Bukti + @else + Lihat File + @endif + + @else + - + @endif +
+
+ Kembali + + + +
+ diff --git a/website/resources/views/prestasis/create.blade.php b/website/resources/views/prestasis/create.blade.php new file mode 100644 index 0000000..a4c43cd --- /dev/null +++ b/website/resources/views/prestasis/create.blade.php @@ -0,0 +1,172 @@ + + +

+ {{ __('Tambah prestasi') }} +

+
+ +
+
+
+
+
+

Tambah Prestasi Baru

+

Catat prestasi yang diraih oleh santri

+
+ +
+ @csrf + + +
+

Informasi Prestasi

+
+ {{-- Santri --}} +
+ + + @error('santri_id') +
{{ $message }}
+ @enderror +
+ + {{-- Jenis Prestasi --}} +
+ + + @error('jenis_prestasi') +
{{ $message }}
+ @enderror +
+ + {{-- Nama Prestasi --}} +
+ + + @error('nama_prestasi') +
{{ $message }}
+ @enderror +
+ + {{-- Tingkat --}} +
+ + + @error('tingkat') +
{{ $message }}
+ @enderror +
+ + {{-- Kelas --}} +
+ + + @error('kelas_id')

{{ $message }}

@enderror +
+ + {{-- Peringkat --}} +
+ + + @error('peringkat') +
{{ $message }}
+ @enderror +
+ + {{-- Tanggal Prestasi --}} +
+ + + @error('tanggal_prestasi') +
{{ $message }}
+ @enderror +
+
+ + {{-- Deskripsi --}} +
+ + + @error('deskripsi') +
{{ $message }}
+ @enderror +
+
+ + {{-- Sertifikat Upload --}} +
+

Sertifikat/Piagam

+
+ + +

Format: JPG, PNG, PDF. Maksimal 5MB.

+ @error('sertifikat') +
{{ $message }}
+ @enderror +
+
+ + {{-- Aksi --}} +
+ + Kembali + + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/prestasis/edit.blade.php b/website/resources/views/prestasis/edit.blade.php new file mode 100644 index 0000000..a250d28 --- /dev/null +++ b/website/resources/views/prestasis/edit.blade.php @@ -0,0 +1,162 @@ + + +

+ {{ __('Edit Prestasi') }} +

+
+ +
+
+
+
+
+

Edit Prestasi

+

Perbarui informasi prestasi santri

+
+ +
+ @csrf + @method('PUT') + +
+

Informasi Prestasi

+
+ + {{-- Santri --}} +
+ + + @error('santri_id') +
{{ $message }}
+ @enderror +
+ + {{-- Kelas --}} +
+ + + @error('kelas_id') +
{{ $message }}
+ @enderror +
+ + {{-- Nama Prestasi --}} +
+ + + @error('nama_prestasi') +
{{ $message }}
+ @enderror +
+ + {{-- Jenis Prestasi --}} +
+ + + @error('jenis_prestasi') +
{{ $message }}
+ @enderror +
+ + {{-- Tingkat --}} +
+ + + @error('tingkat') +
{{ $message }}
+ @enderror +
+ + {{-- Peringkat --}} +
+ + + @error('peringkat') +
{{ $message }}
+ @enderror +
+ + {{-- Tanggal --}} +
+ + + @error('tanggal_prestasi') +
{{ $message }}
+ @enderror +
+
+ + {{-- Deskripsi --}} +
+ + + @error('deskripsi') +
{{ $message }}
+ @enderror +
+
+ + {{-- Sertifikat --}} +
+

Sertifikat / Piagam

+ @if($prestasi->sertifikat) +

+ File saat ini: + + Lihat Sertifikat + +

+ @endif + +

Format: JPG, PNG, PDF. Maksimal 5MB.

+ @error('sertifikat') +
{{ $message }}
+ @enderror +
+ + {{-- Aksi --}} +
+ + Kembali + + +
+
+
+
+
+
+
diff --git a/website/resources/views/prestasis/index.blade.php b/website/resources/views/prestasis/index.blade.php new file mode 100644 index 0000000..b2f55ed --- /dev/null +++ b/website/resources/views/prestasis/index.blade.php @@ -0,0 +1,103 @@ + + +

+ {{ __('Daftar Prestasi') }} +

+
+ +
+
+
+
+ +
+ + +
+
+

Data Prestasi Santri

+ + + Tambah Prestasi + +
+ + @if(session('success')) +
+ {{ session('success') }} +
+ @endif + +
+ + + + + + + + + + + + + + + + + @foreach($prestasis as $i => $p) + + + + + + + + + + + + + @endforeach + @if($prestasis->isEmpty()) + + + + @endif + +
NoSantriKelasNama PrestasiJenisTingkatPeringkatTanggalSertifikatAksi
{{ $i + 1 }}{{ $p->santri->nama ?? '-' }}{{ $p->kelas->nama_kelas ?? '-' }}{{ $p->nama_prestasi }}{{ $p->jenis_prestasi }}{{ $p->tingkat }}{{ $p->peringkat }} + {{ \Carbon\Carbon::parse($p->tanggal_prestasi)->format('d M Y') }} + @if ($p->sertifikat) + Lihat + @else + - + @endif + + + Edit + +
+ @csrf + @method('DELETE') + +
+
+ Belum ada data prestasi. +
+
+ +
+ {{ $prestasis->links() }} +
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/profile/edit.blade.php b/website/resources/views/profile/edit.blade.php new file mode 100644 index 0000000..e0e1d38 --- /dev/null +++ b/website/resources/views/profile/edit.blade.php @@ -0,0 +1,29 @@ + + +

+ {{ __('Profile') }} +

+
+ +
+
+
+
+ @include('profile.partials.update-profile-information-form') +
+
+ +
+
+ @include('profile.partials.update-password-form') +
+
+ +
+
+ @include('profile.partials.delete-user-form') +
+
+
+
+
diff --git a/website/resources/views/profile/partials/delete-user-form.blade.php b/website/resources/views/profile/partials/delete-user-form.blade.php new file mode 100644 index 0000000..edeeb4a --- /dev/null +++ b/website/resources/views/profile/partials/delete-user-form.blade.php @@ -0,0 +1,55 @@ +
+
+

+ {{ __('Delete Account') }} +

+ +

+ {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Before deleting your account, please download any data or information that you wish to retain.') }} +

+
+ + {{ __('Delete Account') }} + + +
+ @csrf + @method('delete') + +

+ {{ __('Are you sure you want to delete your account?') }} +

+ +

+ {{ __('Once your account is deleted, all of its resources and data will be permanently deleted. Please enter your password to confirm you would like to permanently delete your account.') }} +

+ +
+ + + + + +
+ +
+ + {{ __('Cancel') }} + + + + {{ __('Delete Account') }} + +
+
+
+
diff --git a/website/resources/views/profile/partials/update-password-form.blade.php b/website/resources/views/profile/partials/update-password-form.blade.php new file mode 100644 index 0000000..eaca1ac --- /dev/null +++ b/website/resources/views/profile/partials/update-password-form.blade.php @@ -0,0 +1,48 @@ +
+
+

+ {{ __('Update Password') }} +

+ +

+ {{ __('Ensure your account is using a long, random password to stay secure.') }} +

+
+ +
+ @csrf + @method('put') + +
+ + + +
+ +
+ + + +
+ +
+ + + +
+ +
+ {{ __('Save') }} + + @if (session('status') === 'password-updated') +

{{ __('Saved.') }}

+ @endif +
+
+
diff --git a/website/resources/views/profile/partials/update-profile-information-form.blade.php b/website/resources/views/profile/partials/update-profile-information-form.blade.php new file mode 100644 index 0000000..1c97e88 --- /dev/null +++ b/website/resources/views/profile/partials/update-profile-information-form.blade.php @@ -0,0 +1,46 @@ +
+
+

+ {{ __('Profile Information') }} +

+ +

+ {{ __("Update your account's profile information and email address.") }} +

+
+ +
+ @csrf +
+ +
+ @csrf + @method('patch') + +
+ + + +
+ +
+ + + +
+ +
+ {{ __('Save') }} + + @if (session('status') === 'profile-updated') +

{{ __('Saved.') }}

+ @endif +
+
+
diff --git a/website/resources/views/santris/create.blade.php b/website/resources/views/santris/create.blade.php new file mode 100644 index 0000000..5760b18 --- /dev/null +++ b/website/resources/views/santris/create.blade.php @@ -0,0 +1,282 @@ + + +

+ {{ __('Tambah Santri') }} +

+
+ +
+
+
+ + {{-- Form Tambah Santri --}} +
+ @csrf + + +
+

Informasi Pribadi

+
+
+ + + @error('nama') +
{{ $message }}
+ @enderror +
+
+ + + @error('nis') +
{{ $message }}
+ @enderror +
+
+ + + @error('tempat_lahir') +
{{ $message }}
+ @enderror +
+
+ + + @error('tanggal_lahir') +
{{ $message }}
+ @enderror +
+
+ + + @error('jenis_kelamin') +
{{ $message }}
+ @enderror +
+
+
+ + +
+

Informasi Kontak

+
+
+ + + @error('alamat') +
{{ $message }}
+ @enderror +
+
+ + + @error('no_telp') +
{{ $message }}
+ @enderror +
+
+
+ + +
+

Informasi Akademik

+
+
+ + + @error('kelas_id') +
{{ $message }}
+ @enderror +
+
+ + + @error('tahun_masuk') +
{{ $message }}
+ @enderror +
+
+
+ + +
+

Foto

+
+ + + @error('foto') +
{{ $message }}
+ @enderror +
+
+ + +
+

Informasi User

+
+
+ + + @error('username') +
{{ $message }}
+ @enderror +
+
+ + + @error('role') +
{{ $message }}
+ @enderror +
+
+
+
+

Informasi Password

+
+ +
+ + + + + + + @error('password') +
{{ $message }}
+ @enderror +
+
+ + +
+
+
+

Password minimal 8 karakter dengan kombinasi huruf dan + angka

+
+
+ + +
+

Status Akun

+
+
+ + + @error('is_active') +
{{ $message }}
+ @enderror +
+
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+ + + \ No newline at end of file diff --git a/website/resources/views/santris/edit.blade.php b/website/resources/views/santris/edit.blade.php new file mode 100644 index 0000000..e423b5a --- /dev/null +++ b/website/resources/views/santris/edit.blade.php @@ -0,0 +1,74 @@ + + +

+ {{ __('Edit Santri') }} +

+
+ +
+
+
+
+
+ @csrf + @method('PUT') +
+
+ + + @error('nama')
{{ $message }}
@enderror +
+
+ + + @error('nis')
{{ $message }}
@enderror +
+
+
+
+ + + @error('alamat')
{{ $message }}
@enderror +
+
+ + + @error('tanggal_lahir')
{{ $message }}
@enderror +
+
+ + + @error('jenis_kelamin')
{{ $message }}
@enderror +
+
+ + @if($santri->foto) + Foto Santri + @endif + + @error('foto') +
{{ $message }}
+ @enderror +
+
+ Kembali + +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/santris/import.blade.php b/website/resources/views/santris/import.blade.php new file mode 100644 index 0000000..0075ee2 --- /dev/null +++ b/website/resources/views/santris/import.blade.php @@ -0,0 +1,35 @@ + + +

+ {{ __('Import Santri') }} +

+
+ +
+
+
+
+ @csrf +
+ + + @error('file') +
{{ $message }}
+ @enderror +
+
+ + Kembali + + +
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/santris/index.blade.php b/website/resources/views/santris/index.blade.php new file mode 100644 index 0000000..2a41d10 --- /dev/null +++ b/website/resources/views/santris/index.blade.php @@ -0,0 +1,75 @@ + + +

+ {{ __('Daftar Santri') }} +

+
+ +
+
+
+
+ Tambah Santri + @if(session('success')) +
{{ session('success') }}
+ @endif + +
+ + +
+ +
+ + + + + + + + + + + + + @foreach($santris as $i => $santri) + + + + + + + + + + @endforeach + +
NoFotoNamaNISKelasAction
{{ $i + 1 }} + @if($santri->foto) + Foto + @else + - + @endif + {{ $santri->nama }}{{ $santri->nis }} + {{ $santri->kelas ? $santri->kelas->nama_kelas : 'Belum Ditetapkan' }} + + Detail + Edit +
+ @csrf + @method('DELETE') + +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/santris/show.blade.php b/website/resources/views/santris/show.blade.php new file mode 100644 index 0000000..10e867a --- /dev/null +++ b/website/resources/views/santris/show.blade.php @@ -0,0 +1,74 @@ + + +

+ {{ __('Detail Santri') }} +

+
+ +
+
+
+ + + + + +
+ +
+ @if($santri->foto) + Foto Santri + @else +
+ Tidak ada foto +
+ @endif +
+ + +
+

{{ $santri->nama }}

+
+ NIS: {{ $santri->nis }} + + Kelas: {{ $santri->kelas ? $santri->kelas->nama_kelas : 'Belum Ditetapkan' }} + +
+ +
+

Tempat, Tanggal Lahir: {{ $santri->tempat_lahir ?? '-' }}, {{ $santri->tanggal_lahir ?? '-' }}

+

Alamat: {{ $santri->alamat ?? '-' }}

+

Jenis Kelamin: {{ $santri->jenis_kelamin ?? '-' }}

+

Telepon/HP: {{ $santri->no_telp ?? '-' }}

+
+ + +
+ + Edit + +
+ @csrf + @method('DELETE') + +
+
+
+
+ +
+
+
+
diff --git a/website/resources/views/semesters/create.blade.php b/website/resources/views/semesters/create.blade.php new file mode 100644 index 0000000..fe0edc3 --- /dev/null +++ b/website/resources/views/semesters/create.blade.php @@ -0,0 +1,106 @@ + + +

+ {{ __('Tambah semester') }} +

+
+ +
+
+
+
+ +
+

Tambah Semester Baru

+

Buat semester baru untuk tahun ajaran

+
+ +
+ @csrf + + +
+

Informasi Semester

+
+
+ + + @error('nama_semester') +
{{ $message }}
+ @enderror +
+
+ + + @error('tahun_ajaran') +
{{ $message }}
+ @enderror +
+
+ + + @error('tanggal_mulai') +
{{ $message }}
+ @enderror +
+
+ + + @error('tanggal_selesai') +
{{ $message }}
+ @enderror +
+
+ + + @error('status') +
{{ $message }}
+ @enderror +
+
+ + + @error('durasi') +
{{ $message }}
+ @enderror +
+
+
+ + + @error('deskripsi') +
{{ $message }}
+ @enderror +
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+
diff --git a/website/resources/views/semesters/edit.blade.php b/website/resources/views/semesters/edit.blade.php new file mode 100644 index 0000000..eb176bc --- /dev/null +++ b/website/resources/views/semesters/edit.blade.php @@ -0,0 +1,36 @@ + + +

+ {{ __('Edit semester') }} +

+
+ +
+
+
+
+ + +
+

Edit Semester

+
+ @csrf + @method('PUT') +
+ + + @error('semester')
{{ $message }}
@enderror +
+
+ + + @error('tahun_ajaran')
{{ $message }}
@enderror +
+
+ + Kembali +
+
+ + + diff --git a/website/resources/views/semesters/index.blade.php b/website/resources/views/semesters/index.blade.php new file mode 100644 index 0000000..bfc4c8c --- /dev/null +++ b/website/resources/views/semesters/index.blade.php @@ -0,0 +1,69 @@ + + +

+ {{ __('Daftar Semester') }} +

+
+ +
+
+
+
+
+

Daftar Semester

+ Tambah Semester +
+ + @if(session('success')) +
{{ session('success') }}
+ @endif + +
+ + + + + + + + + + + + @foreach($semesters as $i => $semester) + + + + + + + + @endforeach + +
NoSemesterTahun AjaranStatusAction
{{ $i+1 }}{{ $semester->semester }}{{ $semester->tahun_ajaran }} + @if($semester->is_active) + Aktif + @else + Tidak Aktif + @endif + + Edit +
+ @csrf + @method('DELETE') + +
+ @if(!$semester->is_active) +
+ @csrf + @method('PATCH') + +
+ @endif +
+
+
+
+
+
+
diff --git a/website/resources/views/users/create.blade.php b/website/resources/views/users/create.blade.php new file mode 100644 index 0000000..2a9fcb4 --- /dev/null +++ b/website/resources/views/users/create.blade.php @@ -0,0 +1,125 @@ + + +

+ {{ __('Tambah user') }} +

+
+ +
+
+
+
+ +
+

Tambah User Baru

+

Buat akun user baru untuk sistem

+
+ +
+ @csrf + + +
+

Informasi User

+
+
+ + + @error('name') +
{{ $message }}
+ @enderror +
+ +
+ + + @error('username') +
{{ $message }}
+ @enderror +
+
+ + + @error('role') +
{{ $message }}
+ @enderror +
+
+
+ + +
+

Informasi Password

+
+
+ + + @error('password') +
{{ $message }}
+ @enderror +
+
+ + +
+
+
+

Password minimal 8 karakter dengan kombinasi huruf dan angka

+
+
+ + +
+

Status Akun

+
+ +
+ + + @error('is_active') +
{{ $message }}
+ @enderror +
+
+
+ + +
+ + + Kembali + + +
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/users/edit.blade.php b/website/resources/views/users/edit.blade.php new file mode 100644 index 0000000..b5616ed --- /dev/null +++ b/website/resources/views/users/edit.blade.php @@ -0,0 +1,82 @@ + + +

+ {{ __('Edit User') }} +

+
+ +
+
+
+
+
+

Edit Data: {{ $user->name }}

+ + + Kembali + +
+ +
+ @csrf + @method('PUT') + +
+
+ + + @error('name') +

{{ $message }}

+ @enderror +
+ +
+ + + @error('username') +

{{ $message }}

+ @enderror +
+ +
+ + +

Kosongkan field ini jika tidak ingin mengubah password.

+ @error('password') +

{{ $message }}

+ @enderror +
+ +
+ + + @error('role') +

{{ $message }}

+ @enderror +
+ +
+ Batal + +
+
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/users/index.blade.php b/website/resources/views/users/index.blade.php new file mode 100644 index 0000000..91ace53 --- /dev/null +++ b/website/resources/views/users/index.blade.php @@ -0,0 +1,133 @@ + + +

+ {{ __('Kelola User') }} +

+
+ +
+
+
+
+
+

Daftar Pengguna

+ +
+ + + + +
+ + + +
+ + @if(session('success')) +
+ {{ session('success') }} +
+ @endif + + @if(session('error')) +
+ {{ session('error') }} +
+ @endif + +
+ + + + + + + + + + + + @forelse($users as $index => $user) + + + + + + + + @empty + + + + @endforelse + +
+ No + Nama + Username + Role + Aksi
{{ $index + 1 }}{{ $user->name }}{{ $user->username }} + + + {{ ucfirst($user->role) }} + + +
+ + + + @if($user->id !== auth()->id()) +
+ @csrf + @method('DELETE') + +
+ @endif +
+
Tidak ada data user
+
+
+
+
+
+
\ No newline at end of file diff --git a/website/resources/views/welcome.blade.php b/website/resources/views/welcome.blade.php new file mode 100644 index 0000000..c893b80 --- /dev/null +++ b/website/resources/views/welcome.blade.php @@ -0,0 +1,277 @@ + + + + + + + Laravel + + + + + + + @if (file_exists(public_path('build/manifest.json')) || file_exists(public_path('hot'))) + @vite(['resources/css/app.css', 'resources/js/app.js']) + @else + + @endif + + +
+ @if (Route::has('login')) + + @endif +
+
+
+
+

Let's get started

+

Laravel has an incredibly rich ecosystem.
We suggest starting with the following.

+ + +
+
+ {{-- Laravel Logo --}} + + + + + + + + + + + {{-- Light Mode 12 SVG --}} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{-- Dark Mode 12 SVG --}} + +
+
+
+
+ + @if (Route::has('login')) + + @endif + + diff --git a/website/routes/api.php b/website/routes/api.php new file mode 100644 index 0000000..d91ebc2 --- /dev/null +++ b/website/routes/api.php @@ -0,0 +1,54 @@ +group(function () { + // 🔓 Logout & Get Info User + Route::post('/logout', [AuthController::class, 'logout']); + Route::get('/me', [AuthController::class, 'me']); + Route::get('/santri/me', [ProfileController::class, 'santriProfile']); + Route::post('/santri/me', [ProfileController::class, 'updateSantriProfile']); + + Route::get('/ping', function () { + return response()->json(['status' => 'ok']); + }); + + Route::get('/absensi', [AbsensiController::class, 'index']); + Route::post('/absensi', [AbsensiController::class, 'store']); + Route::get('/nilai', [NilaiSantriController::class, 'index']); + Route::get('/kesehatan', [CatatanKesehatanController::class, 'index']); + Route::get('/prestasi', [PrestasiController::class, 'index']); + Route::get('/pelanggaran', [PelanggaranController::class, 'index']); + Route::get('/berita', [BeritaController::class, 'index']); + Route::get('/berita/published', [BeritaController::class, 'published']); + Route::get('/berita/{id}', [BeritaController::class, 'show']); + Route::get('/alumni', [AlumniController::class, 'index']); + Route::get('/pembayaran', [PembayaranController::class, 'index']); + Route::post('/pembayaran', [PembayaranController::class, 'store']); + Route::get('/kelas', [KelasController::class, 'index']); + Route::get('/kelas/{id}', [KelasController::class, 'show']); +}); +Route::middleware('auth:sanctum')->put('/password', [ProfileController::class, 'changePassword']); +Route::middleware('auth:api')->post('/fcm-token', [FcmTokenController::class, 'store']); diff --git a/website/routes/auth.php b/website/routes/auth.php new file mode 100644 index 0000000..3926ecf --- /dev/null +++ b/website/routes/auth.php @@ -0,0 +1,59 @@ +group(function () { + Route::get('register', [RegisteredUserController::class, 'create']) + ->name('register'); + + Route::post('register', [RegisteredUserController::class, 'store']); + + Route::get('login', [AuthenticatedSessionController::class, 'create']) + ->name('login'); + + Route::post('login', [AuthenticatedSessionController::class, 'store']); + + Route::get('forgot-password', [PasswordResetLinkController::class, 'create']) + ->name('password.request'); + + Route::post('forgot-password', [PasswordResetLinkController::class, 'store']) + ->name('password.email'); + + Route::get('reset-password/{token}', [NewPasswordController::class, 'create']) + ->name('password.reset'); + + Route::post('reset-password', [NewPasswordController::class, 'store']) + ->name('password.store'); +}); + +Route::middleware('auth')->group(function () { + Route::get('verify-email', EmailVerificationPromptController::class) + ->name('verification.notice'); + + Route::get('verify-email/{id}/{hash}', VerifyEmailController::class) + ->middleware(['signed', 'throttle:6,1']) + ->name('verification.verify'); + + Route::post('email/verification-notification', [EmailVerificationNotificationController::class, 'store']) + ->middleware('throttle:6,1') + ->name('verification.send'); + + Route::get('confirm-password', [ConfirmablePasswordController::class, 'show']) + ->name('password.confirm'); + + Route::post('confirm-password', [ConfirmablePasswordController::class, 'store']); + + Route::put('password', [PasswordController::class, 'update'])->name('password.update'); + + Route::post('logout', [AuthenticatedSessionController::class, 'destroy']) + ->name('logout'); +}); diff --git a/website/routes/console.php b/website/routes/console.php new file mode 100644 index 0000000..3c9adf1 --- /dev/null +++ b/website/routes/console.php @@ -0,0 +1,8 @@ +comment(Inspiring::quote()); +})->purpose('Display an inspiring quote'); diff --git a/website/routes/web.php b/website/routes/web.php new file mode 100644 index 0000000..4fbd6f2 --- /dev/null +++ b/website/routes/web.php @@ -0,0 +1,89 @@ +check()) { + return redirect()->route('dashboard'); + } + return redirect()->route('login'); +}); + +Route::get('/dashboard', function () { + $user = auth()->user(); + if ($user->isAdmin()) { + return redirect()->route('admin.dashboard'); + } elseif ($user->isGuru()) { + return redirect()->route('guru.dashboard'); + } + return '/'; +})->middleware(['auth', 'verified'])->name('dashboard'); + +Route::get('/admin/dashboard', function () { + return view('admin.dashboard'); +})->middleware(['auth', 'verified'])->name('admin.dashboard'); + +Route::get('/guru/dashboard', function () { + return view('guru.dashboard'); +})->middleware(['auth', 'verified'])->name('guru.dashboard'); + +Route::middleware('auth')->group(function () { + Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit'); + Route::patch('/profile', [ProfileController::class, 'update'])->name('profile.update'); + Route::delete('/profile', [ProfileController::class, 'destroy'])->name('profile.destroy'); + Route::resource('santris', SantriController::class); + Route::resource('gurus', GuruController::class); + Route::resource('kelas', KelasController::class); + Route::resource('semesters', SemesterController::class); + Route::patch('semesters/{semester}/activate', [SemesterController::class, 'activate'])->name('semesters.activate'); + Route::resource('mata_pelajarans', MataPelajaranController::class); + Route::resource('jadwals', JadwalController::class); + Route::resource('absensis', AbsensiController::class)->except(['show']); + Route::get('absensis/santri/{santri_id}', [AbsensiController::class, 'show'])->name('absensis.show'); + Route::resource('nilai_santris', NilaiSantriController::class); + Route::resource('prestasis', PrestasiController::class); + Route::resource('pelanggarans', PelanggaranController::class); + Route::resource('catatan_kesehatans', CatatanKesehatanController::class); + Route::resource('beritas', BeritaController::class); + Route::resource('pembayarans', PembayaranController::class); + Route::resource('alumnis', AlumniController::class); + Route::resource('users', UserController::class); +}); + +Route::get('santris/import', [SantriController::class, 'import'])->name('santris.import'); // GET untuk menampilkan form +Route::post('santris/import', [SantriController::class, 'importStore'])->name('santris.import.store'); + +Route::middleware(['auth', 'verified'])->group(function () { + Route::get('/guru/profile', [GuruController::class, 'profile'])->name('guru.profile'); + Route::get('/guru/profile/edit', [GuruController::class, 'editProfile'])->name('guru.profile.edit'); + Route::post('/guru/profile/update', [GuruController::class, 'updateProfile'])->name('guru.profile.update'); +}); + +Route::middleware(['auth', 'verified'])->prefix('guru')->name('guru.')->group(function () { + Route::resource('santris', \App\Http\Controllers\SantriController::class)->only(['index']); + Route::resource('jadwals', \App\Http\Controllers\JadwalController::class)->only(['index']); + Route::resource('nilai_santris', \App\Http\Controllers\NilaiSantriController::class)->except(['show']); + Route::resource('prestasis', \App\Http\Controllers\PrestasiController::class)->except(['show']); + Route::resource('pelanggarans', \App\Http\Controllers\PelanggaranController::class)->except(['show']); + Route::resource('catatan_kesehatans', \App\Http\Controllers\CatatanKesehatanController::class)->except(['show']); + Route::resource('absensis', \App\Http\Controllers\AbsensiController::class)->except(['show']); +}); + +require __DIR__ . '/auth.php'; diff --git a/website/storage/app/.gitignore b/website/storage/app/.gitignore new file mode 100644 index 0000000..fedb287 --- /dev/null +++ b/website/storage/app/.gitignore @@ -0,0 +1,4 @@ +* +!private/ +!public/ +!.gitignore diff --git a/website/storage/app/private/.gitignore b/website/storage/app/private/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/website/storage/app/private/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/website/storage/app/public/.gitignore b/website/storage/app/public/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/website/storage/app/public/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/website/storage/framework/.gitignore b/website/storage/framework/.gitignore new file mode 100644 index 0000000..05c4471 --- /dev/null +++ b/website/storage/framework/.gitignore @@ -0,0 +1,9 @@ +compiled.php +config.php +down +events.scanned.php +maintenance.php +routes.php +routes.scanned.php +schedule-* +services.json diff --git a/website/storage/framework/cache/.gitignore b/website/storage/framework/cache/.gitignore new file mode 100644 index 0000000..01e4a6c --- /dev/null +++ b/website/storage/framework/cache/.gitignore @@ -0,0 +1,3 @@ +* +!data/ +!.gitignore diff --git a/website/storage/framework/cache/data/.gitignore b/website/storage/framework/cache/data/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/website/storage/framework/cache/data/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/website/storage/framework/sessions/.gitignore b/website/storage/framework/sessions/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/website/storage/framework/sessions/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/website/storage/framework/testing/.gitignore b/website/storage/framework/testing/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/website/storage/framework/testing/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/website/storage/framework/views/.gitignore b/website/storage/framework/views/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/website/storage/framework/views/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/website/storage/logs/.gitignore b/website/storage/logs/.gitignore new file mode 100644 index 0000000..d6b7ef3 --- /dev/null +++ b/website/storage/logs/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/website/tailwind.config.js b/website/tailwind.config.js new file mode 100644 index 0000000..33c5809 --- /dev/null +++ b/website/tailwind.config.js @@ -0,0 +1,33 @@ +import defaultTheme from 'tailwindcss/defaultTheme'; +import forms from '@tailwindcss/forms'; + +/** @type {import('tailwindcss').Config} */ +export default { + content: [ + './vendor/laravel/framework/src/Illuminate/Pagination/resources/views/*.blade.php', + './storage/framework/views/*.php', + './resources/views/**/*.blade.php', + ], + + theme: { + extend: { + fontFamily: { + sans: ['Figtree', ...defaultTheme.fontFamily.sans], + }, + colors: { + primary: { + DEFAULT: '#16a34a', // hijau utama + light: '#27ae60', + dark: '#14532d', + }, + accent: { + DEFAULT: '#facc15', // kuning utama + light: '#fde047', + dark: '#ca8a04', + }, + }, + }, + }, + + plugins: [forms], +}; diff --git a/website/test/widget_test.dart b/website/test/widget_test.dart new file mode 100644 index 0000000..9a384ea --- /dev/null +++ b/website/test/widget_test.dart @@ -0,0 +1,29 @@ +// This is a basic Flutter widget test. +// +// To perform an interaction with a widget in your test, use the WidgetTester +// utility in the flutter_test package. For example, you can send tap and scroll +// gestures. You can also use WidgetTester to find child widgets in the widget +// tree, read text, and verify that the values of widget properties are correct. + +import 'package:flutter/material.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:monitoring/main.dart'; + +void main() { + testWidgets('Monitoring Santri App smoke test', (WidgetTester tester) async { + // Build our app and trigger a frame. + await tester.pumpWidget(const MonitoringSantriApp()); + + // Verify that our counter starts at 0. + expect(find.text('0'), findsOneWidget); + expect(find.text('1'), findsNothing); + + // Tap the '+' icon and trigger a frame. + await tester.tap(find.byIcon(Icons.add)); + await tester.pump(); + + // Verify that our counter has incremented. + expect(find.text('0'), findsNothing); + expect(find.text('1'), findsOneWidget); + }); +} diff --git a/website/tests/Feature/Auth/AuthenticationTest.php b/website/tests/Feature/Auth/AuthenticationTest.php new file mode 100644 index 0000000..7df7390 --- /dev/null +++ b/website/tests/Feature/Auth/AuthenticationTest.php @@ -0,0 +1,54 @@ +get('/login'); + + $response->assertStatus(200); + } + + public function test_users_can_authenticate_using_the_login_screen(): void + { + $user = User::factory()->create(); + + $response = $this->post('/login', [ + 'username' => $user->username, + 'password' => 'password', + ]); + + $this->assertAuthenticated(); + $response->assertRedirect(route('dashboard', absolute: false)); + } + + public function test_users_can_not_authenticate_with_invalid_password(): void + { + $user = User::factory()->create(); + + $this->post('/login', [ + 'username' => $user->username, + 'password' => 'wrong-password', + ]); + + $this->assertGuest(); + } + + public function test_users_can_logout(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/logout'); + + $this->assertGuest(); + $response->assertRedirect('/'); + } +} diff --git a/website/tests/Feature/Auth/EmailVerificationTest.php b/website/tests/Feature/Auth/EmailVerificationTest.php new file mode 100644 index 0000000..4987784 --- /dev/null +++ b/website/tests/Feature/Auth/EmailVerificationTest.php @@ -0,0 +1,2 @@ +create(); + + $response = $this->actingAs($user)->get('/confirm-password'); + + $response->assertStatus(200); + } + + public function test_password_can_be_confirmed(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/confirm-password', [ + 'password' => 'password', + ]); + + $response->assertRedirect(); + $response->assertSessionHasNoErrors(); + } + + public function test_password_is_not_confirmed_with_invalid_password(): void + { + $user = User::factory()->create(); + + $response = $this->actingAs($user)->post('/confirm-password', [ + 'password' => 'wrong-password', + ]); + + $response->assertSessionHasErrors(); + } +} diff --git a/website/tests/Feature/Auth/PasswordResetTest.php b/website/tests/Feature/Auth/PasswordResetTest.php new file mode 100644 index 0000000..ec94397 --- /dev/null +++ b/website/tests/Feature/Auth/PasswordResetTest.php @@ -0,0 +1,73 @@ +get('/forgot-password'); + + $response->assertStatus(200); + } + + public function test_reset_password_link_can_be_requested(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['username' => $user->username]); + + Notification::assertSentTo($user, ResetPassword::class); + } + + public function test_reset_password_screen_can_be_rendered(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['username' => $user->username]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) { + $response = $this->get('/reset-password/'.$notification->token); + + $response->assertStatus(200); + + return true; + }); + } + + public function test_password_can_be_reset_with_valid_token(): void + { + Notification::fake(); + + $user = User::factory()->create(); + + $this->post('/forgot-password', ['username' => $user->username]); + + Notification::assertSentTo($user, ResetPassword::class, function ($notification) use ($user) { + $response = $this->post('/reset-password', [ + 'token' => $notification->token, + 'username' => $user->username, + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect(route('login')); + + return true; + }); + } +} diff --git a/website/tests/Feature/Auth/PasswordUpdateTest.php b/website/tests/Feature/Auth/PasswordUpdateTest.php new file mode 100644 index 0000000..ca28c6c --- /dev/null +++ b/website/tests/Feature/Auth/PasswordUpdateTest.php @@ -0,0 +1,51 @@ +create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->put('/password', [ + 'current_password' => 'password', + 'password' => 'new-password', + 'password_confirmation' => 'new-password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/profile'); + + $this->assertTrue(Hash::check('new-password', $user->refresh()->password)); + } + + public function test_correct_password_must_be_provided_to_update_password(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->put('/password', [ + 'current_password' => 'wrong-password', + 'password' => 'new-password', + 'password_confirmation' => 'new-password', + ]); + + $response + ->assertSessionHasErrorsIn('updatePassword', 'current_password') + ->assertRedirect('/profile'); + } +} diff --git a/website/tests/Feature/Auth/RegistrationTest.php b/website/tests/Feature/Auth/RegistrationTest.php new file mode 100644 index 0000000..f59718d --- /dev/null +++ b/website/tests/Feature/Auth/RegistrationTest.php @@ -0,0 +1,33 @@ +get('/register'); + + $response->assertStatus(200); + } + + public function test_user_can_register(): void + { + $response = $this->post('/register', [ + 'name' => 'Test User', + 'username' => 'testuser', + 'password' => 'password', + 'password_confirmation' => 'password', + ]); + $response->assertRedirect(route('dashboard', absolute: false)); + $this->assertDatabaseHas('users', [ + 'name' => 'Test User', + 'username' => 'testuser', + ]); + } +} diff --git a/website/tests/Feature/ExampleTest.php b/website/tests/Feature/ExampleTest.php new file mode 100644 index 0000000..8364a84 --- /dev/null +++ b/website/tests/Feature/ExampleTest.php @@ -0,0 +1,19 @@ +get('/'); + + $response->assertStatus(200); + } +} diff --git a/website/tests/Feature/ProfileTest.php b/website/tests/Feature/ProfileTest.php new file mode 100644 index 0000000..a01d43d --- /dev/null +++ b/website/tests/Feature/ProfileTest.php @@ -0,0 +1,71 @@ +create(); + + $response = $this + ->actingAs($user) + ->get('/profile'); + + $response->assertOk(); + } + + public function test_profile_update(): void + { + $user = User::factory()->create(); + $response = $this->actingAs($user)->put('/profile', [ + 'name' => 'Test User', + 'username' => 'testuser', + ]); + $response->assertSessionHasNoErrors(); + $this->assertSame('Test User', $user->fresh()->name); + $this->assertSame('testuser', $user->fresh()->username); + } + + public function test_user_can_delete_their_account(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->delete('/profile', [ + 'password' => 'password', + ]); + + $response + ->assertSessionHasNoErrors() + ->assertRedirect('/'); + + $this->assertGuest(); + $this->assertNull($user->fresh()); + } + + public function test_correct_password_must_be_provided_to_delete_account(): void + { + $user = User::factory()->create(); + + $response = $this + ->actingAs($user) + ->from('/profile') + ->delete('/profile', [ + 'password' => 'wrong-password', + ]); + + $response + ->assertSessionHasErrorsIn('userDeletion', 'password') + ->assertRedirect('/profile'); + + $this->assertNotNull($user->fresh()); + } +} diff --git a/website/tests/TestCase.php b/website/tests/TestCase.php new file mode 100644 index 0000000..fe1ffc2 --- /dev/null +++ b/website/tests/TestCase.php @@ -0,0 +1,10 @@ +assertTrue(true); + } +} diff --git a/website/vite.config.js b/website/vite.config.js new file mode 100644 index 0000000..421b569 --- /dev/null +++ b/website/vite.config.js @@ -0,0 +1,11 @@ +import { defineConfig } from 'vite'; +import laravel from 'laravel-vite-plugin'; + +export default defineConfig({ + plugins: [ + laravel({ + input: ['resources/css/app.css', 'resources/js/app.js'], + refresh: true, + }), + ], +}); diff --git a/website/web/favicon.png b/website/web/favicon.png new file mode 100644 index 0000000..8aaa46a Binary files /dev/null and b/website/web/favicon.png differ diff --git a/website/web/icons/Icon-192.png b/website/web/icons/Icon-192.png new file mode 100644 index 0000000..b749bfe Binary files /dev/null and b/website/web/icons/Icon-192.png differ diff --git a/website/web/icons/Icon-512.png b/website/web/icons/Icon-512.png new file mode 100644 index 0000000..88cfd48 Binary files /dev/null and b/website/web/icons/Icon-512.png differ diff --git a/website/web/icons/Icon-maskable-192.png b/website/web/icons/Icon-maskable-192.png new file mode 100644 index 0000000..eb9b4d7 Binary files /dev/null and b/website/web/icons/Icon-maskable-192.png differ diff --git a/website/web/icons/Icon-maskable-512.png b/website/web/icons/Icon-maskable-512.png new file mode 100644 index 0000000..d69c566 Binary files /dev/null and b/website/web/icons/Icon-maskable-512.png differ diff --git a/website/web/index.html b/website/web/index.html new file mode 100644 index 0000000..e6e0cf8 --- /dev/null +++ b/website/web/index.html @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + monitoring + + + + + + diff --git a/website/web/manifest.json b/website/web/manifest.json new file mode 100644 index 0000000..8b1b984 --- /dev/null +++ b/website/web/manifest.json @@ -0,0 +1,35 @@ +{ + "name": "monitoring", + "short_name": "monitoring", + "start_url": ".", + "display": "standalone", + "background_color": "#0175C2", + "theme_color": "#0175C2", + "description": "A new Flutter project.", + "orientation": "portrait-primary", + "prefer_related_applications": false, + "icons": [ + { + "src": "icons/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "icons/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + }, + { + "src": "icons/Icon-maskable-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "maskable" + }, + { + "src": "icons/Icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/website/windows/.gitignore b/website/windows/.gitignore new file mode 100644 index 0000000..d492d0d --- /dev/null +++ b/website/windows/.gitignore @@ -0,0 +1,17 @@ +flutter/ephemeral/ + +# Visual Studio user-specific files. +*.suo +*.user +*.userosscache +*.sln.docstates + +# Visual Studio build-related files. +x64/ +x86/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ diff --git a/website/windows/CMakeLists.txt b/website/windows/CMakeLists.txt new file mode 100644 index 0000000..d3cd9f3 --- /dev/null +++ b/website/windows/CMakeLists.txt @@ -0,0 +1,108 @@ +# Project-level configuration. +cmake_minimum_required(VERSION 3.14) +project(monitoring LANGUAGES CXX) + +# The name of the executable created for the application. Change this to change +# the on-disk name of your application. +set(BINARY_NAME "monitoring") + +# Explicitly opt in to modern CMake behaviors to avoid warnings with recent +# versions of CMake. +cmake_policy(VERSION 3.14...3.25) + +# Define build configuration option. +get_property(IS_MULTICONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG) +if(IS_MULTICONFIG) + set(CMAKE_CONFIGURATION_TYPES "Debug;Profile;Release" + CACHE STRING "" FORCE) +else() + if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + set(CMAKE_BUILD_TYPE "Debug" CACHE + STRING "Flutter build mode" FORCE) + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS + "Debug" "Profile" "Release") + endif() +endif() +# Define settings for the Profile build mode. +set(CMAKE_EXE_LINKER_FLAGS_PROFILE "${CMAKE_EXE_LINKER_FLAGS_RELEASE}") +set(CMAKE_SHARED_LINKER_FLAGS_PROFILE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE}") +set(CMAKE_C_FLAGS_PROFILE "${CMAKE_C_FLAGS_RELEASE}") +set(CMAKE_CXX_FLAGS_PROFILE "${CMAKE_CXX_FLAGS_RELEASE}") + +# Use Unicode for all projects. +add_definitions(-DUNICODE -D_UNICODE) + +# Compilation settings that should be applied to most targets. +# +# Be cautious about adding new options here, as plugins use this function by +# default. In most cases, you should add new options to specific targets instead +# of modifying this function. +function(APPLY_STANDARD_SETTINGS TARGET) + target_compile_features(${TARGET} PUBLIC cxx_std_17) + target_compile_options(${TARGET} PRIVATE /W4 /WX /wd"4100") + target_compile_options(${TARGET} PRIVATE /EHsc) + target_compile_definitions(${TARGET} PRIVATE "_HAS_EXCEPTIONS=0") + target_compile_definitions(${TARGET} PRIVATE "$<$:_DEBUG>") +endfunction() + +# Flutter library and tool build rules. +set(FLUTTER_MANAGED_DIR "${CMAKE_CURRENT_SOURCE_DIR}/flutter") +add_subdirectory(${FLUTTER_MANAGED_DIR}) + +# Application build; see runner/CMakeLists.txt. +add_subdirectory("runner") + + +# Generated plugin build rules, which manage building the plugins and adding +# them to the application. +include(flutter/generated_plugins.cmake) + + +# === Installation === +# Support files are copied into place next to the executable, so that it can +# run in place. This is done instead of making a separate bundle (as on Linux) +# so that building and running from within Visual Studio will work. +set(BUILD_BUNDLE_DIR "$") +# Make the "install" step default, as it's required to run. +set(CMAKE_VS_INCLUDE_INSTALL_TO_DEFAULT_BUILD 1) +if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) + set(CMAKE_INSTALL_PREFIX "${BUILD_BUNDLE_DIR}" CACHE PATH "..." FORCE) +endif() + +set(INSTALL_BUNDLE_DATA_DIR "${CMAKE_INSTALL_PREFIX}/data") +set(INSTALL_BUNDLE_LIB_DIR "${CMAKE_INSTALL_PREFIX}") + +install(TARGETS ${BINARY_NAME} RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_ICU_DATA_FILE}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + COMPONENT Runtime) + +install(FILES "${FLUTTER_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +if(PLUGIN_BUNDLED_LIBRARIES) + install(FILES "${PLUGIN_BUNDLED_LIBRARIES}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) +endif() + +# Copy the native assets provided by the build.dart from all packages. +set(NATIVE_ASSETS_DIR "${PROJECT_BUILD_DIR}native_assets/windows/") +install(DIRECTORY "${NATIVE_ASSETS_DIR}" + DESTINATION "${INSTALL_BUNDLE_LIB_DIR}" + COMPONENT Runtime) + +# Fully re-copy the assets directory on each build to avoid having stale files +# from a previous install. +set(FLUTTER_ASSET_DIR_NAME "flutter_assets") +install(CODE " + file(REMOVE_RECURSE \"${INSTALL_BUNDLE_DATA_DIR}/${FLUTTER_ASSET_DIR_NAME}\") + " COMPONENT Runtime) +install(DIRECTORY "${PROJECT_BUILD_DIR}/${FLUTTER_ASSET_DIR_NAME}" + DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" COMPONENT Runtime) + +# Install the AOT library on non-Debug builds only. +install(FILES "${AOT_LIBRARY}" DESTINATION "${INSTALL_BUNDLE_DATA_DIR}" + CONFIGURATIONS Profile;Release + COMPONENT Runtime) diff --git a/website/windows/flutter/CMakeLists.txt b/website/windows/flutter/CMakeLists.txt new file mode 100644 index 0000000..903f489 --- /dev/null +++ b/website/windows/flutter/CMakeLists.txt @@ -0,0 +1,109 @@ +# This file controls Flutter-level build steps. It should not be edited. +cmake_minimum_required(VERSION 3.14) + +set(EPHEMERAL_DIR "${CMAKE_CURRENT_SOURCE_DIR}/ephemeral") + +# Configuration provided via flutter tool. +include(${EPHEMERAL_DIR}/generated_config.cmake) + +# TODO: Move the rest of this into files in ephemeral. See +# https://github.com/flutter/flutter/issues/57146. +set(WRAPPER_ROOT "${EPHEMERAL_DIR}/cpp_client_wrapper") + +# Set fallback configurations for older versions of the flutter tool. +if (NOT DEFINED FLUTTER_TARGET_PLATFORM) + set(FLUTTER_TARGET_PLATFORM "windows-x64") +endif() + +# === Flutter Library === +set(FLUTTER_LIBRARY "${EPHEMERAL_DIR}/flutter_windows.dll") + +# Published to parent scope for install step. +set(FLUTTER_LIBRARY ${FLUTTER_LIBRARY} PARENT_SCOPE) +set(FLUTTER_ICU_DATA_FILE "${EPHEMERAL_DIR}/icudtl.dat" PARENT_SCOPE) +set(PROJECT_BUILD_DIR "${PROJECT_DIR}/build/" PARENT_SCOPE) +set(AOT_LIBRARY "${PROJECT_DIR}/build/windows/app.so" PARENT_SCOPE) + +list(APPEND FLUTTER_LIBRARY_HEADERS + "flutter_export.h" + "flutter_windows.h" + "flutter_messenger.h" + "flutter_plugin_registrar.h" + "flutter_texture_registrar.h" +) +list(TRANSFORM FLUTTER_LIBRARY_HEADERS PREPEND "${EPHEMERAL_DIR}/") +add_library(flutter INTERFACE) +target_include_directories(flutter INTERFACE + "${EPHEMERAL_DIR}" +) +target_link_libraries(flutter INTERFACE "${FLUTTER_LIBRARY}.lib") +add_dependencies(flutter flutter_assemble) + +# === Wrapper === +list(APPEND CPP_WRAPPER_SOURCES_CORE + "core_implementations.cc" + "standard_codec.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_CORE PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_PLUGIN + "plugin_registrar.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_PLUGIN PREPEND "${WRAPPER_ROOT}/") +list(APPEND CPP_WRAPPER_SOURCES_APP + "flutter_engine.cc" + "flutter_view_controller.cc" +) +list(TRANSFORM CPP_WRAPPER_SOURCES_APP PREPEND "${WRAPPER_ROOT}/") + +# Wrapper sources needed for a plugin. +add_library(flutter_wrapper_plugin STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} +) +apply_standard_settings(flutter_wrapper_plugin) +set_target_properties(flutter_wrapper_plugin PROPERTIES + POSITION_INDEPENDENT_CODE ON) +set_target_properties(flutter_wrapper_plugin PROPERTIES + CXX_VISIBILITY_PRESET hidden) +target_link_libraries(flutter_wrapper_plugin PUBLIC flutter) +target_include_directories(flutter_wrapper_plugin PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_plugin flutter_assemble) + +# Wrapper sources needed for the runner. +add_library(flutter_wrapper_app STATIC + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_APP} +) +apply_standard_settings(flutter_wrapper_app) +target_link_libraries(flutter_wrapper_app PUBLIC flutter) +target_include_directories(flutter_wrapper_app PUBLIC + "${WRAPPER_ROOT}/include" +) +add_dependencies(flutter_wrapper_app flutter_assemble) + +# === Flutter tool backend === +# _phony_ is a non-existent file to force this command to run every time, +# since currently there's no way to get a full input/output list from the +# flutter tool. +set(PHONY_OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/_phony_") +set_source_files_properties("${PHONY_OUTPUT}" PROPERTIES SYMBOLIC TRUE) +add_custom_command( + OUTPUT ${FLUTTER_LIBRARY} ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} + ${PHONY_OUTPUT} + COMMAND ${CMAKE_COMMAND} -E env + ${FLUTTER_TOOL_ENVIRONMENT} + "${FLUTTER_ROOT}/packages/flutter_tools/bin/tool_backend.bat" + ${FLUTTER_TARGET_PLATFORM} $ + VERBATIM +) +add_custom_target(flutter_assemble DEPENDS + "${FLUTTER_LIBRARY}" + ${FLUTTER_LIBRARY_HEADERS} + ${CPP_WRAPPER_SOURCES_CORE} + ${CPP_WRAPPER_SOURCES_PLUGIN} + ${CPP_WRAPPER_SOURCES_APP} +) diff --git a/website/windows/flutter/generated_plugin_registrant.cc b/website/windows/flutter/generated_plugin_registrant.cc new file mode 100644 index 0000000..602b168 --- /dev/null +++ b/website/windows/flutter/generated_plugin_registrant.cc @@ -0,0 +1,20 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#include "generated_plugin_registrant.h" + +#include +#include +#include + +void RegisterPlugins(flutter::PluginRegistry* registry) { + FileSelectorWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FileSelectorWindows")); + FlutterSecureStorageWindowsPluginRegisterWithRegistrar( + registry->GetRegistrarForPlugin("FlutterSecureStorageWindowsPlugin")); + UrlLauncherWindowsRegisterWithRegistrar( + registry->GetRegistrarForPlugin("UrlLauncherWindows")); +} diff --git a/website/windows/flutter/generated_plugin_registrant.h b/website/windows/flutter/generated_plugin_registrant.h new file mode 100644 index 0000000..dc139d8 --- /dev/null +++ b/website/windows/flutter/generated_plugin_registrant.h @@ -0,0 +1,15 @@ +// +// Generated file. Do not edit. +// + +// clang-format off + +#ifndef GENERATED_PLUGIN_REGISTRANT_ +#define GENERATED_PLUGIN_REGISTRANT_ + +#include + +// Registers Flutter plugins. +void RegisterPlugins(flutter::PluginRegistry* registry); + +#endif // GENERATED_PLUGIN_REGISTRANT_ diff --git a/website/windows/flutter/generated_plugins.cmake b/website/windows/flutter/generated_plugins.cmake new file mode 100644 index 0000000..b918cf8 --- /dev/null +++ b/website/windows/flutter/generated_plugins.cmake @@ -0,0 +1,26 @@ +# +# Generated file, do not edit. +# + +list(APPEND FLUTTER_PLUGIN_LIST + file_selector_windows + flutter_secure_storage_windows + url_launcher_windows +) + +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + +set(PLUGIN_BUNDLED_LIBRARIES) + +foreach(plugin ${FLUTTER_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${plugin}/windows plugins/${plugin}) + target_link_libraries(${BINARY_NAME} PRIVATE ${plugin}_plugin) + list(APPEND PLUGIN_BUNDLED_LIBRARIES $) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) +endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin) diff --git a/website/windows/runner/CMakeLists.txt b/website/windows/runner/CMakeLists.txt new file mode 100644 index 0000000..394917c --- /dev/null +++ b/website/windows/runner/CMakeLists.txt @@ -0,0 +1,40 @@ +cmake_minimum_required(VERSION 3.14) +project(runner LANGUAGES CXX) + +# Define the application target. To change its name, change BINARY_NAME in the +# top-level CMakeLists.txt, not the value here, or `flutter run` will no longer +# work. +# +# Any new source files that you add to the application should be added here. +add_executable(${BINARY_NAME} WIN32 + "flutter_window.cpp" + "main.cpp" + "utils.cpp" + "win32_window.cpp" + "${FLUTTER_MANAGED_DIR}/generated_plugin_registrant.cc" + "Runner.rc" + "runner.exe.manifest" +) + +# Apply the standard set of build settings. This can be removed for applications +# that need different build settings. +apply_standard_settings(${BINARY_NAME}) + +# Add preprocessor definitions for the build version. +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION=\"${FLUTTER_VERSION}\"") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MAJOR=${FLUTTER_VERSION_MAJOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_MINOR=${FLUTTER_VERSION_MINOR}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_PATCH=${FLUTTER_VERSION_PATCH}") +target_compile_definitions(${BINARY_NAME} PRIVATE "FLUTTER_VERSION_BUILD=${FLUTTER_VERSION_BUILD}") + +# Disable Windows macros that collide with C++ standard library functions. +target_compile_definitions(${BINARY_NAME} PRIVATE "NOMINMAX") + +# Add dependency libraries and include directories. Add any application-specific +# dependencies here. +target_link_libraries(${BINARY_NAME} PRIVATE flutter flutter_wrapper_app) +target_link_libraries(${BINARY_NAME} PRIVATE "dwmapi.lib") +target_include_directories(${BINARY_NAME} PRIVATE "${CMAKE_SOURCE_DIR}") + +# Run the Flutter tool portions of the build. This must not be removed. +add_dependencies(${BINARY_NAME} flutter_assemble) diff --git a/website/windows/runner/Runner.rc b/website/windows/runner/Runner.rc new file mode 100644 index 0000000..102e3b8 --- /dev/null +++ b/website/windows/runner/Runner.rc @@ -0,0 +1,121 @@ +// Microsoft Visual C++ generated resource script. +// +#pragma code_page(65001) +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (United States) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""winres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_APP_ICON ICON "resources\\app_icon.ico" + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +#if defined(FLUTTER_VERSION_MAJOR) && defined(FLUTTER_VERSION_MINOR) && defined(FLUTTER_VERSION_PATCH) && defined(FLUTTER_VERSION_BUILD) +#define VERSION_AS_NUMBER FLUTTER_VERSION_MAJOR,FLUTTER_VERSION_MINOR,FLUTTER_VERSION_PATCH,FLUTTER_VERSION_BUILD +#else +#define VERSION_AS_NUMBER 1,0,0,0 +#endif + +#if defined(FLUTTER_VERSION) +#define VERSION_AS_STRING FLUTTER_VERSION +#else +#define VERSION_AS_STRING "1.0.0" +#endif + +VS_VERSION_INFO VERSIONINFO + FILEVERSION VERSION_AS_NUMBER + PRODUCTVERSION VERSION_AS_NUMBER + FILEFLAGSMASK VS_FFI_FILEFLAGSMASK +#ifdef _DEBUG + FILEFLAGS VS_FF_DEBUG +#else + FILEFLAGS 0x0L +#endif + FILEOS VOS__WINDOWS32 + FILETYPE VFT_APP + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904e4" + BEGIN + VALUE "CompanyName", "com.example" "\0" + VALUE "FileDescription", "monitoring" "\0" + VALUE "FileVersion", VERSION_AS_STRING "\0" + VALUE "InternalName", "monitoring" "\0" + VALUE "LegalCopyright", "Copyright (C) 2025 com.example. All rights reserved." "\0" + VALUE "OriginalFilename", "monitoring.exe" "\0" + VALUE "ProductName", "monitoring" "\0" + VALUE "ProductVersion", VERSION_AS_STRING "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1252 + END +END + +#endif // English (United States) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED diff --git a/website/windows/runner/flutter_window.cpp b/website/windows/runner/flutter_window.cpp new file mode 100644 index 0000000..955ee30 --- /dev/null +++ b/website/windows/runner/flutter_window.cpp @@ -0,0 +1,71 @@ +#include "flutter_window.h" + +#include + +#include "flutter/generated_plugin_registrant.h" + +FlutterWindow::FlutterWindow(const flutter::DartProject& project) + : project_(project) {} + +FlutterWindow::~FlutterWindow() {} + +bool FlutterWindow::OnCreate() { + if (!Win32Window::OnCreate()) { + return false; + } + + RECT frame = GetClientArea(); + + // The size here must match the window dimensions to avoid unnecessary surface + // creation / destruction in the startup path. + flutter_controller_ = std::make_unique( + frame.right - frame.left, frame.bottom - frame.top, project_); + // Ensure that basic setup of the controller was successful. + if (!flutter_controller_->engine() || !flutter_controller_->view()) { + return false; + } + RegisterPlugins(flutter_controller_->engine()); + SetChildContent(flutter_controller_->view()->GetNativeWindow()); + + flutter_controller_->engine()->SetNextFrameCallback([&]() { + this->Show(); + }); + + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + + return true; +} + +void FlutterWindow::OnDestroy() { + if (flutter_controller_) { + flutter_controller_ = nullptr; + } + + Win32Window::OnDestroy(); +} + +LRESULT +FlutterWindow::MessageHandler(HWND hwnd, UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + // Give Flutter, including plugins, an opportunity to handle window messages. + if (flutter_controller_) { + std::optional result = + flutter_controller_->HandleTopLevelWindowProc(hwnd, message, wparam, + lparam); + if (result) { + return *result; + } + } + + switch (message) { + case WM_FONTCHANGE: + flutter_controller_->engine()->ReloadSystemFonts(); + break; + } + + return Win32Window::MessageHandler(hwnd, message, wparam, lparam); +} diff --git a/website/windows/runner/flutter_window.h b/website/windows/runner/flutter_window.h new file mode 100644 index 0000000..6da0652 --- /dev/null +++ b/website/windows/runner/flutter_window.h @@ -0,0 +1,33 @@ +#ifndef RUNNER_FLUTTER_WINDOW_H_ +#define RUNNER_FLUTTER_WINDOW_H_ + +#include +#include + +#include + +#include "win32_window.h" + +// A window that does nothing but host a Flutter view. +class FlutterWindow : public Win32Window { + public: + // Creates a new FlutterWindow hosting a Flutter view running |project|. + explicit FlutterWindow(const flutter::DartProject& project); + virtual ~FlutterWindow(); + + protected: + // Win32Window: + bool OnCreate() override; + void OnDestroy() override; + LRESULT MessageHandler(HWND window, UINT const message, WPARAM const wparam, + LPARAM const lparam) noexcept override; + + private: + // The project to run. + flutter::DartProject project_; + + // The Flutter instance hosted by this window. + std::unique_ptr flutter_controller_; +}; + +#endif // RUNNER_FLUTTER_WINDOW_H_ diff --git a/website/windows/runner/main.cpp b/website/windows/runner/main.cpp new file mode 100644 index 0000000..62a1397 --- /dev/null +++ b/website/windows/runner/main.cpp @@ -0,0 +1,43 @@ +#include +#include +#include + +#include "flutter_window.h" +#include "utils.h" + +int APIENTRY wWinMain(_In_ HINSTANCE instance, _In_opt_ HINSTANCE prev, + _In_ wchar_t *command_line, _In_ int show_command) { + // Attach to console when present (e.g., 'flutter run') or create a + // new console when running with a debugger. + if (!::AttachConsole(ATTACH_PARENT_PROCESS) && ::IsDebuggerPresent()) { + CreateAndAttachConsole(); + } + + // Initialize COM, so that it is available for use in the library and/or + // plugins. + ::CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); + + flutter::DartProject project(L"data"); + + std::vector command_line_arguments = + GetCommandLineArguments(); + + project.set_dart_entrypoint_arguments(std::move(command_line_arguments)); + + FlutterWindow window(project); + Win32Window::Point origin(10, 10); + Win32Window::Size size(1280, 720); + if (!window.Create(L"monitoring", origin, size)) { + return EXIT_FAILURE; + } + window.SetQuitOnClose(true); + + ::MSG msg; + while (::GetMessage(&msg, nullptr, 0, 0)) { + ::TranslateMessage(&msg); + ::DispatchMessage(&msg); + } + + ::CoUninitialize(); + return EXIT_SUCCESS; +} diff --git a/website/windows/runner/resource.h b/website/windows/runner/resource.h new file mode 100644 index 0000000..66a65d1 --- /dev/null +++ b/website/windows/runner/resource.h @@ -0,0 +1,16 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by Runner.rc +// +#define IDI_APP_ICON 101 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/website/windows/runner/resources/app_icon.ico b/website/windows/runner/resources/app_icon.ico new file mode 100644 index 0000000..c04e20c Binary files /dev/null and b/website/windows/runner/resources/app_icon.ico differ diff --git a/website/windows/runner/runner.exe.manifest b/website/windows/runner/runner.exe.manifest new file mode 100644 index 0000000..153653e --- /dev/null +++ b/website/windows/runner/runner.exe.manifest @@ -0,0 +1,14 @@ + + + + + PerMonitorV2 + + + + + + + + + diff --git a/website/windows/runner/utils.cpp b/website/windows/runner/utils.cpp new file mode 100644 index 0000000..3a0b465 --- /dev/null +++ b/website/windows/runner/utils.cpp @@ -0,0 +1,65 @@ +#include "utils.h" + +#include +#include +#include +#include + +#include + +void CreateAndAttachConsole() { + if (::AllocConsole()) { + FILE *unused; + if (freopen_s(&unused, "CONOUT$", "w", stdout)) { + _dup2(_fileno(stdout), 1); + } + if (freopen_s(&unused, "CONOUT$", "w", stderr)) { + _dup2(_fileno(stdout), 2); + } + std::ios::sync_with_stdio(); + FlutterDesktopResyncOutputStreams(); + } +} + +std::vector GetCommandLineArguments() { + // Convert the UTF-16 command line arguments to UTF-8 for the Engine to use. + int argc; + wchar_t** argv = ::CommandLineToArgvW(::GetCommandLineW(), &argc); + if (argv == nullptr) { + return std::vector(); + } + + std::vector command_line_arguments; + + // Skip the first argument as it's the binary name. + for (int i = 1; i < argc; i++) { + command_line_arguments.push_back(Utf8FromUtf16(argv[i])); + } + + ::LocalFree(argv); + + return command_line_arguments; +} + +std::string Utf8FromUtf16(const wchar_t* utf16_string) { + if (utf16_string == nullptr) { + return std::string(); + } + unsigned int target_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + -1, nullptr, 0, nullptr, nullptr) + -1; // remove the trailing null character + int input_length = (int)wcslen(utf16_string); + std::string utf8_string; + if (target_length == 0 || target_length > utf8_string.max_size()) { + return utf8_string; + } + utf8_string.resize(target_length); + int converted_length = ::WideCharToMultiByte( + CP_UTF8, WC_ERR_INVALID_CHARS, utf16_string, + input_length, utf8_string.data(), target_length, nullptr, nullptr); + if (converted_length == 0) { + return std::string(); + } + return utf8_string; +} diff --git a/website/windows/runner/utils.h b/website/windows/runner/utils.h new file mode 100644 index 0000000..3879d54 --- /dev/null +++ b/website/windows/runner/utils.h @@ -0,0 +1,19 @@ +#ifndef RUNNER_UTILS_H_ +#define RUNNER_UTILS_H_ + +#include +#include + +// Creates a console for the process, and redirects stdout and stderr to +// it for both the runner and the Flutter library. +void CreateAndAttachConsole(); + +// Takes a null-terminated wchar_t* encoded in UTF-16 and returns a std::string +// encoded in UTF-8. Returns an empty std::string on failure. +std::string Utf8FromUtf16(const wchar_t* utf16_string); + +// Gets the command line arguments passed in as a std::vector, +// encoded in UTF-8. Returns an empty std::vector on failure. +std::vector GetCommandLineArguments(); + +#endif // RUNNER_UTILS_H_ diff --git a/website/windows/runner/win32_window.cpp b/website/windows/runner/win32_window.cpp new file mode 100644 index 0000000..60608d0 --- /dev/null +++ b/website/windows/runner/win32_window.cpp @@ -0,0 +1,288 @@ +#include "win32_window.h" + +#include +#include + +#include "resource.h" + +namespace { + +/// Window attribute that enables dark mode window decorations. +/// +/// Redefined in case the developer's machine has a Windows SDK older than +/// version 10.0.22000.0. +/// See: https://docs.microsoft.com/windows/win32/api/dwmapi/ne-dwmapi-dwmwindowattribute +#ifndef DWMWA_USE_IMMERSIVE_DARK_MODE +#define DWMWA_USE_IMMERSIVE_DARK_MODE 20 +#endif + +constexpr const wchar_t kWindowClassName[] = L"FLUTTER_RUNNER_WIN32_WINDOW"; + +/// Registry key for app theme preference. +/// +/// A value of 0 indicates apps should use dark mode. A non-zero or missing +/// value indicates apps should use light mode. +constexpr const wchar_t kGetPreferredBrightnessRegKey[] = + L"Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"; +constexpr const wchar_t kGetPreferredBrightnessRegValue[] = L"AppsUseLightTheme"; + +// The number of Win32Window objects that currently exist. +static int g_active_window_count = 0; + +using EnableNonClientDpiScaling = BOOL __stdcall(HWND hwnd); + +// Scale helper to convert logical scaler values to physical using passed in +// scale factor +int Scale(int source, double scale_factor) { + return static_cast(source * scale_factor); +} + +// Dynamically loads the |EnableNonClientDpiScaling| from the User32 module. +// This API is only needed for PerMonitor V1 awareness mode. +void EnableFullDpiSupportIfAvailable(HWND hwnd) { + HMODULE user32_module = LoadLibraryA("User32.dll"); + if (!user32_module) { + return; + } + auto enable_non_client_dpi_scaling = + reinterpret_cast( + GetProcAddress(user32_module, "EnableNonClientDpiScaling")); + if (enable_non_client_dpi_scaling != nullptr) { + enable_non_client_dpi_scaling(hwnd); + } + FreeLibrary(user32_module); +} + +} // namespace + +// Manages the Win32Window's window class registration. +class WindowClassRegistrar { + public: + ~WindowClassRegistrar() = default; + + // Returns the singleton registrar instance. + static WindowClassRegistrar* GetInstance() { + if (!instance_) { + instance_ = new WindowClassRegistrar(); + } + return instance_; + } + + // Returns the name of the window class, registering the class if it hasn't + // previously been registered. + const wchar_t* GetWindowClass(); + + // Unregisters the window class. Should only be called if there are no + // instances of the window. + void UnregisterWindowClass(); + + private: + WindowClassRegistrar() = default; + + static WindowClassRegistrar* instance_; + + bool class_registered_ = false; +}; + +WindowClassRegistrar* WindowClassRegistrar::instance_ = nullptr; + +const wchar_t* WindowClassRegistrar::GetWindowClass() { + if (!class_registered_) { + WNDCLASS window_class{}; + window_class.hCursor = LoadCursor(nullptr, IDC_ARROW); + window_class.lpszClassName = kWindowClassName; + window_class.style = CS_HREDRAW | CS_VREDRAW; + window_class.cbClsExtra = 0; + window_class.cbWndExtra = 0; + window_class.hInstance = GetModuleHandle(nullptr); + window_class.hIcon = + LoadIcon(window_class.hInstance, MAKEINTRESOURCE(IDI_APP_ICON)); + window_class.hbrBackground = 0; + window_class.lpszMenuName = nullptr; + window_class.lpfnWndProc = Win32Window::WndProc; + RegisterClass(&window_class); + class_registered_ = true; + } + return kWindowClassName; +} + +void WindowClassRegistrar::UnregisterWindowClass() { + UnregisterClass(kWindowClassName, nullptr); + class_registered_ = false; +} + +Win32Window::Win32Window() { + ++g_active_window_count; +} + +Win32Window::~Win32Window() { + --g_active_window_count; + Destroy(); +} + +bool Win32Window::Create(const std::wstring& title, + const Point& origin, + const Size& size) { + Destroy(); + + const wchar_t* window_class = + WindowClassRegistrar::GetInstance()->GetWindowClass(); + + const POINT target_point = {static_cast(origin.x), + static_cast(origin.y)}; + HMONITOR monitor = MonitorFromPoint(target_point, MONITOR_DEFAULTTONEAREST); + UINT dpi = FlutterDesktopGetDpiForMonitor(monitor); + double scale_factor = dpi / 96.0; + + HWND window = CreateWindow( + window_class, title.c_str(), WS_OVERLAPPEDWINDOW, + Scale(origin.x, scale_factor), Scale(origin.y, scale_factor), + Scale(size.width, scale_factor), Scale(size.height, scale_factor), + nullptr, nullptr, GetModuleHandle(nullptr), this); + + if (!window) { + return false; + } + + UpdateTheme(window); + + return OnCreate(); +} + +bool Win32Window::Show() { + return ShowWindow(window_handle_, SW_SHOWNORMAL); +} + +// static +LRESULT CALLBACK Win32Window::WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + if (message == WM_NCCREATE) { + auto window_struct = reinterpret_cast(lparam); + SetWindowLongPtr(window, GWLP_USERDATA, + reinterpret_cast(window_struct->lpCreateParams)); + + auto that = static_cast(window_struct->lpCreateParams); + EnableFullDpiSupportIfAvailable(window); + that->window_handle_ = window; + } else if (Win32Window* that = GetThisFromHandle(window)) { + return that->MessageHandler(window, message, wparam, lparam); + } + + return DefWindowProc(window, message, wparam, lparam); +} + +LRESULT +Win32Window::MessageHandler(HWND hwnd, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept { + switch (message) { + case WM_DESTROY: + window_handle_ = nullptr; + Destroy(); + if (quit_on_close_) { + PostQuitMessage(0); + } + return 0; + + case WM_DPICHANGED: { + auto newRectSize = reinterpret_cast(lparam); + LONG newWidth = newRectSize->right - newRectSize->left; + LONG newHeight = newRectSize->bottom - newRectSize->top; + + SetWindowPos(hwnd, nullptr, newRectSize->left, newRectSize->top, newWidth, + newHeight, SWP_NOZORDER | SWP_NOACTIVATE); + + return 0; + } + case WM_SIZE: { + RECT rect = GetClientArea(); + if (child_content_ != nullptr) { + // Size and position the child window. + MoveWindow(child_content_, rect.left, rect.top, rect.right - rect.left, + rect.bottom - rect.top, TRUE); + } + return 0; + } + + case WM_ACTIVATE: + if (child_content_ != nullptr) { + SetFocus(child_content_); + } + return 0; + + case WM_DWMCOLORIZATIONCOLORCHANGED: + UpdateTheme(hwnd); + return 0; + } + + return DefWindowProc(window_handle_, message, wparam, lparam); +} + +void Win32Window::Destroy() { + OnDestroy(); + + if (window_handle_) { + DestroyWindow(window_handle_); + window_handle_ = nullptr; + } + if (g_active_window_count == 0) { + WindowClassRegistrar::GetInstance()->UnregisterWindowClass(); + } +} + +Win32Window* Win32Window::GetThisFromHandle(HWND const window) noexcept { + return reinterpret_cast( + GetWindowLongPtr(window, GWLP_USERDATA)); +} + +void Win32Window::SetChildContent(HWND content) { + child_content_ = content; + SetParent(content, window_handle_); + RECT frame = GetClientArea(); + + MoveWindow(content, frame.left, frame.top, frame.right - frame.left, + frame.bottom - frame.top, true); + + SetFocus(child_content_); +} + +RECT Win32Window::GetClientArea() { + RECT frame; + GetClientRect(window_handle_, &frame); + return frame; +} + +HWND Win32Window::GetHandle() { + return window_handle_; +} + +void Win32Window::SetQuitOnClose(bool quit_on_close) { + quit_on_close_ = quit_on_close; +} + +bool Win32Window::OnCreate() { + // No-op; provided for subclasses. + return true; +} + +void Win32Window::OnDestroy() { + // No-op; provided for subclasses. +} + +void Win32Window::UpdateTheme(HWND const window) { + DWORD light_mode; + DWORD light_mode_size = sizeof(light_mode); + LSTATUS result = RegGetValue(HKEY_CURRENT_USER, kGetPreferredBrightnessRegKey, + kGetPreferredBrightnessRegValue, + RRF_RT_REG_DWORD, nullptr, &light_mode, + &light_mode_size); + + if (result == ERROR_SUCCESS) { + BOOL enable_dark_mode = light_mode == 0; + DwmSetWindowAttribute(window, DWMWA_USE_IMMERSIVE_DARK_MODE, + &enable_dark_mode, sizeof(enable_dark_mode)); + } +} diff --git a/website/windows/runner/win32_window.h b/website/windows/runner/win32_window.h new file mode 100644 index 0000000..e901dde --- /dev/null +++ b/website/windows/runner/win32_window.h @@ -0,0 +1,102 @@ +#ifndef RUNNER_WIN32_WINDOW_H_ +#define RUNNER_WIN32_WINDOW_H_ + +#include + +#include +#include +#include + +// A class abstraction for a high DPI-aware Win32 Window. Intended to be +// inherited from by classes that wish to specialize with custom +// rendering and input handling +class Win32Window { + public: + struct Point { + unsigned int x; + unsigned int y; + Point(unsigned int x, unsigned int y) : x(x), y(y) {} + }; + + struct Size { + unsigned int width; + unsigned int height; + Size(unsigned int width, unsigned int height) + : width(width), height(height) {} + }; + + Win32Window(); + virtual ~Win32Window(); + + // Creates a win32 window with |title| that is positioned and sized using + // |origin| and |size|. New windows are created on the default monitor. Window + // sizes are specified to the OS in physical pixels, hence to ensure a + // consistent size this function will scale the inputted width and height as + // as appropriate for the default monitor. The window is invisible until + // |Show| is called. Returns true if the window was created successfully. + bool Create(const std::wstring& title, const Point& origin, const Size& size); + + // Show the current window. Returns true if the window was successfully shown. + bool Show(); + + // Release OS resources associated with window. + void Destroy(); + + // Inserts |content| into the window tree. + void SetChildContent(HWND content); + + // Returns the backing Window handle to enable clients to set icon and other + // window properties. Returns nullptr if the window has been destroyed. + HWND GetHandle(); + + // If true, closing this window will quit the application. + void SetQuitOnClose(bool quit_on_close); + + // Return a RECT representing the bounds of the current client area. + RECT GetClientArea(); + + protected: + // Processes and route salient window messages for mouse handling, + // size change and DPI. Delegates handling of these to member overloads that + // inheriting classes can handle. + virtual LRESULT MessageHandler(HWND window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Called when CreateAndShow is called, allowing subclass window-related + // setup. Subclasses should return false if setup fails. + virtual bool OnCreate(); + + // Called when Destroy is called. + virtual void OnDestroy(); + + private: + friend class WindowClassRegistrar; + + // OS callback called by message pump. Handles the WM_NCCREATE message which + // is passed when the non-client area is being created and enables automatic + // non-client DPI scaling so that the non-client area automatically + // responds to changes in DPI. All other messages are handled by + // MessageHandler. + static LRESULT CALLBACK WndProc(HWND const window, + UINT const message, + WPARAM const wparam, + LPARAM const lparam) noexcept; + + // Retrieves a class instance pointer for |window| + static Win32Window* GetThisFromHandle(HWND const window) noexcept; + + // Update the window frame's theme to match the system theme. + static void UpdateTheme(HWND const window); + + bool quit_on_close_ = false; + + // window handle for top level window. + HWND window_handle_ = nullptr; + + // window handle for hosted content. + HWND child_content_ = nullptr; +}; + +#endif // RUNNER_WIN32_WINDOW_H_