diff --git a/.all-contributorsrc b/.all-contributorsrc index b91e5afeb0..5b730fb705 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -3206,7 +3206,8 @@ "avatar_url": "https://avatars.githubusercontent.com/u/3755203?v=4", "profile": "https://github.com/swift2512", "contributions": [ - "bug" + "bug", + "code" ] }, { @@ -4198,6 +4199,42 @@ "contributions": [ "code" ] + }, + { + "login": "FlorestanII", + "name": "Johannes Pollitt", + "avatar_url": "https://avatars.githubusercontent.com/u/15015119?v=4", + "profile": "https://github.com/FlorestanII", + "contributions": [ + "code" + ] + }, + { + "login": "strobelm", + "name": "Michael Strobel", + "avatar_url": "https://avatars.githubusercontent.com/u/14185442?v=4", + "profile": "https://strobelm.de", + "contributions": [ + "code" + ] + }, + { + "login": "nickwest", + "name": "Nicky West", + "avatar_url": "https://avatars.githubusercontent.com/u/634790?v=4", + "profile": "http://nickwest.me", + "contributions": [ + "code" + ] + }, + { + "login": "akaspeh1", + "name": "akaspeh1", + "avatar_url": "https://avatars.githubusercontent.com/u/1347327?v=4", + "profile": "https://github.com/akaspeh1", + "contributions": [ + "code" + ] } ] } diff --git a/.env.example b/.env.example index 61ec3295d1..6e423d4fe2 100644 --- a/.env.example +++ b/.env.example @@ -193,11 +193,17 @@ LDAP_TIME_LIM=600 IMPORT_TIME_LIMIT=600 IMPORT_MEMORY_LIMIT=500M REPORT_TIME_LIMIT=12000 -REQUIRE_SAML=false API_THROTTLE_PER_MINUTE=120 CSV_ESCAPE_FORMULAS=true LIVEWIRE_URL_PREFIX=null + +# -------------------------------------------- +# OPTIONAL: SAML SETTINGS +# -------------------------------------------- +REQUIRE_SAML=false +SAML_KEY_SIZE=2048 + # -------------------------------------------- # OPTIONAL: HASHING # -------------------------------------------- diff --git a/.github/ISSUE_TEMPLATE/Bug-Report.yml b/.github/ISSUE_TEMPLATE/Bug-Report.yml new file mode 100644 index 0000000000..523ebc5e26 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Bug-Report.yml @@ -0,0 +1,105 @@ +name: Bug Report +description: File a bug report. +title: "[Bug]: " +projects: ["grokability/snipe-it"] +type: bug +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this bug report! Most issues are documented in the [Snipe-IT repository's issues](https://github.com/grokability/snipe-it/issues) or in the official [Common Issues section of the Documentation](https://snipe-it.readme.io/docs/common-issues#/) and are due to the following: + + - `.env` misconfiguration + - [Server Permissions](https://snipe-it.readme.io/docs/debugging-permissions#/) + - [Database Migrations](https://snipe-it.readme.io/docs/database-issues#run-migrations) + + Please make sure you've checked these resources before submitting a new issue. If you find an existing issue, please add your context to it instead of opening a new issue. If your issue is more of a question, consider [opening a new discussion](https://github.com/grokability/snipe-it/discussions) or [pop by our Discord](https://discord.gg/yZFtShAcKk) instead of creating an issue. + + **Please write your bug report in English.** You can use tools like [DeepL](https://www.deepl.com) or [Google Translate](https://translate.google.com/) to translate if necessary. + + **If you choose to upload screenshots or videos (which we always encourage), please make sure they do not contain any sensitive information.** + - type: input + id: version + attributes: + label: Snipe-IT Version + description: What version of Snipe-IT are you seeing this issue on? You can find the version number in the footer of any page in Snipe-IT. + placeholder: ex. v8.3.1 - build 19577 (master) + validations: + required: true + - type: input + id: db-version + attributes: + label: MySQL/MariaDB version + description: What database are you using, and what version? + placeholder: ex. MySQL 5.7 + validations: + required: true + - type: dropdown + id: install-method + attributes: + label: How did you install Snipe-IT? + options: + - Git install + - Manual install (downloading zip/tar.gz) + - Docker + - install.sh + - Hosted by Grokability + - Other + - Not sure + validations: + required: true + - type: textarea + id: what-happened + attributes: + label: What happened? + description: Also tell us, what did you expect to happen? + placeholder: Tell us what you see! (Be nice!) + validations: + required: true + - type: dropdown + id: browsers + attributes: + label: What browsers are you seeing the problem on? + multiple: true + options: + - Firefox + - Chrome + - Safari + - Microsoft Edge + - Other + - type: textarea + id: server-logs + attributes: + label: Application log output + description: Please copy and paste any relevant log output from `storage/logs/laravel.log`. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: textarea + id: browser-logs + attributes: + label: Browser console output + description: Please copy and paste any relevant log output from your browser console. This will be automatically formatted into code, so no need for backticks. + render: shell + - type: checkboxes + id: common-issues + attributes: + label: Common Issues + description: Please make sure you have done the following before submitting your issue. + options: + - label: I have searched this repo for existing issues related to my issue (including closed issues) + required: true + - label: My APP_URL is set correctly in my .env file (including http or https and no trailing slash) + required: true + - label: I have searched the official Snipe-IT documentation and have checked the Common Issues documentation (where applicable) + required: true + - label: I have run database migrations (where applicable). + required: true + - label: I have attached screenshots and/or videos of the issue (where applicable) + required: true + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/grokability/snipe-it/blob/master/CODE_OF_CONDUCT.md). + options: + - label: I agree to follow this project's Code of Conduct + required: true diff --git a/.github/ISSUE_TEMPLATE/Feature-Request.yml b/.github/ISSUE_TEMPLATE/Feature-Request.yml new file mode 100644 index 0000000000..71aeeb35a0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/Feature-Request.yml @@ -0,0 +1,38 @@ +name: Feature Request +description: Request a new feature. +title: "[Feature]: " +projects: ["grokability/snipe-it"] +type: feature +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this feature request! Please make sure to search the existing issues in this repository to see if your feature has already been requested, and feel free to add your context to any existing requests. + + **Please write your issue in English.** You can use tools like [DeepL](https://www.deepl.com) or [Google Translate](https://translate.google.com/) to translate if necessary. + + **If you choose to upload screenshots or videos (which we always encourage), please make sure they do not contain any sensitive information.** + - type: input + id: version + attributes: + label: Snipe-IT Version + description: What version of Snipe-IT are you currently running? You can find the version number in the footer of any page in Snipe-IT. + placeholder: ex. v8.3.1 - build 19577 (master) + validations: + required: true + - type: textarea + id: feature-description + attributes: + label: How can we help? + description: Let us know in detail what feature you'd like to see added. While we can't promise to implement every feature request, we do read every one and take them into consideration when planning future releases. + placeholder: Tell us what you'd like to see in Snipe-IT! (Be nice!) + validations: + required: true + - type: checkboxes + id: terms + attributes: + label: Code of Conduct + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/grokability/snipe-it/blob/master/CODE_OF_CONDUCT.md). + options: + - label: I agree to follow this project's Code of Conduct + required: true \ No newline at end of file diff --git a/.github/workflows/SA-codeql.yml b/.github/workflows/SA-codeql.yml index 29f3e1b1f1..4730bfb38e 100644 --- a/.github/workflows/SA-codeql.yml +++ b/.github/workflows/SA-codeql.yml @@ -26,14 +26,14 @@ jobs: language: [ 'javascript' ] steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@v5 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v3 + uses: github/codeql-action/init@v4 with: languages: ${{ matrix.language }} - name: Autobuild - uses: github/codeql-action/autobuild@v3 + uses: github/codeql-action/autobuild@v4 - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 + uses: github/codeql-action/analyze@v4 diff --git a/.github/workflows/codacy-analysis.yml b/.github/workflows/codacy-analysis.yml index 32de700bdc..cbe249bf5a 100644 --- a/.github/workflows/codacy-analysis.yml +++ b/.github/workflows/codacy-analysis.yml @@ -32,7 +32,7 @@ jobs: steps: # Checkout the repository to the GitHub Actions runner - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v5 # Execute Codacy Analysis CLI and generate a SARIF output with the security issues identified during the analysis - name: Run Codacy Analysis CLI @@ -52,6 +52,6 @@ jobs: # Upload the SARIF file generated in the previous step - name: Upload SARIF results file - uses: github/codeql-action/upload-sarif@v3 + uses: github/codeql-action/upload-sarif@v4 with: sarif_file: results.sarif diff --git a/.github/workflows/crowdin-upload.yml b/.github/workflows/crowdin-upload.yml index 7b9331c97d..b2e798d562 100644 --- a/.github/workflows/crowdin-upload.yml +++ b/.github/workflows/crowdin-upload.yml @@ -9,7 +9,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v5 - name: Crowdin push uses: crowdin/github-action@v2 diff --git a/.github/workflows/docker-alpine.yml b/.github/workflows/docker-alpine.yml index 86e0c022e2..a65d48d2e2 100644 --- a/.github/workflows/docker-alpine.yml +++ b/.github/workflows/docker-alpine.yml @@ -42,7 +42,7 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v4 + uses: actions/checkout@v5 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx diff --git a/.github/workflows/docker-ubuntu.yml b/.github/workflows/docker-ubuntu.yml index a78ba7413c..c345105b7e 100644 --- a/.github/workflows/docker-ubuntu.yml +++ b/.github/workflows/docker-ubuntu.yml @@ -42,7 +42,7 @@ jobs: steps: # https://github.com/actions/checkout - name: Checkout codebase - uses: actions/checkout@v4 + uses: actions/checkout@v5 # https://github.com/docker/setup-buildx-action - name: Setup Docker Buildx diff --git a/.github/workflows/dockerhub-description.yml b/.github/workflows/dockerhub-description.yml index f9064dec95..8b5782339b 100644 --- a/.github/workflows/dockerhub-description.yml +++ b/.github/workflows/dockerhub-description.yml @@ -11,7 +11,7 @@ jobs: dockerHubDescription: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Docker Hub Description uses: grokability/dockerhub-description@7ea9d275c7cdbe2b676a093a0308c50665e3b8b4 diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 5a4042aee4..accac22485 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -11,7 +11,7 @@ jobs: issues: write # pull-requests: write steps: - - uses: actions/stale@v9 + - uses: actions/stale@v10 with: debug-only: true ascending: true diff --git a/.github/workflows/tests-mysql.yml b/.github/workflows/tests-mysql.yml index 16190900b0..bc1c9275bb 100644 --- a/.github/workflows/tests-mysql.yml +++ b/.github/workflows/tests-mysql.yml @@ -37,7 +37,7 @@ jobs: php-version: "${{ matrix.php-version }}" coverage: none - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Get Composer Cache Directory id: composer-cache @@ -76,4 +76,16 @@ jobs: DB_DATABASE: snipeit DB_PORT: ${{ job.services.mysql.ports[3306] }} DB_USERNAME: root + LOG_CHANNEL: single + LOG_LEVEL: debug run: php artisan test + + - name: Upload Laravel logs as artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }} + path: | + storage/logs/*.log + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/tests-postgres.yml b/.github/workflows/tests-postgres.yml index d111fc87a5..5d7d4d0001 100644 --- a/.github/workflows/tests-postgres.yml +++ b/.github/workflows/tests-postgres.yml @@ -34,7 +34,7 @@ jobs: php-version: "${{ matrix.php-version }}" coverage: none - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Get Composer Cache Directory id: composer-cache @@ -75,4 +75,16 @@ jobs: DB_PORT: ${{ job.services.postgresql.ports[5432] }} DB_USERNAME: snipeit DB_PASSWORD: password + LOG_CHANNEL: single + LOG_LEVEL: debug run: php artisan test + + - name: Upload Laravel logs as artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }} + path: | + storage/logs/*.log + if-no-files-found: ignore + retention-days: 7 diff --git a/.github/workflows/tests-sqlite.yml b/.github/workflows/tests-sqlite.yml index cd06805e01..e00e0f7319 100644 --- a/.github/workflows/tests-sqlite.yml +++ b/.github/workflows/tests-sqlite.yml @@ -25,7 +25,7 @@ jobs: php-version: "${{ matrix.php-version }}" coverage: none - - uses: actions/checkout@v4 + - uses: actions/checkout@v5 - name: Get Composer Cache Directory id: composer-cache @@ -61,4 +61,16 @@ jobs: - name: Execute tests (Unit and Feature tests) via PHPUnit env: DB_CONNECTION: sqlite + LOG_CHANNEL: single + LOG_LEVEL: debug run: php artisan test + + - name: Upload Laravel logs as artifacts + if: always() + uses: actions/upload-artifact@v4 + with: + name: laravel-logs-php-${{ matrix.php-version }}-run-${{ github.run_attempt }} + path: | + storage/logs/*.log + if-no-files-found: ignore + retention-days: 7 diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ed141050d5..ad29260375 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -52,7 +52,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken | [
coach1988](https://github.com/coach1988)
[💻](https://github.com/snipe/snipe-it/commits?author=coach1988 "Code") | [
MrM](https://github.com/mauro-miatello)
[💻](https://github.com/snipe/snipe-it/commits?author=mauro-miatello "Code") | [
koiakoia](https://github.com/koiakoia)
[💻](https://github.com/snipe/snipe-it/commits?author=koiakoia "Code") | [
Mustafa Online](https://github.com/mustafa-online)
[💻](https://github.com/snipe/snipe-it/commits?author=mustafa-online "Code") | [
franceslui](https://github.com/franceslui)
[💻](https://github.com/snipe/snipe-it/commits?author=franceslui "Code") | [
Q4kK](https://github.com/Q4kK)
[💻](https://github.com/snipe/snipe-it/commits?author=Q4kK "Code") | [
squintfox](https://github.com/squintfox)
[💻](https://github.com/snipe/snipe-it/commits?author=squintfox "Code") | | [
Jeff Clay](https://github.com/jeffclay)
[💻](https://github.com/snipe/snipe-it/commits?author=jeffclay "Code") | [
Phil J R](https://github.com/PP-JN-RL)
[💻](https://github.com/snipe/snipe-it/commits?author=PP-JN-RL "Code") | [
i_virus](https://www.corelight.com/)
[💻](https://github.com/snipe/snipe-it/commits?author=chandanchowdhury "Code") | [
Paul Grime](https://github.com/gitgrimbo)
[💻](https://github.com/snipe/snipe-it/commits?author=gitgrimbo "Code") | [
Lee Porte](https://leeporte.co.uk)
[💻](https://github.com/snipe/snipe-it/commits?author=LeePorte "Code") | [
BRYAN ](https://github.com/bryanlopezinc)
[💻](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Code") [⚠️](https://github.com/snipe/snipe-it/commits?author=bryanlopezinc "Tests") | [
U-H-T](https://github.com/U-H-T)
[💻](https://github.com/snipe/snipe-it/commits?author=U-H-T "Code") | | [
Matt Tyree](https://github.com/Tyree)
[📖](https://github.com/snipe/snipe-it/commits?author=Tyree "Documentation") | [
Florent Bervas](http://spoontux.net)
[💻](https://github.com/snipe/snipe-it/commits?author=FlorentDotMe "Code") | [
Daniel Albertsen](https://ditscheri.com)
[💻](https://github.com/snipe/snipe-it/commits?author=dbakan "Code") | [
r-xyz](https://github.com/r-xyz)
[💻](https://github.com/snipe/snipe-it/commits?author=r-xyz "Code") | [
Steven Mainor](https://github.com/DrekiDegga)
[💻](https://github.com/snipe/snipe-it/commits?author=DrekiDegga "Code") | [
arne-kroeger](https://github.com/arne-kroeger)
[💻](https://github.com/snipe/snipe-it/commits?author=arne-kroeger "Code") | [
Glukose1](https://github.com/Glukose1)
[💻](https://github.com/snipe/snipe-it/commits?author=Glukose1 "Code") | -| [
Scarzy](https://github.com/Scarzy)
[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [
setpill](https://github.com/setpill)
[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [
swift2512](https://github.com/swift2512)
[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") | [
Darren Rainey](https://darrenraineys.co.uk)
[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [
maciej-poleszczyk](https://github.com/maciej-poleszczyk)
[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [
Sebastian Groß](https://github.com/sgross-emlix)
[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") | [
Anouar Touati](https://github.com/AnouarTouati)
[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") | +| [
Scarzy](https://github.com/Scarzy)
[💻](https://github.com/snipe/snipe-it/commits?author=Scarzy "Code") | [
setpill](https://github.com/setpill)
[💻](https://github.com/snipe/snipe-it/commits?author=setpill "Code") | [
swift2512](https://github.com/swift2512)
[🐛](https://github.com/snipe/snipe-it/issues?q=author%3Aswift2512 "Bug reports") [💻](https://github.com/snipe/snipe-it/commits?author=swift2512 "Code") | [
Darren Rainey](https://darrenraineys.co.uk)
[💻](https://github.com/snipe/snipe-it/commits?author=DarrenRainey "Code") | [
maciej-poleszczyk](https://github.com/maciej-poleszczyk)
[💻](https://github.com/snipe/snipe-it/commits?author=maciej-poleszczyk "Code") | [
Sebastian Groß](https://github.com/sgross-emlix)
[💻](https://github.com/snipe/snipe-it/commits?author=sgross-emlix "Code") | [
Anouar Touati](https://github.com/AnouarTouati)
[💻](https://github.com/snipe/snipe-it/commits?author=AnouarTouati "Code") | | [
aHVzY2g](https://github.com/aHVzY2g)
[💻](https://github.com/snipe/snipe-it/commits?author=aHVzY2g "Code") | [
林博仁 Buo-ren Lin](https://brlin.me)
[💻](https://github.com/snipe/snipe-it/commits?author=brlin-tw "Code") | [
Adugna Gizaw](https://orbalia.pythonanywhere.com/)
[🌍](#translation-addex12 "Translation") | [
Jesse Ostrander](https://github.com/jostrander)
[💻](https://github.com/snipe/snipe-it/commits?author=jostrander "Code") | [
James M](https://github.com/azmcnutt)
[💻](https://github.com/snipe/snipe-it/commits?author=azmcnutt "Code") | [
Fiala06](https://github.com/Fiala06)
[💻](https://github.com/snipe/snipe-it/commits?author=Fiala06 "Code") | [
Nathan Taylor](https://github.com/ntaylor-86)
[💻](https://github.com/snipe/snipe-it/commits?author=ntaylor-86 "Code") | | [
fvollmer](https://github.com/fvollmer)
[💻](https://github.com/snipe/snipe-it/commits?author=fvollmer "Code") | [
36864](https://github.com/36864)
[💻](https://github.com/snipe/snipe-it/commits?author=36864 "Code") | [
Daniel O'Connor](http://clockwerx.blogspot.com/)
[💻](https://github.com/snipe/snipe-it/commits?author=CloCkWeRX "Code") | [
BeatSpark](https://github.com/BeatSpark)
[💻](https://github.com/snipe/snipe-it/commits?author=BeatSpark "Code") | [
mrdahbi](https://github.com/mrdahbi)
[💻](https://github.com/snipe/snipe-it/commits?author=mrdahbi "Code") | [
Fabian Schmid](http://sr.solutions)
[💻](https://github.com/snipe/snipe-it/commits?author=chfsx "Code") | [
Chris Olin](https://www.chrisolin.com)
[💻](https://github.com/snipe/snipe-it/commits?author=realchrisolin "Code") | | [
Dan](https://github.com/mnemonicly)
[💻](https://github.com/snipe/snipe-it/commits?author=mnemonicly "Code") | [
Nebel](https://github.com/NebelKreis)
[💻](https://github.com/snipe/snipe-it/commits?author=NebelKreis "Code") | [
test1337ahp](https://github.com/test1337ahp)
[💻](https://github.com/snipe/snipe-it/commits?author=test1337ahp "Code") | [
Jonathon Reinhart](https://github.com/JonathonReinhart)
[💻](https://github.com/snipe/snipe-it/commits?author=JonathonReinhart "Code") | [
aranar-pro](https://github.com/aranar-pro)
[💻](https://github.com/snipe/snipe-it/commits?author=aranar-pro "Code") | [
Phil](https://github.com/phil-flip)
[💻](https://github.com/snipe/snipe-it/commits?author=phil-flip "Code") | [
Steffy Fort](https://fe80.fr/)
[💻](https://github.com/snipe/snipe-it/commits?author=fe80 "Code") | @@ -68,7 +68,7 @@ Thanks goes to all of these wonderful people ([emoji key](https://github.com/ken | [
Juan Font](https://github.com/juanfont)
[💻](https://github.com/snipe/snipe-it/commits?author=juanfont "Code") | [
Juho Taipale](https://github.com/juhotaipale)
[💻](https://github.com/snipe/snipe-it/commits?author=juhotaipale "Code") | [
Korvin Szanto](https://github.com/KorvinSzanto)
[💻](https://github.com/snipe/snipe-it/commits?author=KorvinSzanto "Code") | [
Lewis Foster](https://lewisfoster.foo/)
[💻](https://github.com/snipe/snipe-it/commits?author=sniff122 "Code") | [
Logan Swartzendruber](https://github.com/loganswartz)
[💻](https://github.com/snipe/snipe-it/commits?author=loganswartz "Code") | [
Lorenzo P.](https://github.com/lopezio)
[💻](https://github.com/snipe/snipe-it/commits?author=lopezio "Code") | [
Lukas Jung](https://github.com/m4us1ne)
[💻](https://github.com/snipe/snipe-it/commits?author=m4us1ne "Code") | | [
Ellie](https://leafedfox.xyz/)
[💻](https://github.com/snipe/snipe-it/commits?author=LeafedFox "Code") | [
GA Stamper](https://github.com/gastamper)
[💻](https://github.com/snipe/snipe-it/commits?author=gastamper "Code") | [
Guillaume Lefranc](https://github.com/gl-pup)
[💻](https://github.com/snipe/snipe-it/commits?author=gl-pup "Code") | [
Hajo Möller](https://github.com/dasjoe)
[💻](https://github.com/snipe/snipe-it/commits?author=dasjoe "Code") | [
Istvan Basa](https://github.com/pottom)
[💻](https://github.com/snipe/snipe-it/commits?author=pottom "Code") | [
JJ Asghar](https://jjasghar.github.io/)
[💻](https://github.com/snipe/snipe-it/commits?author=jjasghar "Code") | [
James E. Msenga](https://github.com/JemCdo)
[💻](https://github.com/snipe/snipe-it/commits?author=JemCdo "Code") | | [
Jan Felix Wiebe](https://github.com/jfwiebe)
[💻](https://github.com/snipe/snipe-it/commits?author=jfwiebe "Code") | [
Jo Drexl](https://www.nfon.com/)
[💻](https://github.com/snipe/snipe-it/commits?author=drexljo "Code") | [
Austin Sasko](https://github.com/austinsasko)
[💻](https://github.com/snipe/snipe-it/commits?author=austinsasko "Code") | [
Jasson](http://jassoncordones.github.io)
[💻](https://github.com/snipe/snipe-it/commits?author=JassonCordones "Code") | [
Okean](https://github.com/Tinyblargon)
[💻](https://github.com/snipe/snipe-it/commits?author=Tinyblargon "Code") | [
Alejandro Medrano](https://www.lst.tfo.upm.es/alejandro-medrano/)
[💻](https://github.com/snipe/snipe-it/commits?author=amedranogil "Code") | [
Lukas Kraic](https://github.com/lukaskraic)
[💻](https://github.com/snipe/snipe-it/commits?author=lukaskraic "Code") | -| [
Герхард PICCORO Lenz McKAY ](https://github-readme-stats.vercel.app/api?username=mckaygerhard)
[💻](https://github.com/snipe/snipe-it/commits?author=mckaygerhard "Code") | +| [
Герхард PICCORO Lenz McKAY ](https://github-readme-stats.vercel.app/api?username=mckaygerhard)
[💻](https://github.com/snipe/snipe-it/commits?author=mckaygerhard "Code") | [
Johannes Pollitt](https://github.com/FlorestanII)
[💻](https://github.com/snipe/snipe-it/commits?author=FlorestanII "Code") | [
Michael Strobel](https://strobelm.de)
[💻](https://github.com/snipe/snipe-it/commits?author=strobelm "Code") | [
Nicky West](http://nickwest.me)
[💻](https://github.com/snipe/snipe-it/commits?author=nickwest "Code") | [
akaspeh1](https://github.com/akaspeh1)
[💻](https://github.com/snipe/snipe-it/commits?author=akaspeh1 "Code") | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! diff --git a/app/Console/Commands/LdapSync.php b/app/Console/Commands/LdapSync.php index 88015b14a1..381ae900d9 100644 --- a/app/Console/Commands/LdapSync.php +++ b/app/Console/Commands/LdapSync.php @@ -55,6 +55,8 @@ class LdapSync extends Command ini_set('max_execution_time', env('LDAP_TIME_LIM', 600)); //600 seconds = 10 minutes ini_set('memory_limit', env('LDAP_MEM_LIM', '500M')); + + // Map the LDAP attributes to the Snipe-IT user fields. $ldap_map = [ "username" => Setting::getSettings()->ldap_username_field, "last_name" => Setting::getSettings()->ldap_lname_field, @@ -63,11 +65,17 @@ class LdapSync extends Command "emp_num" => Setting::getSettings()->ldap_emp_num, "email" => Setting::getSettings()->ldap_email, "phone" => Setting::getSettings()->ldap_phone_field, + "mobile" => Setting::getSettings()->ldap_mobile, "jobtitle" => Setting::getSettings()->ldap_jobtitle, + "address" => Setting::getSettings()->ldap_address, + "city" => Setting::getSettings()->ldap_city, + "state" => Setting::getSettings()->ldap_state, + "zip" => Setting::getSettings()->ldap_zip, "country" => Setting::getSettings()->ldap_country, "location" => Setting::getSettings()->ldap_location, "dept" => Setting::getSettings()->ldap_dept, "manager" => Setting::getSettings()->ldap_manager, + "display_name" => Setting::getSettings()->ldap_display_name, ]; $ldap_default_group = Setting::getSettings()->ldap_default_group; @@ -234,9 +242,11 @@ class LdapSync extends Command } + // Assign the mapped LDAP attributes for each user to the Snipe-IT user fields for ($i = 0; $i < $results['count']; $i++) { $item = []; $item['username'] = $results[$i][$ldap_map["username"]][0] ?? ''; + $item['display_name'] = $results[$i][$ldap_map["display_name"]][0] ?? ''; $item['employee_number'] = $results[$i][$ldap_map["emp_num"]][0] ?? ''; $item['lastname'] = $results[$i][$ldap_map["last_name"]][0] ?? ''; $item['firstname'] = $results[$i][$ldap_map["first_name"]][0] ?? ''; @@ -244,8 +254,13 @@ class LdapSync extends Command $item['ldap_location_override'] = $results[$i]['ldap_location_override'] ?? ''; $item['location_id'] = $results[$i]['location_id'] ?? ''; $item['telephone'] = $results[$i][$ldap_map["phone"]][0] ?? ''; + $item['mobile'] = $results[$i][$ldap_map["mobile"]][0] ?? ''; $item['jobtitle'] = $results[$i][$ldap_map["jobtitle"]][0] ?? ''; + $item['address'] = $results[$i][$ldap_map["address"]][0] ?? ''; + $item['city'] = $results[$i][$ldap_map["city"]][0] ?? ''; + $item['state'] = $results[$i][$ldap_map["state"]][0] ?? ''; $item['country'] = $results[$i][$ldap_map["country"]][0] ?? ''; + $item['zip'] = $results[$i][$ldap_map["zip"]][0] ?? ''; $item['department'] = $results[$i][$ldap_map["dept"]][0] ?? ''; $item['manager'] = $results[$i][$ldap_map["manager"]][0] ?? ''; $item['location'] = $results[$i][$ldap_map["location"]][0] ?? ''; @@ -278,6 +293,9 @@ class LdapSync extends Command if($ldap_map["username"] != null){ $user->username = $item['username']; } + if($ldap_map["display_name"] != null){ + $user->display_name = $item['display_name']; + } if($ldap_map["last_name"] != null){ $user->last_name = $item['lastname']; } @@ -293,6 +311,9 @@ class LdapSync extends Command if($ldap_map["phone"] != null){ $user->phone = $item['telephone']; } + if($ldap_map["mobile"] != null){ + $user->mobile = $item['mobile']; + } if($ldap_map["jobtitle"] != null){ $user->jobtitle = $item['jobtitle']; } diff --git a/app/Console/Commands/LdapTroubleshooter.php b/app/Console/Commands/LdapTroubleshooter.php index 5bb3cdd366..cb19ff8c53 100644 --- a/app/Console/Commands/LdapTroubleshooter.php +++ b/app/Console/Commands/LdapTroubleshooter.php @@ -6,6 +6,7 @@ use Illuminate\Console\Command; use App\Models\Setting; use Exception; use Illuminate\Support\Facades\Crypt; +use App\Models\Ldap; /** * Check if a given ip is in a network @@ -160,7 +161,15 @@ class LdapTroubleshooter extends Command $output[] = "-x"; $output[] = "-b ".escapeshellarg($settings->ldap_basedn); $output[] = "-D ".escapeshellarg($settings->ldap_uname); - $output[] = "-w ".escapeshellarg(Crypt::Decrypt($settings->ldap_pword)); + + try { + $w = Crypt::Decrypt($settings->ldap_pword); + } catch (\Exception $e) { + $this->warn("Could not decrypt password. This usually means an LDAP password was not set or the APP_KEY was changed since the LDAP pasword was last saved. Aborting."); + exit(0); + } + + $output[] = "-w ". escapeshellarg($w); $output[] = escapeshellarg(parenthesized_filter($settings->ldap_filter)); if($settings->ldap_tls) { $this->line("# adding STARTTLS option"); @@ -171,6 +180,23 @@ class LdapTroubleshooter extends Command $this->line(implode(" \\\n",$output)); exit(0); } + + //PHP Version check for warning + $php_version = phpversion(); + list($major, $minor, $patch) = explode('.', $php_version); + if ( + $major < 8 || + ($major == 8 && $minor < 3) || + ($major == 8 && $minor == 3 && $patch < 21) || + ($major == 8 && $minor == 4 && $patch < 7) + ) { + $this->warn("PHP Version: $php_version WARNING - Versions before 8.3.21 or 8.4.7 will return INCONSISTENT results!"); + if (!$this->confirm("Are you sure you wish to continue?")) { + $this->warn("ABORTING"); + exit(-1); + } + } + if(!$this->option('force')) { $confirmation = $this->confirm('WARNING: This command will make several attempts to connect to your LDAP server. Are you sure this is ok?'); if(!$confirmation) { @@ -179,7 +205,7 @@ class LdapTroubleshooter extends Command } } //$this->line(print_r($settings,true)); - $this->info("STAGE 1: Checking settings"); + $this->line("STAGE 1: Checking settings"); if(!$settings->ldap_enabled) { $this->error("WARNING: Snipe-IT's LDAP setting is not turned on. (That may be OK if you're still trying to figure out settings)"); } @@ -210,32 +236,40 @@ class LdapTroubleshooter extends Command $this->info("Determined LDAP hostname to be: ".$parsed['host']); } - $this->info("Performing DNS lookup of: ".$parsed['host']); - $ips = dns_get_record($parsed['host']); $raw_ips = []; - //$this->info("Host IP is: ".print_r($ips,true)); + if (inet_pton($parsed['host']) !== false) { + $this->line($parsed['host'] . " already looks like an address; skipping DNS lookup"); + $raw_ips[] = $parsed['host']; + } else { + $this->line("Performing DNS lookup of: " . $parsed['host']); + $ips = dns_get_record($parsed['host']); - if(!$ips || count($ips) == 0) { - $this->error("ERROR: DNS lookup of host: ".$parsed['host']." has failed. ABORTING."); - exit(-1); - } - $this->debugout("IP's? ".print_r($ips,true)); - foreach($ips as $ip) { - if(!isset($ip['ip'])) { - continue; + //$this->info("Host IP is: ".print_r($ips,true)); + + if (!$ips || count($ips) == 0) { + $this->error("ERROR: DNS lookup of host: " . $parsed['host'] . " has failed. ABORTING."); + exit(-1); } - $raw_ips[]=$ip['ip']; - if($ip['ip'] == "127.0.0.1") { + $this->debugout("IP's? " . print_r($ips, true)); + foreach ($ips as $ip) { + if (!isset($ip['ip'])) { + continue; + } + $raw_ips[] = $ip['ip']; + } + } + foreach ($raw_ips as $ip) { + if ($ip == "127.0.0.1") { $this->error("WARNING: Using the localhost IP as the LDAP server. This is usually wrong"); } - if(ip_in_range($ip['ip'],'10.0.0.0/8') || ip_in_range($ip['ip'],'192.168.0.0/16') || ip_in_range($ip['ip'], '172.16.0.0/12')) { + if (ip_in_range($ip, '10.0.0.0/8') || ip_in_range($ip, '192.168.0.0/16') || ip_in_range($ip, '172.16.0.0/12')) { $this->error("WARNING: Using an RFC1918 Private address for LDAP server. This may be correct, but it can be a problem if your Snipe-IT instance is not hosted on your private network"); } } - $this->info("STAGE 2: Checking basic network connectivity"); - $ports = [389,636]; + $this->line("STAGE 2: Checking basic network connectivity"); + $ports = [636, 389]; if(@$parsed['port'] && !in_array($parsed['port'],$ports)) { $ports[] = $parsed['port']; } @@ -246,7 +280,7 @@ class LdapTroubleshooter extends Command $errstr = ''; $timeout = 30.0; $result = ''; - $this->info("Attempting to connect to port: ".$port." - may take up to $timeout seconds"); + $this->line("Attempting to connect to port: " . $port . " - may take up to $timeout seconds"); try { $result = fsockopen($parsed['host'], $port, $errno, $errstr, 30.0); } catch(Exception $e) { @@ -265,9 +299,9 @@ class LdapTroubleshooter extends Command exit(-1); } - $this->info("STAGE 3: Determine encryption algorithm, if any"); + $this->line("STAGE 3: Determine encryption algorithm, if any"); - $ldap_urls = []; + $ldap_urls = []; // [url, cert-check?, start_tls?] $pretty_ldap_urls = []; foreach($open_ports as $port) { $this->line("Trying TLS first for port $port"); @@ -275,35 +309,46 @@ class LdapTroubleshooter extends Command if($this->test_anonymous_bind($ldap_url)) { $this->info("Anonymous bind succesful to $ldap_url!"); $ldap_urls[] = [ $ldap_url, true, false ]; - $pretty_ldap_urls[] = [ $ldap_url, "YES", "no" ]; + $pretty_ldap_urls[] = [$ldap_url, "enabled", "n/a (no)"]; continue; // TODO - lots of copypasta in these if(test_anonymous_bind()) routines... } else { $this->error("WARNING: Failed to bind to $ldap_url - trying without certificate checks."); } if($this->test_anonymous_bind($ldap_url, false)) { - $this->info("Anonymous bind succesful to $ldap_url with certifcate-checks disabled"); - $ldap_urls[] = [ $ldap_url, false, false ]; - $pretty_ldap_urls[] = [ $ldap_url, "no", "no" ]; + $this->info("Anonymous bind successful to $ldap_url with certificate-checks disabled"); + $ldap_urls[] = [$ldap_url, false, false]; + $pretty_ldap_urls[] = [$ldap_url, "DISABLED", "n/a (no)"]; continue; } else { $this->error("WARNING: Failed to bind to $ldap_url with certificate checks disabled. Trying unencrypted with STARTTLS"); } + // now switching to ldap:// URL's from ldaps:// $ldap_url = "ldap://".$parsed['host'].":$port"; + if($this->test_anonymous_bind($ldap_url, true, true)) { $this->info("Plain connection to $ldap_url with STARTTLS succesful!"); $ldap_urls[] = [ $ldap_url, true, true ]; - $pretty_ldap_urls[] = [ $ldap_url, "YES", "YES" ]; + $pretty_ldap_urls[] = [$ldap_url, "enabled", "STARTTLS ENABLED"]; continue; } else { - $this->error("WARNING: Failed to bind to $ldap_url with STARTTLS enabled. Trying without STARTTLS"); + $this->error("WARNING: Failed to bind to $ldap_url with STARTTLS enabled. Trying without certificate checks."); + } + + if ($this->test_anonymous_bind($ldap_url, false, true)) { + $this->info("Plain connection to $ldap_url with STARTTLS and cert checks *disabled* successful!"); + $ldap_urls[] = [$ldap_url, false, true]; + $pretty_ldap_urls[] = [$ldap_url, "DISABLED", "STARTTLS ENABLED"]; + continue; + } else { + $this->error("WARNING: Failed to bind to $ldap_url with STARTTLS enabled, and cert checks disabled. Trying without STARTTLS"); } if($this->test_anonymous_bind($ldap_url)) { $this->info("Plain connection to $ldap_url succesful!"); $ldap_urls[] = [ $ldap_url, true, false ]; - $pretty_ldap_urls[] = [ $ldap_url, "YES", "no" ]; + $pretty_ldap_urls[] = [$ldap_url, "n/a", "starttls disabled"]; continue; } else { $this->error("WARNING: Failed to bind to $ldap_url. Giving up on port $port"); @@ -313,23 +358,29 @@ class LdapTroubleshooter extends Command $this->debugout(print_r($ldap_urls,true)); if(count($ldap_urls) > 0 ) { - $this->info("Found working LDAP URL's: "); + $this->debugout("Found working LDAP URL's: "); foreach($ldap_urls as $ldap_url) { // TODO maybe do this as a $this->table() instead? - $this->info("LDAP URL: ".$ldap_url[0]); - $this->info($ldap_url[0]. ($ldap_url[1] ? " certificate checks enabled" : " certificate checks disabled"). ($ldap_url[2] ? " STARTTLS Enabled ": " STARTTLS Disabled")); + $this->debugout("LDAP URL: " . $ldap_url[0]); + $this->debugout($ldap_url[0] . ($ldap_url[1] ? " certificate checks enabled" : " certificate checks disabled") . ($ldap_url[2] ? " STARTTLS Enabled " : " STARTTLS Disabled")); } - $this->table(["URL", "Cert Checks Enabled?", "STARTTLS Enabled?"],$pretty_ldap_urls); + $this->table(["URL", "Cert Checks?", "STARTTLS?"], $pretty_ldap_urls); } else { $this->error("ERROR - no valid LDAP URL's available - ABORTING"); exit(1); } - $this->info("STAGE 4: Test Administrative Bind for LDAP Sync"); + $this->line("STAGE 4: Test Administrative Bind for LDAP Sync"); foreach($ldap_urls AS $ldap_url) { - $this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $settings->ldap_uname, Crypt::decrypt($settings->ldap_pword)); + try { + $w = Crypt::Decrypt($settings->ldap_pword); + } catch (\Exception $e) { + $this->warn("Could not decrypt password. This usually means an LDAP password was not set or the APP_KEY was changed since the LDAP pasword was last saved. Aborting."); + exit(0); + } + $this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $settings->ldap_uname, $w); } - $this->info("STAGE 5: Test BaseDN"); + $this->line("STAGE 5: Test BaseDN"); //grab all LDAP_ constants and fill up a reversed array mapping from weird LDAP dotted-strings to (Constant Name) $all_defined_constants = get_defined_constants(); $ldap_constants = []; @@ -341,16 +392,23 @@ class LdapTroubleshooter extends Command $this->debugout("LDAP constants are: ".print_r($ldap_constants,true)); foreach($ldap_urls AS $ldap_url) { - if($this->test_informational_bind($ldap_url[0],$ldap_url[1],$ldap_url[2],$settings->ldap_uname,Crypt::decrypt($settings->ldap_pword),$settings)) { + try { + $w = Crypt::Decrypt($settings->ldap_pword); + } catch (\Exception $e) { + $this->warn("Could not decrypt password. This usually means an LDAP password was not set or the APP_KEY was changed since the LDAP pasword was last saved. Aborting."); + exit(0); + } + + if($this->test_informational_bind($ldap_url[0],$ldap_url[1],$ldap_url[2],$settings->ldap_uname,$w,$settings)) { $this->info("Success getting informational bind!"); } else { $this->error("Unable to get information from bind."); } } - $this->info("STAGE 6: Test LDAP Login to Snipe-IT"); + $this->line("STAGE 6: Test LDAP Login to Snipe-IT"); foreach($ldap_urls AS $ldap_url) { - $this->info("Starting auth to ".$ldap_url[0]); + $this->line("Starting auth to " . $ldap_url[0]); while(true) { $with_tls = $ldap_url[1] ? "with": "without"; $with_startssl = $ldap_url[2] ? "using": "not using"; @@ -359,7 +417,12 @@ class LdapTroubleshooter extends Command } $username = $this->ask("Username"); $password = $this->secret("Password"); - $this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $username, $password); // FIXME - should do some other stuff here, maybe with the concatenating or something? maybe? and/or should put up some results? + $results = $this->test_authed_bind($ldap_url[0], $ldap_url[1], $ldap_url[2], $username, $password); // FIXME - should do some other stuff here, maybe with the concatenating or something? maybe? and/or should put up some results? + if ($results) { + $this->info("Success authenticating with " . $username); + } else { + $this->error("Unable to authenticate with " . $username); + } } } @@ -368,14 +431,17 @@ class LdapTroubleshooter extends Command public function connect_to_ldap($ldap_url, $check_cert, $start_tls) { + if ($check_cert) { + $this->line("we *ARE* checking certs"); + Ldap::ignoreCertificates(false); + + } else { + $this->line("we are IGNORING certs"); + Ldap::ignoreCertificates(true); + } $lconn = ldap_connect($ldap_url); ldap_set_option($lconn, LDAP_OPT_PROTOCOL_VERSION, 3); // should we 'test' different protocol versions here? Does anyone even use anything other than LDAPv3? // no - it's formally deprecated: https://tools.ietf.org/html/rfc3494 - if(!$check_cert) { - putenv('LDAPTLS_REQCERT=never'); // This is horrible; is this *really* the only way to do it? - } else { - putenv('LDAPTLS_REQCERT'); // have to very explicitly and manually *UN* set the env var here to ensure it works - } if($this->settings->ldap_client_tls_cert && $this->settings->ldap_client_tls_key) { // client-side TLS certificate support for LDAP (Google Secure LDAP) putenv('LDAPTLS_CERT=storage/ldap_client_tls.cert'); @@ -404,9 +470,10 @@ class LdapTroubleshooter extends Command return $this->timed_boolean_execute(function () use ($ldap_url, $check_cert , $start_tls) { try { $lconn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls); - $this->info("gonna try to bind now, this can take a while if we mess it up"); + $this->line("Attempting to bind now, this can take a while if we mess it up"); $bind_results = ldap_bind($lconn); - $this->info("Bind results are: ".$bind_results." which translate into boolean: ".(bool)$bind_results); + $this->line("Bind results are: " . $bind_results . " which translate into boolean: " . (bool)$bind_results); + ldap_close($lconn); return (bool)$bind_results; } catch (Exception $e) { $this->error("WARNING: Exception caught during bind - ".$e->getMessage()); @@ -421,6 +488,7 @@ class LdapTroubleshooter extends Command try { $lconn = $this->connect_to_ldap($ldap_url, $check_cert, $start_tls); $bind_results = ldap_bind($lconn, $username, $password); + ldap_close($lconn); if(!$bind_results) { $this->error("WARNING: Failed to bind to $ldap_url as $username"); return false; @@ -446,22 +514,62 @@ class LdapTroubleshooter extends Command return false; } $this->info("SUCCESS - Able to bind to $ldap_url as $username"); - $result = ldap_read($conn, '', '(objectClass=*)'/* , ['supportedControl']*/); - $results = ldap_get_entries($conn, $result); - $cleaned_results = $this->ldap_results_cleaner($results); - $this->line(print_r($cleaned_results,true)); - //okay, great - now how do we display those results? I have no idea. + $cleaned_results = []; + try { + // This _may_ only work for Active Directory? + $result = ldap_read($conn, '', '(objectClass=*)'/* , ['supportedControl']*/); + $results = ldap_get_entries($conn, $result); + $cleaned_results = $this->ldap_results_cleaner($results); + //$this->line(print_r($cleaned_results,true)); + $default_naming_contexts = $cleaned_results[0]['namingcontexts']; + $this->info("Default Naming Contexts:"); + $this->info(implode(", ", $default_naming_contexts)); + //okay, great - now how do we display those results? I have no idea. + } catch (\Exception $e) { + $this->error("Unable to get base naming contexts - here's what we *did* get:"); + $this->line(print_r($cleaned_results, true)); + } // I don't see why this throws an Exception for Google LDAP, but I guess we ought to try and catch it? - $this->comment("I guess we're trying to do the ldap search here, but sometimes it takes too long?"); + $this->debugout("I guess we're trying to do the ldap search here, but sometimes it takes too long?"); $this->debugout("Base DN is: ".$settings->ldap_basedn." and filter is: ".parenthesized_filter($settings->ldap_filter)); $search_results = ldap_search($conn, $settings->ldap_basedn, parenthesized_filter($settings->ldap_filter)); + $entries = ldap_get_entries($conn, $search_results); $this->info("Printing first 10 results: "); - for($i=0;$i<10;$i++) { - $this->info($search_results[$i]); + $pretty_data = array_slice($this->ldap_results_cleaner($entries), 0, 10); + //print_r($data); + $headers = []; + foreach ($pretty_data as $row) { + //populate headers + foreach ($row as $key => $value) { + //skip objectsid and objectguid because it junks up output + if ($key == "objectsid" || $key == "objectguid") { + continue; + } + if (!in_array($key, $headers)) { + $headers[] = $key; + } + } } + $table = []; + //repeat again to populate table + foreach ($pretty_data as $row) { + $newrow = []; + foreach ($headers as $header) { + if (is_array(@$row[$header])) { + $newrow[] = "[" . implode(", ", $row[$header]) . "]"; + } else { + $newrow[] = @$row[$header]; + } + } + $table[] = $newrow; + } + + $this->table($headers, $table); } catch (\Exception $e) { $this->error("WARNING: Exception caught during Authed bind to $username - ".$e->getMessage()); return false; + } finally { + ldap_close($conn); } }); } @@ -477,7 +585,7 @@ class LdapTroubleshooter extends Command { if(!(function_exists('pcntl_sigtimedwait') && function_exists('posix_getpid') && function_exists('pcntl_fork') && function_exists('posix_kill') && function_exists('pcntl_wifsignaled'))) { // POSIX functions needed for forking aren't present, just run the function inline (ignoring timeout) - $this->info('WARNING: Unable to execute POSIX fork() commands, timeout may not be respected'); + $this->line('WARNING: Unable to execute POSIX fork() commands, timeout may not be respected'); return $function(); } else { $parent_pid = posix_getpid(); @@ -514,4 +622,6 @@ class LdapTroubleshooter extends Command } } + + } diff --git a/app/Console/Commands/PaveIt.php b/app/Console/Commands/PaveIt.php index 36aacd6636..8c6bc89a51 100644 --- a/app/Console/Commands/PaveIt.php +++ b/app/Console/Commands/PaveIt.php @@ -59,6 +59,9 @@ class PaveIt extends Command 'migrations', 'settings', 'users', + 'telescope_entries', + 'telescope_entries_tags', + 'telescope_monitoring', ]; // We only need to find out what these are so we can nuke these columns on the assets table. diff --git a/app/Console/Commands/Purge.php b/app/Console/Commands/Purge.php index 351bacf715..4db7bac147 100644 --- a/app/Console/Commands/Purge.php +++ b/app/Console/Commands/Purge.php @@ -65,7 +65,7 @@ class Purge extends Command $maintenances = 0; foreach ($assets as $asset) { - $this->info('- Asset "'.$asset->present()->name().'" deleted.'); + $this->info('- Asset "'.$asset->display_name.'" deleted.'); $asset_assoc += $asset->assetlog()->count(); $asset->assetlog()->forceDelete(); $maintenances += $asset->maintenances()->count(); diff --git a/app/Console/Commands/RemoveInvalidUploadDeleteActionLogItems.php b/app/Console/Commands/RemoveInvalidUploadDeleteActionLogItems.php new file mode 100644 index 0000000000..cbcc0e4307 --- /dev/null +++ b/app/Console/Commands/RemoveInvalidUploadDeleteActionLogItems.php @@ -0,0 +1,56 @@ +where('action_type', 'upload deleted') + ->whereNull('filename') + ->withTrashed() + ->get(); + + $this->info("{$invalidLogs->count()} invalid log items found."); + + if ($invalidLogs->count() === 0) { + return 0; + } + + $this->table(['ID', 'Action Type', 'Item Type', 'Item ID', 'Created At', 'Deleted At'], $invalidLogs->map(fn($log) => [ + $log->id, + $log->action_type, + $log->item_type, + $log->item_id, + $log->created_at, + $log->deleted_at, + ])->toArray()); + + if ($this->confirm("Do you wish to remove {$invalidLogs->count()} log items?")) { + $invalidLogs->each(fn($log) => $log->forceDelete()); + } + + return 0; + } +} diff --git a/app/Console/Commands/RestoreFromBackup.php b/app/Console/Commands/RestoreFromBackup.php index b5109c25ec..7065dab9e7 100644 --- a/app/Console/Commands/RestoreFromBackup.php +++ b/app/Console/Commands/RestoreFromBackup.php @@ -5,6 +5,7 @@ namespace App\Console\Commands; use Illuminate\Console\Command; use ZipArchive; use Illuminate\Support\Facades\Log; +use enshrined\svgSanitize\Sanitizer; class SQLStreamer { private $input; @@ -242,9 +243,10 @@ class RestoreFromBackup extends Command $private_dirs = [ 'storage/private_uploads/accessories', - 'storage/private_uploads/assetmodels', - 'storage/private_uploads/maintenances', - 'storage/private_uploads/models', + 'storage/private_uploads/assetmodels' => 'storage/private_uploads/models', //this was changed from assetmodels => models Aug 10 2025 + 'storage/private_uploads/asset_maintenances' => 'storage/private_uploads/maintenances', //this was changed from asset_maintenances => maintenances Aug 10 2025 + 'storage/private_uploads/maintenances', //but let 'maintenances' take precedence + 'storage/private_uploads/models', //and let 'models' take precedence 'storage/private_uploads/assets', // these are asset _files_, not the pictures. 'storage/private_uploads/audits', 'storage/private_uploads/components', @@ -262,7 +264,7 @@ class RestoreFromBackup extends Command ]; $public_dirs = [ 'public/uploads/accessories', - 'public/uploads/assetmodels', + // 'public/uploads/assetmodels' => 'public/uploads/models', //according to git, this was _never_ a thing... (see below) 'public/uploads/maintenances', 'public/uploads/assets', // these are asset _pictures_, not asset files 'public/uploads/avatars', @@ -273,7 +275,7 @@ class RestoreFromBackup extends Command 'public/uploads/departments', 'public/uploads/locations', 'public/uploads/manufacturers', - 'public/uploads/models', + 'public/uploads/models', // ...it's been this way for 9 years (as of late 2025) 'public/uploads/suppliers', ]; @@ -286,8 +288,6 @@ class RestoreFromBackup extends Command 'public/uploads/favicon-uploaded.*', ]; - $all_files = $private_dirs + $public_dirs; - $sqlfiles = []; $sqlfile_indices = []; @@ -295,6 +295,20 @@ class RestoreFromBackup extends Command $boring_files = []; $unsafe_files = []; + $good_extensions = config('filesystems.allowed_upload_extensions_array'); + + $private_extensions = array_merge($good_extensions, ["csv", "key"]); //add csv, and 'key' + $public_extensions = array_diff($good_extensions, ["xml"]); //remove xml + + $sanitizer = new Sanitizer(); + + /** + * TODO: I _hate_ the "continue 3" thing we keep doing here + * I think a better approach might be to have the "each file" stuff be in a method on this class, and the + * boring_files and interesting_files be properties on it that we fill out. Then, in that method, we could + * just do a 'return' once the file is actually handled (yay or nay). We could also start to break out some of + * the _other_ things that we do into their own methods too? But I don't care about that as much. + */ for ($i = 0; $i < $za->numFiles; $i++) { $stat_results = $za->statIndex($i); // echo "index: $i\n"; @@ -309,7 +323,7 @@ class RestoreFromBackup extends Command // skip macOS resource fork files (?!?!?!) if (strpos($raw_path, '__MACOSX') !== false && strpos($raw_path, '._') !== false) { //print "SKIPPING macOS Resource fork file: $raw_path\n"; - $boring_files[] = $raw_path; + // $boring_files[] = $raw_path; //stop adding this to the boring files list; it's just confusing continue; } if (@pathinfo($raw_path, PATHINFO_EXTENSION) == 'sql') { @@ -318,44 +332,70 @@ class RestoreFromBackup extends Command $sqlfile_indices[] = $i; continue; } + if ($raw_path[-1] == '/') { + //last character is '/' - this is a directory, and we don't need it, and we don't need to warn about it + continue; + } + if (in_array(basename($raw_path), [".gitkeep", ".gitignore", ".DS_Store"])) { + //skip these boring files silently without reporting on them; they're stupid + continue; + } + $extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION)); - foreach (array_merge($private_dirs, $public_dirs) as $dir) { - $last_pos = strrpos($raw_path, $dir . '/'); - if ($last_pos !== false) { - //print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n"); - //print("We would copy $raw_path to $dir.\n"); //FIXME append to a path? - $interesting_files[$raw_path] = ['dest' => $dir, 'index' => $i]; - continue 2; - if ($last_pos + strlen($dir) + 1 == strlen($raw_path)) { - // we don't care about that; we just want files with the appropriate prefix - //print("FOUND THE EXACT DIRECTORY: $dir AT: $raw_path!!!\n"); + foreach (['public' => $public_dirs, 'private' => $private_dirs] as $purpose => $dirs) { + $allowed_extensions = match ($purpose) { + 'public' => $public_extensions, + 'private' => $private_extensions, + }; + foreach ($dirs as $dir => $destdir) { + if (is_int($dir)) { + $dir = $destdir; + } + $last_pos = strrpos($raw_path, $dir . '/'); + if ($last_pos !== false) { + //print("INTERESTING - last_pos is $last_pos when searching $raw_path for $dir - last_pos+strlen(\$dir) is: ".($last_pos+strlen($dir))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n"); + //print("We would copy $raw_path to $dir.\n"); //FIXME append to a path? + //the CSV bit, below, is because we store CSV files as "blahcsv" - without an extension + if (!in_array($extension, $allowed_extensions) && !($dir == "storage/private_uploads/imports" && substr($raw_path, -3) == "csv" && $extension == "")) { + $unsafe_files[] = $raw_path; + Log::debug($raw_path . ' from directory ' . $dir . ' is being skipped'); + } else { + if ($dir != $destdir) { + Log::debug("Getting ready to save file $raw_path to new directory $destdir"); + } + $interesting_files[$raw_path] = ['dest' => $destdir, 'index' => $i]; + } + continue 3; } } } - $good_extensions = config('filesystems.allowed_upload_extensions_array'); - - foreach (array_merge($private_files, $public_files) as $file) { - $has_wildcard = (strpos($file, '*') !== false); - if ($has_wildcard) { - $file = substr($file, 0, -1); //trim last character (which should be the wildcard) - } - $last_pos = strrpos($raw_path, $file); // no trailing slash! - if ($last_pos !== false) { - $extension = strtolower(pathinfo($raw_path, PATHINFO_EXTENSION)); - if (!in_array($extension, $good_extensions)) { - // gathering potentially unsafe files here to return at exit - $unsafe_files[] = $raw_path; - Log::debug('Potentially unsafe file '.$raw_path.' is being skipped'); - $boring_files[] = $raw_path; - continue 2; + foreach (['public' => $public_files, 'private' => $private_files] as $purpose => $files) { + $allowed_extensions = match ($purpose) { + 'public' => $public_extensions, + 'private' => $private_extensions, + }; + foreach ($files as $file) { + $has_wildcard = (strpos($file, '*') !== false); + if ($has_wildcard) { + $file = substr($file, 0, -1); //trim last character (which should be the wildcard) } - //print("INTERESTING - last_pos is $last_pos when searching $raw_path for $file - last_pos+strlen(\$file) is: ".($last_pos+strlen($file))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n"); - //no wildcards found in $file, process 'normally' - if ($last_pos + strlen($file) == strlen($raw_path) || $has_wildcard) { //again, no trailing slash. or this is a wildcard and we just take it. - // print("FOUND THE EXACT FILE: $file AT: $raw_path!!!\n"); //we *do* care about this, though. - $interesting_files[$raw_path] = ['dest' => dirname($file), 'index' => $i]; - continue 2; + $last_pos = strrpos($raw_path, $file); // no trailing slash! + if ($last_pos !== false) { + if (!in_array($extension, $allowed_extensions)) { + // gathering potentially unsafe files here to return at exit + $unsafe_files[] = $raw_path; + Log::debug('Potentially unsafe file ' . $raw_path . ' is being skipped'); + $boring_files[] = $raw_path; + continue 3; + } + //print("INTERESTING - last_pos is $last_pos when searching $raw_path for $file - last_pos+strlen(\$file) is: ".($last_pos+strlen($file))." and strlen(\$rawpath) is: ".strlen($raw_path)."\n"); + //no wildcards found in $file, process 'normally' + if ($last_pos + strlen($file) == strlen($raw_path) || $has_wildcard) { //again, no trailing slash. or this is a wildcard and we just take it. + // print("FOUND THE EXACT FILE: $file AT: $raw_path!!!\n"); //we *do* care about this, though. + $interesting_files[$raw_path] = ['dest' => dirname($file), 'index' => $i]; + continue 3; + } } } } @@ -492,18 +532,25 @@ class RestoreFromBackup extends Command } foreach ($interesting_files as $pretty_file_name => $file_details) { $ugly_file_name = $za->statIndex($file_details['index'])['name']; - $fp = $za->getStream($ugly_file_name); - //$this->info("Weird problem, here are file details? ".print_r($file_details,true)); - if (!is_dir($file_details['dest'])) { - mkdir($file_details['dest'], 0755, true); //0755 is what Laravel uses, so we do that + $migrated_file_name = $file_details['dest'] . '/' . basename($pretty_file_name); + if (strcasecmp(substr($pretty_file_name, -4), ".svg") === 0) { + $svg_contents = $za->getFromIndex($file_details['index']); + $cleaned_svg = $sanitizer->sanitize($svg_contents); + file_put_contents($migrated_file_name, $cleaned_svg); + } else { + $fp = $za->getStream($ugly_file_name); + //$this->info("Weird problem, here are file details? ".print_r($file_details,true)); + if (!is_dir($file_details['dest'])) { + mkdir($file_details['dest'], 0755, true); //0755 is what Laravel uses, so we do that + } + $migrated_file = fopen($migrated_file_name, 'w'); + while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) { + fwrite($migrated_file, $buffer); + } + fclose($migrated_file); + fclose($fp); + //$this->info("Wrote $ugly_file_name to $pretty_file_name"); } - $migrated_file = fopen($file_details['dest'].'/'.basename($pretty_file_name), 'w'); - while (($buffer = fgets($fp, SQLStreamer::$buffer_size)) !== false) { - fwrite($migrated_file, $buffer); - } - fclose($migrated_file); - fclose($fp); - //$this->info("Wrote $ugly_file_name to $pretty_file_name"); if ($bar) { $bar->advance(); } diff --git a/app/Console/Commands/SendAcceptanceReminder.php b/app/Console/Commands/SendAcceptanceReminder.php index c1cf4ffda2..67efecbb34 100644 --- a/app/Console/Commands/SendAcceptanceReminder.php +++ b/app/Console/Commands/SendAcceptanceReminder.php @@ -77,7 +77,7 @@ class SendAcceptanceReminder extends Command if(!$email){ $no_email_list[] = [ 'id' => $acceptance->assignedTo?->id, - 'name' => $acceptance->assignedTo?->present()->fullName(), + 'name' => $acceptance->assignedTo?->display_name, ]; } else { $count++; diff --git a/app/Console/Commands/SendExpirationAlerts.php b/app/Console/Commands/SendExpirationAlerts.php index 64aff907fb..ae9bff48df 100644 --- a/app/Console/Commands/SendExpirationAlerts.php +++ b/app/Console/Commands/SendExpirationAlerts.php @@ -2,6 +2,7 @@ namespace App\Console\Commands; +use App\Helpers\Helper; use App\Mail\ExpiringAssetsMail; use App\Mail\ExpiringLicenseMail; use App\Models\Asset; @@ -52,19 +53,73 @@ class SendExpirationAlerts extends Command ->filter(fn($item) => !empty($item)) ->all(); // Expiring Assets - $assets = Asset::getExpiringWarrantee($alert_interval); + $assets = Asset::getExpiringWarrantyOrEol($alert_interval); if ($assets->count() > 0) { - $this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $alert_interval])); + Mail::to($recipients)->send(new ExpiringAssetsMail($assets, $alert_interval)); + + $this->table( + [ + trans('general.id'), + trans('admin/hardware/form.tag'), + trans('admin/hardware/form.model'), + trans('general.model_no'), + trans('general.purchase_date'), + trans('admin/hardware/form.eol_rate'), + trans('admin/hardware/form.eol_date'), + trans('admin/hardware/form.warranty_expires'), + ], + $assets->map(fn($item) => + [ + trans('general.id') => $item->id, + trans('admin/hardware/form.tag') => $item->asset_tag, + trans('admin/hardware/form.model') => $item->model->name, + trans('general.model_no') => $item->model->model_number, + trans('general.purchase_date') => $item->purchase_date_formatted, + trans('admin/hardware/form.eol_rate') => $item->model->eol, + trans('admin/hardware/form.eol_date') => $item->eol_date ? $item->eol_formatted_date .' ('.$item->eol_diff_for_humans.')' : '', + trans('admin/hardware/form.warranty_expires') => $item->warranty_expires ? $item->warranty_expires_formatted_date .' ('.$item->warranty_expires_diff_for_humans.')' : '', + ]) + ); } // Expiring licenses - $licenses = License::getExpiringLicenses($alert_interval); + $licenses = License::query()->ExpiringLicenses($alert_interval) + ->with('manufacturer','category') + ->orderBy('expiration_date', 'ASC') + ->orderBy('termination_date', 'ASC') + ->get(); if ($licenses->count() > 0) { - $this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $alert_interval])); Mail::to($recipients)->send(new ExpiringLicenseMail($licenses, $alert_interval)); + + $this->table( + [ + trans('general.id'), + trans('general.name'), + trans('general.purchase_date'), + trans('admin/licenses/form.expiration'), + trans('mail.expires'), + trans('admin/licenses/form.termination_date'), + trans('mail.terminates')], + $licenses->map(fn($item) => [ + trans('general.id') => $item->id, + trans('general.name') => $item->name, + trans('general.purchase_date') => $item->purchase_date_formatted, + trans('admin/licenses/form.expiration') => $item->expires_formatted_date, + trans('mail.expires') => $item->expires_diff_for_humans, + trans('admin/licenses/form.termination_date') => $item->terminates_formatted_date, + trans('mail.terminates') => $item->terminates_diff_for_humans + ]) + ); } + + // Send a message even if the count is 0 + $this->info(trans_choice('mail.assets_warrantee_alert', $assets->count(), ['count' => $assets->count(), 'threshold' => $alert_interval])); + $this->info(trans_choice('mail.license_expiring_alert', $licenses->count(), ['count' => $licenses->count(), 'threshold' => $alert_interval])); + + + } else { if ($settings->alert_email == '') { $this->error('Could not send email. No alert email configured in settings'); diff --git a/app/Console/Commands/SendUpcomingAuditReport.php b/app/Console/Commands/SendUpcomingAuditReport.php index 854488adc6..4e422a1dcd 100644 --- a/app/Console/Commands/SendUpcomingAuditReport.php +++ b/app/Console/Commands/SendUpcomingAuditReport.php @@ -47,7 +47,7 @@ class SendUpcomingAuditReport extends Command $today = Carbon::now(); $interval_date = $today->copy()->addDays($interval); - $assets = Asset::whereNull('deleted_at')->dueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'desc')->get(); + $assets = Asset::whereNull('deleted_at')->dueOrOverdueForAudit($settings)->orderBy('assets.next_audit_date', 'asc')->get(); $this->info($assets->count() . ' assets must be audited in on or before ' . $interval_date . ' is deadline'); @@ -61,6 +61,28 @@ class SendUpcomingAuditReport extends Command $this->info('Sending Admin SendUpcomingAuditNotification to: ' . $settings->alert_email); Mail::to($recipients)->send(new SendUpcomingAuditMail($assets, $settings->audit_warning_days)); + + $this->table( + [ + trans('general.id'), + trans('general.name'), + trans('general.last_audit'), + trans('general.next_audit_date'), + trans('mail.Days'), + trans('mail.supplier'), + trans('mail.assigned_to'), + + ], + $assets->map(fn($item) => [ + trans('general.id') => $item->id, + trans('general.name') => $item->display_name, + trans('general.last_audit') => $item->last_audit_formatted_date, + trans('general.next_audit_date') => $item->next_audit_formatted_date, + trans('mail.Days') => round($item->next_audit_diff_in_days), + trans('mail.supplier') => $item->supplier ? $item->supplier->name : '', + trans('mail.assigned_to') => $item->assignedTo ? $item->assignedTo->display_name : '', + ]) + ); } } diff --git a/app/Exceptions/Handler.php b/app/Exceptions/Handler.php index 83411030d1..d68418ce59 100644 --- a/app/Exceptions/Handler.php +++ b/app/Exceptions/Handler.php @@ -138,13 +138,13 @@ class Handler extends ExceptionHandler if (in_array('bulkedit', $ids, true)) { $error_array = session()->get('bulk_asset_errors'); return redirect() - ->route('hardware.bulkedit') + ->route('hardware.index') ->withErrors($error_array, 'bulk_asset_errors') ->withInput(); } - // This gets the MVC model name from the exception and formats in a way that's less fugly - $model_name = strtolower(implode(" ", preg_split('/(?=[A-Z])/', last(explode('\\', $e->getModel()))))); + // This gets the MVC model name from the exception and formats in a way that's less fugly + $model_name = trim(strtolower(implode(" ", preg_split('/(?=[A-Z])/', last(explode('\\', $e->getModel())))))); $route = str_plural(strtolower(last(explode('\\', $e->getModel())))).'.index'; // Sigh. @@ -160,9 +160,7 @@ class Handler extends ExceptionHandler $route = 'maintenances.index'; } elseif ($route === 'licenseseats.index') { $route = 'licenses.index'; - } elseif ($route === 'customfields.index') { - $route = 'fields.index'; - } elseif ($route === 'customfieldsets.index') { + } elseif (($route === 'customfieldsets.index') || ($route === 'customfields.index')) { $route = 'fields.index'; } diff --git a/app/Helpers/Helper.php b/app/Helpers/Helper.php index 33fc21fc9d..963bc8ea77 100644 --- a/app/Helpers/Helper.php +++ b/app/Helpers/Helper.php @@ -95,7 +95,7 @@ class Helper $Parsedown->setSafeMode(true); if ($str) { - return $Parsedown->text($str); + return $Parsedown->text(strip_tags($str)); } } @@ -105,7 +105,7 @@ class Helper $Parsedown->setSafeMode(true); if ($str) { - return $Parsedown->line($str); + return $Parsedown->line(strip_tags($str)); } } @@ -123,9 +123,9 @@ class Helper if (is_numeric($cost)) { if (Setting::getSettings()->digit_separator=='1.234,56') { - return (float) number_format($cost, 2, ',', '.'); + return number_format($cost, 2, ',', '.'); } - return (float) number_format($cost, 2, '.', ','); + return number_format($cost, 2, '.', ','); } // It's already been parsed. return $cost; @@ -435,6 +435,34 @@ class Helper return $colors[$index]; } + /** + * Check if a string has any RTL characters + * @param $value + * @return bool + */ + public static function hasRtl($string) { + $rtlChar = '/[\x{0590}-\x{083F}]|[\x{08A0}-\x{08FF}]|[\x{FB1D}-\x{FDFF}]|[\x{FE70}-\x{FEFF}]/u'; + return preg_match($rtlChar, $string) != 0; + } + + // is chinese, japanese or korean language + public static function isCjk($string) { + return Helper::isChinese($string) || Helper::isJapanese($string) || Helper::isKorean($string); + } + + public static function isChinese($string) { + return preg_match("/\p{Han}+/u", $string); + } + + public static function isJapanese($string) { + return preg_match('/[\x{4E00}-\x{9FBF}\x{3040}-\x{309F}\x{30A0}-\x{30FF}]/u', $string); + } + + public static function isKorean($string) { + return preg_match('/[\x{3130}-\x{318F}\x{AC00}-\x{D7AF}]/u', $string); + } + + /** * Increases or decreases the brightness of a color by a percentage of the current brightness. * @@ -1197,19 +1225,30 @@ class Helper 'webp' => 'far fa-image', 'avif' => 'far fa-image', 'svg' => 'fas fa-vector-square', + // word 'doc' => 'far fa-file-word', 'docx' => 'far fa-file-word', + // Excel 'xls' => 'far fa-file-excel', 'xlsx' => 'far fa-file-excel', + 'ods' => 'far fa-file-excel', + + // Presentation + 'ppt' => 'far fa-file-powerpoint', + 'odp' => 'far fa-file-powerpoint', + // archive 'zip' => 'fas fa-file-archive', 'rar' => 'fas fa-file-archive', + //Text + 'odt' => 'far fa-file-alt', 'txt' => 'far fa-file-alt', 'rtf' => 'far fa-file-alt', 'xml' => 'fas fa-code', + // Misc 'pdf' => 'far fa-file-pdf', 'lic' => 'far fa-save', @@ -1695,5 +1734,5 @@ class Helper } } return $mismatched; - } + } } diff --git a/app/Helpers/IconHelper.php b/app/Helpers/IconHelper.php index 668b01a9f6..8172f2bbbb 100644 --- a/app/Helpers/IconHelper.php +++ b/app/Helpers/IconHelper.php @@ -16,6 +16,7 @@ class IconHelper case 'clone': return 'far fa-clone'; case 'delete': + case 'upload deleted': return 'fas fa-trash'; case 'create': return 'fa-solid fa-plus'; diff --git a/app/Helpers/StorageHelper.php b/app/Helpers/StorageHelper.php index 1b55b69a3f..cbd801d302 100644 --- a/app/Helpers/StorageHelper.php +++ b/app/Helpers/StorageHelper.php @@ -29,7 +29,7 @@ class StorageHelper public static function getMediaType($file_with_path) { - // The file exists and is allowed to be displayed inline + // Get the file extension and determine the media type if (Storage::exists($file_with_path)) { $fileinfo = pathinfo($file_with_path); $extension = strtolower($fileinfo['extension']); @@ -51,6 +51,15 @@ class StorageHelper case 'webm': case 'mov': return 'video'; + case 'doc': + case 'docx': + return 'document'; + case 'txt': + return 'text'; + case 'xls': + case 'xlsx': + case 'ods': + return 'spreadsheet'; default: return $extension; // Default for unknown types } diff --git a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php index 05d60fcbfe..9ed8c0fe45 100644 --- a/app/Http/Controllers/Accessories/AccessoryCheckoutController.php +++ b/app/Http/Controllers/Accessories/AccessoryCheckoutController.php @@ -71,6 +71,7 @@ class AccessoryCheckoutController extends Controller $this->authorize('checkout', $accessory); $target = $this->determineCheckoutTarget(); + session()->put(['checkout_to_type' => $target]); $accessory->checkout_qty = $request->input('checkout_qty', 1); diff --git a/app/Http/Controllers/Account/AcceptanceController.php b/app/Http/Controllers/Account/AcceptanceController.php index c273d36e3a..47dcde4041 100644 --- a/app/Http/Controllers/Account/AcceptanceController.php +++ b/app/Http/Controllers/Account/AcceptanceController.php @@ -8,33 +8,23 @@ use App\Events\ItemAccepted; use App\Events\ItemDeclined; use App\Http\Controllers\Controller; use App\Mail\CheckoutAcceptanceResponseMail; -use App\Models\Actionlog; -use App\Models\Asset; use App\Models\CheckoutAcceptance; use App\Models\Company; use App\Models\Contracts\Acceptable; use App\Models\Setting; use App\Models\User; -use App\Models\AssetModel; -use App\Models\Accessory; -use App\Models\License; -use App\Models\Component; -use App\Models\Consumable; use App\Notifications\AcceptanceAssetAcceptedNotification; use App\Notifications\AcceptanceAssetAcceptedToUserNotification; use App\Notifications\AcceptanceAssetDeclinedNotification; use Exception; use Illuminate\Http\Request; -use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Storage; use Illuminate\Support\Str; -use App\Http\Controllers\SettingsController; -use Barryvdh\DomPDF\Facade\Pdf; -use Carbon\Carbon; use \Illuminate\Contracts\View\View; use \Illuminate\Http\RedirectResponse; use Illuminate\Support\Facades\Log; +use App\Helpers\Helper; class AcceptanceController extends Controller { @@ -85,6 +75,10 @@ class AcceptanceController extends Controller public function store(Request $request, $id) : RedirectResponse { $acceptance = CheckoutAcceptance::find($id); + $assigned_user = User::find($acceptance->assigned_to_id); + $settings = Setting::getSettings(); + $sig_filename=''; + if (is_null($acceptance)) { return redirect()->route('account.accept')->with('error', trans('admin/hardware/message.does_not_exist')); @@ -107,139 +101,84 @@ class AcceptanceController extends Controller } /** - * Get the signature and save it + * Check for the signature directory */ if (! Storage::exists('private_uploads/signatures')) { Storage::makeDirectory('private_uploads/signatures', 775); } - + /** + * Check for the eula-pdfs directory + */ + if (! Storage::exists('private_uploads/eula-pdfs')) { + Storage::makeDirectory('private_uploads/eula-pdfs', 775); + } $item = $acceptance->checkoutable_type::find($acceptance->checkoutable_id); - $display_model = ''; - $pdf_view_route = ''; - $pdf_filename = 'accepted-eula-'.date('Y-m-d-h-i-s').'.pdf'; - $sig_filename=''; + + + + // If signatures are required, make sure we have one + if (Setting::getSettings()->require_accept_signature == '1') { + + // The item was accepted, check for a signature + if ($request->filled('signature_output')) { + $sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png'; + $data_uri = $request->input('signature_output'); + $encoded_image = explode(',', $data_uri); + $decoded_image = base64_decode($encoded_image[1]); + Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image); + + // No image data is present, kick them back. + // This mostly only applies to users on super-duper crapola browsers *cough* IE *cough* + } else { + return redirect()->back()->with('error', trans('general.shitty_browser')); + } + } + + + // Convert PDF logo to base64 for TCPDF + // This is needed for TCPDF to properly embed the image if it's a png and the cache isn't writable + $encoded_logo = null; + if ($settings->acceptance_pdf_logo) { + $encoded_logo = base64_encode(file_get_contents(public_path() . '/uploads/' . $settings->acceptance_pdf_logo)); + } + + // Get the data array ready for the notifications and PDF generation + $data = [ + 'item_tag' => $item->asset_tag, + 'item_name' => $item->name, // this handles licenses seats, which don't have a 'name' field + 'item_model' => $item->model?->name, + 'item_serial' => $item->serial, + 'item_status' => $item->assetstatus?->name, + 'eula' => $item->getEula(), + 'note' => $request->input('note'), + 'check_out_date' => Helper::getFormattedDateObject($acceptance->created_at, 'datetime', false), + 'accepted_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false), + 'declined_date' => Helper::getFormattedDateObject(now()->format('Y-m-d H:i:s'), 'datetime', false), + 'assigned_to' => $assigned_user->display_name, + 'email' => $assigned_user->email, + 'employee_num' => $assigned_user->employee_num, + 'site_name' => $settings->site_name, + 'company_name' => $item->company?->name?? $settings->site_name, + 'signature' => (($sig_filename && array_key_exists('1', $encoded_image))) ? $encoded_image[1] : null, + 'logo' => ($encoded_logo) ?? null, + 'date_settings' => $settings->date_display_format, + 'admin' => auth()->user()->present()?->fullName, + 'qty' => $acceptance->qty ?? 1, + ]; + if ($request->input('asset_acceptance') == 'accepted') { - /** - * Check for the eula-pdfs directory - */ - if (! Storage::exists('private_uploads/eula-pdfs')) { - Storage::makeDirectory('private_uploads/eula-pdfs', 775); - } - if (Setting::getSettings()->require_accept_signature == '1') { - - // Check if the signature directory exists, if not create it - if (!Storage::exists('private_uploads/signatures')) { - Storage::makeDirectory('private_uploads/signatures', 775); - } + $pdf_filename = 'accepted-'.$acceptance->checkoutable_id.'-'.$acceptance->display_checkoutable_type.'-eula-'.date('Y-m-d-h-i-s').'.pdf'; - // The item was accepted, check for a signature - if ($request->filled('signature_output')) { - $sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png'; - $data_uri = $request->input('signature_output'); - $encoded_image = explode(',', $data_uri); - $decoded_image = base64_decode($encoded_image[1]); - Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image); - - // No image data is present, kick them back. - // This mostly only applies to users on super-duper crapola browsers *cough* IE *cough* - } else { - return redirect()->back()->with('error', trans('general.shitty_browser')); - } - } - - - $assigned_user = User::find($acceptance->assigned_to_id); - // this is horrible - switch($acceptance->checkoutable_type){ - case 'App\Models\Asset': - $pdf_view_route ='account.accept.accept-asset-eula'; - $asset_model = AssetModel::find($item->model_id); - if (!$asset_model) { - return redirect()->back()->with('error', trans('admin/models/message.does_not_exist')); - } - $display_model = $asset_model->name; - break; - - case 'App\Models\Accessory': - $pdf_view_route ='account.accept.accept-accessory-eula'; - $accessory = Accessory::find($item->id); - $display_model = $accessory->name; - break; - - case 'App\Models\LicenseSeat': - $pdf_view_route ='account.accept.accept-license-eula'; - $license = License::find($item->license_id); - $display_model = $license->name; - break; - - case 'App\Models\Component': - $pdf_view_route ='account.accept.accept-component-eula'; - $component = Component::find($item->id); - $display_model = $component->name; - break; - - case 'App\Models\Consumable': - $pdf_view_route ='account.accept.accept-consumable-eula'; - $consumable = Consumable::find($item->id); - $display_model = $consumable->name; - break; - } -// if ($acceptance->checkoutable_type == 'App\Models\Asset') { -// $pdf_view_route ='account.accept.accept-asset-eula'; -// $asset_model = AssetModel::find($item->model_id); -// $display_model = $asset_model->name; -// $assigned_to = User::find($item->assigned_to)->present()->fullName; -// -// } elseif ($acceptance->checkoutable_type== 'App\Models\Accessory') { -// $pdf_view_route ='account.accept.accept-accessory-eula'; -// $accessory = Accessory::find($item->id); -// $display_model = $accessory->name; -// $assigned_to = User::find($item->assignedTo); -// -// } - - /** - * Gather the data for the PDF. We fire this whether there is a signature required or not, - * since we want the moment-in-time proof of what the EULA was when they accepted it. - */ - $branding_settings = SettingsController::getPDFBranding(); - - $path_logo = ""; - - // Check for the PDF logo path and use that, otherwise use the regular logo path - if (!is_null($branding_settings->acceptance_pdf_logo)) { - $path_logo = public_path() . '/uploads/' . $branding_settings->acceptance_pdf_logo; - } elseif (!is_null($branding_settings->logo)) { - $path_logo = public_path() . '/uploads/' . $branding_settings->logo; - } - - $data = [ - 'item_tag' => $item->asset_tag, - 'item_model' => $display_model, - 'item_serial' => $item->serial, - 'item_status' => $item->assetstatus?->name, - 'eula' => $item->getEula(), - 'note' => $request->input('note'), - 'check_out_date' => Carbon::parse($acceptance->created_at)->format('Y-m-d'), - 'accepted_date' => Carbon::parse($acceptance->accepted_at)->format('Y-m-d'), - 'assigned_to' => $assigned_user->present()->fullName, - 'company_name' => $branding_settings->site_name, - 'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null, - 'logo' => $path_logo, - 'date_settings' => $branding_settings->date_display_format, - ]; - - if ($pdf_view_route!='') { - Log::debug($pdf_filename.' is the filename, and the route was specified.'); - $pdf = Pdf::loadView($pdf_view_route, $data); - Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output()); - } + // Generate the PDF content + $pdf_content = $acceptance->generateAcceptancePdf($data, $acceptance); + Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf_content); + // Log the acceptance $acceptance->accept($sig_filename, $item->getEula(), $pdf_filename, $request->input('note')); // Send the PDF to the signing user @@ -247,15 +186,14 @@ class AcceptanceController extends Controller // Add the attachment for the signing user into the $data array $data['file'] = $pdf_filename; - try { - $assigned_user->notify(new AcceptanceAssetAcceptedToUserNotification($data)); + $assigned_user->notify((new AcceptanceAssetAcceptedToUserNotification($data))->locale($assigned_user->locale)); } catch (\Exception $e) { Log::warning($e); } } try { - $acceptance->notify(new AcceptanceAssetAcceptedNotification($data)); + $acceptance->notify((new AcceptanceAssetAcceptedNotification($data))->locale(Setting::getSettings()->locale)); } catch (\Exception $e) { Log::warning($e); } @@ -263,95 +201,21 @@ class AcceptanceController extends Controller $return_msg = trans('admin/users/message.accepted'); + // Item was declined } else { - /** - * Check for the eula-pdfs directory - */ - if (! Storage::exists('private_uploads/eula-pdfs')) { - Storage::makeDirectory('private_uploads/eula-pdfs', 775); + for ($i = 0; $i < ($acceptance->qty ?? 1); $i++) { + $acceptance->decline($sig_filename, $request->input('note')); } - if (Setting::getSettings()->require_accept_signature == '1') { - - // Check if the signature directory exists, if not create it - if (!Storage::exists('private_uploads/signatures')) { - Storage::makeDirectory('private_uploads/signatures', 775); - } - - // The item was accepted, check for a signature - if ($request->filled('signature_output')) { - $sig_filename = 'siglog-' . Str::uuid() . '-' . date('Y-m-d-his') . '.png'; - $data_uri = $request->input('signature_output'); - $encoded_image = explode(',', $data_uri); - $decoded_image = base64_decode($encoded_image[1]); - Storage::put('private_uploads/signatures/' . $sig_filename, (string)$decoded_image); - - // No image data is present, kick them back. - // This mostly only applies to users on super-duper crapola browsers *cough* IE *cough* - } else { - return redirect()->back()->with('error', trans('general.shitty_browser')); - } - } - - // Format the data to send the declined notification - $branding_settings = SettingsController::getPDFBranding(); - - // This is the most horriblest - switch($acceptance->checkoutable_type){ - case 'App\Models\Asset': - $asset_model = AssetModel::find($item->model_id); - $display_model = $asset_model->name; - $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; - break; - - case 'App\Models\Accessory': - $accessory = Accessory::find($item->id); - $display_model = $accessory->name; - $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; - break; - - case 'App\Models\LicenseSeat': - $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; - break; - - case 'App\Models\Component': - $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; - break; - - case 'App\Models\Consumable': - $consumable = Consumable::find($item->id); - $display_model = $consumable->name; - $assigned_to = User::find($acceptance->assigned_to_id)->present()->fullName; - break; - } - - $data = [ - 'item_tag' => $item->asset_tag, - 'item_model' => $display_model, - 'item_serial' => $item->serial, - 'item_status' => $item->assetstatus?->name, - 'note' => $request->input('note'), - 'declined_date' => Carbon::parse($acceptance->declined_at)->format('Y-m-d'), - 'signature' => ($sig_filename) ? storage_path() . '/private_uploads/signatures/' . $sig_filename : null, - 'assigned_to' => $assigned_to, - 'company_name' => $branding_settings->site_name, - 'date_settings' => $branding_settings->date_display_format, - ]; - - if ($pdf_view_route!='') { - Log::debug($pdf_filename.' is the filename, and the route was specified.'); - $pdf = Pdf::loadView($pdf_view_route, $data); - Storage::put('private_uploads/eula-pdfs/' .$pdf_filename, $pdf->output()); - } - - $acceptance->decline($sig_filename, $request->input('note')); $acceptance->notify(new AcceptanceAssetDeclinedNotification($data)); Log::debug('New event acceptance.'); event(new CheckoutDeclined($acceptance)); $return_msg = trans('admin/users/message.declined'); } + + // Send an email notification if one is requested if ($acceptance->alert_on_response_id) { try { $recipient = User::find($acceptance->alert_on_response_id); @@ -370,9 +234,10 @@ class AcceptanceController extends Controller Log::warning($e); } } - return redirect()->to('account/accept')->with('success', $return_msg); } + + } diff --git a/app/Http/Controllers/ActionlogController.php b/app/Http/Controllers/ActionlogController.php index 057ca465bc..144e56a69f 100644 --- a/app/Http/Controllers/ActionlogController.php +++ b/app/Http/Controllers/ActionlogController.php @@ -3,11 +3,13 @@ namespace App\Http\Controllers; use App\Helpers\Helper; +use App\Models\Actionlog; use Illuminate\Http\RedirectResponse; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Storage; -use \Illuminate\Http\Response; use Symfony\Component\HttpFoundation\BinaryFileResponse; +use \Illuminate\Http\Response; + class ActionlogController extends Controller { public function displaySig($filename) : RedirectResponse | Response | bool @@ -39,17 +41,29 @@ class ActionlogController extends Controller public function getStoredEula($filename) : Response | BinaryFileResponse | RedirectResponse { - $this->authorize('view', \App\Models\Asset::class); - if (config('filesystems.default') == 's3_private') { - return redirect()->away(Storage::disk('s3_private')->temporaryUrl('private_uploads/eula-pdfs/'.$filename, now()->addMinutes(5))); + if ($actionlog = Actionlog::where('filename', $filename)->with('user')->with('target')->firstOrFail()) { + + $this->authorize('view', $actionlog->target); + $this->authorize('view', $actionlog->user); + + + if (config('filesystems.default') == 's3_private') { + return redirect()->away(Storage::disk('s3_private')->temporaryUrl('private_uploads/eula-pdfs/' . $filename, now()->addMinutes(5))); + } + + if (Storage::exists('private_uploads/eula-pdfs/' . $filename)) { + + if (request()->input('inline') == 'true') { + return response()->file(config('app.private_uploads') . '/eula-pdfs/' . $filename); + } + + return response()->download(config('app.private_uploads') . '/eula-pdfs/' . $filename); + } + + return redirect()->back()->with('error', trans('general.file_does_not_exist')); } - if (Storage::exists('private_uploads/eula-pdfs/'.$filename)) { - return response()->download(config('app.private_uploads').'/eula-pdfs/'.$filename); - } - - return redirect()->back()->with('error', trans('general.file_does_not_exist')); - + return redirect()->back()->with('error', trans('general.record_not_found')); } } diff --git a/app/Http/Controllers/Api/AccessoriesController.php b/app/Http/Controllers/Api/AccessoriesController.php index 90486b40f2..3a198f1dd3 100644 --- a/app/Http/Controllers/Api/AccessoriesController.php +++ b/app/Http/Controllers/Api/AccessoriesController.php @@ -54,6 +54,15 @@ class AccessoriesController extends Controller 'notes', 'checkouts_count', 'qty', + // These are *relationships* so we wouldn't normally include them in this array, + // since they would normally create a `column not found` error, + // BUT we account for them in the ordering switch down at the end of this method + // DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW! + 'company', + 'location', + 'category', + 'supplier', + 'manufacturer', ]; @@ -61,10 +70,23 @@ class AccessoriesController extends Controller ->with('category', 'company', 'manufacturer', 'checkouts', 'location', 'supplier', 'adminuser') ->withCount('checkouts as checkouts_count'); - if ($request->filled('search')) { - $accessories = $accessories->TextSearch($request->input('search')); + $filter = []; + + if ($request->filled('filter')) { + $filter = json_decode($request->input('filter'), true); + $filter = array_filter($filter, function ($key) use ($allowed_columns) { + return in_array($key, $allowed_columns); + }, ARRAY_FILTER_USE_KEY); + } + if ((! is_null($filter)) && (count($filter)) > 0) { + $accessories->ByFilter($filter); + } elseif ($request->filled('search')) { + $accessories->TextSearch($request->input('search')); + } + + if ($request->filled('company_id')) { $accessories->where('accessories.company_id', '=', $request->input('company_id')); } @@ -288,32 +310,42 @@ class AccessoriesController extends Controller 'note' => $request->input('note'), ]); + $accessory_checkout->created_by = auth()->id(); $accessory_checkout->save(); + + $payload = [ + 'accessory_id' => $accessory->id, + 'assigned_to' => $target->id, + 'assigned_type' => $target::class, + 'note' => $request->input('note'), + 'created_by' => auth()->id(), + 'pivot' => $accessory_checkout->id, + ]; } // Set this value to be able to pass the qty through to the event event(new CheckoutableCheckedOut($accessory, $target, auth()->user(), $request->input('note'))); - return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkout.success'))); + return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/accessories/message.checkout.success'))); } /** * Check in the item so that it can be checked out again to someone else * - * @uses Accessory::checkin_email() to determine if an email can and should be sent - * @author [A. Gianotto] [] * @param Request $request * @param int $accessoryUserId * @param string $backto - * @return \Illuminate\Http\RedirectResponse + * @return JsonResponse + * @uses Accessory::checkin_email() to determine if an email can and should be sent + * @author [A. Gianotto] [] * @internal param int $accessoryId */ public function checkin(Request $request, $accessoryUserId = null) { if (is_null($accessory_checkout = AccessoryCheckout::find($accessoryUserId))) { - return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist'))); + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.does_not_exist', ['id' => $accessoryUserId]))); } $accessory = Accessory::find($accessory_checkout->accessory_id); @@ -327,7 +359,14 @@ class AccessoriesController extends Controller $user = User::find($accessory_checkout->assigned_to); } - return response()->json(Helper::formatStandardApiResponse('success', null, trans('admin/accessories/message.checkin.success'))); + $payload = [ + 'accessory_id' => $accessory->id, + 'note' => $request->input('note'), + 'created_by' => auth()->id(), + 'pivot' => $accessory_checkout->id, + ]; + + return response()->json(Helper::formatStandardApiResponse('success', $payload, trans('admin/accessories/message.checkin.success'))); } return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/accessories/message.checkin.error'))); diff --git a/app/Http/Controllers/Api/AssetModelsController.php b/app/Http/Controllers/Api/AssetModelsController.php index 1ed327b3bf..d0a6ceba5b 100644 --- a/app/Http/Controllers/Api/AssetModelsController.php +++ b/app/Http/Controllers/Api/AssetModelsController.php @@ -46,10 +46,20 @@ class AssetModelsController extends Controller 'manufacturer', 'requestable', 'assets_count', + 'assets_assigned_count', + 'assets_archived_count', + 'remaining', 'category', 'fieldset', 'deleted_at', 'updated_at', + 'require_serial', + // These are *relationships* so we wouldn't normally include them in this array, + // since they would normally create a `column not found` error, + // BUT we account for them in the ordering switch down at the end of this method + // DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW! + 'manufacturer', + 'category', ]; $assetmodels = AssetModel::select([ @@ -69,9 +79,31 @@ class AssetModelsController extends Controller 'models.fieldset_id', 'models.deleted_at', 'models.updated_at', + 'models.require_serial' ]) ->with('category', 'depreciation', 'manufacturer', 'fieldset.fields.defaultValues', 'adminuser') - ->withCount('assets as assets_count'); + ->withCount('assets as assets_count') + ->withCount('availableAssets as remaining') + ->withCount('assignedAssets as assets_assigned_count') + ->withCount('archivedAssets as assets_archived_count'); + + $filter = []; + + if ($request->filled('filter')) { + $filter = json_decode($request->input('filter'), true); + + $filter = array_filter($filter, function ($key) use ($allowed_columns) { + return in_array($key, $allowed_columns); + }, ARRAY_FILTER_USE_KEY); + + } + + if ((! is_null($filter)) && (count($filter)) > 0) { + $assetmodels->ByFilter($filter); + } elseif ($request->filled('search')) { + $assetmodels->TextSearch($request->input('search')); + } + if ($request->input('status')=='deleted') { $assetmodels->onlyTrashed(); diff --git a/app/Http/Controllers/Api/AssetsController.php b/app/Http/Controllers/Api/AssetsController.php index 160f4a120a..1a34e3f62f 100644 --- a/app/Http/Controllers/Api/AssetsController.php +++ b/app/Http/Controllers/Api/AssetsController.php @@ -6,6 +6,7 @@ use App\Events\CheckoutableCheckedIn; use App\Http\Requests\StoreAssetRequest; use App\Http\Requests\UpdateAssetRequest; use App\Http\Traits\MigratesLegacyAssetLocations; +use App\Http\Transformers\ComponentsTransformer; use App\Models\AccessoryCheckout; use App\Models\CheckoutAcceptance; use App\Models\LicenseSeat; @@ -115,17 +116,39 @@ class AssetsController extends Controller 'asset_eol_date', 'requestable', 'jobtitle', + // These are *relationships* so we wouldn't normally include them in this array, + // since they would normally create a `column not found` error, + // BUT we account for them in the ordering switch down at the end of this method + // DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW! + 'company', + 'model', + 'location', + 'rtd_location', + 'category', + 'status_label', + 'manufacturer', + 'supplier', + 'jobtitle', + 'assigned_to', + 'created_by', + ]; + $all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load + + foreach ($all_custom_fields as $field) { + $allowed_columns[] = $field->db_column_name(); + } + $filter = []; if ($request->filled('filter')) { $filter = json_decode($request->input('filter'), true); - } - $all_custom_fields = CustomField::all(); //used as a 'cache' of custom fields throughout this page load - foreach ($all_custom_fields as $field) { - $allowed_columns[] = $field->db_column_name(); + $filter = array_filter($filter, function ($key) use ($allowed_columns) { + return in_array($key, $allowed_columns); + }, ARRAY_FILTER_USE_KEY); + } $assets = Asset::select('assets.*') @@ -141,6 +164,7 @@ class AssetsController extends Controller 'model.category', 'model.manufacturer', 'model.fieldset', + 'model.depreciation', 'supplier' ); // it might be tempting to add 'assetlog' here, but don't. It blows up update-heavy users. @@ -604,7 +628,7 @@ class AssetsController extends Controller $asset->use_text = $asset->present()->fullName; if (($asset->checkedOutToUser()) && ($asset->assigned)) { - $asset->use_text .= ' → ' . $asset->assigned->getFullNameAttribute(); + $asset->use_text .= ' → ' . $asset->assigned->display_name; } @@ -1284,9 +1308,19 @@ class AssetsController extends Controller public function assignedAssets(Request $request, Asset $asset) : JsonResponse | array { + $this->authorize('view', Asset::class); + $this->authorize('view', $asset); - return []; - // to do + $query = Asset::where([ + 'assigned_to' => $asset->id, + 'assigned_type' => Asset::class, + ]); + + $total = $query->count(); + + $assets = $query->applyOffsetAndLimit($total)->get(); + + return (new AssetsTransformer)->transformAssets($assets, $total); } public function assignedAccessories(Request $request, Asset $asset) : JsonResponse | array @@ -1306,6 +1340,18 @@ class AssetsController extends Controller return (new AssetsTransformer)->transformCheckedoutAccessories($accessory_checkouts, $total); } + public function assignedComponents(Request $request, Asset $asset): JsonResponse|array + { + $this->authorize('view', Asset::class); + $this->authorize('view', $asset); + + $asset->loadCount('components'); + $total = $asset->components_count; + + $components = $asset->load(['components' => fn($query) => $query->applyOffsetAndLimit($total)])->components; + + return (new ComponentsTransformer)->transformComponents($components, $total); + } /** * Generate asset labels by tag diff --git a/app/Http/Controllers/Api/CategoriesController.php b/app/Http/Controllers/Api/CategoriesController.php index 3b1fc91e12..89edf122ca 100644 --- a/app/Http/Controllers/Api/CategoriesController.php +++ b/app/Http/Controllers/Api/CategoriesController.php @@ -40,6 +40,8 @@ class CategoriesController extends Controller 'consumables_count', 'components_count', 'licenses_count', + 'created_at', + 'updated_at', 'image', 'notes', ]; @@ -61,6 +63,23 @@ class CategoriesController extends Controller ->withCount('accessories as accessories_count', 'consumables as consumables_count', 'components as components_count', 'licenses as licenses_count', 'models as models_count'); + $filter = []; + + if ($request->filled('filter')) { + $filter = json_decode($request->input('filter'), true); + + $filter = array_filter($filter, function ($key) use ($allowed_columns) { + return in_array($key, $allowed_columns); + }, ARRAY_FILTER_USE_KEY); + + } + + if ((! is_null($filter)) && (count($filter)) > 0) { + $categories->ByFilter($filter); + } elseif ($request->filled('search')) { + $categories->TextSearch($request->input('search')); + } + /* * This checks to see if we should override the Admin Setting to show archived assets in list. * We don't currently use it within the Snipe-IT GUI, but will be useful for API integrations where they @@ -74,10 +93,6 @@ class CategoriesController extends Controller $categories = $categories->withCount('showableAssets as assets_count'); } - if ($request->filled('search')) { - $categories = $categories->TextSearch($request->input('search')); - } - if ($request->filled('name')) { $categories->where('name', '=', $request->input('name')); } diff --git a/app/Http/Controllers/Api/ComponentsController.php b/app/Http/Controllers/Api/ComponentsController.php index 8881628b39..57bd6fe589 100644 --- a/app/Http/Controllers/Api/ComponentsController.php +++ b/app/Http/Controllers/Api/ComponentsController.php @@ -45,16 +45,40 @@ class ComponentsController extends Controller 'qty', 'image', 'notes', + // These are *relationships* so we wouldn't normally include them in this array, + // since they would normally create a `column not found` error, + // BUT we account for them in the ordering switch down at the end of this method + // DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW! + 'company', + 'location', + 'category', + 'manufacturer', + 'supplier', + ]; $components = Component::select('components.*') ->with('company', 'location', 'category', 'assets', 'supplier', 'adminuser', 'manufacturer', 'uncontrainedAssets') ->withSum('uncontrainedAssets', 'components_assets.assigned_qty'); - if ($request->filled('search')) { - $components = $components->TextSearch($request->input('search')); + $filter = []; + + if ($request->filled('filter')) { + $filter = json_decode($request->input('filter'), true); + + $filter = array_filter($filter, function ($key) use ($allowed_columns) { + return in_array($key, $allowed_columns); + }, ARRAY_FILTER_USE_KEY); + } + if ((! is_null($filter)) && (count($filter)) > 0) { + $components->ByFilter($filter); + } elseif ($request->filled('search')) { + $components->TextSearch($request->input('search')); + } + + if ($request->filled('name')) { $components->where('name', '=', $request->input('name')); } diff --git a/app/Http/Controllers/Api/ConsumablesController.php b/app/Http/Controllers/Api/ConsumablesController.php index 35fb08470a..7191b0b94a 100644 --- a/app/Http/Controllers/Api/ConsumablesController.php +++ b/app/Http/Controllers/Api/ConsumablesController.php @@ -31,10 +31,53 @@ class ConsumablesController extends Controller $consumables = Consumable::with('company', 'location', 'category', 'supplier', 'manufacturer') ->withCount('users as consumables_users_count'); - if ($request->filled('search')) { - $consumables = $consumables->TextSearch(e($request->input('search'))); + // This array is what determines which fields should be allowed to be sorted on ON the table itself. + // These must match a column on the consumables table directly. + $allowed_columns = [ + 'id', + 'name', + 'order_number', + 'min_amt', + 'purchase_date', + 'purchase_cost', + 'company', + 'category', + 'model_number', + 'item_no', + 'manufacturer', + 'location', + 'qty', + 'image', + // These are *relationships* so we wouldn't normally include them in this array, + // since they would normally create a `column not found` error, + // BUT we account for them in the ordering switch down at the end of this method + // DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW! + 'company', + 'location', + 'category', + 'supplier', + 'manufacturer', + ]; + + + $filter = []; + + if ($request->filled('filter')) { + $filter = json_decode($request->input('filter'), true); + + $filter = array_filter($filter, function ($key) use ($allowed_columns) { + return in_array($key, $allowed_columns); + }, ARRAY_FILTER_USE_KEY); + } + if ((! is_null($filter)) && (count($filter)) > 0) { + $consumables->ByFilter($filter); + } elseif ($request->filled('search')) { + $consumables->TextSearch($request->input('search')); + } + + if ($request->filled('name')) { $consumables->where('name', '=', $request->input('name')); } @@ -96,25 +139,6 @@ class ConsumablesController extends Controller $consumables = $consumables->OrderByCreatedBy($order); break; default: - // This array is what determines which fields should be allowed to be sorted on ON the table itself. - // These must match a column on the consumables table directly. - $allowed_columns = [ - 'id', - 'name', - 'order_number', - 'min_amt', - 'purchase_date', - 'purchase_cost', - 'company', - 'category', - 'model_number', - 'item_no', - 'manufacturer', - 'location', - 'qty', - 'image' - ]; - $sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'created_at'; $consumables = $consumables->orderBy($sort, $order); break; @@ -230,13 +254,13 @@ class ConsumablesController extends Controller 'avatar' => ($consumable_assignment->user) ? e($consumable_assignment->user->present()->gravatar) : '', 'user' => ($consumable_assignment->user) ? [ 'id' => (int) $consumable_assignment->user->id, - 'name'=> e($consumable_assignment->user->present()->fullName()), + 'name'=> e($consumable_assignment->user->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($consumable_assignment->created_at, 'datetime'), 'note' => ($consumable_assignment->note) ? e($consumable_assignment->note) : null, 'created_by' => ($consumable_assignment->adminuser) ? [ 'id' => (int) $consumable_assignment->adminuser->id, - 'name'=> e($consumable_assignment->adminuser->present()->fullName()), + 'name'=> e($consumable_assignment->adminuser->display_name), ] : null, ]; } diff --git a/app/Http/Controllers/Api/ImportController.php b/app/Http/Controllers/Api/ImportController.php index c18df26683..69703770f3 100644 --- a/app/Http/Controllers/Api/ImportController.php +++ b/app/Http/Controllers/Api/ImportController.php @@ -69,7 +69,7 @@ class ImportController extends Controller if (function_exists('iconv')) { $file_contents = $file->getContent(); //TODO - this *does* load the whole file in RAM, but we need that to be able to 'iconv' it? $encoding = $detector->getEncoding($file_contents); - \Log::warning("Discovered encoding: $encoding in uploaded CSV"); + \Log::debug("Discovered encoding: $encoding in uploaded CSV"); $reader = null; if (strcasecmp($encoding, 'UTF-8') != 0) { $transliterated = false; @@ -103,7 +103,7 @@ class ImportController extends Controller $reader = Reader::createFromFileObject($file->openFile('r')); //file pointer leak? try { - $import->header_row = $reader->fetchOne(0); + $import->header_row = $reader->nth(0); } catch (JsonEncodingException $e) { return response()->json( Helper::formatStandardApiResponse( @@ -136,7 +136,7 @@ class ImportController extends Controller try { // Grab the first row to display via ajax as the user picks fields - $import->first_row = $reader->fetchOne(1); + $import->first_row = $reader->nth(1); } catch (JsonEncodingException $e) { return response()->json( Helper::formatStandardApiResponse( @@ -195,7 +195,7 @@ class ImportController extends Controller // Run a backup immediately before processing if ($request->get('run-backup')) { Log::debug('Backup manually requested via importer'); - Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H:i:s')]); + Artisan::call('snipeit:backup', ['--filename' => 'pre-import-backup-'.date('Y-m-d-H-i-s')]); } else { Log::debug('NO BACKUP requested via importer'); } diff --git a/app/Http/Controllers/Api/LicenseSeatsController.php b/app/Http/Controllers/Api/LicenseSeatsController.php index 934261e97a..247f71ff26 100644 --- a/app/Http/Controllers/Api/LicenseSeatsController.php +++ b/app/Http/Controllers/Api/LicenseSeatsController.php @@ -128,7 +128,9 @@ class LicenseSeatsController extends Controller // nothing to update return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success'))); } - + if( $touched && $licenseSeat->unreassignable_seat) { + return response()->json(Helper::formatStandardApiResponse('error', null, trans('admin/licenses/message.checkout.unavailable'))); + } // the logging functions expect only one "target". if both asset and user are present in the request, // we simply let assets take precedence over users... if ($licenseSeat->isDirty('assigned_to')) { @@ -145,7 +147,11 @@ class LicenseSeatsController extends Controller if ($licenseSeat->save()) { if ($is_checkin) { - $licenseSeat->logCheckin($target, $request->input('notes')); + if(!$licenseSeat->license->reassignable){ + $licenseSeat->unreassignable_seat = true; + $licenseSeat->save(); + } + $licenseSeat->logCheckin($target, $licenseSeat->notes); return response()->json(Helper::formatStandardApiResponse('success', $licenseSeat, trans('admin/licenses/message.update.success'))); } diff --git a/app/Http/Controllers/Api/LicensesController.php b/app/Http/Controllers/Api/LicensesController.php index db39f987aa..738311b52b 100644 --- a/app/Http/Controllers/Api/LicensesController.php +++ b/app/Http/Controllers/Api/LicensesController.php @@ -7,6 +7,7 @@ use App\Http\Controllers\Controller; use App\Http\Transformers\LicensesTransformer; use App\Http\Transformers\SelectlistTransformer; use App\Models\License; +use App\Models\Setting; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use Illuminate\Http\JsonResponse; @@ -25,6 +26,15 @@ class LicensesController extends Controller $this->authorize('view', License::class); $licenses = License::with('company', 'manufacturer', 'supplier','category', 'adminuser')->withCount('freeSeats as free_seats_count'); + $settings = Setting::getSettings(); + + if ($request->input('status')=='inactive') { + $licenses->ExpiredLicenses(); + } elseif ($request->input('status')=='expiring') { + $licenses->ExpiringLicenses($settings->alert_interval); + } else { + $licenses->ActiveLicenses(); + } if ($request->filled('company_id')) { $licenses->where('licenses.company_id', '=', $request->input('company_id')); @@ -94,6 +104,8 @@ class LicensesController extends Controller $licenses->onlyTrashed(); } + + // Make sure the offset and limit are actually integers and do not exceed system limits $offset = ($request->input('offset') > $licenses->count()) ? $licenses->count() : app('api_offset_value'); $limit = app('api_limit_value'); diff --git a/app/Http/Controllers/Api/LocationsController.php b/app/Http/Controllers/Api/LocationsController.php index b5c911a6ca..3038cfcf0b 100644 --- a/app/Http/Controllers/Api/LocationsController.php +++ b/app/Http/Controllers/Api/LocationsController.php @@ -37,10 +37,14 @@ class LocationsController extends Controller 'address', 'address2', 'assets_count', - 'assets_count', + 'assigned_assets_count', + 'rtd_assets_count', + 'accessories_count', 'assigned_accessories_count', - 'assigned_assets_count', - 'assigned_assets_count', + 'components_count', + 'consumables_count', + 'users_count', + 'children_count', 'city', 'country', 'created_at', @@ -54,7 +58,6 @@ class LocationsController extends Controller 'rtd_assets_count', 'state', 'updated_at', - 'users_count', 'zip', 'notes', ]; @@ -79,8 +82,9 @@ class LocationsController extends Controller 'locations.currency', 'locations.company_id', 'locations.notes', + 'locations.created_by', + 'locations.deleted_at', ]) - ->withCount('assignedAssets as assigned_assets_count') ->withCount('assignedAssets as assigned_assets_count') ->withCount('assets as assets_count') ->withCount('assignedAccessories as assigned_accessories_count') @@ -88,6 +92,8 @@ class LocationsController extends Controller ->withCount('rtd_assets as rtd_assets_count') ->withCount('children as children_count') ->withCount('users as users_count') + ->withCount('consumables as consumables_count') + ->withCount('components as components_count') ->with('adminuser'); // Only scope locations if the setting is enabled @@ -131,6 +137,14 @@ class LocationsController extends Controller $locations->where('locations.company_id', '=', $request->input('company_id')); } + if ($request->filled('parent_id')) { + $locations->where('locations.parent_id', '=', $request->input('parent_id')); + } + + if ($request->input('status') == 'deleted') { + $locations->onlyTrashed(); + } + // Make sure the offset and limit are actually integers and do not exceed system limits $offset = ($request->input('offset') > $locations->count()) ? $locations->count() : app('api_offset_value'); $limit = app('api_limit_value'); @@ -224,8 +238,13 @@ class LocationsController extends Controller ]) ->withCount('assignedAssets as assigned_assets_count') ->withCount('assets as assets_count') + ->withCount('assignedAccessories as assigned_accessories_count') + ->withCount('accessories as accessories_count') ->withCount('rtd_assets as rtd_assets_count') + ->withCount('children as children_count') ->withCount('users as users_count') + ->withCount('consumables as consumables_count') + ->withCount('components as components_count') ->findOrFail($id); return (new LocationsTransformer)->transformLocation($location); @@ -320,11 +339,15 @@ class LocationsController extends Controller { $this->authorize('delete', Location::class); $location = Location::withCount('assignedAssets as assigned_assets_count') + ->withCount('assignedAssets as assigned_assets_count') ->withCount('assets as assets_count') + ->withCount('assignedAccessories as assigned_accessories_count') + ->withCount('accessories as accessories_count') ->withCount('rtd_assets as rtd_assets_count') ->withCount('children as children_count') ->withCount('users as users_count') - ->withCount('accessories as accessories_count') + ->withCount('consumables as consumables_count') + ->withCount('components as components_count') ->findOrFail($id); if (! $location->isDeletable()) { diff --git a/app/Http/Controllers/Api/MaintenancesController.php b/app/Http/Controllers/Api/MaintenancesController.php index 86f561c86c..319a7b0b18 100644 --- a/app/Http/Controllers/Api/MaintenancesController.php +++ b/app/Http/Controllers/Api/MaintenancesController.php @@ -52,6 +52,10 @@ class MaintenancesController extends Controller $maintenances->where('maintenances.created_by', '=', $request->input('created_by')); } + if ($request->filled('url')) { + $maintenances->where('maintenances.url', '=', $request->input('url')); + } + if ($request->filled('asset_maintenance_type')) { $maintenances->where('asset_maintenance_type', '=', $request->input('asset_maintenance_type')); } diff --git a/app/Http/Controllers/Api/NotesController.php b/app/Http/Controllers/Api/NotesController.php new file mode 100644 index 0000000000..c1a16fd4d6 --- /dev/null +++ b/app/Http/Controllers/Api/NotesController.php @@ -0,0 +1,95 @@ +authorize('view', $asset); + + // Get the manual notes for the asset + $notes = ActionLog::with('user:id,username') + ->where('item_type', Asset::class) + ->where('item_id', $asset->id) + ->where('action_type', 'note added') + ->orderBy('created_at', 'desc') + ->get(['id', 'created_at', 'note', 'created_by', 'item_id', 'item_type', 'action_type', 'target_id', 'target_type']); + + $notesArray = $notes->map(function ($note) { + return [ + 'id' => $note->id, + 'created_at' => $note->created_at, + 'note' => $note->note, + 'created_by' => $note->created_by, + 'username' => $note->user?->username, // adding the username + 'item_id' => $note->item_id, + 'item_type' => $note->item_type, + 'action_type' => $note->action_type, + ]; + }); + + // Return a success response + return response()->json(Helper::formatStandardApiResponse('success', ['notes' => $notesArray, 'asset_id' => $asset->id])); + } + + /** + * Store a manual note on a specified asset and log the action. + * + * Checks authorization for updating assets, validates the presence of the 'note', + * attempts to find the asset by ID, and creates a new ActionLog entry if successful. + * Returns JSON responses indicating success or failure with appropriate HTTP status codes. + * + * @param \Illuminate\Http\Request $request The incoming HTTP request containing the 'note'. + * @param Asset $asset The ID of the asset to attach the note to. + * @return \Illuminate\Http\JsonResponse + */ + public function store(Request $request, Asset $asset): JsonResponse + { + $this->authorize('update', $asset); + + if ($request->input('note', '') == '') { + return response()->json(Helper::formatStandardApiResponse('error', null, trans('validation.required', ['attribute' => 'note'])), 422); + } + + // Create the note + $logaction = new ActionLog(); + $logaction->item_type = get_class($asset); + $logaction->created_by = Auth::id(); + $logaction->item_id = $asset->id; + $logaction->note = $request->input('note', ''); + + if ($logaction->logaction('note added')) { + // Return a success response + return response()->json(Helper::formatStandardApiResponse('success', ['note' => $logaction->note, 'item_id' => $asset->id], trans('general.note_added'))); + } + + // Return an error response if something went wrong + return response()->json(Helper::formatStandardApiResponse('error', null, 'Something went wrong'), 500); + } +} diff --git a/app/Http/Controllers/Api/ProfileController.php b/app/Http/Controllers/Api/ProfileController.php index 69db8aae04..315c74a20d 100644 --- a/app/Http/Controllers/Api/ProfileController.php +++ b/app/Http/Controllers/Api/ProfileController.php @@ -69,7 +69,7 @@ class ProfileController extends Controller if ($checkoutRequest && $checkoutRequest->itemRequested()) { $assets = [ 'image' => e($checkoutRequest->itemRequested()->present()->getImageUrl()), - 'name' => e($checkoutRequest->itemRequested()->present()->name()), + 'name' => e($checkoutRequest->itemRequested()->display_name), 'type' => e($checkoutRequest->itemType()), 'qty' => (int) $checkoutRequest->quantity, 'location' => ($checkoutRequest->location()) ? e($checkoutRequest->location()->name) : null, diff --git a/app/Http/Controllers/Api/SettingsController.php b/app/Http/Controllers/Api/SettingsController.php index 134d24ef2a..f24dd25b17 100644 --- a/app/Http/Controllers/Api/SettingsController.php +++ b/app/Http/Controllers/Api/SettingsController.php @@ -3,7 +3,6 @@ namespace App\Http\Controllers\Api; use App\Helpers\Helper; -use App\Helpers\StorageHelper; use App\Http\Transformers\DatatablesTransformer; use Illuminate\Http\Request; use App\Http\Controllers\Controller; @@ -51,10 +50,22 @@ class SettingsController extends Controller })->slice(0, 10)->map(function ($item) use ($settings) { return (object) [ 'username' => $item[$settings['ldap_username_field']][0] ?? null, + 'display_name' => $item[$settings['ldap_display_name']][0] ?? null, 'employee_number' => $item[$settings['ldap_emp_num']][0] ?? null, 'lastname' => $item[$settings['ldap_lname_field']][0] ?? null, 'firstname' => $item[$settings['ldap_fname_field']][0] ?? null, 'email' => $item[$settings['ldap_email']][0] ?? null, + 'phone' => $item[$settings['ldap_phone_field']][0] ?? null, + 'mobile' => $item[$settings['ldap_mobile']][0] ?? null, + 'jobtitle' => $item[$settings['ldap_jobtitle']][0] ?? null, + 'department' => $item[$settings['ldap_department']][0] ?? null, + 'manager' => $item[$settings['ldap_manager']][0] ?? null, + 'address' => $item[$settings['ldap_address']][0] ?? null, + 'city' => $item[$settings['ldap_city']][0] ?? null, + 'state' => $item[$settings['ldap_state']][0] ?? null, + 'zip' => $item[$settings['ldap_zip']][0] ?? null, + 'country' => $item[$settings['ldap_country']][0] ?? null, + 'location' => $item[$settings['ldap_location']][0] ?? null, ]; }); if ($users->count() > 0) { @@ -78,7 +89,7 @@ class SettingsController extends Controller } } catch (\Exception $e) { Log::debug('Connection failed but we cannot debug it any further on our end.'); - return response()->json(['message' => $e->getMessage()], 500); + return response()->json(['message' => $e->getMessage()], 400); } diff --git a/app/Http/Controllers/Api/UploadedFilesController.php b/app/Http/Controllers/Api/UploadedFilesController.php index cab6ff9992..c9be705895 100644 --- a/app/Http/Controllers/Api/UploadedFilesController.php +++ b/app/Http/Controllers/Api/UploadedFilesController.php @@ -32,7 +32,7 @@ class UploadedFilesController extends Controller { // Check the permissions to make sure the user can view the object - $object = self::$map_object_type[$object_type]::find($id); + $object = self::$map_object_type[$object_type]::withTrashed()->find($id); $this->authorize('view', $object); if (!$object) { @@ -51,11 +51,7 @@ class UploadedFilesController extends Controller ]; - $uploads = Actionlog::select('action_logs.*') - ->whereNotNull('filename') - ->where('item_type', self::$map_object_type[$object_type]) - ->where('item_id', $object->id) - ->where('action_type', '=', 'uploaded') + $uploads = self::$map_object_type[$object_type]::withTrashed()->find($id)->uploads() ->with('adminuser'); $offset = ($request->input('offset') > $uploads->count()) ? $uploads->count() : abs($request->input('offset')); @@ -96,7 +92,7 @@ class UploadedFilesController extends Controller { // Check the permissions to make sure the user can view the object - $object = self::$map_object_type[$object_type]::find($id); + $object = self::$map_object_type[$object_type]::withTrashed()->find($id); $this->authorize('view', $object); if (!$object) { @@ -144,7 +140,7 @@ class UploadedFilesController extends Controller public function show($object_type, $id, $file_id) : JsonResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse { // Check the permissions to make sure the user can view the object - $object = self::$map_object_type[$object_type]::find($id); + $object = self::$map_object_type[$object_type]::withTrashed()->find($id); $this->authorize('view', $object); if (!$object) { @@ -188,7 +184,7 @@ class UploadedFilesController extends Controller { // Check the permissions to make sure the user can view the object - $object = self::$map_object_type[$object_type]::find($id); + $object = self::$map_object_type[$object_type]::withTrashed()->find($id); $this->authorize('update', self::$map_object_type[$object_type]); if (!$object) { @@ -197,8 +193,12 @@ class UploadedFilesController extends Controller // Check for the file - $log = Actionlog::find($file_id)->where('item_type', self::$map_object_type[$object_type]) - ->where('item_id', $object->id)->first(); + $log = Actionlog::query() + ->where('id', $file_id) + ->where('action_type', 'uploaded') + ->where('item_type', self::$map_object_type[$object_type]) + ->where('item_id', $object->id) + ->first(); if ($log) { // Check the file actually exists, and delete it @@ -206,7 +206,7 @@ class UploadedFilesController extends Controller Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename); } // Delete the record of the file - if ($log->delete()) { + if ($log->logUploadDelete($object, $log->filename)) { return response()->json(Helper::formatStandardApiResponse('success', null, trans_choice('general.file_upload_status.delete.success', 1)), 200); } @@ -217,4 +217,4 @@ class UploadedFilesController extends Controller return response()->json(Helper::formatStandardApiResponse('error', null, trans_choice('general.file_upload_status.delete.error', 1)), 500); } -} \ No newline at end of file +} diff --git a/app/Http/Controllers/Api/UsersController.php b/app/Http/Controllers/Api/UsersController.php index a0d9aeaa30..e7896eeeb3 100644 --- a/app/Http/Controllers/Api/UsersController.php +++ b/app/Http/Controllers/Api/UsersController.php @@ -20,6 +20,7 @@ use App\Models\Consumable; use App\Models\License; use App\Models\User; use App\Notifications\CurrentInventory; +use App\Notifications\WelcomeNotification; use Illuminate\Support\Facades\Artisan; use Illuminate\Support\Facades\Auth; use Illuminate\Database\Eloquent\Builder; @@ -64,6 +65,7 @@ class UsersController extends Controller 'users.jobtitle', 'users.last_login', 'users.last_name', + 'users.display_name', 'users.locale', 'users.location_id', 'users.manager_id', @@ -101,9 +103,75 @@ class UsersController extends Controller 'managedLocations as manages_locations_count' ]); + $allowed_columns = + [ + 'last_name', + 'first_name', + 'display_name', + 'email', + 'jobtitle', + 'username', + 'employee_num', + 'groups', + 'activated', + 'created_at', + 'updated_at', + 'two_factor_enrolled', + 'two_factor_optin', + 'last_login', + 'assets_count', + 'licenses_count', + 'consumables_count', + 'accessories_count', + 'manages_users_count', + 'manages_locations_count', + 'phone', + 'mobile', + 'address', + 'city', + 'state', + 'country', + 'zip', + 'id', + 'ldap_import', + 'two_factor_optin', + 'two_factor_enrolled', + 'remote', + 'vip', + 'start_date', + 'end_date', + 'autoassign_licenses', + 'website', + 'locale', + 'notes', + 'employee_num', - if ($request->filled('search') != '') { - $users = $users->TextSearch($request->input('search')); + // These are *relationships* so we wouldn't normally include them in this array, + // since they would normally create a `column not found` error, + // BUT we account for them in the ordering switch down at the end of this method + // DO NOT ADD ANYTHING TO THIS LIST WITHOUT CHECKING THE ORDERING SWITCH BELOW! + 'company', + 'location', + 'department', + 'manager', + 'created_by', + + ]; + + $filter = []; + + if ($request->filled('filter')) { + $filter = json_decode($request->input('filter'), true); + $filter = array_filter($filter, function ($key) use ($allowed_columns) { + return in_array($key, $allowed_columns); + }, ARRAY_FILTER_USE_KEY); + + } + + if ((! is_null($filter)) && (count($filter)) > 0) { + $users->ByFilter($filter); + } elseif ($request->filled('search')) { + $users->TextSearch($request->input('search')); } if ($request->filled('activated')) { @@ -154,6 +222,10 @@ class UsersController extends Controller $users = $users->where('users.last_name', '=', $request->input('last_name')); } + if ($request->filled('display_name')) { + $users = $users->where('users.display_name', '=', $request->input('display_name')); + } + if ($request->filled('employee_num')) { $users = $users->where('users.employee_num', '=', $request->input('employee_num')); } @@ -280,48 +352,6 @@ class UsersController extends Controller $users->orderBy('first_name', $order); break; default: - $allowed_columns = - [ - 'last_name', - 'first_name', - 'email', - 'jobtitle', - 'username', - 'employee_num', - 'groups', - 'activated', - 'created_at', - 'updated_at', - 'two_factor_enrolled', - 'two_factor_optin', - 'last_login', - 'assets_count', - 'licenses_count', - 'consumables_count', - 'accessories_count', - 'manages_users_count', - 'manages_locations_count', - 'phone', - 'mobile', - 'address', - 'city', - 'state', - 'country', - 'zip', - 'id', - 'ldap_import', - 'two_factor_optin', - 'two_factor_enrolled', - 'remote', - 'vip', - 'start_date', - 'end_date', - 'autoassign_licenses', - 'website', - 'locale', - 'notes', - ]; - $sort = in_array($request->input('sort'), $allowed_columns) ? $request->input('sort') : 'first_name'; $users = $users->orderBy($sort, $order); break; @@ -355,6 +385,7 @@ class UsersController extends Controller 'users.employee_num', 'users.first_name', 'users.last_name', + 'users.display_name', 'users.gravatar', 'users.avatar', 'users.email', @@ -365,20 +396,17 @@ class UsersController extends Controller $users = $users->where(function ($query) use ($request) { $query->SimpleNameSearch($request->get('search')) ->orWhere('username', 'LIKE', '%'.$request->get('search').'%') + ->orWhere('display_name', 'LIKE', '%'.$request->get('search').'%') ->orWhere('email', 'LIKE', '%'.$request->get('search').'%') ->orWhere('employee_num', 'LIKE', '%'.$request->get('search').'%'); }); } - $users = $users->orderBy('last_name', 'asc')->orderBy('first_name', 'asc'); + $users = $users->orderBy('display_name', 'asc')->orderBy('last_name', 'asc')->orderBy('first_name', 'asc'); $users = $users->paginate(50); foreach ($users as $user) { - $name_str = ''; - if ($user->last_name != '') { - $name_str .= $user->last_name.', '; - } - $name_str .= $user->first_name; + $name_str = $user->display_name; if ($user->username != '') { $name_str .= ' ('.$user->username.')'; @@ -430,9 +458,20 @@ class UsersController extends Controller $user->password = $user->noPassword(); } - app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar'); + app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar'); if ($user->save()) { + + if (($user->activated == '1') && ($user->email != '') && ($request->input('send_welcome') == '1')) { + + try { + $user->notify(new WelcomeNotification($user)); + } catch (\Exception $e) { + Log::warning('Could not send welcome notification for user: ' . $e->getMessage()); + } + + } + if ($request->filled('groups')) { $user->groups()->sync($request->input('groups')); } else { @@ -511,6 +550,10 @@ class UsersController extends Controller $user->username = $request->input('username'); } + if ($request->filled('display_name')) { + $user->display_name = $request->input('display_name'); + } + if ($request->filled('email')) { $user->email = $request->input('email'); } @@ -540,7 +583,7 @@ class UsersController extends Controller Asset::where('assigned_type', User::class) ->where('assigned_to', $user->id)->update(['location_id' => $request->input('location_id', null)]); } - app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'image', 'avatars', 'avatar'); + app('App\Http\Requests\ImageUploadRequest')->handleImages($user, 600, 'avatar', 'avatars', 'avatar'); if ($user->save()) { // Check if the request has groups passed and has a value, AND that the user us a superuser diff --git a/app/Http/Controllers/AssetModelsController.php b/app/Http/Controllers/AssetModelsController.php index b2745a6e53..a74365298e 100755 --- a/app/Http/Controllers/AssetModelsController.php +++ b/app/Http/Controllers/AssetModelsController.php @@ -82,6 +82,7 @@ class AssetModelsController extends Controller $model->notes = $request->input('notes'); $model->created_by = auth()->id(); $model->requestable = $request->has('requestable'); + $model->require_serial = $request->input('require_serial', 0); if ($request->input('fieldset_id') != '') { $model->fieldset_id = $request->input('fieldset_id'); @@ -155,7 +156,7 @@ class AssetModelsController extends Controller $model->category_id = $request->input('category_id'); $model->notes = $request->input('notes'); $model->requestable = $request->input('requestable', '0'); - + $model->require_serial = $request->input('require_serial', 0); $model->fieldset_id = $request->input('fieldset_id'); if ($model->save()) { diff --git a/app/Http/Controllers/Assets/AssetCheckoutController.php b/app/Http/Controllers/Assets/AssetCheckoutController.php index 0ea9b36418..bfbbbfcad4 100644 --- a/app/Http/Controllers/Assets/AssetCheckoutController.php +++ b/app/Http/Controllers/Assets/AssetCheckoutController.php @@ -65,6 +65,8 @@ class AssetCheckoutController extends Controller */ public function store(AssetCheckoutRequest $request, $assetId) : RedirectResponse { + + try { // Check if the asset exists if (! $asset = Asset::find($assetId)) { @@ -81,6 +83,7 @@ class AssetCheckoutController extends Controller $admin = auth()->user(); $target = $this->determineCheckoutTarget(); + session()->put(['checkout_to_type' => $target]); $asset = $this->updateAssetLocation($asset, $target); diff --git a/app/Http/Controllers/Assets/AssetsController.php b/app/Http/Controllers/Assets/AssetsController.php index 10f03db215..83c7a08ea1 100755 --- a/app/Http/Controllers/Assets/AssetsController.php +++ b/app/Http/Controllers/Assets/AssetsController.php @@ -110,17 +110,35 @@ class AssetsController extends Controller // This is only necessary on create, not update, since bulk editing is handled // differently $asset_tags = $request->input('asset_tags'); + $model = AssetModel::find($request->input('model_id')); + $serial_errors = []; + $serials = $request->input('serials'); $settings = Setting::getSettings(); + //Validate required serial based on model setting + for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) { + if ($model && $model->require_serial === 1 && empty($serials[$a])) { + $serial_errors["serials.$a"] = trans('admin/hardware/form.serial_required', ['number' => $a]); + } + + } + + if (!empty($serial_errors)) { + return redirect()->back() + ->withInput() + ->withErrors($serial_errors); + } + + $asset = null; + $companyId = Company::getIdForCurrentUser($request->input('company_id')); $successes = []; $failures = []; - $serials = $request->input('serials'); - $asset = null; - for ($a = 1; $a <= count($asset_tags); $a++) { + for ($a = 1, $aMax = count($asset_tags); $a <= $aMax; $a++) { $asset = new Asset(); - $asset->model()->associate(AssetModel::find($request->input('model_id'))); + + $asset->model()->associate($model); $asset->name = $request->input('name'); // Check for a corresponding serial @@ -132,7 +150,7 @@ class AssetsController extends Controller $asset->asset_tag = $asset_tags[$a]; } - $asset->company_id = Company::getIdForCurrentUser($request->input('company_id')); + $asset->company_id = $companyId; $asset->model_id = $request->input('model_id'); $asset->order_number = $request->input('order_number'); $asset->notes = $request->input('notes'); @@ -172,7 +190,6 @@ class AssetsController extends Controller // Update custom fields in the database. // Validation for these fields is handled through the AssetRequest form request - $model = AssetModel::find($request->get('model_id')); if (($model) && ($model->fieldset)) { foreach ($model->fieldset->fields as $field) { @@ -346,7 +363,7 @@ class AssetsController extends Controller $asset->purchase_cost = $request->input('purchase_cost', null); $asset->purchase_date = $request->input('purchase_date', null); $asset->next_audit_date = $request->input('next_audit_date', null); - if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && ($asset->model->eol > 0)) { + if ($request->filled('purchase_date') && !$request->filled('asset_eol_date') && ($asset->model?->eol > 0)) { $asset->purchase_date = $request->input('purchase_date', null); $asset->asset_eol_date = Carbon::parse($request->input('purchase_date'))->addMonths($asset->model->eol)->format('Y-m-d'); $asset->eol_explicit = false; @@ -362,7 +379,7 @@ class AssetsController extends Controller } else { $asset->eol_explicit = true; } - } elseif (!$request->filled('asset_eol_date') && (($asset->model->eol) == 0)) { + } elseif (!$request->filled('asset_eol_date') && (($asset->model?->eol) == 0)) { $asset->asset_eol_date = null; $asset->eol_explicit = false; } @@ -381,6 +398,7 @@ class AssetsController extends Controller $asset->assigned_to = null; $asset->assigned_type = null; $asset->accepted = null; + $asset->last_checkin = now(); event(new CheckoutableCheckedIn($asset, $target, auth()->user(), 'Checkin on asset update with '.$status->getStatuslabelType().' status', date('Y-m-d H:i:s'), $originalValues)); } @@ -424,6 +442,9 @@ class AssetsController extends Controller $model = AssetModel::find($request->get('model_id')); if (($model) && ($model->fieldset)) { foreach ($model->fieldset->fields as $field) { + if ($field->element == 'checkbox' && !$request->has($field->db_column)) { + $asset->{$field->db_column} = null; + } if ($request->has($field->db_column)) { if ($field->field_encrypted == '1') { if (Gate::allows('assets.view.encrypted_custom_fields')) { @@ -450,6 +471,13 @@ class AssetsController extends Controller ]); + //Validate required serial based on model setting + if ($model && $model->require_serial === 1 && empty($serial[1])) { + return redirect()->to(Helper::getRedirectOption($request, $asset->id, 'Assets')) + ->with('warning', trans('admin/hardware/form.serial_required_post_model_update', [ + 'asset_model' => $model->name + ])); + } if ($asset->save()) { return Helper::getRedirectOption($request, $asset->id, 'Assets') ->with('success', trans('admin/hardware/message.update.success')); @@ -794,7 +822,7 @@ class AssetsController extends Controller 'item_id' => $asset->id, 'item_type' => Asset::class, 'created_by' => auth()->id(), - 'note' => 'Checkout imported by '.auth()->user()->present()->fullName().' from history importer', + 'note' => 'Checkout imported by '.auth()->user()->display_name.' from history importer', 'target_id' => $item[$asset_tag][$batch_counter]['user_id'], 'target_type' => User::class, 'created_at' => $item[$asset_tag][$batch_counter]['checkout_date'], @@ -822,7 +850,7 @@ class AssetsController extends Controller 'item_id' => $item[$asset_tag][$batch_counter]['asset_id'], 'item_type' => Asset::class, 'created_by' => auth()->id(), - 'note' => 'Checkin imported by '.auth()->user()->present()->fullName().' from history importer', + 'note' => 'Checkin imported by '.auth()->user()->display_name.' from history importer', 'target_id' => null, 'created_at' => $checkin_date, 'action_type' => 'checkin', diff --git a/app/Http/Controllers/Assets/BulkAssetsController.php b/app/Http/Controllers/Assets/BulkAssetsController.php index 1787450e6f..27f6044d03 100644 --- a/app/Http/Controllers/Assets/BulkAssetsController.php +++ b/app/Http/Controllers/Assets/BulkAssetsController.php @@ -163,7 +163,7 @@ class BulkAssetsController extends Controller $modelNames = []; foreach($models as $model) { - $modelNames[] = $model->model->name; + $modelNames[] = $model->model?->name; } if ($request->filled('bulk_actions')) { @@ -470,7 +470,7 @@ class BulkAssetsController extends Controller */ // Does the model have a fieldset? - if ($asset->model->fieldset) { + if ($asset->model?->fieldset) { foreach ($asset->model->fieldset->fields as $field) { // null custom fields @@ -544,7 +544,7 @@ class BulkAssetsController extends Controller session()->put('bulk_asset_errors',$error_array); return redirect() - ->route('hardware.bulkedit') + ->route('hardware.index') ->with('bulk_asset_errors', $error_array) ->withInput(); } @@ -621,9 +621,25 @@ class BulkAssetsController extends Controller { $this->authorize('checkout', Asset::class); + $alreadyAssigned = collect(); + + if (old('selected_assets') && is_array(old('selected_assets'))) { + $assets = Asset::findMany(old('selected_assets')); + + [$assignable, $alreadyAssigned] = $assets->partition(function (Asset $asset) { + return !$asset->assigned_to; + }); + + session()->flashInput(['selected_assets' => $assignable->pluck('id')->values()->toArray()]); + } + $do_not_change = ['' => trans('general.do_not_change')]; $status_label_list = $do_not_change + Helper::deployableStatusLabelList(); - return view('hardware/bulk-checkout')->with('statusLabel_list', $status_label_list); + + return view('hardware/bulk-checkout', [ + 'statusLabel_list' => $status_label_list, + 'removed_assets' => $alreadyAssigned, + ]); } /** @@ -637,6 +653,7 @@ class BulkAssetsController extends Controller $admin = auth()->user(); $target = $this->determineCheckoutTarget(); + session()->put(['checkout_to_type' => $target]); if (! is_array($request->get('selected_assets'))) { return redirect()->route('hardware.bulkcheckout.show')->withInput()->with('error', trans('admin/hardware/message.checkout.no_assets_selected')); @@ -646,6 +663,30 @@ class BulkAssetsController extends Controller $assets = Asset::findOrFail($asset_ids); + // Prevent checking out assets that are already checked out + if ($assets->pluck('assigned_to')->unique()->filter()->isNotEmpty()) { + // re-add the asset ids so the assets select is re-populated + $request->session()->flashInput(['selected_assets' => $asset_ids]); + + return redirect(route('hardware.bulkcheckout.show')) + ->with('error', trans('general.error_assets_already_checked_out')); + } + + // Prevent checking out assets across companies if FMCS enabled + if (Setting::getSettings()->full_multiple_companies_support && $target->company_id) { + $company_ids = $assets->pluck('company_id')->unique(); + + // if there is more than one unique company id or the singular company id does not match + // then the checkout is invalid + if ($company_ids->count() > 1 || $company_ids->first() != $target->company_id) { + // re-add the asset ids so the assets select is re-populated + $request->session()->flashInput(['selected_assets' => $asset_ids]); + + return redirect(route('hardware.bulkcheckout.show')) + ->with('error', trans('general.error_user_company_multiple')); + } + } + if (request('checkout_to_type') == 'asset') { foreach ($asset_ids as $asset_id) { if ($target->id == $asset_id) { diff --git a/app/Http/Controllers/BulkAssetModelsController.php b/app/Http/Controllers/BulkAssetModelsController.php index 5f64ea0838..c1ecf309fb 100644 --- a/app/Http/Controllers/BulkAssetModelsController.php +++ b/app/Http/Controllers/BulkAssetModelsController.php @@ -92,7 +92,9 @@ class BulkAssetModelsController extends Controller $update_array['min_amt'] = $request->input('min_amt'); } - + if ($request->filled('require_serial')) { + $update_array['require_serial'] = $request->input('require_serial'); + } if (count($update_array) > 0) { AssetModel::whereIn('id', $models_raw_array)->update($update_array); diff --git a/app/Http/Controllers/Components/ComponentCheckoutController.php b/app/Http/Controllers/Components/ComponentCheckoutController.php index 4abf426de3..4214abb434 100644 --- a/app/Http/Controllers/Components/ComponentCheckoutController.php +++ b/app/Http/Controllers/Components/ComponentCheckoutController.php @@ -102,13 +102,15 @@ class ComponentCheckoutController extends Controller return redirect()->route('components.checkout.show', $componentId)->with('error', trans('general.error_user_company')); } + $component->checkout_qty = $request->input('assigned_qty'); + // Update the component data $component->asset_id = $request->input('asset_id'); $component->assets()->attach($component->id, [ 'component_id' => $component->id, 'created_by' => auth()->user()->id, 'created_at' => date('Y-m-d H:i:s'), - 'assigned_qty' => $request->input('assigned_qty'), + 'assigned_qty' => $component->checkout_qty, 'asset_id' => $request->input('asset_id'), 'note' => $request->input('note'), ]); diff --git a/app/Http/Controllers/CustomFieldsController.php b/app/Http/Controllers/CustomFieldsController.php index 7862719276..73e17f8942 100644 --- a/app/Http/Controllers/CustomFieldsController.php +++ b/app/Http/Controllers/CustomFieldsController.php @@ -144,10 +144,9 @@ class CustomFieldsController extends Controller */ public function deleteFieldFromFieldset($field_id, $fieldset_id) : RedirectResponse { + $this->authorize('update', CustomField::class); $field = CustomField::find($field_id); - $this->authorize('update', $field); - // Check that the field exists - this is mostly related to the demo, where we // rewrite the data every x minutes, so it's possible someone might be disassociating // a field from a fieldset just as we're wiping the database @@ -157,11 +156,12 @@ class CustomFieldsController extends Controller return redirect()->route('fieldsets.show', ['fieldset' => $fieldset_id]) ->with('success', trans('admin/custom_fields/message.field.delete.success')); } else { - return redirect()->back()->withErrors(['message' => "Field is in use and cannot be deleted."]); + return redirect()->back()->with('error', trans('admin/custom_fields/message.field.delete.error')) + ->withInput(); } } - return redirect()->back()->withErrors(['message' => "Error deleting field from fieldset"]); + return redirect()->back()->with('error', trans('admin/custom_fields/message.field.delete.error')); } @@ -172,20 +172,16 @@ class CustomFieldsController extends Controller * @author [Brady Wetherington] [] * @since [v1.8] */ - public function destroy($field_id) : RedirectResponse + public function destroy(CustomField $field) : RedirectResponse { - if ($field = CustomField::find($field_id)) { - $this->authorize('delete', $field); + $this->authorize('delete', CustomField::class); - if (($field->fieldset) && ($field->fieldset->count() > 0)) { - return redirect()->back()->withErrors(['message' => 'Field is in-use']); - } - $field->delete(); - return redirect()->route("fields.index") - ->with("success", trans('admin/custom_fields/message.field.delete.success')); + if (($field->fieldset) && ($field->fieldset->count() > 0)) { + return redirect()->back()->with('error', trans('admin/custom_fields/message.field.delete.in_use')); } - - return redirect()->back()->withErrors(['message' => 'Field does not exist']); + $field->delete(); + return redirect()->route("fields.index") + ->with("success", trans('admin/custom_fields/message.field.delete.success')); } @@ -198,7 +194,7 @@ class CustomFieldsController extends Controller */ public function edit(Request $request, CustomField $field) : View | RedirectResponse { - $this->authorize('update', $field); + $this->authorize('update', CustomField::class); $fieldsets = CustomFieldset::get(); $customFormat = ''; if ((stripos($field->format, 'regex') === 0) && ($field->format !== CustomField::PREDEFINED_FORMATS['MAC'])) { @@ -228,7 +224,7 @@ class CustomFieldsController extends Controller */ public function update(CustomFieldRequest $request, CustomField $field) : RedirectResponse { - $this->authorize('update', $field); + $this->authorize('update', CustomField::class); $show_in_email = $request->get("show_in_email", 0); $display_in_user_view = $request->get("display_in_user_view", 0); @@ -265,7 +261,6 @@ class CustomFieldsController extends Controller if ($field->save()) { - // Sync fields with fieldsets $fieldset_array = $request->input('associate_fieldsets'); if ($request->has('associate_fieldsets') && (is_array($fieldset_array))) { diff --git a/app/Http/Controllers/Licenses/LicenseCheckinController.php b/app/Http/Controllers/Licenses/LicenseCheckinController.php index 2a17c06d62..2bb2d5e68e 100644 --- a/app/Http/Controllers/Licenses/LicenseCheckinController.php +++ b/app/Http/Controllers/Licenses/LicenseCheckinController.php @@ -64,12 +64,7 @@ class LicenseCheckinController extends Controller $this->authorize('checkout', $license); - if (! $license->reassignable) { - // Not allowed to checkin - Session::flash('error', trans('admin/licenses/message.checkin.not_reassignable') . '.'); - return redirect()->back()->withInput(); - } // Declare the rules for the form validation $rules = [ @@ -98,6 +93,9 @@ class LicenseCheckinController extends Controller $licenseSeat->assigned_to = null; $licenseSeat->asset_id = null; $licenseSeat->notes = $request->input('notes'); + if (! $licenseSeat->license->reassignable) { + $licenseSeat->unreassignable_seat = true; + } session()->put(['redirect_option' => $request->get('redirect_option')]); if ($request->get('redirect_option') === 'target'){ @@ -106,7 +104,7 @@ class LicenseCheckinController extends Controller // Was the asset updated? if ($licenseSeat->save()) { - event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $request->input('notes'))); + event(new CheckoutableCheckedIn($licenseSeat, $return_to, auth()->user(), $licenseSeat->notes)); return Helper::getRedirectOption($request, $license->id, 'Licenses') @@ -132,21 +130,17 @@ class LicenseCheckinController extends Controller $license = License::findOrFail($licenseId); $this->authorize('checkin', $license); - if (! $license->reassignable) { - // Not allowed to checkin - Session::flash('error', 'License not reassignable.'); - - return redirect()->back()->withInput(); - } - $licenseSeatsByUser = LicenseSeat::where('license_id', '=', $licenseId) ->whereNotNull('assigned_to') - ->with('user') + ->with('user', 'license') ->get(); + $license = $licenseSeatsByUser->first()?->license; foreach ($licenseSeatsByUser as $user_seat) { $user_seat->assigned_to = null; - + if ($license && ! $license->reassignable) { + $user_seat->unreassignable_seat = true; + } if ($user_seat->save()) { Log::debug('Checking in '.$license->name.' from user '.$user_seat->username); $user_seat->logCheckin($user_seat->user, trans('admin/licenses/general.bulk.checkin_all.log_msg')); @@ -159,9 +153,12 @@ class LicenseCheckinController extends Controller ->get(); $count = 0; + $license = $licenseSeatsByAsset->first()?->license; foreach ($licenseSeatsByAsset as $asset_seat) { $asset_seat->asset_id = null; - + if ($license && ! $license->reassignable) { + $asset_seat->unreassignable_seat = true; + } if ($asset_seat->save()) { Log::debug('Checking in '.$license->name.' from asset '.$asset_seat->asset_tag); $asset_seat->logCheckin($asset_seat->asset, trans('admin/licenses/general.bulk.checkin_all.log_msg')); diff --git a/app/Http/Controllers/Licenses/LicenseCheckoutController.php b/app/Http/Controllers/Licenses/LicenseCheckoutController.php index e2225442b3..db378b8f0f 100644 --- a/app/Http/Controllers/Licenses/LicenseCheckoutController.php +++ b/app/Http/Controllers/Licenses/LicenseCheckoutController.php @@ -25,7 +25,7 @@ class LicenseCheckoutController extends Controller * @author [A. Gianotto] [] * @since [v1.0] * @param $id - * @return \Illuminate\Contracts\View\View + * @return \Illuminate\Contracts\View\View |\Illuminate\Http\RedirectResponse * @throws \Illuminate\Auth\Access\AuthorizationException */ public function create(License $license) @@ -39,6 +39,16 @@ class LicenseCheckoutController extends Controller return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats')); } + // Make sure the license is expired or terminated + if ($license->isInactive()) { + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.license_is_inactive')); + } + + // We don't currently allow checking out licenses to locations, so we'll reset that to user if needed + if (session()->get('checkout_to_type') == 'location') { + session()->put(['checkout_to_type' => 'user']); + } + // Return the checkout view return view('licenses/checkout', compact('license')); } @@ -65,22 +75,31 @@ class LicenseCheckoutController extends Controller return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.not_found')); } + $this->authorize('checkout', $license); + // Make sure there is at least one available to checkout + if ($license->availCount()->count() < 1) { + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats')); + } + + // Make sure the license is expired or terminated + if ($license->isInactive()) { + return redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.license_is_inactive')); + } + $licenseSeat = $this->findLicenseSeatToCheckout($license, $seatId); $licenseSeat->created_by = auth()->id(); $licenseSeat->notes = $request->input('notes'); - - - $checkoutMethod = 'checkoutTo'.ucwords(request('checkout_to_type')); if ($request->filled('asset_id')) { - + session()->put(['checkout_to_type' => 'asset']); $checkoutTarget = $this->checkoutToAsset($licenseSeat); $request->request->add(['assigned_asset' => $checkoutTarget->id]); session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'asset']); } elseif ($request->filled('assigned_to')) { + session()->put(['checkout_to_type' => 'user']); $checkoutTarget = $this->checkoutToUser($licenseSeat); $request->request->add(['assigned_user' => $checkoutTarget->id]); session()->put(['redirect_option' => $request->get('redirect_option'), 'checkout_to_type' => 'user']); @@ -89,6 +108,7 @@ class LicenseCheckoutController extends Controller if ($checkoutTarget) { + return Helper::getRedirectOption($request, $license->id, 'Licenses') ->with('success', trans('admin/licenses/message.checkout.success')); } @@ -110,6 +130,7 @@ class LicenseCheckoutController extends Controller throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.not_enough_seats'))); } + if (! $licenseSeat->license->is($license)) { throw new \Illuminate\Http\Exceptions\HttpResponseException(redirect()->route('licenses.index')->with('error', trans('admin/licenses/message.checkout.mismatch'))); } diff --git a/app/Http/Controllers/Licenses/LicensesController.php b/app/Http/Controllers/Licenses/LicensesController.php index d67f2a0be1..bdc0dc74e1 100755 --- a/app/Http/Controllers/Licenses/LicensesController.php +++ b/app/Http/Controllers/Licenses/LicensesController.php @@ -245,16 +245,28 @@ class LicensesController extends Controller $license = License::with('assignedusers')->find($license->id); $users_count = User::where('autoassign_licenses', '1')->count(); - $total_seats_count = $license->totalSeatsByLicenseID(); + + $total_seats_count = (int) $license->totalSeatsByLicenseID(); $available_seats_count = $license->availCount()->count(); - $checkedout_seats_count = ($total_seats_count - $available_seats_count); + $unreassignable_seats_count = License::unReassignableCount($license); + + if(!$license->reassignable){ + $checkedout_seats_count = ($total_seats_count - $available_seats_count - $unreassignable_seats_count ); + } + else { + $checkedout_seats_count = ($total_seats_count - $available_seats_count); + } + if($license->isInactive()){ + session()->flash('warning', (trans('admin/licenses/message.checkout.license_is_inactive'))); + } $this->authorize('view', $license); return view('licenses.view', compact('license')) ->with('users_count', $users_count) ->with('total_seats_count', $total_seats_count) ->with('available_seats_count', $available_seats_count) - ->with('checkedout_seats_count', $checkedout_seats_count); + ->with('checkedout_seats_count', $checkedout_seats_count) + ->with('unreassignable_seats_count', $unreassignable_seats_count); } @@ -364,7 +376,7 @@ class LicensesController extends Controller $license->order_number, $license->free_seat_count, $license->seats, - ($license->adminuser ? $license->adminuser->present()->fullName() : trans('admin/reports/general.deleted_user')), + ($license->adminuser ? $license->adminuser->display_name : trans('admin/reports/general.deleted_user')), $license->depreciation ? $license->depreciation->name: '', $license->updated_at, $license->deleted_at, diff --git a/app/Http/Controllers/LocationsController.php b/app/Http/Controllers/LocationsController.php index 46eff73df7..3457e115f9 100755 --- a/app/Http/Controllers/LocationsController.php +++ b/app/Http/Controllers/LocationsController.php @@ -189,30 +189,36 @@ class LocationsController extends Controller { $this->authorize('delete', Location::class); - if (is_null($location = Location::find($locationId))) { + $location = Location::withCount('assignedAssets as assigned_assets_count') + ->withCount('assets as assets_count') + ->withCount('assignedAccessories as assigned_accessories_count') + ->withCount('accessories as accessories_count') + ->withCount('rtd_assets as rtd_assets_count') + ->withCount('children as children_count') + ->withCount('users as users_count') + ->withCount('consumables as consumables_count') + ->withCount('components as components_count') + ->find($locationId); + + if (!$location) { return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.does_not_exist')); } - if ($location->users()->count() > 0) { - return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_users')); - } elseif ($location->children()->count() > 0) { - return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_child_loc')); - } elseif ($location->assets()->count() > 0) { - return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets')); - } elseif ($location->assignedassets()->count() > 0) { - return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_assets')); - } + if ($location->isDeletable()) { - if ($location->image) { - try { - Storage::disk('public')->delete('locations/'.$location->image); - } catch (\Exception $e) { - Log::error($e); + if ($location->image) { + try { + Storage::disk('public')->delete('locations/'.$location->image); + } catch (\Exception $e) { + Log::error($e); + } } + $location->delete(); + return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success')); + } else { + return redirect()->to(route('locations.index'))->with('error', trans('admin/locations/message.assoc_users')); } - $location->delete(); - return redirect()->to(route('locations.index'))->with('success', trans('admin/locations/message.delete.success')); } /** @@ -247,23 +253,41 @@ class LocationsController extends Controller $this->authorize('view', Location::class); if ($location = Location::where('id', $id)->first()) { - $parent = Location::where('id', $location->parent_id)->first(); - $manager = User::where('id', $location->manager_id)->first(); - $company = Company::where('id', $location->company_id)->first(); - $users = User::where('location_id', $id)->with('company', 'department', 'location')->get(); - $assets = Asset::where('assigned_to', $id)->where('assigned_type', Location::class)->with('model', 'model.category')->get(); return view('locations/print') - ->with('assets', $assets) - ->with('users',$users) + ->with('assigned', false) + ->with('assets', $location->assets) + ->with('assignedAssets', $location->assignedAssets) + ->with('accessories', $location->accessories) + ->with('assignedAccessories', $location->assignedAccessories) + ->with('users',$location->users) ->with('location', $location) - ->with('parent', $parent) - ->with('manager', $manager) - ->with('company', $company); + ->with('consumables', $location->consumables) + ->with('components', $location->components) + ->with('children', $location->children); } return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist')); } + public function print_all_assigned($id) : View | RedirectResponse + { + $this->authorize('view', Location::class); + if ($location = Location::where('id', $id)->first()) { + return view('locations/print') + ->with('assigned', true) + ->with('assets', $location->assets) + ->with('assignedAssets', $location->assignedAssets) + ->with('accessories', $location->accessories) + ->with('assignedAccessories', $location->assignedAccessories) + ->with('users',$location->users) + ->with('location', $location) + ->with('consumables', $location->consumables) + ->with('components', $location->components) + ->with('children', $location->children); + } + return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist')); + } + /** * Returns a view that presents a form to clone a location. @@ -321,33 +345,12 @@ class LocationsController extends Controller return redirect()->route('locations.index')->with('success', trans('admin/locations/message.restore.success')); } - // Check validation return redirect()->back()->with('error', trans('general.could_not_restore', ['item_type' => trans('general.location'), 'error' => $location->getErrors()->first()])); } return redirect()->back()->with('error', trans('admin/models/message.does_not_exist')); } - public function print_all_assigned($id) : View | RedirectResponse - { - $this->authorize('view', Location::class); - if ($location = Location::where('id', $id)->first()) { - $parent = Location::where('id', $location->parent_id)->first(); - $manager = User::where('id', $location->manager_id)->first(); - $company = Company::where('id', $location->company_id)->first(); - $users = User::where('location_id', $id)->with('company', 'department', 'location')->get(); - $assets = Asset::where('location_id', $id)->with('model', 'model.category')->get(); - return view('locations/print') - ->with('assets', $assets) - ->with('users',$users) - ->with('location', $location) - ->with('parent', $parent) - ->with('manager', $manager) - ->with('company', $company); - } - return redirect()->route('locations.index')->with('error', trans('admin/locations/message.does_not_exist')); - } - /** * Returns a view that allows the user to bulk delete locations @@ -366,8 +369,12 @@ class LocationsController extends Controller $locations = Location::whereIn('id', $locations_raw_array) ->withCount('assignedAssets as assigned_assets_count') ->withCount('assets as assets_count') + ->withCount('assignedAccessories as assigned_accessories_count') + ->withCount('accessories as accessories_count') ->withCount('rtd_assets as rtd_assets_count') ->withCount('children as children_count') + ->withCount('consumables as consumables_count') + ->withCount('components as components_count') ->withCount('users as users_count')->get(); $valid_count = 0; @@ -400,9 +407,13 @@ class LocationsController extends Controller $locations = Location::whereIn('id', $locations_raw_array) ->withCount('assignedAssets as assigned_assets_count') ->withCount('assets as assets_count') + ->withCount('assignedAccessories as assigned_accessories_count') + ->withCount('accessories as accessories_count') ->withCount('rtd_assets as rtd_assets_count') ->withCount('children as children_count') - ->withCount('users as users_count')->get(); + ->withCount('users as users_count') + ->withCount('consumables as consumables_count') + ->withCount('components as components_count')->get(); $success_count = 0; $error_count = 0; diff --git a/app/Http/Controllers/MaintenancesController.php b/app/Http/Controllers/MaintenancesController.php index e893b75f39..b3f287e6e7 100644 --- a/app/Http/Controllers/MaintenancesController.php +++ b/app/Http/Controllers/MaintenancesController.php @@ -78,6 +78,7 @@ class MaintenancesController extends Controller $maintenance->is_warranty = $request->input('is_warranty'); $maintenance->cost = $request->input('cost'); $maintenance->notes = $request->input('notes'); + $maintenance->url = $request->input('url'); // Save the asset maintenance data $maintenance->asset_id = $asset->id; @@ -152,6 +153,7 @@ class MaintenancesController extends Controller $maintenance->name = $request->input('name'); $maintenance->start_date = $request->input('start_date'); $maintenance->completion_date = $request->input('completion_date'); + $maintenance->url = $request->input('url'); // Todo - put this in a getter/setter? diff --git a/app/Http/Controllers/ReportsController.php b/app/Http/Controllers/ReportsController.php index 954b7cb64c..d1a649a14e 100644 --- a/app/Http/Controllers/ReportsController.php +++ b/app/Http/Controllers/ReportsController.php @@ -159,7 +159,7 @@ class ReportsController extends Controller $row[] = e($asset->serial); if ($target = $asset->assignedTo) { - $row[] = e($target->present()->name()); + $row[] = e($target->display_name); } else { $row[] = ''; // Empty string if unassigned } @@ -274,22 +274,18 @@ class ReportsController extends Controller $target_name = ''; if ($actionlog->target) { - if ($actionlog->targetType() == 'user') { - $target_name = $actionlog->target->getFullNameAttribute(); - } else { - $target_name = $actionlog->target->getDisplayNameAttribute(); - } + $target_name = $actionlog->target->display_name; } - if($actionlog->item){ - $item_name = e($actionlog->item->getDisplayNameAttribute()); + if ($actionlog->item){ + $item_name = e($actionlog->item->display_name); } else { $item_name = ''; } $row = [ $actionlog->created_at, - ($actionlog->adminuser) ? e($actionlog->adminuser->getFullNameAttribute()) : '', + ($actionlog->adminuser) ? $actionlog->adminuser->display_name : '', $actionlog->present()->actionType(), e($actionlog->itemType()), ($actionlog->itemType() == 'user') ? $actionlog->filename : $item_name, @@ -298,10 +294,10 @@ class ReportsController extends Controller (($actionlog->item) && ($actionlog->item->model)) ? $actionlog->item->model->model_number : null, $target_name, ($actionlog->note) ? e($actionlog->note) : '', - $actionlog->log_meta, $actionlog->remote_ip, $actionlog->user_agent, $actionlog->action_source, + $actionlog->log_meta, ]; fputcsv($handle, $row); } @@ -689,6 +685,14 @@ class ReportsController extends Controller $assets->whereBetween('assets.purchase_date', [$request->input('purchase_start'), $request->input('purchase_end')]); } + if ($request->filled('purchase_cost_start')) { + if ($request->filled('purchase_cost_end')) { + $assets->whereBetween('assets.purchase_cost', [$request->input('purchase_cost_start'), $request->input('purchase_cost_end')]); + } else { + $assets->where('assets.purchase_cost', ">", $request->input('purchase_cost_start')); + } + } + if (($request->filled('created_start')) && ($request->filled('created_end'))) { $created_start = Carbon::parse($request->input('created_start'))->startOfDay(); $created_end = Carbon::parse($request->input('created_end'))->endOfDay(); @@ -830,7 +834,7 @@ class ReportsController extends Controller } if ($request->filled('location')) { - $row[] = ($asset->location) ? $asset->location->present()->name() : ''; + $row[] = ($asset->location) ? $asset->location->display_name : ''; } if ($request->filled('location_address')) { @@ -843,7 +847,7 @@ class ReportsController extends Controller } if ($request->filled('rtd_location')) { - $row[] = ($asset->defaultLoc) ? $asset->defaultLoc->present()->name() : ''; + $row[] = ($asset->defaultLoc) ? $asset->defaultLoc->display_name : ''; } if ($request->filled('rtd_location_address')) { @@ -856,8 +860,8 @@ class ReportsController extends Controller } if ($request->filled('assigned_to')) { - $row[] = ($asset->checkedOutToUser() && $asset->assigned) ? $asset->assigned->getFullNameAttribute() : ($asset->assigned ? $asset->assigned->display_name : ''); - $row[] = ($asset->checkedOutToUser() && $asset->assigned) ? 'user' : $asset->assignedType(); + $row[] = ($asset->assigned) ? $asset->assigned->display_name : ''; + $row[] = ($asset->assigned) ? $asset->assignedType() : ''; } if ($request->filled('username')) { @@ -1260,7 +1264,7 @@ class ReportsController extends Controller $row[] = str_replace(',', '', e($item['assetItem']->model->name)); $row[] = str_replace(',', '', e($item['assetItem']->name)); $row[] = str_replace(',', '', e($item['assetItem']->asset_tag)); - $row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->present()->name() : trans('admin/reports/general.deleted_user'))); + $row[] = str_replace(',', '', e(($item['acceptance']->assignedTo) ? $item['acceptance']->assignedTo->display_name : trans('admin/reports/general.deleted_user'))); $rows[] = implode(',', $row); } } diff --git a/app/Http/Controllers/SettingsController.php b/app/Http/Controllers/SettingsController.php index 56b36470d4..8c57efa5eb 100644 --- a/app/Http/Controllers/SettingsController.php +++ b/app/Http/Controllers/SettingsController.php @@ -873,6 +873,7 @@ class SettingsController extends Controller $setting->ldap_default_group = $request->input('ldap_default_group'); $setting->ldap_filter = $request->input('ldap_filter'); $setting->ldap_username_field = $request->input('ldap_username_field'); + $setting->ldap_display_name = $request->input('ldap_display_name'); $setting->ldap_lname_field = $request->input('ldap_lname_field'); $setting->ldap_fname_field = $request->input('ldap_fname_field'); $setting->ldap_auth_filter_query = $request->input('ldap_auth_filter_query'); @@ -889,7 +890,12 @@ class SettingsController extends Controller $setting->ldap_pw_sync = $request->input('ldap_pw_sync', '0'); $setting->custom_forgot_pass_url = $request->input('custom_forgot_pass_url'); $setting->ldap_phone_field = $request->input('ldap_phone'); + $setting->ldap_mobile = $request->input('ldap_mobile'); $setting->ldap_jobtitle = $request->input('ldap_jobtitle'); + $setting->ldap_address = $request->input('ldap_address'); + $setting->ldap_city = $request->input('ldap_city'); + $setting->ldap_state = $request->input('ldap_state'); + $setting->ldap_zip = $request->input('ldap_zip'); $setting->ldap_country = $request->input('ldap_country'); $setting->ldap_location = $request->input('ldap_location'); $setting->ldap_dept = $request->input('ldap_dept'); diff --git a/app/Http/Controllers/UploadedFilesController.php b/app/Http/Controllers/UploadedFilesController.php index eb1c45110d..8a9f4304ad 100644 --- a/app/Http/Controllers/UploadedFilesController.php +++ b/app/Http/Controllers/UploadedFilesController.php @@ -36,7 +36,7 @@ class UploadedFilesController extends Controller { // Check the permissions to make sure the user can view the object - $object = self::$map_object_type[$object_type]::find($id); + $object = self::$map_object_type[$object_type]::withTrashed()->find($id); $this->authorize('update', $object); if (!$object) { @@ -85,7 +85,7 @@ class UploadedFilesController extends Controller public function show($object_type, $id, $file_id) : RedirectResponse | StreamedResponse | Storage | StorageHelper | BinaryFileResponse { // Check the permissions to make sure the user can view the object - $object = self::$map_object_type[$object_type]::find($id); + $object = self::$map_object_type[$object_type]::withTrashed()->find($id); $this->authorize('view', $object); if (!$object) { @@ -130,7 +130,7 @@ class UploadedFilesController extends Controller { // Check the permissions to make sure the user can view the object - $object = self::$map_object_type[$object_type]::find($id); + $object = self::$map_object_type[$object_type]::withTrashed()->find($id); $this->authorize('update', self::$map_object_type[$object_type]); if (!$object) { @@ -139,7 +139,7 @@ class UploadedFilesController extends Controller // Check for the file - $log = Actionlog::find($file_id)->where('item_type', self::$map_object_type[$object_type]) + $log = Actionlog::where('id',$file_id)->where('item_type', self::$map_object_type[$object_type]) ->where('item_id', $object->id)->first(); if ($log) { @@ -148,7 +148,7 @@ class UploadedFilesController extends Controller Storage::delete(self::$map_storage_path[$object_type].'/'.$log->filename); } // Delete the record of the file - if ($log->delete()) { + if ($log->logUploadDelete($object, $log->filename)) { return redirect()->back()->withFragment('files')->with('success', trans_choice('general.file_upload_status.delete.success', 1)); } diff --git a/app/Http/Controllers/Users/UsersController.php b/app/Http/Controllers/Users/UsersController.php index 2275e565cb..aa42415065 100755 --- a/app/Http/Controllers/Users/UsersController.php +++ b/app/Http/Controllers/Users/UsersController.php @@ -13,7 +13,9 @@ use App\Models\Company; use App\Models\Group; use App\Models\Setting; use App\Models\User; +use App\Notifications\WelcomeNotification; use Illuminate\Http\Request; +use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Password; use Symfony\Component\HttpFoundation\StreamedResponse; use App\Notifications\CurrentInventory; @@ -88,6 +90,7 @@ class UsersController extends Controller //Username, email, and password need to be handled specially because the need to respect config values on an edit. $user->email = trim($request->input('email')); $user->username = trim($request->input('username')); + $user->display_name = $request->input('display_name'); if ($request->filled('password')) { $user->password = bcrypt($request->input('password')); } @@ -127,7 +130,7 @@ class UsersController extends Controller // we have to invoke the form request here to handle image uploads app(ImageUploadRequest::class)->handleImages($user, 600, 'avatar', 'avatars', 'avatar'); - if($request->get('redirect_option') === 'back'){ + if ($request->get('redirect_option') === 'back'){ session()->put(['redirect_option' => 'index']); } else { session()->put(['redirect_option' => $request->get('redirect_option')]); @@ -135,6 +138,18 @@ class UsersController extends Controller if ($user->save()) { + + if (($user->activated == '1') && ($user->email != '') && ($request->input('send_welcome') == '1')) { + + try { + $user->notify(new WelcomeNotification($user)); + } catch (\Exception $e) { + Log::warning('Could not send welcome notification for user: ' . $e->getMessage()); + } + + + } + if ($request->filled('groups')) { $user->groups()->sync($request->input('groups')); } else { @@ -240,6 +255,7 @@ class UsersController extends Controller $user->first_name = $request->input('first_name'); $user->last_name = $request->input('last_name'); + $user->display_name = $request->input('display_name'); $user->two_factor_optin = $request->input('two_factor_optin') ?: 0; $user->locale = $request->input('locale'); $user->employee_num = $request->input('employee_num'); @@ -562,10 +578,10 @@ class UsersController extends Controller $user->employee_num, $user->first_name, $user->last_name, - $user->present()->fullName(), + $user->display_name, $user->username, $user->email, - ($user->manager) ? $user->manager->present()->fullName() : '', + ($user->manager) ? $user->manager->display_name : '', ($user->userloc) ? $user->userloc->name : '', ($user->department) ? $user->department->name : '', $user->assets->count(), diff --git a/app/Http/Controllers/ViewAssetsController.php b/app/Http/Controllers/ViewAssetsController.php index c4e72971b4..2b767650ad 100755 --- a/app/Http/Controllers/ViewAssetsController.php +++ b/app/Http/Controllers/ViewAssetsController.php @@ -185,7 +185,7 @@ class ViewAssetsController extends Controller $logaction->target_type = User::class; $data['item_quantity'] = $request->has('request-quantity') ? e($request->input('request-quantity')) : 1; - $data['requested_by'] = $user->present()->fullName(); + $data['requested_by'] = $user->display_name; $data['item'] = $item; $data['item_type'] = $itemType; $data['target'] = auth()->user(); diff --git a/app/Http/Middleware/AssetCountForSidebar.php b/app/Http/Middleware/AssetCountForSidebar.php index 636c04713d..58bee0d834 100644 --- a/app/Http/Middleware/AssetCountForSidebar.php +++ b/app/Http/Middleware/AssetCountForSidebar.php @@ -34,10 +34,7 @@ class AssetCountForSidebar } try { - $total_assets = Asset::count(); - if ($settings->show_archived_in_list != '1') { - $total_assets -= Asset::Archived()->count(); - } + $total_assets = Asset::AssetsForShow()->count(); view()->share('total_assets', $total_assets); } catch (\Exception $e) { Log::debug($e); diff --git a/app/Http/Middleware/SecurityHeaders.php b/app/Http/Middleware/SecurityHeaders.php index 8e6c17b4e7..e740c76678 100644 --- a/app/Http/Middleware/SecurityHeaders.php +++ b/app/Http/Middleware/SecurityHeaders.php @@ -26,7 +26,6 @@ class SecurityHeaders $response = $next($request); $response->headers->set('X-Content-Type-Options', 'nosniff'); - $response->headers->set('X-XSS-Protection', '1; mode=block'); // Ugh. Feature-Policy is dumb and clumsy and mostly irrelevant for Snipe-IT, // since we don't provide any way to IFRAME anything in in the first place. diff --git a/app/Http/Requests/CustomAssetReportRequest.php b/app/Http/Requests/CustomAssetReportRequest.php index 2a8fbe7fab..074db091a5 100644 --- a/app/Http/Requests/CustomAssetReportRequest.php +++ b/app/Http/Requests/CustomAssetReportRequest.php @@ -14,6 +14,15 @@ class CustomAssetReportRequest extends Request return true; } + + public function prepareForValidation() + { + if($this->filled('purchase_cost_end') && !$this->filled('purchase_cost_start')){ + $this->merge(['purchase_cost_start' => 0 ]); + } + } + + /** * Get the validation rules that apply to the request. * @@ -24,6 +33,7 @@ class CustomAssetReportRequest extends Request return [ 'purchase_start' => 'date|date_format:Y-m-d|nullable', 'purchase_end' => 'date|date_format:Y-m-d|nullable', + 'purchase_cost_end' => 'numeric|nullable|gte:purchase_cost_start', 'created_start' => 'date|date_format:Y-m-d|nullable', 'created_end' => 'date|date_format:Y-m-d|nullable', 'checkout_date_start' => 'date|date_format:Y-m-d|nullable', diff --git a/app/Http/Requests/SettingsSamlRequest.php b/app/Http/Requests/SettingsSamlRequest.php index f5483df9d2..53a3521018 100644 --- a/app/Http/Requests/SettingsSamlRequest.php +++ b/app/Http/Requests/SettingsSamlRequest.php @@ -109,7 +109,7 @@ class SettingsSamlRequest extends FormRequest ]; $pkey = openssl_pkey_new([ - 'private_key_bits' => 2048, + 'private_key_bits' => config('app.saml_key_size'), 'private_key_type' => OPENSSL_KEYTYPE_RSA, ]); diff --git a/app/Http/Requests/StoreAssetRequest.php b/app/Http/Requests/StoreAssetRequest.php index 66179ac739..e920f09a00 100644 --- a/app/Http/Requests/StoreAssetRequest.php +++ b/app/Http/Requests/StoreAssetRequest.php @@ -26,6 +26,7 @@ class StoreAssetRequest extends ImageUploadRequest public function prepareForValidation(): void { + parent::prepareForValidation(); // call ImageUploadRequest thing // Guard against users passing in an array for company_id instead of an integer. // If the company_id is not an integer then we simply use what was // provided to be caught by model level validation later. diff --git a/app/Http/Traits/ConvertsBase64ToFiles.php b/app/Http/Traits/ConvertsBase64ToFiles.php index 704610ddbf..4e023da267 100644 --- a/app/Http/Traits/ConvertsBase64ToFiles.php +++ b/app/Http/Traits/ConvertsBase64ToFiles.php @@ -2,6 +2,7 @@ namespace App\Http\Traits; +use Illuminate\Validation\ValidationException; use Illuminate\Http\UploadedFile; use Illuminate\Support\Arr; use Illuminate\Support\Collection; @@ -38,20 +39,13 @@ trait ConvertsBase64ToFiles if (!$base64Contents) { return; } - - // autogenerate filenames - if ($filename == 'auto'){ - $header = explode(';', $base64Contents, 2)[0]; - // Grab the image type from the header while we're at it. - $filename = $key . '.' . substr($header, strpos($header, '/')+1); - } // Generate a temporary path to store the Base64 contents $tempFilePath = tempnam(sys_get_temp_dir(), $filename); - // Store the contents using a stream, or by decoding manually + // Store the contents using a stream, or throw an Error (which doesn't do anything?) if (Str::startsWith($base64Contents, 'data:') && count(explode(',', $base64Contents)) > 1) { - $source = fopen($base64Contents, 'r'); + $source = fopen($base64Contents, 'r'); // PHP has special processing for "data:" URL's $destination = fopen($tempFilePath, 'w'); stream_copy_to_stream($source, $destination); @@ -59,7 +53,8 @@ trait ConvertsBase64ToFiles fclose($source); fclose($destination); } else { - file_put_contents($tempFilePath, base64_decode($base64Contents, true)); + // TODO - to get a better error message here, can we maybe do something with modifying the errorBag? + throw new ValidationException("Need Base64 URL starting with 'data:'"); // This doesn't actually throw? } $uploadedFile = new UploadedFile($tempFilePath, $filename, null, null, true); diff --git a/app/Http/Transformers/AccessoriesTransformer.php b/app/Http/Transformers/AccessoriesTransformer.php index b502490884..c7af414d08 100644 --- a/app/Http/Transformers/AccessoriesTransformer.php +++ b/app/Http/Transformers/AccessoriesTransformer.php @@ -36,6 +36,7 @@ class AccessoriesTransformer 'qty' => ($accessory->qty) ? (int) $accessory->qty : null, 'purchase_date' => ($accessory->purchase_date) ? Helper::getFormattedDateObject($accessory->purchase_date, 'date') : null, 'purchase_cost' => Helper::formatCurrencyOutput($accessory->purchase_cost), + 'total_cost' => Helper::formatCurrencyOutput($accessory->totalCostSum()), 'order_number' => ($accessory->order_number) ? e($accessory->order_number) : null, 'min_qty' => ($accessory->min_amt) ? (int) $accessory->min_amt : null, // Legacy - should phase out - replaced by below, for the bootstrap table formatter 'min_amt' => ($accessory->min_amt) ? (int) $accessory->min_amt : null, @@ -44,7 +45,7 @@ class AccessoriesTransformer 'checkouts_count' => $accessory->checkouts_count, 'created_by' => ($accessory->adminuser) ? [ 'id' => (int) $accessory->adminuser->id, - 'name'=> e($accessory->adminuser->present()->fullName()), + 'name'=> e($accessory->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($accessory->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($accessory->updated_at, 'datetime'), diff --git a/app/Http/Transformers/ActionlogsTransformer.php b/app/Http/Transformers/ActionlogsTransformer.php index 64086ca46e..f03f7404ba 100644 --- a/app/Http/Transformers/ActionlogsTransformer.php +++ b/app/Http/Transformers/ActionlogsTransformer.php @@ -50,17 +50,20 @@ class ActionlogsTransformer public function transformActionlog (Actionlog $actionlog, $settings = null) { + $icon = $actionlog->present()->icon(); + if (($actionlog->filename!='') && ($actionlog->action_type!='upload deleted')) { + $icon = Helper::filetype_icon($actionlog->filename); + } + static $custom_fields = false; if ($custom_fields === false) { $custom_fields = CustomField::all(); } - if ($actionlog->filename!='') { - $icon = Helper::filetype_icon($actionlog->filename); - } + // This is necessary since we can't escape special characters within a JSON object if (($actionlog->log_meta) && ($actionlog->log_meta!='')) { @@ -144,15 +147,15 @@ class ActionlogsTransformer [ 'url' => $actionlog->uploads_file_url(), 'filename' => $actionlog->filename, - 'inlineable' => StorageHelper::allowSafeInline($actionlog->uploads_file_url()), + 'inlineable' => StorageHelper::allowSafeInline($actionlog->uploads_file_path()), 'exists_on_disk' => Storage::exists($actionlog->uploads_file_path()) ? true : false, ] : null, 'item' => ($actionlog->item) ? [ 'id' => (int) $actionlog->item->id, - 'name' => ($actionlog->itemType()=='user') ? e($actionlog->item->getFullNameAttribute()) : e($actionlog->item->getDisplayNameAttribute()), + 'name' => e($actionlog->item->display_name) ?? null, 'type' => e($actionlog->itemType()), - 'serial' =>e($actionlog->item->serial) ? e($actionlog->item->serial) : null + 'serial' => e($actionlog->item->serial) ? e($actionlog->item->serial) : null ] : null, 'location' => ($actionlog->location) ? [ 'id' => (int) $actionlog->location->id, @@ -165,19 +168,19 @@ class ActionlogsTransformer 'action_type' => $actionlog->present()->actionType(), 'admin' => ($actionlog->adminuser) ? [ 'id' => (int) $actionlog->adminuser->id, - 'name' => e($actionlog->adminuser->getFullNameAttribute()), + 'name' => e($actionlog->adminuser->display_name) ?? null, 'first_name'=> e($actionlog->adminuser->first_name), 'last_name'=> e($actionlog->adminuser->last_name) ] : null, 'created_by' => ($actionlog->adminuser) ? [ 'id' => (int) $actionlog->adminuser->id, - 'name' => e($actionlog->adminuser->getFullNameAttribute()), + 'name' => e($actionlog->adminuser->display_name), 'first_name'=> e($actionlog->adminuser->first_name), 'last_name'=> e($actionlog->adminuser->last_name) ] : null, 'target' => ($actionlog->target) ? [ 'id' => (int) $actionlog->target->id, - 'name' => ($actionlog->targetType()=='user') ? e($actionlog->target->getFullNameAttribute()) : e($actionlog->target->getDisplayNameAttribute()), + 'name' => e($actionlog->target->display_name) ?? null, 'type' => e($actionlog->targetType()), ] : null, diff --git a/app/Http/Transformers/AssetModelsTransformer.php b/app/Http/Transformers/AssetModelsTransformer.php index 2d47ca47db..69c14da67d 100644 --- a/app/Http/Transformers/AssetModelsTransformer.php +++ b/app/Http/Transformers/AssetModelsTransformer.php @@ -48,12 +48,15 @@ class AssetModelsTransformer 'image' => ($assetmodel->image != '') ? Storage::disk('public')->url('models/'.e($assetmodel->image)) : null, 'model_number' => ($assetmodel->model_number ? e($assetmodel->model_number): null), 'min_amt' => ($assetmodel->min_amt) ? (int) $assetmodel->min_amt : null, - 'remaining' => (int) ($assetmodel->assets_count - $assetmodel->min_amt), + 'depreciation' => ($assetmodel->depreciation) ? [ 'id' => (int) $assetmodel->depreciation->id, 'name'=> e($assetmodel->depreciation->name), ] : null, 'assets_count' => (int) $assetmodel->assets_count, + 'assets_assigned_count' => (int) $assetmodel->assets_assigned_count, + 'assets_archived_count' => (int) $assetmodel->assets_archived_count, + 'remaining' => (int) ($assetmodel->assets_count - (int) $assetmodel->assets_assigned_count) - (int) $assetmodel->assets_archived_count, 'category' => ($assetmodel->category) ? [ 'id' => (int) $assetmodel->category->id, 'name'=> e($assetmodel->category->name), @@ -65,10 +68,11 @@ class AssetModelsTransformer 'default_fieldset_values' => $default_field_values, 'eol' => ($assetmodel->eol > 0) ? $assetmodel->eol.' months' : 'None', 'requestable' => ($assetmodel->requestable == '1') ? true : false, + 'require_serial' => $assetmodel->require_serial, 'notes' => Helper::parseEscapedMarkedownInline($assetmodel->notes), 'created_by' => ($assetmodel->adminuser) ? [ 'id' => (int) $assetmodel->adminuser->id, - 'name'=> e($assetmodel->adminuser->present()->fullName()), + 'name'=> e($assetmodel->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($assetmodel->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($assetmodel->updated_at, 'datetime'), diff --git a/app/Http/Transformers/AssetsTransformer.php b/app/Http/Transformers/AssetsTransformer.php index 976aff94f1..e971f1e7ae 100644 --- a/app/Http/Transformers/AssetsTransformer.php +++ b/app/Http/Transformers/AssetsTransformer.php @@ -58,6 +58,13 @@ class AssetsTransformer 'id' => (int) $asset->model->manufacturer->id, 'name'=> e($asset->model->manufacturer->name), ] : null, + 'depreciation' => (($asset->model) && ($asset->model->depreciation)) ? [ + 'id' => (int) $asset->model->depreciation->id, + 'name'=> e($asset->model->depreciation->name), + 'months'=> (int) $asset->model->depreciation->months, + 'type'=> e($asset->model->depreciation->depreciation_type), + 'minimum'=> ($asset->model->depreciation->depreciation_min) ? (int) $asset->model->depreciation->depreciation_min : null, + ] : null, 'supplier' => ($asset->supplier) ? [ 'id' => (int) $asset->supplier->id, 'name'=> e($asset->supplier->name), @@ -84,7 +91,7 @@ class AssetsTransformer 'warranty_expires' => ($asset->warranty_months > 0) ? Helper::getFormattedDateObject($asset->warranty_expires, 'date') : null, 'created_by' => ($asset->adminuser) ? [ 'id' => (int) $asset->adminuser->id, - 'name'=> e($asset->adminuser->present()->fullName()), + 'name'=> e($asset->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($asset->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($asset->updated_at, 'datetime'), @@ -280,7 +287,7 @@ class AssetsTransformer 'id' => (int) $asset->id, 'image' => ($asset->getImageUrl()) ? $asset->getImageUrl() : null, 'type' => 'asset', - 'name' => e($asset->present()->fullName()), + 'name' => e($asset->display_name), 'model' => ($asset->model) ? e($asset->model->name) : null, 'model_number' => (($asset->model) && ($asset->model->model_number)) ? e($asset->model->model_number) : null, 'asset_tag' => e($asset->asset_tag), diff --git a/app/Http/Transformers/CategoriesTransformer.php b/app/Http/Transformers/CategoriesTransformer.php index 0d1834649d..348c5d4552 100644 --- a/app/Http/Transformers/CategoriesTransformer.php +++ b/app/Http/Transformers/CategoriesTransformer.php @@ -64,7 +64,7 @@ class CategoriesTransformer 'licenses_count' => (int) $category->licenses_count, 'created_by' => ($category->adminuser) ? [ 'id' => (int) $category->adminuser->id, - 'name'=> e($category->adminuser->present()->fullName()), + 'name'=> e($category->adminuser->display_name), ] : null, 'notes' => Helper::parseEscapedMarkedownInline($category->notes), 'created_at' => Helper::getFormattedDateObject($category->created_at, 'datetime'), diff --git a/app/Http/Transformers/CompaniesTransformer.php b/app/Http/Transformers/CompaniesTransformer.php index 8ca5344de6..13f9a05e27 100644 --- a/app/Http/Transformers/CompaniesTransformer.php +++ b/app/Http/Transformers/CompaniesTransformer.php @@ -38,7 +38,7 @@ class CompaniesTransformer 'users_count' => (int) $company->users_count, 'created_by' => ($company->adminuser) ? [ 'id' => (int) $company->adminuser->id, - 'name'=> e($company->adminuser->present()->fullName()), + 'name'=> e($company->adminuser->display_name), ] : null, 'notes' => Helper::parseEscapedMarkedownInline($company->notes), 'created_at' => Helper::getFormattedDateObject($company->created_at, 'datetime'), diff --git a/app/Http/Transformers/ComponentsTransformer.php b/app/Http/Transformers/ComponentsTransformer.php index 90d10ba9a5..82e4448277 100644 --- a/app/Http/Transformers/ComponentsTransformer.php +++ b/app/Http/Transformers/ComponentsTransformer.php @@ -43,6 +43,7 @@ class ComponentsTransformer 'order_number' => e($component->order_number), 'purchase_date' => Helper::getFormattedDateObject($component->purchase_date, 'date'), 'purchase_cost' => Helper::formatCurrencyOutput($component->purchase_cost), + 'total_cost' => Helper::formatCurrencyOutput($component->totalCostSum()), 'remaining' => (int) $component->numRemaining(), 'company' => ($component->company) ? [ 'id' => (int) $component->company->id, @@ -51,7 +52,7 @@ class ComponentsTransformer 'notes' => ($component->notes) ? Helper::parseEscapedMarkedownInline($component->notes) : null, 'created_by' => ($component->adminuser) ? [ 'id' => (int) $component->adminuser->id, - 'name'=> e($component->adminuser->present()->fullName()), + 'name'=> e($component->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($component->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($component->updated_at, 'datetime'), @@ -76,7 +77,7 @@ class ComponentsTransformer $array[] = [ 'assigned_pivot_id' => $asset->pivot->id, 'id' => (int) $asset->id, - 'name' => e($asset->model->present()->name).' '.e($asset->present()->name), + 'name' => e($asset->model->display_name).' '.e($asset->display_name), 'qty' => $asset->pivot->assigned_qty, 'note' => $asset->pivot->note, 'type' => 'asset', diff --git a/app/Http/Transformers/ConsumablesTransformer.php b/app/Http/Transformers/ConsumablesTransformer.php index b31e31ac96..2739b3b8f0 100644 --- a/app/Http/Transformers/ConsumablesTransformer.php +++ b/app/Http/Transformers/ConsumablesTransformer.php @@ -25,7 +25,7 @@ class ConsumablesTransformer $array = [ 'id' => (int) $consumable->id, 'name' => e($consumable->name), - 'image' => ($consumable->image) ? Storage::disk('public')->url('consumables/'.e($consumable->image)) : null, + 'image' => ($consumable->getImageUrl()) ? ($consumable->getImageUrl()) : null, 'category' => ($consumable->category) ? ['id' => $consumable->category->id, 'name' => e($consumable->category->name)] : null, 'company' => ($consumable->company) ? ['id' => (int) $consumable->company->id, 'name' => e($consumable->company->name)] : null, 'item_no' => e($consumable->item_no), @@ -37,12 +37,13 @@ class ConsumablesTransformer 'remaining' => $consumable->numRemaining(), 'order_number' => e($consumable->order_number), 'purchase_cost' => Helper::formatCurrencyOutput($consumable->purchase_cost), + 'total_cost' => Helper::formatCurrencyOutput($consumable->totalCostSum()), 'purchase_date' => Helper::getFormattedDateObject($consumable->purchase_date, 'date'), 'qty' => (int) $consumable->qty, 'notes' => ($consumable->notes) ? Helper::parseEscapedMarkedownInline($consumable->notes) : null, 'created_by' => ($consumable->adminuser) ? [ 'id' => (int) $consumable->adminuser->id, - 'name'=> e($consumable->adminuser->present()->fullName()), + 'name'=> e($consumable->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($consumable->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($consumable->updated_at, 'datetime'), diff --git a/app/Http/Transformers/DepartmentsTransformer.php b/app/Http/Transformers/DepartmentsTransformer.php index 3d1e4c6f90..e072585a12 100644 --- a/app/Http/Transformers/DepartmentsTransformer.php +++ b/app/Http/Transformers/DepartmentsTransformer.php @@ -35,7 +35,7 @@ class DepartmentsTransformer ] : null, 'manager' => ($department->manager) ? [ 'id' => (int) $department->manager->id, - 'name' => e($department->manager->getFullNameAttribute()), + 'name' => e($department->manager->display_name), 'first_name'=> e($department->manager->first_name), 'last_name'=> e($department->manager->last_name), ] : null, diff --git a/app/Http/Transformers/DepreciationsTransformer.php b/app/Http/Transformers/DepreciationsTransformer.php index af153539e2..3b0d68392c 100644 --- a/app/Http/Transformers/DepreciationsTransformer.php +++ b/app/Http/Transformers/DepreciationsTransformer.php @@ -33,7 +33,7 @@ class DepreciationsTransformer 'licenses_count' => ($depreciation->licenses_count > 0) ? (int) $depreciation->licenses_count : 0, 'created_by' => ($depreciation->adminuser) ? [ 'id' => (int) $depreciation->adminuser->id, - 'name'=> e($depreciation->adminuser->present()->fullName()), + 'name'=> e($depreciation->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($depreciation->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($depreciation->updated_at, 'datetime') diff --git a/app/Http/Transformers/GroupsTransformer.php b/app/Http/Transformers/GroupsTransformer.php index 9495aeeecc..7593926155 100644 --- a/app/Http/Transformers/GroupsTransformer.php +++ b/app/Http/Transformers/GroupsTransformer.php @@ -29,7 +29,7 @@ class GroupsTransformer 'notes' => Helper::parseEscapedMarkedownInline($group->notes), 'created_by' => ($group->adminuser) ? [ 'id' => (int) $group->adminuser->id, - 'name'=> e($group->adminuser->present()->fullName()), + 'name'=> e($group->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($group->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($group->updated_at, 'datetime'), diff --git a/app/Http/Transformers/LicenseSeatsTransformer.php b/app/Http/Transformers/LicenseSeatsTransformer.php index 57f4087e9f..d018934e18 100644 --- a/app/Http/Transformers/LicenseSeatsTransformer.php +++ b/app/Http/Transformers/LicenseSeatsTransformer.php @@ -7,7 +7,6 @@ use App\Models\License; use App\Models\LicenseSeat; use Illuminate\Support\Facades\Gate; use Illuminate\Database\Eloquent\Collection; - class LicenseSeatsTransformer { public function transformLicenseSeats(Collection $seats, $total) @@ -52,6 +51,7 @@ class LicenseSeatsTransformer 'reassignable' => (bool) $seat->license->reassignable, 'notes' => e($seat->notes), 'user_can_checkout' => (($seat->assigned_to == '') && ($seat->asset_id == '')), + 'disabled' => $seat->unreassignable_seat || $seat->license->isInactive(), ]; $permissions_array['available_actions'] = [ diff --git a/app/Http/Transformers/LicensesTransformer.php b/app/Http/Transformers/LicensesTransformer.php index af2e902087..c360834c1c 100644 --- a/app/Http/Transformers/LicensesTransformer.php +++ b/app/Http/Transformers/LicensesTransformer.php @@ -31,13 +31,13 @@ class LicensesTransformer 'purchase_order' => ($license->purchase_order) ? e($license->purchase_order) : null, 'purchase_date' => Helper::getFormattedDateObject($license->purchase_date, 'date'), 'termination_date' => Helper::getFormattedDateObject($license->termination_date, 'date'), + 'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'), 'depreciation' => ($license->depreciation) ? ['id' => (int) $license->depreciation->id,'name'=> e($license->depreciation->name)] : null, 'purchase_cost' => Helper::formatCurrencyOutput($license->purchase_cost), 'purchase_cost_numeric' => $license->purchase_cost, 'notes' => Helper::parseEscapedMarkedownInline($license->notes), - 'expiration_date' => Helper::getFormattedDateObject($license->expiration_date, 'date'), 'seats' => (int) $license->seats, - 'free_seats_count' => (int) $license->free_seats_count, + 'free_seats_count' => (int) $license->free_seats_count - License::unReassignableCount($license), 'remaining' => (int) $license->free_seats_count, 'min_amt' => ($license->min_amt) ? (int) ($license->min_amt) : null, 'license_name' => ($license->license_name) ? e($license->license_name) : null, @@ -48,13 +48,13 @@ class LicensesTransformer 'category' => ($license->category) ? ['id' => (int) $license->category->id, 'name'=> e($license->category->name)] : null, 'created_by' => ($license->adminuser) ? [ 'id' => (int) $license->adminuser->id, - 'name'=> e($license->adminuser->present()->fullName()), + 'name'=> e($license->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($license->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($license->updated_at, 'datetime'), 'deleted_at' => Helper::getFormattedDateObject($license->deleted_at, 'datetime'), 'user_can_checkout' => (bool) ($license->free_seats_count > 0), - + 'disabled' => $license->isInactive(), ]; $permissions_array['available_actions'] = [ diff --git a/app/Http/Transformers/LocationsTransformer.php b/app/Http/Transformers/LocationsTransformer.php index 4965ff99d5..538f7e54c3 100644 --- a/app/Http/Transformers/LocationsTransformer.php +++ b/app/Http/Transformers/LocationsTransformer.php @@ -53,6 +53,9 @@ class LocationsTransformer 'assets_count' => (int) $location->assets_count, 'rtd_assets_count' => (int) $location->rtd_assets_count, 'users_count' => (int) $location->users_count, + 'consumables_count' => (int) $location->consumables_count, + 'components_count' => (int) $location->components_count, + 'children_count' => (int) $location->children_count, 'currency' => ($location->currency) ? e($location->currency) : null, 'ldap_ou' => ($location->ldap_ou) ? e($location->ldap_ou) : null, 'notes' => Helper::parseEscapedMarkedownInline($location->notes), @@ -76,12 +79,13 @@ class LocationsTransformer ]; $permissions_array['available_actions'] = [ - 'update' => Gate::allows('update', Location::class) ? true : false, + 'update' => (Gate::allows('update', Location::class) && ($location->deleted_at == '')), 'delete' => $location->isDeletable(), 'bulk_selectable' => [ 'delete' => $location->isDeletable() ], 'clone' => (Gate::allows('create', Location::class) && ($location->deleted_at == '')), + 'restore' => (Gate::allows('create', Location::class) && ($location->deleted_at != '')), ]; $array += $permissions_array; diff --git a/app/Http/Transformers/MaintenancesTransformer.php b/app/Http/Transformers/MaintenancesTransformer.php index c2fc8a0e14..05268de5ac 100644 --- a/app/Http/Transformers/MaintenancesTransformer.php +++ b/app/Http/Transformers/MaintenancesTransformer.php @@ -66,6 +66,7 @@ class MaintenancesTransformer 'id' => $assetmaintenance->supplier->id, 'name'=> e($assetmaintenance->supplier->name) ] : null, + 'url' => ($assetmaintenance->url) ? e($assetmaintenance->url) : null, 'cost' => Helper::formatCurrencyOutput($assetmaintenance->cost), 'asset_maintenance_type' => e($assetmaintenance->asset_maintenance_type), 'start_date' => Helper::getFormattedDateObject($assetmaintenance->start_date, 'date'), @@ -73,11 +74,11 @@ class MaintenancesTransformer 'completion_date' => Helper::getFormattedDateObject($assetmaintenance->completion_date, 'date'), 'user_id' => ($assetmaintenance->adminuser) ? [ 'id' => $assetmaintenance->adminuser->id, - 'name'=> e($assetmaintenance->adminuser->present()->fullName()) + 'name'=> e($assetmaintenance->adminuser->display_name) ] : null, // legacy to not change the shape of the API 'created_by' => ($assetmaintenance->adminuser) ? [ 'id' => (int) $assetmaintenance->adminuser->id, - 'name'=> e($assetmaintenance->adminuser->present()->fullName()), + 'name'=> e($assetmaintenance->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($assetmaintenance->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($assetmaintenance->updated_at, 'datetime'), diff --git a/app/Http/Transformers/ManufacturersTransformer.php b/app/Http/Transformers/ManufacturersTransformer.php index cf17eb7764..0d1373414c 100644 --- a/app/Http/Transformers/ManufacturersTransformer.php +++ b/app/Http/Transformers/ManufacturersTransformer.php @@ -40,7 +40,7 @@ class ManufacturersTransformer 'notes' => Helper::parseEscapedMarkedownInline($manufacturer->notes), 'created_by' => ($manufacturer->adminuser) ? [ 'id' => (int) $manufacturer->adminuser->id, - 'name'=> e($manufacturer->adminuser->present()->fullName()), + 'name'=> e($manufacturer->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($manufacturer->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($manufacturer->updated_at, 'datetime'), diff --git a/app/Http/Transformers/PredefinedKitsTransformer.php b/app/Http/Transformers/PredefinedKitsTransformer.php index 61c9e476a9..3660ff269e 100644 --- a/app/Http/Transformers/PredefinedKitsTransformer.php +++ b/app/Http/Transformers/PredefinedKitsTransformer.php @@ -34,7 +34,7 @@ class PredefinedKitsTransformer 'name' => e($kit->name), 'created_by' => ($kit->adminuser) ? [ 'id' => (int) $kit->adminuser->id, - 'name'=> e($kit->adminuser->present()->fullName()), + 'name'=> e($kit->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($kit->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($kit->updated_at, 'datetime'), diff --git a/app/Http/Transformers/ProfileTransformer.php b/app/Http/Transformers/ProfileTransformer.php index 9b1104515c..3b8e58e133 100644 --- a/app/Http/Transformers/ProfileTransformer.php +++ b/app/Http/Transformers/ProfileTransformer.php @@ -4,7 +4,6 @@ namespace App\Http\Transformers; use App\Helpers\Helper; use App\Models\Actionlog; -use App\Models\Asset; use Illuminate\Database\Eloquent\Collection; class ProfileTransformer @@ -26,7 +25,7 @@ class ProfileTransformer 'id' => (int) $file->id, 'icon' => Helper::filetype_icon($file->filename), 'item' => ($file->item) ? [ - 'name' => ($file->itemType()=='user') ? e($file->item->getFullNameAttribute()) : e($file->item->getDisplayNameAttribute()), + 'name' => $file->item->display_name ? e($file->item->display_name) : null, 'type' => e($file->itemType()), ] : null, 'filename' => e($file->filename), diff --git a/app/Http/Transformers/StatuslabelsTransformer.php b/app/Http/Transformers/StatuslabelsTransformer.php index 751edb7016..6409795994 100644 --- a/app/Http/Transformers/StatuslabelsTransformer.php +++ b/app/Http/Transformers/StatuslabelsTransformer.php @@ -32,7 +32,7 @@ class StatuslabelsTransformer 'notes' => e($statuslabel->notes), 'created_by' => ($statuslabel->adminuser) ? [ 'id' => (int) $statuslabel->adminuser->id, - 'name'=> e($statuslabel->adminuser->present()->fullName()), + 'name'=> e($statuslabel->adminuser->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($statuslabel->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($statuslabel->updated_at, 'datetime'), diff --git a/app/Http/Transformers/UploadedFilesTransformer.php b/app/Http/Transformers/UploadedFilesTransformer.php index ae6c981eda..e32aabc8e5 100644 --- a/app/Http/Transformers/UploadedFilesTransformer.php +++ b/app/Http/Transformers/UploadedFilesTransformer.php @@ -45,7 +45,7 @@ class UploadedFilesTransformer ] : null, 'created_at' => Helper::getFormattedDateObject($file->created_at, 'datetime'), 'deleted_at' => Helper::getFormattedDateObject($file->deleted_at, 'datetime'), - 'inlineable' => StorageHelper::allowSafeInline($file->uploads_file_path()), + 'inlineable' => StorageHelper::allowSafeInline($file->uploads_file_path()) ?? false, 'exists_on_disk' => (Storage::exists($file->uploads_file_path()) ? true : false), ]; diff --git a/app/Http/Transformers/UsersTransformer.php b/app/Http/Transformers/UsersTransformer.php index fb941007ab..1de71615cf 100644 --- a/app/Http/Transformers/UsersTransformer.php +++ b/app/Http/Transformers/UsersTransformer.php @@ -22,7 +22,7 @@ class UsersTransformer public function transformUser(User $user) { - $role = ''; + $role = null; if ($user->isSuperUser()) { $role = 'superadmin'; } elseif ($user->isAdmin()) { @@ -31,16 +31,17 @@ class UsersTransformer $array = [ 'id' => (int) $user->id, 'avatar' => e($user->present()->gravatar) ?? null, - 'name' => e($user->getFullNameAttribute()), - 'first_name' => e($user->first_name), - 'last_name' => e($user->last_name), - 'username' => e($user->username), + 'name' => e($user->getFullNameAttribute()) ?? null, + 'first_name' => e($user->first_name) ?? null, + 'last_name' => e($user->last_name) ?? null, + 'display_name' => ($user->getRawOriginal('display_name')) ? e($user->getRawOriginal('display_name')) : null, + 'username' => e($user->username) ?? null, 'remote' => ($user->remote == '1') ? true : false, 'locale' => ($user->locale) ? e($user->locale) : null, 'employee_num' => ($user->employee_num) ? e($user->employee_num) : null, 'manager' => ($user->manager) ? [ 'id' => (int) $user->manager->id, - 'name'=> e($user->manager->first_name).' '.e($user->manager->last_name), + 'name'=> e($user->manager->display_name), ] : null, 'jobtitle' => ($user->jobtitle) ? e($user->jobtitle) : null, 'vip' => ($user->vip == '1') ? true : false, @@ -59,7 +60,7 @@ class UsersTransformer ] : null, 'department_manager' => ($user->department?->manager) ? [ 'id' => (int) $user->department->manager->id, - 'name'=> e($user->department->manager->full_name), + 'name'=> e($user->department->manager->display_name), ] : null, 'location' => ($user->userloc) ? [ 'id' => (int) $user->userloc->id, @@ -82,7 +83,7 @@ class UsersTransformer 'company' => ($user->company) ? ['id' => (int) $user->company->id, 'name'=> e($user->company->name)] : null, 'created_by' => ($user->createdBy) ? [ 'id' => (int) $user->createdBy->id, - 'name'=> e($user->createdBy->present()->fullName), + 'name'=> e($user->createdBy->display_name), ] : null, 'created_at' => Helper::getFormattedDateObject($user->created_at, 'datetime'), 'updated_at' => Helper::getFormattedDateObject($user->updated_at, 'datetime'), @@ -138,6 +139,7 @@ class UsersTransformer 'first_name' => e($user->first_name), 'last_name' => e($user->last_name), 'username' => e($user->username), + 'display_name' => e($user->display_name), 'created_by' => $user->adminuser ? [ 'id' => (int) $user->adminuser->id, 'name'=> e($user->adminuser->present()->fullName), diff --git a/app/Importer/AssetModelImporter.php b/app/Importer/AssetModelImporter.php index 7cfd8a530d..b458742313 100644 --- a/app/Importer/AssetModelImporter.php +++ b/app/Importer/AssetModelImporter.php @@ -40,11 +40,32 @@ class AssetModelImporter extends ItemImporter { $editingAssetModel = false; - $assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->first(); + + /** + * This part gets a little confusing, since folks might be importing multiple models with the same name and different model numbers for the first time + * or they might be wanting to update existing models with new model numbers. + */ + + // They are not trying to update existing models, so we'll check for duplicates with model name *and* number + if (! $this->updating) { + $this->log('Finding model by name and model number: '.$this->findCsvMatch($row, 'name').' / '.$this->findCsvMatch($row, 'model_number')); + $assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->where('model_number', '=', $this->findCsvMatch($row, 'model_number'))->first(); + } else { + + if ($this->findCsvMatch($row, 'id')!='') { + // Override model if an ID was given + $this->log('Finding model by ID: '.$this->findCsvMatch($row, 'id')); + $assetModel = AssetModel::find($this->findCsvMatch($row, 'id')); + } else { + $this->log('Finding model by name: '.$this->findCsvMatch($row, 'name')); + $assetModel = AssetModel::where('name', '=', $this->findCsvMatch($row, 'name'))->first(); + } + } + if ($assetModel) { if (! $this->updating) { - $this->log('A matching Model '.$this->item['name'].' already exists'); + $this->log('A matching Model '.$this->item['name'].' already exists and we are not updating. Skipping.'); return; } @@ -66,6 +87,7 @@ class AssetModelImporter extends ItemImporter $this->item['fieldset'] = trim($this->findCsvMatch($row, 'fieldset')); $this->item['depreciation'] = trim($this->findCsvMatch($row, 'depreciation')); $this->item['requestable'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'requestable'))) == 1) ? 1 : 0; + $this->item['require_serial'] = trim(($this->fetchHumanBoolean($this->findCsvMatch($row, 'require_serial'))) == 1) ? 1 : 0; if (!empty($this->item['category'])) { if ($category = $this->createOrFetchCategory($this->item['category'])) { diff --git a/app/Importer/Importer.php b/app/Importer/Importer.php index 3c0ea4e264..a5142f4380 100644 --- a/app/Importer/Importer.php +++ b/app/Importer/Importer.php @@ -72,6 +72,7 @@ abstract class Importer 'termination_date' => 'termination date', 'warranty_months' => 'warranty', 'full_name' => 'full name', + 'display_name' => 'display name', 'email' => 'email', 'username' => 'username', 'address' => 'address', @@ -299,6 +300,7 @@ abstract class Importer 'full_name' => $this->findCsvMatch($row, 'full_name'), 'first_name' => $this->findCsvMatch($row, 'first_name'), 'last_name' => $this->findCsvMatch($row, 'last_name'), + 'display_name' => $this->findCsvMatch($row, 'display_name'), 'email' => $this->findCsvMatch($row, 'email'), 'manager_id'=> '', 'department_id' => '', @@ -369,6 +371,7 @@ abstract class Importer $user->first_name = $user_array['first_name']; $user->last_name = $user_array['last_name']; $user->username = $user_array['username']; + $user->display_name = $user_array['display_name'] ?? null; $user->email = $user_array['email']; $user->manager_id = $user_array['manager_id'] ?? null; $user->department_id = $user_array['department_id'] ?? null; diff --git a/app/Importer/ManufacturerImporter.php b/app/Importer/ManufacturerImporter.php index 5272bf698a..4c627e9d99 100644 --- a/app/Importer/ManufacturerImporter.php +++ b/app/Importer/ManufacturerImporter.php @@ -27,7 +27,7 @@ class ManufacturerImporter extends ItemImporter } /** - * Create a supplier if a duplicate does not exist. + * Create a manufacturer if a duplicate does not exist. * @todo Investigate how this should interact with Importer::createManufacturerIfNotExists * * @author A. Gianotto @@ -39,16 +39,16 @@ class ManufacturerImporter extends ItemImporter $editingManufacturer = false; - $supplier = Manufacturer::where('name', '=', $this->findCsvMatch($row, 'name'))->first(); + $manufacturer = Manufacturer::where('name', '=', $this->findCsvMatch($row, 'name'))->first(); if ($this->findCsvMatch($row, 'id')!='') { - // Override supplier if an ID was given - \Log::debug('Finding supplier by ID: '.$this->findCsvMatch($row, 'id')); - $supplier = Manufacturer::find($this->findCsvMatch($row, 'id')); + // Override manufacturer if an ID was given + \Log::debug('Finding manufacturer by ID: '.$this->findCsvMatch($row, 'id')); + $manufacturer = Manufacturer::find($this->findCsvMatch($row, 'id')); } - if ($supplier) { + if ($manufacturer) { if (! $this->updating) { $this->log('A matching Manufacturer '.$this->item['name'].' already exists'); return; @@ -58,8 +58,8 @@ class ManufacturerImporter extends ItemImporter $editingManufacturer = true; } else { $this->log('No Matching Manufacturer, Create a new one'); - $supplier = new Manufacturer; - $supplier->created_by = auth()->id(); + $manufacturer = new Manufacturer; + $manufacturer->created_by = auth()->id(); } // Pull the records from the CSV to determine their values @@ -79,21 +79,21 @@ class ManufacturerImporter extends ItemImporter if ($editingManufacturer) { - Log::debug('Updating existing supplier'); - $supplier->update($this->sanitizeItemForUpdating($supplier)); + Log::debug('Updating existing manufacturer'); + $manufacturer->update($this->sanitizeItemForUpdating($manufacturer)); } else { - Log::debug('Creating supplier'); - $supplier->fill($this->sanitizeItemForStoring($supplier)); + Log::debug('Creating manufacturer'); + $manufacturer->fill($this->sanitizeItemForStoring($manufacturer)); } - if ($supplier->save()) { - $this->log('Manufacturer '.$supplier->name.' created or updated from CSV import'); - return $supplier; + if ($manufacturer->save()) { + $this->log('Manufacturer '.$manufacturer->name.' created or updated from CSV import'); + return $manufacturer; } else { - Log::debug($supplier->getErrors()); - $this->logError($supplier, 'Manufacturer "'.$this->item['name'].'"'); - return $supplier->errors; + Log::debug($manufacturer->getErrors()); + $this->logError($manufacturer, 'Manufacturer "'.$this->item['name'].'"'); + return $manufacturer->errors; } diff --git a/app/Importer/UserImporter.php b/app/Importer/UserImporter.php index 633551c24d..942f1cf4a2 100644 --- a/app/Importer/UserImporter.php +++ b/app/Importer/UserImporter.php @@ -47,6 +47,7 @@ class UserImporter extends ItemImporter // Pull the records from the CSV to determine their values $this->item['id'] = trim($this->findCsvMatch($row, 'id')); $this->item['username'] = trim($this->findCsvMatch($row, 'username')); + $this->item['display_name'] = trim($this->findCsvMatch($row, 'display_name')); $this->item['first_name'] = trim($this->findCsvMatch($row, 'first_name')); $this->item['last_name'] = trim($this->findCsvMatch($row, 'last_name')); $this->item['email'] = trim($this->findCsvMatch($row, 'email')); diff --git a/app/Listeners/CheckoutableListener.php b/app/Listeners/CheckoutableListener.php index 7e289b19e6..908dd58dfd 100644 --- a/app/Listeners/CheckoutableListener.php +++ b/app/Listeners/CheckoutableListener.php @@ -96,7 +96,8 @@ class CheckoutableListener if (!empty($to)) { try { - Mail::to(array_flatten($to))->cc(array_flatten($cc))->send($mailable); + $toMail = (clone $mailable)->locale($notifiable->locale); + Mail::to(array_flatten($to))->send($toMail); Log::info('Checkout Mail sent to checkout target'); } catch (ClientException $e) { Log::debug("Exception caught during checkout email: " . $e->getMessage()); @@ -104,6 +105,16 @@ class CheckoutableListener Log::debug("Exception caught during checkout email: " . $e->getMessage()); } } + if (!empty($cc)) { + try { + $ccMail = (clone $mailable)->locale(Setting::getSettings()->locale); + Mail::to(array_flatten($cc))->send($ccMail); + } catch (ClientException $e) { + Log::debug("Exception caught during checkout email: " . $e->getMessage()); + } catch (Exception $e) { + Log::debug("Exception caught during checkout email: " . $e->getMessage()); + } + } } if ($shouldSendWebhookNotification) { @@ -178,15 +189,26 @@ class CheckoutableListener [$to, $cc] = $this->generateEmailRecipients($shouldSendEmailToUser, $shouldSendEmailToAlertAddress, $notifiable); - try { - if (!empty($to)) { - Mail::to(array_flatten($to))->cc(array_flatten($cc))->send($mailable); - Log::info('Checkin Mail sent to CC addresses'); + if (!empty($to)) { + try { + $toMail = (clone $mailable)->locale($notifiable->locale); + Mail::to(array_flatten($to))->send($toMail); + Log::info('Checkin Mail sent to checkin target'); + } catch (ClientException $e) { + Log::debug("Exception caught during checkin email: " . $e->getMessage()); + } catch (Exception $e) { + Log::debug("Exception caught during checkin email: " . $e->getMessage()); + } + } + if (!empty($cc)) { + try { + $ccMail = (clone $mailable)->locale(Setting::getSettings()->locale); + Mail::to(array_flatten($cc))->send($ccMail); + } catch (ClientException $e) { + Log::debug("Exception caught during checkin email: " . $e->getMessage()); + } catch (Exception $e) { + Log::debug("Exception caught during checkin email: " . $e->getMessage()); } - } catch (ClientException $e) { - Log::debug("Exception caught during checkin email: " . $e->getMessage()); - } catch (Exception $e) { - Log::debug("Exception caught during checkin email: " . $e->getMessage()); } } @@ -240,6 +262,12 @@ class CheckoutableListener $acceptance->checkoutable()->associate($event->checkoutable); $acceptance->assignedTo()->associate($event->checkedOutTo); + $acceptance->qty = 1; + + if (isset($event->checkoutable->checkout_qty)) { + $acceptance->qty = $event->checkoutable->checkout_qty; + } + $category = $this->getCategoryFromCheckoutable($event->checkoutable); if ($category?->alert_on_response) { diff --git a/app/Livewire/Importer.php b/app/Livewire/Importer.php index 6e6a6f1847..dd80eec2cc 100644 --- a/app/Livewire/Importer.php +++ b/app/Livewire/Importer.php @@ -339,6 +339,7 @@ class Importer extends Component 'start_date' => trans('general.start_date'), 'state' => trans('general.state'), 'username' => trans('admin/users/table.username'), + 'display_name' => trans('admin/users/table.display_name'), 'vip' => trans('general.importer.vip'), 'website' => trans('general.website'), 'zip' => trans('general.zip'), @@ -402,6 +403,7 @@ class Importer extends Component $this->assetmodels_fields = [ + 'id' => trans('general.id'), 'category' => trans('general.category'), 'eol' => trans('general.eol'), 'fieldset' => trans('admin/models/general.fieldset'), @@ -411,6 +413,7 @@ class Importer extends Component 'model_number' => trans('general.model_no'), 'notes' => trans('general.item_notes', ['item' => trans('admin/hardware/form.model')]), 'requestable' => trans('admin/models/general.requestable'), + 'require_serial' => trans('admin/hardware/general.require_serial'), ]; @@ -485,6 +488,13 @@ class Importer extends Component 'username', trans('general.importer.checked_out_to_username'), ], + 'display_name' => + [ + 'display name', + 'displayName', + 'display', + trans('admin/users/table.display_name'), + ], 'first_name' => [ 'first name', @@ -527,6 +537,10 @@ class Importer extends Component 'product key', 'key', ], + 'require_serial' => + [ + 'serial required', + ], 'model_number' => [ 'model', diff --git a/app/Mail/CheckinAssetMail.php b/app/Mail/CheckinAssetMail.php index 355c2f9f13..72f129dd6d 100644 --- a/app/Mail/CheckinAssetMail.php +++ b/app/Mail/CheckinAssetMail.php @@ -47,7 +47,7 @@ class CheckinAssetMail extends Mailable return new Envelope( from: $from, - subject: trans('mail.Asset_Checkin_Notification'), + subject: trans('mail.Asset_Checkin_Notification', ['tag' => $this->item->asset_tag]), ); } diff --git a/app/Mail/CheckoutAccessoryMail.php b/app/Mail/CheckoutAccessoryMail.php index 64c02e31ed..24efd57933 100644 --- a/app/Mail/CheckoutAccessoryMail.php +++ b/app/Mail/CheckoutAccessoryMail.php @@ -3,6 +3,8 @@ namespace App\Mail; use App\Models\Accessory; +use App\Models\Asset; +use App\Models\Location; use App\Models\Setting; use App\Models\User; use Illuminate\Bus\Queueable; @@ -41,7 +43,7 @@ class CheckoutAccessoryMail extends Mailable return new Envelope( from: $from, - subject: (trans('mail.Accessory_Checkout_Notification')), + subject: trans_choice('mail.Accessory_Checkout_Notification', $this->checkout_qty), ); } @@ -54,6 +56,17 @@ class CheckoutAccessoryMail extends Mailable $eula = $this->item->getEula(); $req_accept = $this->item->requireAcceptance(); $accept_url = is_null($this->acceptance) ? null : route('account.accept.item', $this->acceptance); + $name = null; + + if($this->target instanceof User){ + $name = $this->target->display_name; + } + else if($this->target instanceof Asset){ + $name = $this->target->assignedto?->display_name; + } + else if($this->target instanceof Location){ + $name = $this->target->manager->name; + } return new Content( markdown: 'mail.markdown.checkout-accessory', @@ -61,15 +74,38 @@ class CheckoutAccessoryMail extends Mailable 'item' => $this->item, 'admin' => $this->admin, 'note' => $this->note, - 'target' => $this->target, + 'target' => $name, 'eula' => $eula, 'req_accept' => $req_accept, 'accept_url' => $accept_url, 'checkout_qty' => $this->checkout_qty, + 'introduction_line' => $this->introductionLine(), ], ); } + private function introductionLine(): string + { + if ($this->target instanceof Location) { + return trans_choice('mail.new_item_checked_location', $this->checkout_qty, ['location' => $this->target->name]); + } + + if ($this->requiresAcceptance()) { + return trans_choice('mail.new_item_checked_with_acceptance', $this->checkout_qty); + } + + if (!$this->requiresAcceptance()) { + return trans_choice('mail.new_item_checked', $this->checkout_qty); + } + + // we shouldn't get here but let's send a default message just in case + return trans('new_item_checked'); + } + private function requiresAcceptance(): int|bool + { + return method_exists($this->item, 'requireAcceptance') ? $this->item->requireAcceptance() : 0; + } + /** * Get the attachments for the message. * diff --git a/app/Mail/CheckoutAssetMail.php b/app/Mail/CheckoutAssetMail.php index 44e0c06100..324c1c8f29 100644 --- a/app/Mail/CheckoutAssetMail.php +++ b/app/Mail/CheckoutAssetMail.php @@ -4,6 +4,7 @@ namespace App\Mail; use App\Helpers\Helper; use App\Models\Asset; +use App\Models\Location; use App\Models\Setting; use App\Models\User; use Illuminate\Bus\Queueable; @@ -36,14 +37,6 @@ class CheckoutAssetMail extends Mailable $this->settings = Setting::getSettings(); $this->target = $checkedOutTo; - // Location is a target option, but there are no emails currently associated with locations. - if($this->target instanceof User){ - $this->target = $this->target->present()?->fullName(); - } - else if($this->target instanceof Asset){ - $this->target = $this->target->assignedto?->present()?->fullName(); - } - $this->last_checkout = ''; $this->expected_checkin = ''; @@ -85,6 +78,17 @@ class CheckoutAssetMail extends Mailable $eula = method_exists($this->item, 'getEula') ? $this->item->getEula() : ''; $req_accept = $this->requiresAcceptance(); $fields = []; + $name = null; + + if($this->target instanceof User){ + $name = $this->target->display_name; + } + else if($this->target instanceof Asset){ + $name = $this->target->assignedto?->display_name; + } + else if($this->target instanceof Location){ + $name = $this->target->manager->name; + } // Check if the item has custom fields associated with it if (($this->item->model) && ($this->item->model->fieldset)) { @@ -100,7 +104,7 @@ class CheckoutAssetMail extends Mailable 'admin' => $this->admin, 'status' => $this->item->assetstatus?->name, 'note' => $this->note, - 'target' => $this->target, + 'target' => $name, 'fields' => $fields, 'eula' => $eula, 'req_accept' => $req_accept, @@ -125,7 +129,7 @@ class CheckoutAssetMail extends Mailable private function getSubject(): string { if ($this->firstTimeSending) { - return trans('mail.Asset_Checkout_Notification'); + return trans('mail.Asset_Checkout_Notification', ['tag' => $this->item->asset_tag]); } return trans('mail.unaccepted_asset_reminder'); @@ -133,12 +137,16 @@ class CheckoutAssetMail extends Mailable private function introductionLine(): string { + if ($this->firstTimeSending && $this->target instanceof Location) { + return trans_choice('mail.new_item_checked_location', 1, ['location' => $this->target->name]); + } + if ($this->firstTimeSending && $this->requiresAcceptance()) { - return trans('mail.new_item_checked_with_acceptance'); + return trans_choice('mail.new_item_checked_with_acceptance', 1); } if ($this->firstTimeSending && !$this->requiresAcceptance()) { - return trans('mail.new_item_checked'); + return trans_choice('mail.new_item_checked', 1); } if (!$this->firstTimeSending && $this->requiresAcceptance()) { diff --git a/app/Mail/CheckoutComponentMail.php b/app/Mail/CheckoutComponentMail.php index e914d14196..4a866b1410 100644 --- a/app/Mail/CheckoutComponentMail.php +++ b/app/Mail/CheckoutComponentMail.php @@ -26,7 +26,7 @@ class CheckoutComponentMail extends Mailable $this->note = $note; $this->target = $checkedOutTo; $this->acceptance = $acceptance; - $this->qty = $component->assets->first()?->pivot?->assigned_qty; + $this->qty = $component->checkout_qty; $this->settings = Setting::getSettings(); } diff --git a/app/Mail/CheckoutLicenseMail.php b/app/Mail/CheckoutLicenseMail.php index e0701413e7..f3688bae5a 100644 --- a/app/Mail/CheckoutLicenseMail.php +++ b/app/Mail/CheckoutLicenseMail.php @@ -31,10 +31,10 @@ class CheckoutLicenseMail extends Mailable $this->target = $checkedOutTo; if($this->target instanceof User){ - $this->target = $this->target->present()?->fullName(); + $this->target = $this->target->display_name; } elseif($this->target instanceof Asset){ - $this->target = $this->target->assignedto?->present()?->fullName(); + $this->target = $this->target->display_name; } } diff --git a/app/Models/Accessory.php b/app/Models/Accessory.php index 18c0b853c6..8b461900aa 100755 --- a/app/Models/Accessory.php +++ b/app/Models/Accessory.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Helpers\Helper; use App\Models\Traits\Acceptable; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\HasUploads; use App\Models\Traits\Searchable; use App\Presenters\Presentable; @@ -65,7 +66,7 @@ class Accessory extends SnipeModel 'company_id' => 'integer|nullable', 'location_id' => 'exists:locations,id|nullable|fmcs_location', 'min_amt' => 'integer|min:0|nullable', - 'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999', + 'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99', 'purchase_date' => 'date_format:Y-m-d|nullable', ]; @@ -308,27 +309,6 @@ class Accessory extends SnipeModel return $this->category->require_acceptance ?? false; } - /** - * Checks for a category-specific EULA, and if that doesn't exist, - * checks for a settings level EULA - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @return string - */ - public function getEula() - { - - if ($this->category->eula_text) { - return Helper::parseEscapedMarkedown($this->category->eula_text); - } elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) { - return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text); - } - - return null; - } - - /** * Check how many items within an accessory are checked out * @@ -377,6 +357,10 @@ class Accessory extends SnipeModel $accessory_checkout->limit(1)->delete(); } + public function totalCostSum() { + + return $this->purchase_cost !== null ? $this->qty * $this->purchase_cost : null; + } /** * ----------------------------------------------- @@ -406,7 +390,91 @@ class Accessory extends SnipeModel * BEGIN QUERY SCOPES * ----------------------------------------------- **/ + /** + * Query builder scope to search on text filters for complex Bootstrap Tables API + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param text $filter JSON array of search keys and terms + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeByFilter($query, $filter) + { + return $query->where( + function ($query) use ($filter) { + foreach ($filter as $fieldname => $search_val) { + + if ($fieldname == 'name') { + $query->where('accessories.name', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'notes') { + $query->where('accessories.notes', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'model_number') { + $query->where('accessories.model_number', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'order_number') { + $query->where('accessories.order_number', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'purchase_cost') { + $query->where('accessories.purchase_cost', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'location') { + $query->whereHas( + 'location', function ($query) use ($search_val) { + $query->where('locations.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + if ($fieldname == 'manufacturer') { + $query->whereHas( + 'manufacturer', function ($query) use ($search_val) { + $query->where('manufacturers.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + if ($fieldname == 'supplier') { + $query->whereHas( + 'supplier', function ($query) use ($search_val) { + $query->where('suppliers.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + if ($fieldname == 'category') { + $query->whereHas( + 'category', function ($query) use ($search_val) { + $query->where('categories.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + if ($fieldname == 'company') { + $query->whereHas( + 'company', function ($query) use ($search_val) { + $query->where('companies.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + + } + + + } + ); + } /** * Query builder scope to order on created_by name diff --git a/app/Models/Actionlog.php b/app/Models/Actionlog.php index bc1b5c72a2..3d5820f730 100755 --- a/app/Models/Actionlog.php +++ b/app/Models/Actionlog.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Carbon\Carbon; @@ -245,19 +246,6 @@ class Actionlog extends SnipeModel } - /** - * Establishes the actionlog -> uploads relationship - * - * @author [A. Gianotto] [] - * @since [v3.0] - * @return \Illuminate\Database\Eloquent\Relations\Relation - */ - public function uploads() - { - return $this->morphTo('item') - ->where('action_type', '=', 'uploaded') - ->withTrashed(); - } /** * Establishes the actionlog -> userlog relationship @@ -455,6 +443,26 @@ class Actionlog extends SnipeModel } + + /** + * @author Godfrey Martinez + * @since [v8.0.4] + * @return \App\Models\Actionlog + */ + public function logUploadDelete($object, $filename) + { + $log = new Actionlog; + $log->item_type = $object instanceof SnipeModel ? get_class($object) : $object; + $log->item_id = $object->id; + $log->created_by = auth()->id(); + $log->target_id = null; + $log->filename = $filename; + $log->created_at = date('Y-m-d H:i:s'); + $log->logaction('upload deleted'); + + return $log; + } + public function uploads_file_url() { @@ -485,6 +493,10 @@ class Actionlog extends SnipeModel return 'private_uploads/eula-pdfs/'.$this->filename; } + if ($this->action_type == 'audit') { + return 'private_uploads/audits/'.$this->filename; + } + switch ($this->item_type) { case Accessory::class: return 'private_uploads/accessories/'.$this->filename; diff --git a/app/Models/Asset.php b/app/Models/Asset.php index 244101723f..cba63987b5 100644 --- a/app/Models/Asset.php +++ b/app/Models/Asset.php @@ -7,19 +7,20 @@ use App\Exceptions\CheckoutNotAllowed; use App\Helpers\Helper; use App\Http\Traits\UniqueUndeletedTrait; use App\Models\Traits\Acceptable; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\HasUploads; use App\Models\Traits\Searchable; -use App\Presenters\Presentable; use App\Presenters\AssetPresenter; +use App\Presenters\Presentable; use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Crypt; use Illuminate\Support\Facades\Gate; use Illuminate\Support\Facades\Storage; use Watson\Validating\ValidatingTrait; -use Illuminate\Database\Eloquent\Casts\Attribute; /** * Model for Assets. @@ -113,7 +114,7 @@ class Asset extends Depreciable 'rtd_location_id' => ['nullable', 'exists:locations,id', 'fmcs_location'], 'purchase_date' => ['nullable', 'date', 'date_format:Y-m-d'], 'serial' => ['nullable', 'string', 'unique_undeleted:assets,serial'], - 'purchase_cost' => ['nullable', 'numeric', 'gte:0', 'max:9999999999999'], + 'purchase_cost' => ['nullable', 'numeric', 'gte:0', 'max:99999999999999999.99'], 'supplier_id' => ['nullable', 'exists:suppliers,id'], 'asset_eol_date' => ['nullable', 'date'], 'eol_explicit' => ['nullable', 'boolean'], @@ -160,7 +161,6 @@ class Asset extends Depreciable 'eol_explicit', 'last_audit_date', 'next_audit_date', - 'asset_eol_date', 'last_checkin', 'last_checkout', ]; @@ -227,7 +227,6 @@ class Asset extends Depreciable } - public function customFieldValidationRules() { @@ -266,7 +265,6 @@ class Asset extends Depreciable return parent::save($params); } - public function getDisplayNameAttribute() { return $this->present()->name(); @@ -277,20 +275,128 @@ class Asset extends Depreciable * * @return \Carbon\Carbon|null */ - public function getWarrantyExpiresAttribute() + + + protected function warrantyExpires(): Attribute { - if (isset($this->attributes['warranty_months']) && isset($this->attributes['purchase_date'])) { - if (is_string($this->attributes['purchase_date']) || is_string($this->attributes['purchase_date'])) { - $purchase_date = \Carbon\Carbon::parse($this->attributes['purchase_date']); - } else { - $purchase_date = \Carbon\Carbon::instance($this->attributes['purchase_date']); + return Attribute:: make( + get: fn(mixed $value, array $attributes) => ($attributes['warranty_months'] && $attributes['purchase_date']) ? Carbon::parse($attributes['purchase_date'])->addMonths($attributes['warranty_months']) : null, + ); + } + + protected function warrantyExpiresFormattedDate(): Attribute + { + + return Attribute:: make( + get: fn(mixed $value, array $attributes) => Helper::getFormattedDateObject($this->warrantyExpires, 'date', false) + ); + } + + protected function warrantyExpiresDiff(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->warrantyExpires ? round((Carbon::now()->diffInDays($this->warrantyExpires))) : null, + ); + + } + + protected function warrantyExpiresDiffForHumans(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->warrantyExpires ? Carbon::parse($this->warrantyExpires)->diffForHumans() : null, + ); + + } + + + protected function lastAuditFormattedDate(): Attribute + { + + return Attribute:: make( + get: fn(mixed $value, array $attributes) => Helper::getFormattedDateObject($this->last_audit_date, 'datetime', false) + ); + } + + protected function lastAuditDiff(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->warrantyExpires ? round((Carbon::now()->diffInDays($this->warrantyExpires))) : null, + ); + + } + + protected function lastAuditDiffForHumans(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['last_audit_date'] ? Carbon::parse($attributes['last_audit_date'])->diffForHumans() : null, + ); + + } + + protected function nextAuditFormattedDate(): Attribute + { + + return Attribute:: make( + get: fn(mixed $value, array $attributes) => Helper::getFormattedDateObject($this->next_audit_date, 'date', false) + ); + } + + protected function nextAuditDiffInDays(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['next_audit_date'] ? Carbon::now()->diffInDays($attributes['next_audit_date']) : null, + ); + } + + protected function nextAuditDiffForHumans(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['next_audit_date'] ? Carbon::parse($attributes['next_audit_date'])->diffForHumans() : null, + ); + + } + + protected function eolDate(): Attribute + { + + return Attribute:: make( + get: function(mixed $value, array $attributes) { + if ($attributes['asset_eol_date'] && $attributes['eol_explicit'] == '1') { + return Carbon::parse($attributes['asset_eol_date']); + } elseif ($attributes['purchase_date'] && $this->model && ((int) $this->model->eol > 0)) { + return Carbon::parse($attributes['purchase_date'])->addMonths((int) $this->model->eol); + } else { + return null; + } } - $purchase_date->setTime(0, 0, 0); + ); - return $purchase_date->addMonths((int) $this->attributes['warranty_months']); - } + } + + + + protected function eolFormattedDate(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->eolDate ? Helper::getFormattedDateObject($this->eolDate, 'date', false) : null, + ); + } + + protected function eolDiffInDays(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->eolDate ? round((Carbon::now()->diffInDays(Carbon::parse($this->eolDate), false, 1))) : null, + ); + + } + + protected function eolDiffForHumans(): Attribute + { + + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $this->eolDate ? Carbon::parse($this->eolDate)->diffForHumans() : null, + ); - return null; } @@ -823,21 +929,26 @@ class Asset extends Depreciable * @since [v2.0] * @return mixed */ - public static function getExpiringWarrantee($days = 30) + public static function getExpiringWarrantyOrEol($days = 30) { - $days = (is_null($days)) ? 30 : $days; - - return self::where('archived', '=', '0') // this can stay for right now, as `archived` defaults to 0 at the db level, but should probably be replaced with assetstatus->archived? - ->whereNotNull('warranty_months') - ->whereNotNull('purchase_date') - ->whereNull('deleted_at') + + return self::where('archived', '=', '0') ->NotArchived() - ->whereRaw( - 'DATE_ADD(`purchase_date`, INTERVAL `warranty_months` MONTH) <= DATE_ADD(NOW(), INTERVAL ' - . $days - . ' DAY) AND DATE_ADD(`purchase_date`, INTERVAL `warranty_months` MONTH) > NOW()' - ) - ->orderByRaw('DATE_ADD(`purchase_date`,INTERVAL `warranty_months` MONTH)') + ->whereNull('deleted_at') + ->where(function ($query) use ($days) { + // Check for manual asset EOL first + $query->where(function ($query) use ($days) { + $query->whereNotNull('asset_eol_date') + ->whereBetween('asset_eol_date', [Carbon::now(), Carbon::now()->addDays($days)]); + // Otherwise use the warranty months + purchase date + threshold + })->orWhere(function ($query) use ($days) { + $query->whereNotNull('purchase_date') + ->whereNotNull('warranty_months') + ->whereBetween('purchase_date', [Carbon::now(), Carbon::now()->addMonths('assets.warranty_months')->addDays($days)]); + }); + }) + ->orderBy('asset_eol_date', 'ASC') + ->orderBy('purchase_date', 'ASC') ->get(); } @@ -1018,31 +1129,6 @@ class Asset extends Depreciable return false; } - - /** - * Checks for a category-specific EULA, and if that doesn't exist, - * checks for a settings level EULA - * - * @author [A. Gianotto] [] - * @since [v4.0] - * @return string | false - */ - public function getEula() - { - - if (($this->model) && ($this->model->category)) { - if (($this->model->category->eula_text) && ($this->model->category->use_default_eula === 0)) { - return Helper::parseEscapedMarkedown($this->model->category->eula_text); - } elseif ($this->model->category->use_default_eula === 1) { - return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text); - } else { - - return false; - } - } - - return false; - } public function getComponentCost() { $cost = 0; @@ -1795,16 +1881,32 @@ class Asset extends Depreciable ); } - if ($fieldname =='assigned_to') { + if ($fieldname == 'assigned_to') { $query->whereHasMorph( 'assignedTo', [User::class], function ($query) use ($search_val) { $query->where( function ($query) use ($search_val) { $query->where('users.first_name', 'LIKE', '%'.$search_val.'%') - ->orWhere('users.last_name', 'LIKE', '%'.$search_val.'%'); + ->orWhere('users.last_name', 'LIKE', '%'.$search_val.'%') + ->orWhere('users.username', 'LIKE', '%'.$search_val.'%'); } ); } + )->orWhereHasMorph( + 'assignedTo', [Location::class], function ($query) use ($search_val) { + $query->where('locations.name', 'LIKE', '%'.$search_val.'%'); + } + )->orWhereHasMorph( + 'assignedTo', [Asset::class], function ($query) use ($search_val) { + $query->where( + function ($query) use ($search_val) { + // Don't use the asset table prefix here because it will pull from the original asset, + // not the subselect we're doing here to get the assigned asset + $query->where('name', 'LIKE', '%'.$search_val.'%') + ->orWhere('asset_tag', 'LIKE', '%'.$search_val.'%'); + } + ); + } ); } @@ -1844,52 +1946,69 @@ class Asset extends Depreciable } if ($fieldname == 'model') { - $query->where( - function ($query) use ($search_val) { - $query->whereHas( - 'model', function ($query) use ($search_val) { - $query->where('models.name', 'LIKE', '%'.$search_val.'%'); - } - ); - } + $query->whereHas( + 'model', function ($query) use ($search_val) { + $query->where('models.name', 'LIKE', '%'.$search_val.'%'); + } ); } + if ($fieldname == 'model_number') { - $query->where( - function ($query) use ($search_val) { - $query->whereHas( - 'model', function ($query) use ($search_val) { - $query->where('models.model_number', 'LIKE', '%'.$search_val.'%'); - } - ); - } + $query->whereHas( + 'model', function ($query) use ($search_val) { + $query->where('models.model_number', 'LIKE', '%'.$search_val.'%'); + } ); } if ($fieldname == 'company') { - $query->where( - function ($query) use ($search_val) { - $query->whereHas( - 'company', function ($query) use ($search_val) { - $query->where('companies.name', 'LIKE', '%'.$search_val.'%'); - } - ); - } + $query->whereHas( + 'company', function ($query) use ($search_val) { + $query->where('companies.name', 'LIKE', '%'.$search_val.'%'); + } ); } if ($fieldname == 'supplier') { - $query->where( - function ($query) use ($search_val) { - $query->whereHas( - 'supplier', function ($query) use ($search_val) { - $query->where('suppliers.name', 'LIKE', '%'.$search_val.'%'); + $query->whereHas( + 'supplier', function ($query) use ($search_val) { + $query->where('suppliers.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + if ($fieldname == 'status_label') { + $query->whereHas( + 'assetstatus', function ($query) use ($search_val) { + $query->where('status_labels.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + if ($fieldname == 'jobtitle') { + $query->where(function ($query) use ($search_val) { + if (is_array($search_val)) { + $query->whereHasMorph( + 'assignedTo', + [User::class], + function ($query) use ($search_val) { + $query->whereIn('users.jobtitle', $search_val); + } + ); + } else { + $query->whereHasMorph( + 'assignedTo', + [User::class], + function ($query) use ($search_val) { + $query->where(function ($query) use ($search_val) { + $query->where('users.jobtitle', 'LIKE', '%' . $search_val . '%'); + }); } ); } - ); + }); } @@ -1916,7 +2035,7 @@ class Asset extends Depreciable */ if (($fieldname!='category') && ($fieldname!='model_number') && ($fieldname!='rtd_location') && ($fieldname!='location') && ($fieldname!='supplier') - && ($fieldname!='status_label') && ($fieldname!='assigned_to') && ($fieldname!='model') && ($fieldname!='company') && ($fieldname!='manufacturer') + && ($fieldname!='status_label') && ($fieldname!='assigned_to') && ($fieldname!='model') && ($fieldname!='jobtitle') && ($fieldname!='company') && ($fieldname!='manufacturer') ) { $query->where('assets.'.$fieldname, 'LIKE', '%' . $search_val . '%'); } diff --git a/app/Models/AssetModel.php b/app/Models/AssetModel.php index c73e4492ac..0fe5160b39 100755 --- a/app/Models/AssetModel.php +++ b/app/Models/AssetModel.php @@ -71,6 +71,7 @@ class AssetModel extends SnipeModel 'name', 'notes', 'requestable', + 'require_serial' ]; use Searchable; @@ -121,6 +122,22 @@ class AssetModel extends SnipeModel return $this->hasMany(\App\Models\Asset::class, 'model_id'); } + + public function availableAssets() + { + return $this->hasMany(\App\Models\Asset::class, 'model_id')->RTD(); + } + + public function assignedAssets() + { + return $this->hasMany(\App\Models\Asset::class, 'model_id')->Deployed(); + } + + public function archivedAssets() + { + return $this->hasMany(\App\Models\Asset::class, 'model_id')->Archived(); + } + /** * Establishes the model -> category relationship * @@ -239,6 +256,57 @@ class AssetModel extends SnipeModel * ----------------------------------------------- **/ + /** + * Query builder scope to search on text filters for complex Bootstrap Tables API + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param text $filter JSON array of search keys and terms + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeByFilter($query, $filter) + { + return $query->where( + function ($query) use ($filter) { + foreach ($filter as $fieldname => $search_val) { + + if ($fieldname == 'name') { + $query->where('models.name', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'notes') { + $query->where('models.notes', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'model_number') { + $query->where('models.model_number', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'category') { + $query->whereHas( + 'category', function ($query) use ($search_val) { + $query->where('categories.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + if ($fieldname == 'manufacturer') { + $query->whereHas( + 'manufacturer', function ($query) use ($search_val) { + $query->where('manufacturers.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + + } + + + } + ); + } + /** * scopeInCategory * Get all models that are in the array of category ids diff --git a/app/Models/Category.php b/app/Models/Category.php index 7d9d7a14ae..c3b6080c1e 100755 --- a/app/Models/Category.php +++ b/app/Models/Category.php @@ -290,6 +290,35 @@ class Category extends SnipeModel * ----------------------------------------------- **/ + /** + * Query builder scope to search on text filters for complex Bootstrap Tables API + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param text $filter JSON array of search keys and terms + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeByFilter($query, $filter) + { + return $query->where( + function ($query) use ($filter) { + foreach ($filter as $fieldname => $search_val) { + + if ($fieldname == 'name') { + $query->where('categories.name', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'category_type') { + $query->where('categories.category_type', 'LIKE', '%' . $search_val . '%'); + } + + } + + + } + ); + } + /** * Query builder scope for whether or not the category requires acceptance * diff --git a/app/Models/CheckoutAcceptance.php b/app/Models/CheckoutAcceptance.php index 0599286f85..b036292077 100644 --- a/app/Models/CheckoutAcceptance.php +++ b/app/Models/CheckoutAcceptance.php @@ -2,11 +2,14 @@ namespace App\Models; +use App\Helpers\Helper; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Notifications\Notifiable; +use TCPDF; class CheckoutAcceptance extends Model { @@ -32,7 +35,19 @@ class CheckoutAcceptance extends Model return array_filter($recipients); } + public function getCheckoutableItemTypeAttribute(): string + { + $type = $this->checkoutable_type; + return match ($type) { + Asset::class => trans('general.asset'), + LicenseSeat::class => trans('general.license'), + Accessory::class => trans('general.accessory'), + Component::class => trans('general.component'), + Consumable::class => trans('general.consumable'), + default => class_basename($type), + }; + } /** * The resource that was is out * @@ -117,8 +132,7 @@ class CheckoutAcceptance extends Model /** * Filter checkout acceptences by the user * - * @param Illuminate\Database\Eloquent\Builder $query - * @param User $user + * @param User $user * @return \Illuminate\Database\Eloquent\Builder */ public function scopeForUser(Builder $query, User $user) @@ -129,11 +143,114 @@ class CheckoutAcceptance extends Model /** * Filter to only get pending acceptances * - * @param Illuminate\Database\Eloquent\Builder $query * @return \Illuminate\Database\Eloquent\Builder */ public function scopePending(Builder $query) { return $query->whereNull('accepted_at')->whereNull('declined_at'); } + + public function scopeDeclined(Builder $query) + { + return $query->whereNull('accepted_at')->whereNotNull('declined_at'); + } + + protected function displayCheckoutableType(): Attribute + { + return Attribute:: make( + get: fn(mixed $value) => strtolower(str_replace('App\Models\\', '', $this->checkoutable_type)), + ); + } + + public function generateAcceptancePdf($data, $pdf_filename) { + + // set some language dependent data: + $lg = Array(); + $lg['a_meta_charset'] = 'UTF-8'; + $lg['w_page'] = 'page'; + + $pdf = new TCPDF('P', 'mm', 'A4', true, 'UTF-8', false); + $pdf->setRTL(false); + $pdf->setLanguageArray($lg); + $pdf->SetFontSubsetting(true); + $pdf->SetCreator('Snipe-IT Asset Management System'); + $pdf->SetAuthor($data['assigned_to']); + $pdf->SetTitle('Asset Acceptance: '.$data['item_tag']); + $pdf->SetSubject('Asset Acceptance: '.$data['item_tag']); + $pdf->SetKeywords('Snipe-IT, assets, acceptance, eula, tos'); + $pdf->SetFont('dejavusans', '', 8, '', true); + $pdf->SetPrintHeader(false); + $pdf->SetPrintFooter(false); + + $pdf->AddPage(); + if ($data['logo'] != null) { + $pdf->writeHTML('', true, 0, true, 0, ''); + } else { + $pdf->writeHTML('

'.$data['site_name'].'



', true, 0, true, 0, 'C'); + } + + $pdf->Ln(); + $pdf->writeHTML(trans('general.date') . ': ' . Helper::getFormattedDateObject(now(), 'datetime', false), true, 0, true, 0, ''); + + if ($data['company_name'] != null) { + $pdf->writeHTML(trans('general.company') . ': ' . e($data['company_name']), true, 0, true, 0, ''); + } + if ($data['item_tag'] != null) { + $pdf->writeHTML(trans('general.asset_tag') . ': ' . e($data['item_tag']), true, 0, true, 0, ''); + } + if ($data['item_name'] != null) { + $pdf->writeHTML(trans('general.name') . ': ' . e($data['item_name']), true, 0, true, 0, ''); + } + if ($data['item_model'] != null) { + $pdf->writeHTML(trans('general.asset_model') . ': ' . e($data['item_model']), true, 0, true, 0, ''); + } + if ($data['item_serial'] != null) { + $pdf->writeHTML(trans('admin/hardware/form.serial').': '.e($data['item_serial']), true, 0, true, 0, ''); + } + if (($data['qty'] != null) && ($data['qty'] > 1)) { + $pdf->writeHTML(trans('general.qty').': '.e($data['qty']), true, 0, true, 0, ''); + } + $pdf->writeHTML(trans('general.assignee').': '.e($data['assigned_to']) . ($data['employee_num'] ? ' ('.$data['employee_num'].')' : ''), true, 0, true, 0, ''); + if ($data['email'] != null) { + $pdf->writeHTML(trans('general.email').': '.e($data['email']), true, 0, true, 0, ''); + } + $pdf->Ln(); + $pdf->writeHTML('
', true, 0, true, 0, ''); + + + // Break the EULA into lines based on newlines, and check each line for RTL or CJK characters + $eula_lines = preg_split("/\r\n|\n|\r/", $data['eula']); + + foreach ($eula_lines as $eula_line) { + Helper::hasRtl($eula_line) ? $pdf->setRTL(true) : $pdf->setRTL(false); + Helper::isCjk($eula_line) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true); + + $pdf->writeHTML(Helper::parseEscapedMarkedown($eula_line), true, 0, true, 0, ''); + } + $pdf->Ln(); + $pdf->Ln(); + $pdf->setRTL(false); + $pdf->Ln(); + + if ($data['signature'] != null) { + $pdf->writeHTML('', true, 0, true, 0, ''); + $pdf->writeHTML('
', true, 0, true, 0, ''); + $pdf->writeHTML(e($data['assigned_to']), true, 0, true, 0, 'C'); + $pdf->Ln(); + } + + if ($data['note'] != null) { + Helper::isCjk($data['note']) ? $pdf->SetFont('cid0cs', '', 9) : $pdf->SetFont('dejavusans', '', 8, '', true); + $pdf->writeHTML(trans('general.notes') . ': ' . e($data['note']), true, 0, true, 0, ''); + $pdf->Ln(); + } + + + $pdf->writeHTML(trans('general.assigned_date').': '.e($data['check_out_date']), true, 0, true, 0, ''); + $pdf->writeHTML(trans('general.accepted_date').': '.e($data['accepted_date']), true, 0, true, 0, ''); + + return $pdf->Output($pdf_filename, 'S'); + + + } } diff --git a/app/Models/CheckoutRequest.php b/app/Models/CheckoutRequest.php index 42512d8fda..b651275dd8 100644 --- a/app/Models/CheckoutRequest.php +++ b/app/Models/CheckoutRequest.php @@ -46,7 +46,7 @@ class CheckoutRequest extends Model public function name() { if ($this->itemType() == 'asset') { - return $this->itemRequested()->present()->name(); + return $this->itemRequested()->display_name; } return $this->itemRequested()->name; diff --git a/app/Models/Company.php b/app/Models/Company.php index a2f5ddc38b..72a12aebc6 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -2,14 +2,16 @@ namespace App\Models; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\Searchable; use App\Presenters\Presentable; -use Illuminate\Support\Facades\Auth; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Gate; -use Watson\Validating\ValidatingTrait; use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Schema; +use Watson\Validating\ValidatingTrait; + /** * Model for Companies. * diff --git a/app/Models/Component.php b/app/Models/Component.php index a83993c225..fb62a872c2 100644 --- a/app/Models/Component.php +++ b/app/Models/Component.php @@ -3,13 +3,13 @@ namespace App\Models; use App\Helpers\Helper; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\HasUploads; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Gate; -use Illuminate\Support\Facades\Storage; use Watson\Validating\ValidatingTrait; /** @@ -43,7 +43,7 @@ class Component extends SnipeModel 'location_id' => 'exists:locations,id|nullable|fmcs_location', 'min_amt' => 'integer|min:0|nullable', 'purchase_date' => 'date_format:Y-m-d|nullable', - 'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999', + 'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99', 'manufacturer_id' => 'integer|exists:manufacturers,id|nullable', ]; @@ -217,24 +217,6 @@ class Component extends SnipeModel return $this->category->require_acceptance; } - /** - * Checks for a category-specific EULA, and if that doesn't exist, - * checks for a settings level EULA - * - * @author [A. Gianotto] [] - * @since [v4.0] - * @return string | false - */ - public function getEula() - { - if ($this->category->eula_text) { - return Helper::parseEscapedMarkedown($this->category->eula_text); - } elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) { - return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text); - } else { - return null; - } - } /** * Establishes the component -> action logs relationship @@ -306,7 +288,10 @@ class Component extends SnipeModel return $this->qty - $this->numCheckedOut(); } + public function totalCostSum() { + return $this->purchase_cost !== null ? $this->qty * $this->purchase_cost : null; + } /** * ----------------------------------------------- * BEGIN MUTATORS @@ -336,6 +321,97 @@ class Component extends SnipeModel * ----------------------------------------------- **/ + /** + * Query builder scope to search on text filters for complex Bootstrap Tables API + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param text $filter JSON array of search keys and terms + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeByFilter($query, $filter) + { + return $query->where( + function ($query) use ($filter) { + foreach ($filter as $fieldname => $search_val) { + + if ($fieldname == 'name') { + $query->where('components.name', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'notes') { + $query->where('components.notes', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'model_number') { + $query->where('components.model_number', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'order_number') { + $query->where('components.order_number', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'serial') { + $query->where('components.serial', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'serial') { + $query->where('components.serial', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'purchase_cost') { + $query->where('components.purchase_cost', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'location') { + $query->whereHas( + 'location', function ($query) use ($search_val) { + $query->where('locations.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + if ($fieldname == 'manufacturer') { + $query->whereHas( + 'manufacturer', function ($query) use ($search_val) { + $query->where('manufacturers.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + if ($fieldname == 'supplier') { + $query->whereHas( + 'supplier', function ($query) use ($search_val) { + $query->where('suppliers.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + if ($fieldname == 'category') { + $query->whereHas( + 'category', function ($query) use ($search_val) { + $query->where('categories.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + if ($fieldname == 'company') { + $query->whereHas( + 'company', function ($query) use ($search_val) { + $query->where('companies.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + } + + + } + ); + } /** * Query builder scope to order on company diff --git a/app/Models/Consumable.php b/app/Models/Consumable.php index f4b6a3ca6b..339b88044e 100644 --- a/app/Models/Consumable.php +++ b/app/Models/Consumable.php @@ -4,22 +4,16 @@ namespace App\Models; use App\Helpers\Helper; use App\Models\Traits\Acceptable; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\HasUploads; use App\Models\Traits\Searchable; +use App\Presenters\ConsumablePresenter; use App\Presenters\Presentable; use Illuminate\Database\Eloquent\Factories\HasFactory; +use Illuminate\Database\Eloquent\Relations\Relation; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Storage; use Watson\Validating\ValidatingTrait; -use Illuminate\Database\Eloquent\Relations\Relation; -use App\Presenters\ConsumablePresenter; -use App\Models\Actionlog; -use App\Models\ConsumableAssignment; -use App\Models\User; -use App\Models\Location; -use App\Models\Manufacturer; -use App\Models\Supplier; -use App\Models\Category; class Consumable extends SnipeModel { @@ -53,7 +47,7 @@ class Consumable extends SnipeModel 'company_id' => 'integer|nullable', 'location_id' => 'exists:locations,id|nullable|fmcs_location', 'min_amt' => 'integer|min:0|max:99999|nullable', - 'purchase_cost' => 'numeric|nullable|gte:0|max:9999999999999', + 'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99', 'purchase_date' => 'date_format:Y-m-d|nullable', ]; @@ -230,11 +224,16 @@ class Consumable extends SnipeModel */ public function getImageUrl() { + // If there is a consumable image, use that if ($this->image) { return Storage::disk('public')->url(app('consumables_upload_path').$this->image); - } - return false; + // Otherwise check for a category image + } elseif (($this->category) && ($this->category->image)) { + return Storage::disk('public')->url(app('categories_upload_path').e($this->category->image)); + } + + return false; } /** @@ -286,25 +285,6 @@ class Consumable extends SnipeModel return $this->category->require_acceptance; } - /** - * Checks for a category-specific EULA, and if that doesn't exist, - * checks for a settings level EULA - * - * @author [A. Gianotto] [] - * @since [v4.0] - * @return string | false - */ - public function getEula() - { - if ($this->category->eula_text) { - return Helper::parseEscapedMarkedown($this->category->eula_text); - } elseif ((Setting::getSettings()->default_eula_text) && ($this->category->use_default_eula == '1')) { - return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text); - } else { - return null; - } - } - /** * Check how many items within a consumable are checked out * @@ -332,7 +312,10 @@ class Consumable extends SnipeModel return $remaining; } + public function totalCostSum() { + return $this->purchase_cost !== null ? $this->qty * $this->purchase_cost : null; + } /** * ----------------------------------------------- * BEGIN MUTATORS @@ -362,6 +345,99 @@ class Consumable extends SnipeModel * ----------------------------------------------- **/ + /** + * Query builder scope to search on text filters for complex Bootstrap Tables API + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param text $filter JSON array of search keys and terms + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeByFilter($query, $filter) + { + return $query->where( + function ($query) use ($filter) { + foreach ($filter as $fieldname => $search_val) { + + if ($fieldname == 'name') { + $query->where('consumables.name', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'notes') { + $query->where('consumables.notes', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'model_number') { + $query->where('consumables.model_number', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'order_number') { + $query->where('consumables.order_number', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'item_no') { + $query->where('consumables.item_no', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'serial') { + $query->where('consumables.serial', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'purchase_cost') { + $query->where('consumables.purchase_cost', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'location') { + $query->whereHas( + 'location', function ($query) use ($search_val) { + $query->where('locations.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + if ($fieldname == 'manufacturer') { + $query->whereHas( + 'manufacturer', function ($query) use ($search_val) { + $query->where('manufacturers.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + if ($fieldname == 'supplier') { + $query->whereHas( + 'supplier', function ($query) use ($search_val) { + $query->where('suppliers.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + if ($fieldname == 'category') { + $query->whereHas( + 'category', function ($query) use ($search_val) { + $query->where('categories.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + if ($fieldname == 'company') { + $query->whereHas( + 'company', function ($query) use ($search_val) { + $query->where('companies.name', 'LIKE', '%'.$search_val.'%'); + } + ); + } + + + + } + + + } + ); + } + /** * Query builder scope to order on company * diff --git a/app/Models/ConsumableAssignment.php b/app/Models/ConsumableAssignment.php index 4c9a19703e..0e634f580f 100644 --- a/app/Models/ConsumableAssignment.php +++ b/app/Models/ConsumableAssignment.php @@ -2,6 +2,7 @@ namespace App\Models; +use App\Models\Traits\CompanyableTrait; use Illuminate\Database\Eloquent\Model; use Watson\Validating\ValidatingTrait; diff --git a/app/Models/Department.php b/app/Models/Department.php index 79616101e3..1569081fdd 100644 --- a/app/Models/Department.php +++ b/app/Models/Department.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Http\Traits\UniqueUndeletedTrait; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\Searchable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Watson\Validating\ValidatingTrait; diff --git a/app/Models/Labels/DefaultLabel.php b/app/Models/Labels/DefaultLabel.php index fa60dafab3..0ac2eb14da 100644 --- a/app/Models/Labels/DefaultLabel.php +++ b/app/Models/Labels/DefaultLabel.php @@ -229,7 +229,7 @@ class DefaultLabel extends RectangleSheet static::writeText( $pdf, $record->get('title'), $textX1, 0, - 'freesans', 'b', $this->textSize, 'L', + Helper::isCjk($record->get('title')) ? 'cid0cs' : 'freesans', 'b', $this->textSize, 'L', $textW, $this->textSize, true, 0 ); @@ -246,11 +246,12 @@ class DefaultLabel extends RectangleSheet static::writeText( $pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'], $textX1, $textY, - 'freesans', '', $this->textSize, 'L', + Helper::isCjk($field['label']) ? 'cid0cs' : 'freesans', '', $this->textSize, 'L', $textW, $this->textSize, true, 0 ); + $textY += $this->textSize + self::TEXT_MARGIN; $fieldsDone++; } diff --git a/app/Models/Labels/FieldOption.php b/app/Models/Labels/FieldOption.php index 916707b21d..cf65af57ba 100644 --- a/app/Models/Labels/FieldOption.php +++ b/app/Models/Labels/FieldOption.php @@ -30,10 +30,10 @@ class FieldOption if ($asset->relationLoaded('assignedTo')) { // If the "assignedTo" relationship was eager loaded then the way to get the // relationship changes from $asset->assignedTo to $asset->assigned. - return $asset->assigned ? $asset->assigned->present()->fullName() : null; + return $asset->assigned ? $asset->assigned->display_name : null; } - return $asset->assignedTo ? $asset->assignedTo->present()->fullName() : null; + return $asset->assignedTo ? $asset->assignedTo->display_name : null; } // Handle Laravel's stupid Carbon datetime casting diff --git a/app/Models/Labels/Label.php b/app/Models/Labels/Label.php index cff859f359..2c463e0921 100644 --- a/app/Models/Labels/Label.php +++ b/app/Models/Labels/Label.php @@ -211,29 +211,36 @@ abstract class Label */ public final function writeText(TCPDF $pdf, $text, $x, $y, $font=null, $style=null, $size=null, $align='L', $width=null, $height=null, $squash=false, $border=0, $spacing=0) { + + $prevFamily = $pdf->getFontFamily(); $prevStyle = $pdf->getFontStyle(); $prevSizePt = $pdf->getFontSizePt(); + $text = !empty($text) ? $text : ''; $fontFamily = !empty($font) ? $font : $prevFamily; $fontStyle = !empty($style) ? $style : $prevStyle; - if ($size) { $fontSizePt = Helper::convertUnit($size, $this->getUnit(), 'pt', true); - } else { $fontSizePt = $prevSizePt; + + + if ($size) { + $fontSizePt = Helper::convertUnit($size, $this->getUnit(), 'pt', true); + } else { + $fontSizePt = $prevSizePt; } $pdf->SetFontSpacing($spacing); $parts = collect(explode('**', $text)) ->map( - function ($part, $index) use ($pdf, $fontFamily, $fontStyle, $fontSizePt) { + function ($part, $index) use ($pdf, $fontFamily, $fontStyle, $fontSizePt, $text) { $modStyle = ($index % 2 == 1) ? 'B' : $fontStyle; $pdf->setFont($fontFamily, $modStyle, $fontSizePt); return [ 'text' => $part, 'text_width' => $pdf->GetStringWidth($part), - 'font_family' => $fontFamily, + 'font_family' => Helper::isCjk($text) ? 'cid0cs' : $fontFamily, 'font_style' => $modStyle, 'font_size' => $fontSizePt, ]; diff --git a/app/Models/Labels/Sheets/Avery/L6009.php b/app/Models/Labels/Sheets/Avery/L6009.php new file mode 100644 index 0000000000..11d6cfffca --- /dev/null +++ b/app/Models/Labels/Sheets/Avery/L6009.php @@ -0,0 +1,110 @@ +getUnit(), 0); + $this->pageWidth = $paperSize->width; + $this->pageHeight = $paperSize->height; + + $this->pageMarginLeft = Helper::convertUnit(self::COLUMN1_X, 'pt', $this->getUnit()); + $this->pageMarginTop = Helper::convertUnit(self::ROW1_Y, 'pt', $this->getUnit()); + + $columnSpacingPt = self::COLUMN2_X - self::COLUMN1_X - self::LABEL_W; + $this->columnSpacing = Helper::convertUnit($columnSpacingPt, 'pt', $this->getUnit()); + $rowSpacingPt = self::ROW2_Y - self::ROW1_Y - self::LABEL_H; + $this->rowSpacing = Helper::convertUnit($rowSpacingPt, 'pt', $this->getUnit()); + + $this->labelWidth = Helper::convertUnit(self::LABEL_W, 'pt', $this->getUnit()); + $this->labelHeight = Helper::convertUnit(self::LABEL_H, 'pt', $this->getUnit()); + } + + public function getPageWidth() + { + return $this->pageWidth; + } + public function getPageHeight() + { + return $this->pageHeight; + } + + public function getPageMarginTop() + { + return $this->pageMarginTop; + } + public function getPageMarginBottom() + { + return $this->pageMarginTop; + } + public function getPageMarginLeft() + { + return $this->pageMarginLeft; + } + public function getPageMarginRight() + { + return $this->pageMarginLeft; + } + + public function getColumns() + { + return 4; + } + public function getRows() + { + return 12; + } + + public function getLabelColumnSpacing() + { + return $this->columnSpacing; + } + public function getLabelRowSpacing() + { + return $this->rowSpacing; + } + + public function getLabelWidth() + { + return $this->labelWidth; + } + public function getLabelHeight() + { + return $this->labelHeight; + } + + public function getLabelBorder() + { + return 0; + } +} + +?> diff --git a/app/Models/Labels/Sheets/Avery/L6009_A.php b/app/Models/Labels/Sheets/Avery/L6009_A.php new file mode 100644 index 0000000000..09f3aa8358 --- /dev/null +++ b/app/Models/Labels/Sheets/Avery/L6009_A.php @@ -0,0 +1,121 @@ +getLabelPrintableArea(); + + $currentX = $pa->x1; + $currentY = $pa->y1; + $usableWidth = $pa->w; + $usableHeight = $pa->h; + + if ($record->has('title')) { + static::writeText( + $pdf, $record->get('title'), + $pa->x1, $pa->y1, + 'freesans', '', self::TITLE_SIZE, 'C', + $pa->w, self::TITLE_SIZE, true, 0 + ); + + } + $currentY += self::TITLE_SIZE + self::TITLE_MARGIN; + $usableHeight -= self::TITLE_SIZE + self::TITLE_MARGIN; + $barcodeSize = $usableHeight; + if ($record->has('barcode2d')) { + static::write2DBarcode( + $pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type, + $currentX, $currentY, + $barcodeSize, $barcodeSize + ); + $currentX += $barcodeSize + self::BARCODE_MARGIN; + $usableWidth -= $barcodeSize + self::BARCODE_MARGIN; + } + + foreach ($record->get('fields') as $field) { + static::writeText( + $pdf, $field['label'], + $currentX, $currentY, + 'freesans', '', self::LABEL_SIZE, 'L', + $usableWidth, self::LABEL_SIZE, true, 0 + ); + $currentY += self::LABEL_SIZE + self::LABEL_MARGIN; + + static::writeText( + $pdf, $field['value'], + $currentX, $currentY, + 'freemono', 'B', self::FIELD_SIZE, 'L', + $usableWidth, self::FIELD_SIZE, true, 0, 0.01 + ); + $currentY += self::FIELD_SIZE + self::FIELD_MARGIN; + } + + } +} + + +?> diff --git a/app/Models/Labels/Tapes/Brother/TZe_24mm_E.php b/app/Models/Labels/Tapes/Brother/TZe_24mm_E.php new file mode 100644 index 0000000000..9e1fcdadf8 --- /dev/null +++ b/app/Models/Labels/Tapes/Brother/TZe_24mm_E.php @@ -0,0 +1,107 @@ +getPrintableArea(); + + $currentX = $pa->x1; + $currentY = $pa->y1; + $usableWidth = $pa->w; + + + $usableHeight = $pa->h - self::BARCODE1D_SIZE; + $barcodeSize = $usableHeight - self::TAG_SIZE; + + if ($record->has('barcode2d')) { + static::writeText( + $pdf, $record->get('tag'), + $pa->x1, $pa->y2 - self::TAG_SIZE - self::BARCODE1D_SIZE, + 'freesans', 'b', self::TAG_SIZE, 'C', + $barcodeSize, self::TAG_SIZE, true, 0 + ); + static::write2DBarcode( + $pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type, + $currentX, $currentY, + $barcodeSize, $barcodeSize + ); + $currentX += $barcodeSize + self::BARCODE_MARGIN; + $usableWidth -= $barcodeSize + self::BARCODE_MARGIN; + } else { + static::writeText( + $pdf, $record->get('tag'), + $pa->x1, $pa->y2 - self::TAG_SIZE - self::BARCODE1D_SIZE, + 'freesans', 'B', self::TAG_SIZE, 'R', + $usableWidth, self::TAG_SIZE, true, 0 + ); + } + + if ($record->has('title')) { + static::writeText( + $pdf, $record->get('title'), + $currentX, $currentY, + 'freesans', 'B', self::TITLE_SIZE, 'L', + $usableWidth, self::TITLE_SIZE, true, 0 + ); + $currentY += self::TITLE_SIZE + self::TITLE_MARGIN; + } + + foreach ($record->get('fields') as $field) { + // Write label and value on the same line + // Calculate label width with proportional character spacing + $labelWidth = $pdf->GetStringWidth($field['label'], 'freesans', '', self::LABEL_SIZE); + $charCount = strlen($field['label']); + $spacingPerChar = 0.5; + $totalSpacing = $charCount * $spacingPerChar; + $adjustedWidth = $labelWidth + $totalSpacing; + + static::writeText( + $pdf, $field['label'], + $currentX, $currentY, + 'freesans', 'B', self::LABEL_SIZE, 'L', + $adjustedWidth, self::LABEL_SIZE, true, 0, $spacingPerChar + ); + + static::writeText( + $pdf, $field['value'], + $currentX + $adjustedWidth + 2, $currentY, + 'freesans', 'B', self::FIELD_SIZE, 'L', + $usableWidth - $adjustedWidth - 2, self::FIELD_SIZE, true, 0, 0.3 + ); + + $currentY += max(self::LABEL_SIZE, self::FIELD_SIZE) + self::FIELD_MARGIN; + } + + + if ($record->has('barcode1d')) { + static::write1DBarcode( + $pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type, + $currentX, $barcodeSize + self::BARCODE_MARGIN, $usableWidth - self::TAG_SIZE, self::TAG_SIZE + ); + } + } +} diff --git a/app/Models/Labels/Tapes/Dymo/LabelWriter_11354.php b/app/Models/Labels/Tapes/Dymo/LabelWriter_11354.php new file mode 100644 index 0000000000..08f2fb6d27 --- /dev/null +++ b/app/Models/Labels/Tapes/Dymo/LabelWriter_11354.php @@ -0,0 +1,116 @@ +getPrintableArea(); + + $currentX = $pa->x1; + $currentY = $pa->y1; + $usableWidth = $pa->w; + $usableHeight = $pa->h; + + // Wide 1D barcode on top + if ($record->has('barcode1d')) { + static::write1DBarcode( + $pdf, $record->get('barcode1d')->content, $record->get('barcode1d')->type, + $currentX, $currentY, $usableWidth, self::BARCODE1D_HEIGHT + ); + $currentY += self::BARCODE1D_HEIGHT + self::BARCODE_MARGIN; + $usableHeight -= self::BARCODE1D_HEIGHT + self::BARCODE_MARGIN; + } + + // 2D Barcode in left column + if ($record->has('barcode2d')) { + $barcodeSize = $usableHeight - self::TAG_SIZE; + + static::writeText( + $pdf, $record->get('tag'), + $currentX, $pa->y2 - self::TAG_SIZE, + 'freesans', 'b', self::TAG_SIZE, 'C', + $barcodeSize, self::TAG_SIZE, true, 0 + ); + static::write2DBarcode( + $pdf, $record->get('barcode2d')->content, $record->get('barcode2d')->type, + $currentX, $currentY, + $barcodeSize, $barcodeSize + ); + $currentX += $barcodeSize + self::BARCODE_MARGIN; + $usableWidth -= $barcodeSize + self::BARCODE_MARGIN; + } + + // Right column + if ($record->has('title')) { + static::writeText( + $pdf, $record->get('title'), + $currentX, $currentY, + 'freesans', 'b', self::TITLE_SIZE, 'L', + $usableWidth, self::TITLE_SIZE, true, 0 + ); + $currentY += self::TITLE_SIZE + self::TITLE_MARGIN; + } + + foreach ($record->get('fields') as $field) { + static::writeText( + $pdf, (($field['label']) ? $field['label'].' ' : '') . $field['value'], + $currentX, $currentY, + 'freesans', '', self::FIELD_SIZE, 'L', + $usableWidth, self::FIELD_SIZE, true, 0, 0.3 + ); + $currentY += self::FIELD_SIZE + self::FIELD_MARGIN; + } + } + +} \ No newline at end of file diff --git a/app/Models/Ldap.php b/app/Models/Ldap.php index e99ae07265..168da8b571 100644 --- a/app/Models/Ldap.php +++ b/app/Models/Ldap.php @@ -27,6 +27,35 @@ use Illuminate\Support\Facades\Crypt; class Ldap extends Model { + public static function ignoreCertificates(bool $ignore_cert = true) + { + if (defined('LDAP_OPT_X_TLS_REQUIRE_CERT') && defined('LDAP_OPT_X_TLS_NEVER')) { + // TODO - we are currently, as a 'safety', doing *both* the following 'new-style' ldap_set_option calls, + // as well as "falling-through" to the 'old-style' putenv() calls. + // + // I *suspect* we can eventually remove the putenv() calls, but I'm just a little nervous about that. + // According to the PHP docs, the LDAP_OPT_X_TLS_REQUIRE_CERT constant has been available since PHP 7.0. + // We're currently using PHP versions way, way later than that (v8.2-v8.4 as of this writing). So it's + // unlikely that these constants wouldn't be defined - unless you didn't have LDAP support in the first + // place. But if that were to happen, I would hope we would've detected that long, long ago, rather than at + // this point. + if ($ignore_cert) { + if (ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_NEVER)) { + //return true; + } + } else { + if (ldap_set_option(null, LDAP_OPT_X_TLS_REQUIRE_CERT, LDAP_OPT_X_TLS_DEMAND)) { + //return true; + } + } + } + if ($ignore_cert) { + return putenv('LDAPTLS_REQCERT=never'); + } else { + return putenv('LDAPTLS_REQCERT'); + } + } + /** * Makes a connection to LDAP using the settings in Admin > Settings. * @@ -43,14 +72,18 @@ class Ldap extends Model // If we are ignoring the SSL cert we need to setup the environment variable // before we create the connection - if ($ldap_server_cert_ignore == '1') { - putenv('LDAPTLS_REQCERT=never'); - } + self::ignoreCertificates((bool)$ldap_server_cert_ignore); // If the user specifies where CA Certs are, make sure to use them if (env('LDAPTLS_CACERT')) { putenv('LDAPTLS_CACERT='.env('LDAPTLS_CACERT')); } + // You _were_ allowed to do this *after* the ldap_connect() in some versions of PHP, but it's not how they want + // you to anymore, and it seems to not work at all in later PHP versions. + if (Setting::getSettings()->ldap_client_tls_cert && Setting::getSettings()->ldap_client_tls_key) { + ldap_set_option(null, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path()); + ldap_set_option(null, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path()); + } $connection = @ldap_connect($ldap_host); @@ -63,11 +96,6 @@ class Ldap extends Model ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, $ldap_version); ldap_set_option($connection, LDAP_OPT_NETWORK_TIMEOUT, 20); - if (Setting::getSettings()->ldap_client_tls_cert && Setting::getSettings()->ldap_client_tls_key) { - ldap_set_option(null, LDAP_OPT_X_TLS_CERTFILE, Setting::get_client_side_cert_path()); - ldap_set_option(null, LDAP_OPT_X_TLS_KEYFILE, Setting::get_client_side_key_path()); - } - if ($ldap_use_tls=='1') { ldap_start_tls($connection); } diff --git a/app/Models/License.php b/app/Models/License.php index a40728a832..3fcd7e7bab 100755 --- a/app/Models/License.php +++ b/app/Models/License.php @@ -3,17 +3,19 @@ namespace App\Models; use App\Helpers\Helper; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\HasUploads; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Carbon\Carbon; -use Illuminate\Support\Facades\DB; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; -use Illuminate\Support\Facades\Auth; +use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\Session; use Watson\Validating\ValidatingTrait; + class License extends Depreciable { use HasFactory; @@ -51,7 +53,7 @@ class License extends Depreciable 'notes' => 'string|nullable', 'category_id' => 'required|exists:categories,id', 'company_id' => 'integer|nullable', - 'purchase_cost'=> 'numeric|nullable|gte:0', + 'purchase_cost' => 'numeric|nullable|gte:0|max:99999999999999999.99', 'purchase_date' => 'date_format:Y-m-d|nullable|max:10|required_with:depreciation_id', 'expiration_date' => 'date_format:Y-m-d|nullable|max:10', 'termination_date' => 'date_format:Y-m-d|nullable|max:10', @@ -155,6 +157,29 @@ class License extends Depreciable ); } + + protected function terminatesFormattedDate(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['termination_date'] ? Helper::getFormattedDateObject($attributes['termination_date'], 'date', false) : null, + ); + } + + protected function terminatesDiffInDays(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['termination_date'] ? Carbon::now()->diffInDays($attributes['termination_date']) : null, + ); + } + + protected function terminatesDiffForHumans(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['termination_date'] ? Carbon::parse($attributes['termination_date'])->diffForHumans() : null, + ); + } + + public function prepareLimitChangeRule($parameters, $field) { $actual_seat_count = $this->licenseseats()->count(); //we use the *actual* seat count here, in case your license has gone wonky @@ -296,6 +321,38 @@ class License extends Depreciable } $this->attributes['termination_date'] = $value; } + + public function isInactive(): bool +{ + $day = now()->startOfDay(); + + $expired = $this->expiration_date && $this->asDateTime($this->expiration_date)->startofDay()->lessThanOrEqualTo($day); + + $terminated = $this->termination_date && $this->asDateTime($this->termination_date)->startofDay()->lessThanOrEqualTo($day); + + + return $this->isExpired() || $this->isTerminated(); +} + + public function isExpired(): bool + { + $day = now()->startOfDay(); + + $expired = $this->expiration_date && $this->asDateTime($this->expiration_date)->startofDay()->lessThanOrEqualTo($day); + + return $expired; + } + + public function isTerminated(): bool + { + $day = now()->startOfDay(); + + $terminated = $this->termination_date && $this->asDateTime($this->termination_date)->startofDay()->lessThanOrEqualTo($day); + + + return $terminated; + } + /** * Sets free_seat_count attribute * @@ -375,27 +432,6 @@ class License extends Depreciable return false; } - /** - * Checks for a category-specific EULA, and if that doesn't exist, - * checks for a settings level EULA - * - * @author [A. Gianotto] [] - * @since [v4.0] - * @return string | false - */ - public function getEula() - { - if ($this->category) { - if ($this->category->eula_text) { - return Helper::parseEscapedMarkedown($this->category->eula_text); - } elseif ($this->category->use_default_eula == '1') { - return Helper::parseEscapedMarkedown(Setting::getSettings()->default_eula_text); - } - } - - return false; - - } /** * Establishes the license -> assigned user relationship @@ -534,6 +570,7 @@ class License extends Depreciable return $this->licenseSeatsRelation() ->whereNull('asset_id') ->whereNull('assigned_to') + ->where('unreassignable_seat', '=', false) ->whereNull('deleted_at'); } @@ -585,7 +622,22 @@ class License extends Depreciable return 0; } - + /** + * Calculates the number of unreassignable seats + * + * @author G. Martinez + * @since [v7.1.15] + */ + public static function unReassignableCount($license) : int + { + $count = 0; + if (!$license->reassignable) { + $count = LicenseSeat::query()->where('unreassignable_seat', '=', true) + ->where('license_id', '=', $license->id) + ->count(); + } + return $count; + } /** * Calculates the number of remaining seats * @@ -593,11 +645,12 @@ class License extends Depreciable * @since [v1.0] * @return int */ - public function remaincount() + public function remaincount() : int { $total = $this->licenseSeatsCount; $taken = $this->assigned_seats_count; - $diff = ($total - $taken); + $unreassignable = self::unReassignableCount($this); + $diff = ($total - $taken - $unreassignable); return (int) $diff; } @@ -655,12 +708,11 @@ class License extends Depreciable { return $this->licenseseats() ->whereNull('deleted_at') - ->where( - function ($query) { - $query->whereNull('assigned_to') - ->whereNull('asset_id'); - } - ) + ->where('unreassignable_seat', '=', false) + ->where(function ($query) { + $query->whereNull('assigned_to') + ->whereNull('asset_id'); + }) ->orderBy('id', 'asc') ->first(); } @@ -678,25 +730,74 @@ class License extends Depreciable return $this->hasMany(\App\Models\LicenseSeat::class)->whereNull('assigned_to')->whereNull('deleted_at')->whereNull('asset_id'); } + public function scopeActiveLicenses($query) + { + + return $query->whereNull('licenses.deleted_at') + + // The termination date is null or within range + ->where(function ($query) { + $query->whereNull('termination_date') + ->orWhereDate('termination_date', '>', [Carbon::now()]); + }) + ->where(function ($query) { + $query->whereNull('expiration_date') + ->orWhereDate('expiration_date', '>', [Carbon::now()]); + }); + } + /** - * Returns expiring licenses - * - * @todo should refactor. I don't like get() in model methods + * Expiried/terminated licenses scope * * @author A. Gianotto * @since [v1.0] * @return \Illuminate\Database\Eloquent\Relations\Relation + * @see \App\Console\Commands\SendExpiringLicenseNotifications */ - public static function getExpiringLicenses($days = 60) + public function scopeExpiredLicenses($query) { - $days = (is_null($days)) ? 60 : $days; + return $query->whereDate('termination_date', '<=', Carbon::now())// The termination date is null or within range + ->orWhere(function ($query) { + $query->whereDate('expiration_date', '<=', Carbon::now()); + }) + ->whereNull('licenses.deleted_at'); + } - return self::whereNotNull('expiration_date') - ->whereNull('deleted_at') - ->whereRaw('DATE_SUB(`expiration_date`,INTERVAL '.$days.' DAY) <= DATE(NOW()) ') - ->where('expiration_date', '>', date('Y-m-d')) - ->orderBy('expiration_date', 'ASC') - ->get(); + /** + * Expiring/terminating licenses scope + * + * This checks if: + * + * 1) The license has not been deleted + * 2) The expiration date is between now and the number of days specified + * 3) There is an expiration date set and the termination date has not passed + * 4) The license termination date is null or has not passed + * + * @author A. Gianotto + * @since [v1.0] + * @return \Illuminate\Database\Eloquent\Relations\Relation + * @see \App\Console\Commands\SendExpiringLicenseNotifications + */ + public function scopeExpiringLicenses($query, $days = 60) + { + return $query// The termination date is null or within range + ->where(function ($query) use ($days) { + $query->whereNull('termination_date') + ->orWhereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]); + }) + ->where(function ($query) use ($days) { + $query->whereNotNull('expiration_date') + // Handle expiring licenses without termination dates + ->where(function ($query) use ($days) { + $query->whereNull('termination_date') + ->whereBetween('expiration_date', [Carbon::now(), Carbon::now()->addDays($days)]); + }) + + // Handle expiring licenses with termination dates in the future + ->orWhere(function ($query) use ($days) { + $query->whereBetween('termination_date', [Carbon::now(), Carbon::now()->addDays($days)]); + }); + }); } /** diff --git a/app/Models/LicenseSeat.php b/app/Models/LicenseSeat.php index 52cbd9be5a..39cb53f9d8 100755 --- a/app/Models/LicenseSeat.php +++ b/app/Models/LicenseSeat.php @@ -3,9 +3,11 @@ namespace App\Models; use App\Models\Traits\Acceptable; +use App\Models\Traits\CompanyableChildTrait; use App\Notifications\CheckinLicenseNotification; use App\Notifications\CheckoutLicenseNotification; use App\Presenters\Presentable; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; @@ -21,6 +23,9 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild protected $guarded = 'id'; protected $table = 'license_seats'; + protected $casts = [ + 'unreassignable_seat' => 'boolean', + ]; /** * The attributes that are mass assignable. @@ -60,6 +65,21 @@ class LicenseSeat extends SnipeModel implements ICompanyableChild return $this->license->getEula(); } + protected function name(): Attribute + { + return Attribute:: make( + get: fn(mixed $value) => $this->license->name, + ); + } + + protected function displayName(): Attribute + { + return Attribute:: make( + get: fn(mixed $value) => $this->license->name, + ); + } + + /** * Establishes the seat -> license relationship * diff --git a/app/Models/Location.php b/app/Models/Location.php index 64187082d3..8d7bee0cbd 100755 --- a/app/Models/Location.php +++ b/app/Models/Location.php @@ -3,16 +3,11 @@ namespace App\Models; use App\Http\Traits\UniqueUndeletedTrait; -use App\Models\Asset; -use App\Models\Setting; -use App\Models\SnipeModel; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\HasUploads; use App\Models\Traits\Searchable; -use App\Models\User; use App\Presenters\Presentable; -use Illuminate\Support\Facades\DB; use Illuminate\Database\Eloquent\Factories\HasFactory; -use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\SoftDeletes; use Illuminate\Support\Facades\Gate; use Watson\Validating\ValidatingTrait; @@ -48,6 +43,7 @@ class Location extends SnipeModel 'company_id' => 'integer', ]; + /** * Whether the model should inject its identifier to the unique * validation rules before attempting validation. If this property @@ -118,13 +114,19 @@ class Location extends SnipeModel { return Gate::allows('delete', $this) - && ($this->assets_count == 0) - && ($this->assigned_assets_count == 0) - && ($this->children_count == 0) - && ($this->accessories_count == 0) - && ($this->users_count == 0); + && ($this->deleted_at == '') + && (($this->assets_count ?? $this->assets()->count()) === 0) + && (($this->assigned_assets_count ?? $this->assignedAssets()->count()) === 0) + && (($this->accessories_count ?? $this->accessories()->count()) === 0) + && (($this->assigned_accessories_count ?? $this->assignedAccessories()->count()) === 0) + && (($this->children_count ?? $this->children()->count()) === 0) + && (($this->components_count ?? $this->components()->count()) === 0) + && (($this->consumables_count ?? $this->consumables()->count()) === 0) + && (($this->rtd_assets_count ?? $this->rtd_assets()->count()) === 0) + && (($this->users_count ?? $this->users()->count()) === 0); } + /** * Establishes the user -> location relationship * diff --git a/app/Models/Maintenance.php b/app/Models/Maintenance.php index 4b6320739e..40a96dcb62 100644 --- a/app/Models/Maintenance.php +++ b/app/Models/Maintenance.php @@ -3,12 +3,13 @@ namespace App\Models; use App\Helpers\Helper; +use App\Models\Traits\CompanyableChildTrait; +use App\Models\Traits\HasUploads; use App\Models\Traits\Searchable; use App\Presenters\Presentable; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\SoftDeletes; use Watson\Validating\ValidatingTrait; -use App\Models\Traits\HasUploads; /** * Model for Asset Maintenances. @@ -31,12 +32,13 @@ class Maintenance extends SnipeModel implements ICompanyableChild 'asset_id' => 'required|integer', 'supplier_id' => 'nullable|integer', 'asset_maintenance_type' => 'required', - 'name' => 'required|max:100', + 'name' => 'required|max:100', 'is_warranty' => 'boolean', 'start_date' => 'required|date_format:Y-m-d', 'completion_date' => 'date_format:Y-m-d|nullable|after_or_equal:start_date', 'notes' => 'string|nullable', - 'cost' => 'numeric|nullable', + 'cost' => 'numeric|nullable|gte:0|max:99999999999999999.99', + 'url' => 'nullable|url|max:255', ]; @@ -56,6 +58,7 @@ class Maintenance extends SnipeModel implements ICompanyableChild 'asset_maintenance_time', 'notes', 'cost', + 'url', ]; use Searchable; diff --git a/app/Models/SnipeModel.php b/app/Models/SnipeModel.php index f26946d22a..68bfc57824 100644 --- a/app/Models/SnipeModel.php +++ b/app/Models/SnipeModel.php @@ -3,7 +3,11 @@ namespace App\Models; use App\Helpers\Helper; +use Carbon\Carbon; +use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Model; +use Illuminate\Support\Facades\Request; class SnipeModel extends Model { @@ -16,12 +20,43 @@ class SnipeModel extends Model $this->attributes['purchase_date'] = $value; } + + protected function purchaseDateFormatted(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => $attributes['purchase_date'] ? Helper::getFormattedDateObject(Carbon::parse($attributes['purchase_date']), 'date', false) : null, + ); + } + + + protected function expiresDiffInDays(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => in_array('expiration_date', $attributes) ? Carbon::now()->diffInDays($attributes['expiration_date']) : null, + ); + } + + + protected function expiresDiffForHumans(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => in_array('expiration_date', $attributes) ? Carbon::parse($attributes['expiration_date'])->diffForHumans() : null, + ); + } + + protected function expiresFormattedDate(): Attribute + { + return Attribute:: make( + get: fn(mixed $value, array $attributes) => in_array('expiration_date', $attributes) ? Helper::getFormattedDateObject($attributes['expiration_date'], 'date', false) : null, + ); + } + /** * @param $value */ public function setPurchaseCostAttribute($value) { - if (is_float($value)) { + if (is_numeric($value)) { //value is *already* a floating-point number. Just assign it directly $this->attributes['purchase_cost'] = $value; return; @@ -155,9 +190,50 @@ class SnipeModel extends Model $this->attributes['status_id'] = $value; } - // - public function getDisplayNameAttribute() + /** + * Applies offset (from request) and limit to query. + * + * @param Builder $query + * @param int $total + * @return void + */ + public function scopeApplyOffsetAndLimit(Builder $query, int $total) { - return $this->name; + $offset = (Request::input('offset') > $total) ? $total : app('api_offset_value'); + $limit = app('api_limit_value'); + + $query->skip($offset)->take($limit); } + + protected function displayName(): Attribute + { + return Attribute:: make( + get: fn(mixed $value) => $this->name, + ); + } + + + public function getEula() + { + + // This is - for now - only for assets, where the asset model is the thing tied to the category + if (($this->model) && ($this->model->category)) { + if (($this->model->category->eula_text) && ($this->model->category->use_default_eula == 0)) { + return $this->model->category->eula_text; + } elseif ($this->model->category->use_default_eula == 1) { + return Setting::getSettings()->default_eula_text; + } else { + return false; + } + // For everything else, just check the category for EULA info + } elseif (($this->category) && ($this->category->eula_text)) { + return $this->category->eula_text; + } elseif ((Setting::getSettings()->default_eula_text) && (($this->category) && ($this->category->use_default_eula == '1'))) { + return Setting::getSettings()->default_eula_text; + } + + return null; + } + + } diff --git a/app/Models/SnipeSCIMConfig.php b/app/Models/SnipeSCIMConfig.php index b7b789bf3d..7387569e10 100644 --- a/app/Models/SnipeSCIMConfig.php +++ b/app/Models/SnipeSCIMConfig.php @@ -34,6 +34,7 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig 'validations' => [ $user_prefix . 'userName' => 'required', + $user_prefix . 'displayName' => 'nullable|string', $user_prefix . 'name.givenName' => 'required', $user_prefix . 'name.familyName' => 'nullable|string', $user_prefix . 'externalId' => 'nullable|string', @@ -121,7 +122,7 @@ class SnipeSCIMConfig extends \ArieTimmerman\Laravel\SCIMServer\SCIMConfig 'honorificSuffix' => null ], - 'displayName' => null, + 'displayName' => AttributeMapping::eloquent("display_name"), 'nickName' => null, 'profileUrl' => null, 'title' => AttributeMapping::eloquent('jobtitle'), diff --git a/app/Models/CompanyableChildTrait.php b/app/Models/Traits/CompanyableChildTrait.php similarity index 79% rename from app/Models/CompanyableChildTrait.php rename to app/Models/Traits/CompanyableChildTrait.php index 1158c70e98..36e19cffa8 100644 --- a/app/Models/CompanyableChildTrait.php +++ b/app/Models/Traits/CompanyableChildTrait.php @@ -1,6 +1,8 @@ hasMany(Actionlog::class, 'item_id') ->where('item_type', self::class) ->where('action_type', '=', 'uploaded') - ->whereNotNull('filename'); + ->whereNotNull('filename') + ->whereNotIn('filename', function ($query) { + $query->select('filename') + ->from('action_logs') + ->where('item_type', '=', self::class) + ->where('action_type', '=', 'upload deleted') + ->where('item_id', $this->id); + }); } diff --git a/app/Models/User.php b/app/Models/User.php index 0c1cbe21fd..fda296ff91 100644 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -3,9 +3,11 @@ namespace App\Models; use App\Http\Traits\UniqueUndeletedTrait; -use App\Models\Traits\Searchable; +use App\Models\Traits\CompanyableTrait; use App\Models\Traits\HasUploads; +use App\Models\Traits\Searchable; use App\Presenters\Presentable; +use App\Presenters\UserPresenter; use Illuminate\Auth\Authenticatable; use Illuminate\Auth\Passwords\CanResetPassword; use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract; @@ -13,6 +15,7 @@ use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract; use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract; use Illuminate\Contracts\Translation\HasLocalePreference; use Illuminate\Database\Eloquent\Builder; +use Illuminate\Database\Eloquent\Casts\Attribute; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\SoftDeletes; @@ -22,8 +25,6 @@ use Illuminate\Support\Facades\Gate; use Illuminate\Support\Str; use Laravel\Passport\HasApiTokens; use Watson\Validating\ValidatingTrait; -use Illuminate\Database\Eloquent\Casts\Attribute; -use App\Presenters\UserPresenter; class User extends SnipeModel implements AuthenticatableContract, AuthorizableContract, CanResetPasswordContract, HasLocalePreference { @@ -64,6 +65,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo 'first_name', 'jobtitle', 'last_name', + 'display_name', 'ldap_import', 'locale', 'location_id', @@ -103,6 +105,8 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo protected $rules = [ 'first_name' => 'required|string|min:1|max:191', + 'last_name' => 'nullable|string|max:191', + 'display_name' => 'nullable|string|max:191', 'username' => 'required|string|min:1|unique_undeleted|max:191', 'email' => 'email|nullable|max:191', 'password' => 'required|min:8', @@ -113,9 +117,9 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo 'start_date' => 'nullable|date_format:Y-m-d', 'end_date' => 'nullable|date_format:Y-m-d|after_or_equal:start_date', 'autoassign_licenses' => 'boolean', - 'address' => 'max:191|nullable', - 'city' => 'max:191|nullable', - 'state' => 'min:2|max:191|nullable', + 'address' => 'nullable|string|max:191', + 'city' => 'nullable|string|max:191', + 'state' => 'nullable|string|max:191', 'country' => 'min:2|max:191|nullable', 'zip' => 'max:10|nullable', 'vip' => 'boolean', @@ -132,15 +136,16 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo 'address', 'city', 'country', + 'display_name', 'email', 'employee_num', 'first_name', 'jobtitle', 'last_name', 'locale', + 'mobile', 'notes', 'phone', - 'mobile', 'state', 'username', 'website', @@ -157,7 +162,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo 'department' => ['name'], 'groups' => ['name'], 'company' => ['name'], - 'manager' => ['first_name', 'last_name', 'username'], + 'manager' => ['first_name', 'last_name', 'username', 'display_name'], ]; @@ -196,8 +201,20 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo }); } + /** + * This overrides the SnipeModel displayName accessor to return the full name if display_name is not set + * @see SnipeModel::displayName() + * @return Attribute + */ - public function isAvatarExternal() + protected function displayName(): Attribute + { + return Attribute:: make( + get: fn(mixed $value) => $value ?? $this->getFullNameAttribute(), + ); + } + + public function isAvatarExternal() : bool { // Check if it's a google avatar or some external avatar if (Str::startsWith($this->avatar, ['http://', 'https://'])) { @@ -846,6 +863,141 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo return new \stdClass; } + + /** + * Query builder scope to search on text filters for complex Bootstrap Tables API + * + * @param \Illuminate\Database\Query\Builder $query Query builder instance + * @param text $filter JSON array of search keys and terms + * + * @return \Illuminate\Database\Query\Builder Modified query builder + */ + public function scopeByFilter($query, $filter) + { + return $query->where( + function ($query) use ($filter) { + foreach ($filter as $fieldname => $search_val) { + + if ($fieldname == 'first_name') { + $query->where('users.first_name', 'LIKE', '%' . $search_val . '%'); + } + if ($fieldname == 'last_name') { + $query->where('users.last_name', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'display_name') { + $query->where('users.display_name', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'name') { + $query->where('users.last_name', 'LIKE', '%' . $search_val . '%') + ->orWhere('users.first_name', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'username') { + $query->where('users.username', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'email') { + $query->where('users.email', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'phone') { + $query->where('users.phone', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'mobile') { + $query->where('users.mobile', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'phone') { + $query->where('users.phone', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'jobtitle') { + $query->where('users.jobtitle', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'created_at') { + $query->where('users.created_at', '=', '%' . $search_val . '%'); + } + + if ($fieldname == 'updated_at') { + $query->where('users.updated_at', '=', '%' . $search_val . '%'); + } + + if ($fieldname == 'start_date') { + $query->where('users.start_date', '=', '%' . $search_val . '%'); + } + + if ($fieldname == 'end_date') { + $query->where('users.end_date', '=', '%' . $search_val . '%'); + } + + if ($fieldname == 'employee_num') { + $query->where('users.employee_num', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'locale') { + $query->where('users.locale', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'address') { + $query->where('users.address', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'state') { + $query->where('users.state', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'zip') { + $query->where('users.zip', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'country') { + $query->where('users.country', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'vip') { + $query->where('users.vip', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'remote') { + $query->where('users.remote', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'start_date') { + $query->where('users.purchase_date', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'notes') { + $query->where('users.notes', 'LIKE', '%' . $search_val . '%'); + } + + if ($fieldname == 'location') { + $query->whereHas( + 'location', function ($query) use ($search_val) { + $query->where('locations.name', 'LIKE', '%' . $search_val . '%'); + } + ); + } + + if ($fieldname == 'company') { + $query->whereHas( + 'company', function ($query) use ($search_val) { + $query->where('companies.name', 'LIKE', '%' . $search_val . '%'); + } + ); + } + + + } + + + } + ); + } + /** * Query builder scope to search user by name with spaces in it. * We don't use the advancedTextSearch() scope because that searches @@ -859,6 +1011,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo { return $query->where('first_name', 'LIKE', '%' . $search . '%') ->orWhere('last_name', 'LIKE', '%' . $search . '%') + ->orWhere('display_name', 'LIKE', '%' . $search . '%') ->orWhereMultipleColumns( [ 'users.first_name', @@ -1068,6 +1221,7 @@ class User extends SnipeModel implements AuthenticatableContract, AuthorizableCo ->orWhere('users.jobtitle', 'LIKE', '%' . $search . '%') ->orWhere('users.employee_num', 'LIKE', '%' . $search . '%') ->orWhere('users.username', 'LIKE', '%' . $search . '%') + ->orWhere('users.display_name', 'LIKE', '%' . $search . '%') ->orwhereRaw('CONCAT(users.first_name," ",users.last_name) LIKE \''.$search.'%\''); } diff --git a/app/Notifications/AcceptanceAssetAcceptedNotification.php b/app/Notifications/AcceptanceAssetAcceptedNotification.php index 7798dbc0d5..6e33a8a823 100644 --- a/app/Notifications/AcceptanceAssetAcceptedNotification.php +++ b/app/Notifications/AcceptanceAssetAcceptedNotification.php @@ -2,6 +2,7 @@ namespace App\Notifications; +use AllowDynamicProperties; use App\Helpers\Helper; use App\Models\Setting; use Illuminate\Bus\Queueable; @@ -10,7 +11,7 @@ use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Messages\SlackMessage; use Illuminate\Notifications\Notification; -class AcceptanceAssetAcceptedNotification extends Notification +#[AllowDynamicProperties] class AcceptanceAssetAcceptedNotification extends Notification { use Queueable; @@ -22,14 +23,18 @@ class AcceptanceAssetAcceptedNotification extends Notification public function __construct($params) { $this->item_tag = $params['item_tag']; + $this->item_name = $params['item_name']; $this->item_model = $params['item_model']; $this->item_serial = $params['item_serial']; $this->item_status = $params['item_status']; - $this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'date', false); + $this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'datetime', false); $this->assigned_to = $params['assigned_to']; - $this->note = $params['note']; $this->company_name = $params['company_name']; $this->settings = Setting::getSettings(); + $this->file = $params['file'] ?? null; + $this->qty = $params['qty'] ?? null; + $this->note = $params['note'] ?? null; + $this->admin = $params['admin'] ?? null; } @@ -64,6 +69,7 @@ class AcceptanceAssetAcceptedNotification extends Notification $message = (new MailMessage)->markdown('notifications.markdown.asset-acceptance', [ 'item_tag' => $this->item_tag, + 'item_name' => $this->item_name, 'item_model' => $this->item_model, 'item_serial' => $this->item_serial, 'item_status' => $this->item_status, @@ -71,6 +77,8 @@ class AcceptanceAssetAcceptedNotification extends Notification 'accepted_date' => $this->accepted_date, 'assigned_to' => $this->assigned_to, 'company_name' => $this->company_name, + 'admin' => $this->admin, + 'qty' => $this->qty, 'intro_text' => trans('mail.acceptance_asset_accepted'), ]) ->subject(trans('mail.acceptance_asset_accepted')); diff --git a/app/Notifications/AcceptanceAssetAcceptedToUserNotification.php b/app/Notifications/AcceptanceAssetAcceptedToUserNotification.php index 22a97b709f..1f53443449 100644 --- a/app/Notifications/AcceptanceAssetAcceptedToUserNotification.php +++ b/app/Notifications/AcceptanceAssetAcceptedToUserNotification.php @@ -2,13 +2,14 @@ namespace App\Notifications; +use AllowDynamicProperties; use App\Helpers\Helper; use App\Models\Setting; use Illuminate\Bus\Queueable; use Illuminate\Notifications\Messages\MailMessage; use Illuminate\Notifications\Notification; -class AcceptanceAssetAcceptedToUserNotification extends Notification +#[AllowDynamicProperties] class AcceptanceAssetAcceptedToUserNotification extends Notification { use Queueable; @@ -20,16 +21,18 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification public function __construct($params) { $this->item_tag = $params['item_tag']; + $this->item_name = $params['item_name']; $this->item_model = $params['item_model']; $this->item_serial = $params['item_serial']; $this->item_status = $params['item_status']; - $this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'date', false); + $this->accepted_date = Helper::getFormattedDateObject($params['accepted_date'], 'datetime', false); $this->assigned_to = $params['assigned_to']; - $this->note = $params['note']; + $this->note = $params['note'] ?? null; $this->company_name = $params['company_name']; $this->settings = Setting::getSettings(); $this->file = $params['file'] ?? null; - + $this->qty = $params['qty'] ?? null; + $this->admin = $params['admin'] ?? null; } /** @@ -59,6 +62,7 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification $message = (new MailMessage)->markdown('notifications.markdown.asset-acceptance', [ 'item_tag' => $this->item_tag, + 'item_name' => $this->item_name, 'item_model' => $this->item_model, 'item_serial' => $this->item_serial, 'item_status' => $this->item_status, @@ -66,10 +70,12 @@ class AcceptanceAssetAcceptedToUserNotification extends Notification 'accepted_date' => $this->accepted_date, 'assigned_to' => $this->assigned_to, 'company_name' => $this->company_name, - 'intro_text' => trans('mail.acceptance_asset_accepted_to_user', ['site_name' => $this->company_name ?? $this->settings->site_name]), + 'admin' => $this->admin, + 'qty' => $this->qty, + 'intro_text' => trans_choice('mail.acceptance_asset_accepted_to_user', $this->qty, ['qty' => $this->qty, 'site_name' => $this->settings->site_name]), ]) ->attach($pdf_path) - ->subject(trans('mail.acceptance_asset_accepted_to_user', ['site_name' => $this->settings->site_name])); + ->subject(trans_choice('mail.acceptance_asset_accepted_to_user', $this->qty, ['qty' => $this->qty, 'site_name' => $this->settings->site_name])); return $message; } diff --git a/app/Notifications/AcceptanceAssetDeclinedNotification.php b/app/Notifications/AcceptanceAssetDeclinedNotification.php index 0a9d6c211f..6ff06c7094 100644 --- a/app/Notifications/AcceptanceAssetDeclinedNotification.php +++ b/app/Notifications/AcceptanceAssetDeclinedNotification.php @@ -30,6 +30,7 @@ class AcceptanceAssetDeclinedNotification extends Notification $this->assigned_to = $params['assigned_to']; $this->company_name = $params['company_name']; $this->settings = Setting::getSettings(); + $this->qty = $params['qty'] ?? null; } /** @@ -69,6 +70,7 @@ class AcceptanceAssetDeclinedNotification extends Notification 'declined_date' => $this->declined_date, 'assigned_to' => $this->assigned_to, 'company_name' => $this->company_name, + 'qty' => $this->qty, 'intro_text' => trans('mail.acceptance_asset_declined'), ]) ->subject(trans('mail.acceptance_asset_declined')); diff --git a/app/Notifications/AuditNotification.php b/app/Notifications/AuditNotification.php index a7056e8cbd..6d71e21bd2 100644 --- a/app/Notifications/AuditNotification.php +++ b/app/Notifications/AuditNotification.php @@ -57,14 +57,14 @@ use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage; $channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : ''; return (new SlackMessage) ->success() - ->content(class_basename(get_class($this->params['item'])).' Audited') + ->content(class_basename(get_class($this->params['item'])).' '.trans('general.audited')) ->from(($this->settings->webhook_botname) ? $this->settings->webhook_botname : 'Snipe-Bot') ->to($channel) ->attachment(function ($attachment) { - $item = $this->params['item']; + $item = $this->params['item'] ?? null; $admin_user = $this->params['admin']; $fields = [ - 'By' => '<'.$admin_user->present()->viewUrl().'|'.$admin_user->present()->fullName().'>', + 'By' => '<'.$admin_user->present()->viewUrl().'|'.$admin_user->display_name.'>', ]; array_key_exists('note', $this->params) && $fields['Notes'] = $this->params['note']; array_key_exists('location', $this->params) && $fields['Location'] = $this->params['location']; @@ -76,24 +76,24 @@ use NotificationChannels\MicrosoftTeams\MicrosoftTeamsMessage; public static function toMicrosoftTeams($params) { - $item = $params['item']; - $admin_user = $params['admin']; - $note = $params['note']; - $location = $params['location']; + $item = $params['item'] ?? null; + $admin_user = $params['admin'] ?? null; + $note = $params['note'] ?? ''; + $location = $params['location'] ?? ''; $setting = Setting::getSettings(); if(!Str::contains($setting->webhook_endpoint, 'workflows')) { return MicrosoftTeamsMessage::create() ->to($setting->webhook_endpoint) ->type('success') - ->title(class_basename(get_class($params['item'])) . ' Audited') + ->title(class_basename(get_class($params['item'])) .' '.trans('general.audited')) ->addStartGroupToSection('activityText') ->fact(trans('mail.asset'), $item) - ->fact(trans('general.administrator'), $admin_user->present()->viewUrl() . '|' . $admin_user->present()->fullName()); + ->fact(trans('general.administrator'), $admin_user->present()->viewUrl() . '|' . $admin_user->display_name); } - $message = class_basename(get_class($params['item'])) . ' Audited By '.$admin_user->present()->fullName(); + $message = class_basename(get_class($params['item'])) . ' Audited By '.$admin_user->display_name; $details = [ - trans('mail.asset') => htmlspecialchars_decode($item->present()->name), + trans('mail.asset') => htmlspecialchars_decode($item->display_name), trans('mail.notes') => $note ?: '', trans('general.location') => $location ?: '', ]; diff --git a/app/Notifications/CheckinAccessoryNotification.php b/app/Notifications/CheckinAccessoryNotification.php index 5354775d7e..45c6fa617d 100644 --- a/app/Notifications/CheckinAccessoryNotification.php +++ b/app/Notifications/CheckinAccessoryNotification.php @@ -73,8 +73,8 @@ class CheckinAccessoryNotification extends Notification $channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : ''; $fields = [ - trans('general.from') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', - trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + trans('general.from') => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', + trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->display_name.'>', ]; if ($item->location) { @@ -90,7 +90,7 @@ class CheckinAccessoryNotification extends Notification ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $admin, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); @@ -107,18 +107,18 @@ class CheckinAccessoryNotification extends Notification ->addStartGroupToSection('activityTitle') ->title(trans('Accessory_Checkin_Notification')) ->addStartGroupToSection('activityText') - ->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle') + ->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle') ->fact(trans('mail.checked_into'), $item->location->name ? $item->location->name : '') - ->fact(trans('mail.Accessory_Checkin_Notification')." by ", $admin->present()->fullName()) + ->fact(trans('mail.Accessory_Checkin_Notification')." by ", $admin->display_name) ->fact(trans('admin/consumables/general.remaining'), $item->numRemaining()) ->fact(trans('mail.notes'), $note ?: ''); } $message = trans('mail.Accessory_Checkin_Notification'); $details = [ - trans('mail.accessory_name') => htmlspecialchars_decode($item->present()->name), + trans('mail.accessory_name') => htmlspecialchars_decode($item->display_name), trans('mail.checked_into') => $item->location->name ? $item->location->name : '', - trans('mail.Accessory_Checkin_Notification'). ' by' => $admin->present()->fullName(), + trans('mail.Accessory_Checkin_Notification'). ' by' => $admin->display_name, trans('admin/consumables/general.remaining')=> $item->numRemaining(), trans('mail.notes') => $note ?: '', ]; @@ -135,7 +135,7 @@ class CheckinAccessoryNotification extends Notification Card::create() ->header( ''.trans('mail.Accessory_Checkin_Notification').'' ?: '', - htmlspecialchars_decode($item->present()->name) ?: '', + htmlspecialchars_decode($item->display_name) ?: '', ) ->section( Section::create( diff --git a/app/Notifications/CheckinAssetNotification.php b/app/Notifications/CheckinAssetNotification.php index 5de3ff1be8..12f45884c9 100644 --- a/app/Notifications/CheckinAssetNotification.php +++ b/app/Notifications/CheckinAssetNotification.php @@ -78,7 +78,7 @@ class CheckinAssetNotification extends Notification $channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : ''; $fields = [ - trans('general.administrator') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + trans('general.administrator') => '<'.$admin->present()->viewUrl().'|'.$admin->display_name.'>', trans('general.status') => $item->assetstatus?->name, trans('general.location') => ($item->location) ? $item->location->name : '', ]; @@ -93,11 +93,11 @@ class CheckinAssetNotification extends Notification return (new SlackMessage) - ->content(':arrow_down: :computer: '.trans('mail.Asset_Checkin_Notification')) + ->content(':arrow_down: :computer: '.trans('mail.Asset_Checkin_Notification', ['tag' => ''])) ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $admin, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); @@ -112,21 +112,21 @@ class CheckinAssetNotification extends Notification return MicrosoftTeamsMessage::create() ->to($this->settings->webhook_endpoint) ->type('success') - ->title(trans('mail.Asset_Checkin_Notification')) + ->title(trans('mail.Asset_Checkin_Notification', ['tag' => ''])) ->addStartGroupToSection('activityText') - ->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText') + ->fact(htmlspecialchars_decode($item->display_name), '', 'activityText') ->fact(trans('mail.checked_into'), ($item->location) ? $item->location->name : '') - ->fact(trans('mail.Asset_Checkin_Notification') . " by ", $admin->present()->fullName()) + ->fact(trans('general.administrator'), $admin->display_name) ->fact(trans('admin/hardware/form.status'), $item->assetstatus?->name) ->fact(trans('mail.notes'), $note ?: ''); } - $message = trans('mail.Asset_Checkin_Notification'); + $message = trans('mail.Asset_Checkin_Notification', ['tag' => '']); $details = [ - trans('mail.asset') => htmlspecialchars_decode($item->present()->name), + trans('mail.asset') => htmlspecialchars_decode($item->display_name), trans('mail.checked_into') => ($item->location) ? $item->location->name : '', - trans('mail.Asset_Checkin_Notification')." by " => $admin->present()->fullName(), + trans('general.administrator') => $admin->display_name, trans('admin/hardware/form.status') => $item->assetstatus?->name, trans('mail.notes') => $note ?: '', ]; @@ -144,8 +144,8 @@ class CheckinAssetNotification extends Notification ->card( Card::create() ->header( - ''.trans('mail.Asset_Checkin_Notification').'' ?: '', - htmlspecialchars_decode($item->present()->name) ?: '', + ''.trans('mail.Asset_Checkin_Notification', ['tag' =>'']).'' ?: '', + htmlspecialchars_decode($item->display_name) ?: '', ) ->section( Section::create( diff --git a/app/Notifications/CheckinComponentNotification.php b/app/Notifications/CheckinComponentNotification.php index 4057c26812..b302ee8979 100644 --- a/app/Notifications/CheckinComponentNotification.php +++ b/app/Notifications/CheckinComponentNotification.php @@ -76,8 +76,8 @@ class CheckinComponentNotification extends Notification if ($admin) { $fields = [ - trans('general.from') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', - trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + trans('general.from') => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', + trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->display_name.'>', ]; if ($item->location) { @@ -90,7 +90,7 @@ class CheckinComponentNotification extends Notification } else { $fields = [ - 'To' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', + 'To' => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', 'By' => 'CLI tool', ]; } @@ -100,7 +100,7 @@ class CheckinComponentNotification extends Notification ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $admin, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); @@ -118,17 +118,17 @@ class CheckinComponentNotification extends Notification ->addStartGroupToSection('activityTitle') ->title(trans('mail.Component_checkin_notification')) ->addStartGroupToSection('activityText') - ->fact(htmlspecialchars_decode($item->present()->name), '', 'header') - ->fact(trans('mail.Component_checkin_notification')." by ", $admin->present()->fullName() ?: 'CLI tool') - ->fact(trans('mail.checkedin_from'), $target->present()->fullName()) + ->fact(htmlspecialchars_decode($item->display_name), '', 'header') + ->fact(trans('mail.Component_checkin_notification')." by ", $admin->display_name ?: 'CLI tool') + ->fact(trans('mail.checkedin_from'), $target->display_name) ->fact(trans('admin/consumables/general.remaining'), $item->numRemaining()) ->fact(trans('mail.notes'), $note ?: ''); } $message = trans('mail.Component_checkin_notification'); $details = [ - trans('mail.checkedin_from')=> $target->present()->fullName(), - trans('mail.Component_checkin_notification')." by " => $admin->present()->fullName() ?: 'CLI tool', + trans('mail.checkedin_from')=> $target->display_name, + trans('mail.Component_checkin_notification')." by " => $admin->display_name ?: 'CLI tool', trans('admin/consumables/general.remaining') => $item->numRemaining(), trans('mail.notes') => $note ?: '', ]; @@ -147,13 +147,13 @@ class CheckinComponentNotification extends Notification Card::create() ->header( ''.trans('mail.Component_checkin_notification').'' ?: '', - htmlspecialchars_decode($item->present()->name) ?: '', + htmlspecialchars_decode($item->display_name) ?: '', ) ->section( Section::create( KeyValue::create( trans('mail.checkedin_from') ?: '', - $target->present()->fullName() ?: '', + $target->display_name ?: '', trans('admin/consumables/general.remaining').': '.$item->numRemaining(), ) ->onClick(route('components.show', $item->id)) diff --git a/app/Notifications/CheckinLicenseSeatNotification.php b/app/Notifications/CheckinLicenseSeatNotification.php index 07c3308dbc..60eec737d6 100644 --- a/app/Notifications/CheckinLicenseSeatNotification.php +++ b/app/Notifications/CheckinLicenseSeatNotification.php @@ -77,8 +77,8 @@ class CheckinLicenseSeatNotification extends Notification if ($admin) { $fields = [ - trans('general.from') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', - trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + trans('general.from') => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', + trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->display_name.'>', ]; if ($item->location) { @@ -91,7 +91,7 @@ class CheckinLicenseSeatNotification extends Notification } else { $fields = [ - 'To' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', + 'To' => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', 'By' => 'CLI tool', ]; } @@ -101,7 +101,7 @@ class CheckinLicenseSeatNotification extends Notification ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $admin, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); @@ -119,18 +119,18 @@ class CheckinLicenseSeatNotification extends Notification ->addStartGroupToSection('activityTitle') ->title(trans('mail.License_Checkin_Notification')) ->addStartGroupToSection('activityText') - ->fact(htmlspecialchars_decode($item->present()->name), '', 'header') - ->fact(trans('mail.License_Checkin_Notification')." by ", $admin->present()->fullName() ?: 'CLI tool') - ->fact(trans('mail.checkedin_from'), $target->present()->fullName()) + ->fact(htmlspecialchars_decode($item->display_name), '', 'header') + ->fact(trans('mail.License_Checkin_Notification')." by ", $admin->display_name ?: 'CLI tool') + ->fact(trans('mail.checkedin_from'), $target->display_name) ->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count()) ->fact(trans('mail.notes'), $note ?: ''); } $message = trans('mail.License_Checkin_Notification'); $details = [ - trans('mail.checkedin_from')=> $target->present()->fullName(), - trans('mail.license_for') => htmlspecialchars_decode($item->present()->name), - trans('mail.License_Checkin_Notification')." by " => $admin->present()->fullName() ?: 'CLI tool', + trans('mail.checkedin_from')=> $target->display_name, + trans('mail.license_for') => htmlspecialchars_decode($item->display_name), + trans('mail.License_Checkin_Notification')." by " => $admin->display_name ?: 'CLI tool', trans('admin/consumables/general.remaining') => $item->availCount()->count(), trans('mail.notes') => $note ?: '', ]; @@ -149,13 +149,13 @@ class CheckinLicenseSeatNotification extends Notification Card::create() ->header( ''.trans('mail.License_Checkin_Notification').'' ?: '', - htmlspecialchars_decode($item->present()->name) ?: '', + htmlspecialchars_decode($item->display_name) ?: '', ) ->section( Section::create( KeyValue::create( trans('mail.checkedin_from') ?: '', - $target->present()->fullName() ?: '', + $target->display_name ?: '', trans('admin/consumables/general.remaining').': '.$item->availCount()->count(), ) ->onClick(route('licenses.show', $item->id)) diff --git a/app/Notifications/CheckoutAccessoryNotification.php b/app/Notifications/CheckoutAccessoryNotification.php index 016bfc526c..f1a9551318 100644 --- a/app/Notifications/CheckoutAccessoryNotification.php +++ b/app/Notifications/CheckoutAccessoryNotification.php @@ -100,8 +100,8 @@ class CheckoutAccessoryNotification extends Notification $channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : ''; $fields = [ - trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', - trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', + trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->display_name.'>', ]; if ($item->location) { @@ -117,7 +117,7 @@ class CheckoutAccessoryNotification extends Notification ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $admin, $fields) { - $attachment->title(htmlspecialchars_decode($this->checkout_qty.' x '.$item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($this->checkout_qty.' x '.$item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); @@ -136,11 +136,11 @@ class CheckoutAccessoryNotification extends Notification ->addStartGroupToSection('activityTitle') ->title(trans('mail.Accessory_Checkout_Notification')) ->addStartGroupToSection('activityText') - ->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle') - ->fact(trans('mail.assigned_to'), $target->present()->name) + ->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle') + ->fact(trans('mail.assigned_to'), $target->display_name) ->fact(trans('general.qty'), $this->checkout_qty) ->fact(trans('mail.checkedout_from'), $item->location->name ? $item->location->name : '') - ->fact(trans('mail.Accessory_Checkout_Notification') . " by ", $admin->present()->fullName()) + ->fact(trans('mail.Accessory_Checkout_Notification') . " by ", $admin->display_name) ->fact(trans('admin/consumables/general.remaining'), $item->numRemaining()) ->fact(trans('mail.notes'), $note ?: ''); } @@ -148,10 +148,10 @@ class CheckoutAccessoryNotification extends Notification $message = trans('mail.Accessory_Checkout_Notification'); $details = [ trans('mail.assigned_to') => $target->present()->name, - trans('mail.accessory_name') => htmlspecialchars_decode($item->present()->name), + trans('mail.accessory_name') => htmlspecialchars_decode($item->display_name), trans('general.qty') => $this->checkout_qty, trans('mail.checkedout_from') => $item->location->name ? $item->location->name : '', - trans('mail.Accessory_Checkout_Notification'). ' by' => $admin->present()->fullName(), + trans('mail.Accessory_Checkout_Notification'). ' by' => $admin->display_name, trans('admin/consumables/general.remaining')=> $item->numRemaining(), trans('mail.notes') => $note ?: '', ]; @@ -169,7 +169,7 @@ class CheckoutAccessoryNotification extends Notification Card::create() ->header( ''.trans('mail.Accessory_Checkout_Notification').'' ?: '', - htmlspecialchars_decode($item->present()->name) ?: '', + htmlspecialchars_decode($item->display_name) ?: '', ) ->section( Section::create( diff --git a/app/Notifications/CheckoutAssetNotification.php b/app/Notifications/CheckoutAssetNotification.php index 8cdfbdd046..213e0f77c6 100644 --- a/app/Notifications/CheckoutAssetNotification.php +++ b/app/Notifications/CheckoutAssetNotification.php @@ -93,8 +93,8 @@ class CheckoutAssetNotification extends Notification $channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : ''; $fields = [ - trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', - trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', + trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->display_name.'>', ]; if ($item->location) { @@ -110,11 +110,11 @@ class CheckoutAssetNotification extends Notification } return (new SlackMessage) - ->content(':arrow_up: :computer: '.trans('mail.Asset_Checkout_Notification')) + ->content(':arrow_up: :computer: '.trans('mail.Asset_Checkout_Notification', ['tag' => ''])) ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $admin, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); @@ -131,19 +131,19 @@ class CheckoutAssetNotification extends Notification return MicrosoftTeamsMessage::create() ->to($this->settings->webhook_endpoint) ->type('success') - ->title(trans('mail.Asset_Checkout_Notification')) + ->title(trans('mail.Asset_Checkout_Notification', ['tag' => ''])) ->addStartGroupToSection('activityText') - ->fact(trans('mail.assigned_to'), $target->present()->name) - ->fact(htmlspecialchars_decode($item->present()->name), '', 'activityText') - ->fact(trans('mail.Asset_Checkout_Notification') . " by ", $admin->present()->fullName()) + ->fact(trans('mail.assigned_to'), $target->display_name) + ->fact(htmlspecialchars_decode($item->display_name), '', 'activityText') + ->fact(trans('general.administrator'), $admin->display_name) ->fact(trans('mail.notes'), $note ?: ''); } - $message = trans('mail.Asset_Checkout_Notification'); + $message = trans('mail.Asset_Checkout_Notification', ['tag' => '']); $details = [ trans('mail.assigned_to') => $target->present()->name, - trans('mail.asset') => htmlspecialchars_decode($item->present()->name), - trans('mail.Asset_Checkout_Notification'). ' by' => $admin->present()->fullName(), + trans('mail.asset') => htmlspecialchars_decode($item->display_name), + trans('general.administrator') => $admin->display_name, trans('mail.notes') => $note ?: '', ]; return array($message, $details); @@ -159,8 +159,8 @@ public function toGoogleChat() ->card( Card::create() ->header( - ''.trans('mail.Asset_Checkout_Notification').'' ?: '', - htmlspecialchars_decode($item->present()->name) ?: '', + ''.trans('mail.Asset_Checkout_Notification', ['tag' => '']).'' ?: '', + htmlspecialchars_decode($item->display_name) ?: '', ) ->section( Section::create( diff --git a/app/Notifications/CheckoutComponentNotification.php b/app/Notifications/CheckoutComponentNotification.php index fab303fb52..86ab20fcb4 100644 --- a/app/Notifications/CheckoutComponentNotification.php +++ b/app/Notifications/CheckoutComponentNotification.php @@ -80,8 +80,8 @@ class CheckoutComponentNotification extends Notification $channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : ''; $fields = [ - trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', - trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', + trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->display_name.'>', ]; if ($item->location) { @@ -97,7 +97,7 @@ class CheckoutComponentNotification extends Notification ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $admin, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); @@ -116,18 +116,18 @@ class CheckoutComponentNotification extends Notification ->addStartGroupToSection('activityTitle') ->title(trans('mail.Component_checkout_notification')) ->addStartGroupToSection('activityText') - ->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle') - ->fact(trans('mail.Component_checkout_notification')." by ", $admin->present()->fullName()) - ->fact(trans('mail.assigned_to'), $target->present()->fullName()) + ->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle') + ->fact(trans('mail.Component_checkout_notification')." by ", $admin->display_name) + ->fact(trans('mail.assigned_to'), $target->display_name) ->fact(trans('admin/consumables/general.remaining'), $item->numRemaining()) ->fact(trans('mail.notes'), $note ?: ''); } $message = trans('mail.Component_checkout_notification'); $details = [ - trans('mail.assigned_to') => $target->present()->fullName(), - trans('mail.item') => htmlspecialchars_decode($item->present()->name), - trans('mail.Component_checkout_notification').' by' => $admin->present()->fullName(), + trans('mail.assigned_to') => $target->display_name, + trans('mail.item') => htmlspecialchars_decode($item->display_name), + trans('mail.Component_checkout_notification').' by' => $admin->display_name, trans('admin/consumables/general.remaining') => $item->numRemaining(), trans('mail.notes') => $note ?: '', ]; @@ -146,13 +146,13 @@ class CheckoutComponentNotification extends Notification Card::create() ->header( ''.trans('mail.Component_checkout_notification').'' ?: '', - htmlspecialchars_decode($item->present()->name) ?: '', + htmlspecialchars_decode($item->display_name) ?: '', ) ->section( Section::create( KeyValue::create( trans('mail.assigned_to') ?: '', - $target->present()->fullName() ?: '', + $target->display_name ?: '', trans('admin/consumables/general.remaining').': '.$item->numRemaining(), ) ->onClick(route('api.assets.show', $target->id)) diff --git a/app/Notifications/CheckoutConsumableNotification.php b/app/Notifications/CheckoutConsumableNotification.php index e8db8b8bd1..96568c4bd6 100644 --- a/app/Notifications/CheckoutConsumableNotification.php +++ b/app/Notifications/CheckoutConsumableNotification.php @@ -80,8 +80,8 @@ class CheckoutConsumableNotification extends Notification $channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : ''; $fields = [ - trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', - trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', + trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->display_name.'>', ]; if ($item->location) { @@ -97,7 +97,7 @@ class CheckoutConsumableNotification extends Notification ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $admin, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); @@ -116,18 +116,18 @@ class CheckoutConsumableNotification extends Notification ->addStartGroupToSection('activityTitle') ->title(trans('mail.Consumable_checkout_notification')) ->addStartGroupToSection('activityText') - ->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle') - ->fact(trans('mail.Consumable_checkout_notification')." by ", $admin->present()->fullName()) - ->fact(trans('mail.assigned_to'), $target->present()->fullName()) + ->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle') + ->fact(trans('mail.Consumable_checkout_notification')." by ", $admin->display_name) + ->fact(trans('mail.assigned_to'), $target->display_name) ->fact(trans('admin/consumables/general.remaining'), $item->numRemaining()) ->fact(trans('mail.notes'), $note ?: ''); } $message = trans('mail.Consumable_checkout_notification'); $details = [ - trans('mail.assigned_to') => $target->present()->fullName(), - trans('mail.item') => htmlspecialchars_decode($item->present()->name), - trans('mail.Consumable_checkout_notification').' by' => $admin->present()->fullName(), + trans('mail.assigned_to') => $target->display_name, + trans('mail.item') => htmlspecialchars_decode($item->display_name), + trans('mail.Consumable_checkout_notification').' by' => $admin->display_name, trans('admin/consumables/general.remaining') => $item->numRemaining(), trans('mail.notes') => $note ?: '', ]; @@ -146,13 +146,13 @@ class CheckoutConsumableNotification extends Notification Card::create() ->header( ''.trans('mail.Consumable_checkout_notification').'' ?: '', - htmlspecialchars_decode($item->present()->name) ?: '', + htmlspecialchars_decode($item->display_name) ?: '', ) ->section( Section::create( KeyValue::create( trans('mail.assigned_to') ?: '', - $target->present()->fullName() ?: '', + $target->display_name ?: '', trans('admin/consumables/general.remaining').': '.$item->numRemaining(), ) ->onClick(route('users.show', $target->id)) diff --git a/app/Notifications/CheckoutLicenseSeatNotification.php b/app/Notifications/CheckoutLicenseSeatNotification.php index fa00421885..43de9f698b 100644 --- a/app/Notifications/CheckoutLicenseSeatNotification.php +++ b/app/Notifications/CheckoutLicenseSeatNotification.php @@ -78,8 +78,8 @@ class CheckoutLicenseSeatNotification extends Notification $channel = ($this->settings->webhook_channel) ? $this->settings->webhook_channel : ''; $fields = [ - trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', - trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->present()->fullName().'>', + trans('general.to') => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', + trans('general.by') => '<'.$admin->present()->viewUrl().'|'.$admin->display_name.'>', ]; if ($item->location) { @@ -95,7 +95,7 @@ class CheckoutLicenseSeatNotification extends Notification ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $admin, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); @@ -114,18 +114,18 @@ class CheckoutLicenseSeatNotification extends Notification ->addStartGroupToSection('activityTitle') ->title(trans('mail.License_Checkout_Notification')) ->addStartGroupToSection('activityText') - ->fact(htmlspecialchars_decode($item->present()->name), '', 'activityTitle') - ->fact(trans('mail.License_Checkout_Notification')." by ", $admin->present()->fullName()) - ->fact(trans('mail.assigned_to'), $target->present()->fullName()) + ->fact(htmlspecialchars_decode($item->display_name), '', 'activityTitle') + ->fact(trans('mail.License_Checkout_Notification')." by ", $admin->display_name) + ->fact(trans('mail.assigned_to'), $target->display_name) ->fact(trans('admin/consumables/general.remaining'), $item->availCount()->count()) ->fact(trans('mail.notes'), $note ?: ''); } $message = trans('mail.License_Checkout_Notification'); $details = [ - trans('mail.assigned_to') => $target->present()->fullName(), - trans('mail.license_for') => htmlspecialchars_decode($item->present()->name), - trans('mail.License_Checkout_Notification').' by' => $admin->present()->fullName(), + trans('mail.assigned_to') => $target->display_name, + trans('mail.license_for') => htmlspecialchars_decode($item->display_name), + trans('mail.License_Checkout_Notification').' by' => $admin->display_name, trans('admin/consumables/general.remaining') => $item->availCount()->count(), trans('mail.notes') => $note ?: '', ]; @@ -143,7 +143,7 @@ class CheckoutLicenseSeatNotification extends Notification Card::create() ->header( ''.trans('mail.License_Checkout_Notification').'' ?: '', - htmlspecialchars_decode($item->present()->name) ?: '', + htmlspecialchars_decode($item->display_name) ?: '', ) ->section( Section::create( diff --git a/app/Notifications/ExpectedCheckinNotification.php b/app/Notifications/ExpectedCheckinNotification.php index 6248b72779..cf8d71f131 100644 --- a/app/Notifications/ExpectedCheckinNotification.php +++ b/app/Notifications/ExpectedCheckinNotification.php @@ -50,11 +50,11 @@ class ExpectedCheckinNotification extends Notification $message = (new MailMessage)->markdown('notifications.markdown.expected-checkin', [ 'date' => Helper::getFormattedDateObject($this->params->expected_checkin, 'date', false), - 'asset' => $this->params->present()->name(), + 'asset' => $this->params->display_name, 'serial' => $this->params->serial, 'asset_tag' => $this->params->asset_tag, ]) - ->subject(trans('mail.Expected_Checkin_Notification', ['name' => $this->params->present()->name()])); + ->subject(trans('mail.Expected_Checkin_Notification', ['name' => $this->params->display_name])); return $message; } diff --git a/app/Notifications/RequestAssetCancelation.php b/app/Notifications/RequestAssetCancelation.php index 6c06ede3ca..d6e5f44fd9 100644 --- a/app/Notifications/RequestAssetCancelation.php +++ b/app/Notifications/RequestAssetCancelation.php @@ -79,7 +79,7 @@ class RequestAssetCancelation extends Notification $fields = [ 'QTY' => $qty, - 'Canceled By' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', + 'Canceled By' => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', ]; if (($this->expected_checkin) && ($this->expected_checkin != '')) { @@ -91,7 +91,7 @@ class RequestAssetCancelation extends Notification ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); diff --git a/app/Notifications/RequestAssetNotification.php b/app/Notifications/RequestAssetNotification.php index d2001f2e13..85f5aef50c 100644 --- a/app/Notifications/RequestAssetNotification.php +++ b/app/Notifications/RequestAssetNotification.php @@ -78,7 +78,7 @@ class RequestAssetNotification extends Notification $fields = [ 'QTY' => $qty, - 'Requested By' => '<'.$target->present()->viewUrl().'|'.$target->present()->fullName().'>', + 'Requested By' => '<'.$target->present()->viewUrl().'|'.$target->display_name.'>', ]; return (new SlackMessage) @@ -86,7 +86,7 @@ class RequestAssetNotification extends Notification ->from($botname) ->to($channel) ->attachment(function ($attachment) use ($item, $note, $fields) { - $attachment->title(htmlspecialchars_decode($item->present()->name), $item->present()->viewUrl()) + $attachment->title(htmlspecialchars_decode($item->display_name), $item->present()->viewUrl()) ->fields($fields) ->content($note); }); diff --git a/app/Observers/AssetObserver.php b/app/Observers/AssetObserver.php index 6c07a355ff..adb9292dc1 100644 --- a/app/Observers/AssetObserver.php +++ b/app/Observers/AssetObserver.php @@ -168,14 +168,14 @@ class AssetObserver public function saving(Asset $asset) { // determine if calculated eol and then calculate it - this should only happen on a new asset - if (is_null($asset->asset_eol_date) && !is_null($asset->purchase_date) && ($asset->model->eol > 0)){ + if (is_null($asset->asset_eol_date) && !is_null($asset->purchase_date) && ($asset->model?->eol > 0)) { $asset->asset_eol_date = $asset->purchase_date->addMonths($asset->model->eol)->format('Y-m-d'); $asset->eol_explicit = false; } // determine if explicit and set eol_explicit to true if (!is_null($asset->asset_eol_date) && !is_null($asset->purchase_date)) { - if($asset->model->eol > 0) { + if ($asset->model?->eol > 0) { $months = (int) Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date, true); if($months != $asset->model->eol) { $asset->eol_explicit = true; @@ -184,9 +184,9 @@ class AssetObserver } elseif (!is_null($asset->asset_eol_date) && is_null($asset->purchase_date)) { $asset->eol_explicit = true; } - if ((!is_null($asset->asset_eol_date)) && (!is_null($asset->purchase_date)) && (is_null($asset->model->eol) || ($asset->model->eol == 0))) { + + if ((!is_null($asset->asset_eol_date)) && (!is_null($asset->purchase_date)) && (is_null($asset->model?->eol) || ($asset->model?->eol == 0))) { $asset->eol_explicit = true; } - } } diff --git a/app/Policies/SnipePermissionsPolicy.php b/app/Policies/SnipePermissionsPolicy.php index cb1359fcd9..59c35394c5 100644 --- a/app/Policies/SnipePermissionsPolicy.php +++ b/app/Policies/SnipePermissionsPolicy.php @@ -85,7 +85,7 @@ abstract class SnipePermissionsPolicy } /** - * Determine whether the user can view the accessory. + * Determine whether the user can view the model. * * @param \App\Models\User $user * @return mixed @@ -101,7 +101,7 @@ abstract class SnipePermissionsPolicy } /** - * Determine whether the user can create accessories. + * Determine whether the user can create model. * * @param \App\Models\User $user * @return mixed @@ -112,7 +112,7 @@ abstract class SnipePermissionsPolicy } /** - * Determine whether the user can update the accessory. + * Determine whether the user can update the model. * * @param \App\Models\User $user * @return mixed @@ -124,7 +124,7 @@ abstract class SnipePermissionsPolicy /** - * Determine whether the user can update the accessory. + * Determine whether the user can update the model. * * @param \App\Models\User $user * @return mixed @@ -135,7 +135,7 @@ abstract class SnipePermissionsPolicy } /** - * Determine whether the user can delete the accessory. + * Determine whether the user can delete the model. * * @param \App\Models\User $user * @return mixed @@ -151,7 +151,7 @@ abstract class SnipePermissionsPolicy } /** - * Determine whether the user can manage the accessory. + * Determine whether the user can manage the model. * * @param \App\Models\User $user * @return mixed diff --git a/app/Presenters/AccessoryPresenter.php b/app/Presenters/AccessoryPresenter.php index 368ddd3f65..d4aaa768c3 100644 --- a/app/Presenters/AccessoryPresenter.php +++ b/app/Presenters/AccessoryPresenter.php @@ -120,7 +120,13 @@ class AccessoryPresenter extends Presenter 'field' => 'purchase_cost', 'searchable' => true, 'sortable' => true, - 'title' => trans('general.purchase_cost'), + 'title' => trans('general.unit_cost'), + 'class' => 'text-right text-padding-number-cell', + ], [ + 'field' => 'total_cost', + 'searchable' => true, + 'sortable' => true, + 'title' => trans('general.total_cost'), 'footerFormatter' => 'sumFormatterQuantity', 'class' => 'text-right text-padding-number-cell', ], [ diff --git a/app/Presenters/ActionlogPresenter.php b/app/Presenters/ActionlogPresenter.php index 4b7aefc87a..0f82d1f667 100644 --- a/app/Presenters/ActionlogPresenter.php +++ b/app/Presenters/ActionlogPresenter.php @@ -62,6 +62,10 @@ class ActionlogPresenter extends Presenter return 'fa-solid fa-user-minus'; } + if ($this->action_type == 'upload deleted') { + return 'fa-solid fa-trash'; + } + if ($this->action_type == 'update') { return 'fa-solid fa-user-pen'; } @@ -74,7 +78,7 @@ class ActionlogPresenter extends Presenter return 'fa-solid fa-plus'; } - if ($this->action_type == 'delete') { + if (($this->action_type == 'delete') || ($this->action_type == 'upload deleted')) { return 'fa-solid fa-trash'; } @@ -141,7 +145,7 @@ class ActionlogPresenter extends Presenter return $target->present()->nameUrl(); } - return ''.$target->present()->name().''; + return ''.$target->display_name.''; } return ''; diff --git a/app/Presenters/AssetModelPresenter.php b/app/Presenters/AssetModelPresenter.php index 6c6fcd564a..ac9aa5e661 100644 --- a/app/Presenters/AssetModelPresenter.php +++ b/app/Presenters/AssetModelPresenter.php @@ -53,7 +53,7 @@ class AssetModelPresenter extends Presenter ], [ 'field' => 'manufacturer', - 'searchable' => false, + 'searchable' => true, 'sortable' => true, 'switchable' => true, 'title' => trans('general.manufacturer'), @@ -62,7 +62,7 @@ class AssetModelPresenter extends Presenter ], [ 'field' => 'model_number', - 'searchable' => false, + 'searchable' => true, 'sortable' => true, 'switchable' => true, 'title' => trans('admin/models/table.modelnumber'), @@ -89,17 +89,36 @@ class AssetModelPresenter extends Presenter 'class' => 'text-right text-padding-number-cell', 'footerFormatter' => 'qtySumFormatter', ], - + [ + 'field' => 'assets_assigned_count', + 'searchable' => false, + 'sortable' => true, + 'switchable' => true, + 'title' => trans('general.assigned'), + 'visible' => true, + 'class' => 'text-right text-padding-number-cell', + 'footerFormatter' => 'qtySumFormatter', + ], [ 'field' => 'remaining', 'searchable' => false, - 'sortable' => false, + 'sortable' => true, 'switchable' => true, 'title' => trans('general.remaining'), 'visible' => true, 'class' => 'text-right text-padding-number-cell', 'footerFormatter' => 'qtySumFormatter', ], + [ + 'field' => 'assets_archived_count', + 'searchable' => false, + 'sortable' => true, + 'switchable' => true, + 'title' => trans('general.archived'), + 'visible' => true, + 'class' => 'text-right text-padding-number-cell', + 'footerFormatter' => 'qtySumFormatter', + ], [ 'field' => 'depreciation', 'searchable' => false, @@ -111,7 +130,7 @@ class AssetModelPresenter extends Presenter ], [ 'field' => 'category', - 'searchable' => false, + 'searchable' => true, 'sortable' => true, 'switchable' => true, 'title' => trans('general.category'), @@ -143,6 +162,14 @@ class AssetModelPresenter extends Presenter 'title' => trans('admin/hardware/general.requestable'), 'formatter' => 'trueFalseFormatter', ], + [ + 'field' => 'require_serial', + 'searchable' => false, + 'sortable' => true, + 'visible' => false, + 'title' => trans('admin/hardware/general.require_serial'), + 'formatter' => 'trueFalseFormatter', + ], [ 'field' => 'notes', 'searchable' => true, diff --git a/app/Presenters/AssetPresenter.php b/app/Presenters/AssetPresenter.php index 220ea67834..6f467644fd 100644 --- a/app/Presenters/AssetPresenter.php +++ b/app/Presenters/AssetPresenter.php @@ -328,7 +328,7 @@ class AssetPresenter extends Presenter // name can break the listings page. - snipe foreach ($fields as $field) { $layout[] = [ - 'field' => 'custom_fields.'.$field->db_column, + 'field' => $field->db_column, 'searchable' => true, 'sortable' => true, 'switchable' => true, diff --git a/app/Presenters/CategoryPresenter.php b/app/Presenters/CategoryPresenter.php index d8b401a040..9299d15c33 100644 --- a/app/Presenters/CategoryPresenter.php +++ b/app/Presenters/CategoryPresenter.php @@ -97,7 +97,7 @@ class CategoryPresenter extends Presenter 'formatter' => 'usersLinkObjFormatter', ], [ 'field' => 'created_at', - 'searchable' => true, + 'searchable' => false, 'sortable' => true, 'switchable' => true, 'title' => trans('general.created_at'), @@ -105,7 +105,7 @@ class CategoryPresenter extends Presenter 'formatter' => 'dateDisplayFormatter', ], [ 'field' => 'updated_at', - 'searchable' => true, + 'searchable' => false, 'sortable' => true, 'switchable' => true, 'title' => trans('general.updated_at'), diff --git a/app/Presenters/ComponentPresenter.php b/app/Presenters/ComponentPresenter.php index 32e63ac713..0b13ef159f 100644 --- a/app/Presenters/ComponentPresenter.php +++ b/app/Presenters/ComponentPresenter.php @@ -79,6 +79,25 @@ class ComponentPresenter extends Presenter 'title' => trans('general.manufacturer'), 'visible' => false, 'formatter' => 'manufacturersLinkObjFormatter', + ], [ + 'field' => 'location', + 'searchable' => true, + 'sortable' => true, + 'title' => trans('general.location'), + 'formatter' => 'locationsLinkObjFormatter', + ], [ + 'field' => 'order_number', + 'searchable' => true, + 'sortable' => true, + 'title' => trans('general.order_number'), + 'visible' => true, + ], [ + 'field' => 'purchase_date', + 'searchable' => true, + 'sortable' => true, + 'title' => trans('general.purchase_date'), + 'visible' => true, + 'formatter' => 'dateDisplayFormatter', ], [ 'field' => 'min_amt', 'searchable' => false, @@ -103,33 +122,20 @@ class ComponentPresenter extends Presenter 'visible' => true, 'class' => 'text-right text-padding-number-cell', 'footerFormatter' => 'qtySumFormatter', - ], [ - 'field' => 'location', - 'searchable' => true, - 'sortable' => true, - 'title' => trans('general.location'), - 'formatter' => 'locationsLinkObjFormatter', - ], [ - 'field' => 'order_number', - 'searchable' => true, - 'sortable' => true, - 'title' => trans('general.order_number'), - 'visible' => true, - ], [ - 'field' => 'purchase_date', - 'searchable' => true, - 'sortable' => true, - 'title' => trans('general.purchase_date'), - 'visible' => true, - 'formatter' => 'dateDisplayFormatter', ], [ 'field' => 'purchase_cost', 'searchable' => true, 'sortable' => true, - 'title' => trans('general.purchase_cost'), + 'title' => trans('general.unit_cost'), 'visible' => true, - 'footerFormatter' => 'sumFormatterQuantity', 'class' => 'text-right', + ], [ + 'field' => 'total_cost', + 'searchable' => false, + 'sortable' => true, + 'title' => trans('general.total_cost'), + 'footerFormatter' => 'sumFormatterQuantity', + 'class' => 'text-right text-padding-number-cell', ], [ 'field' => 'notes', 'searchable' => true, diff --git a/app/Presenters/ConsumablePresenter.php b/app/Presenters/ConsumablePresenter.php index 57f628c5ba..2b2eec5b2e 100644 --- a/app/Presenters/ConsumablePresenter.php +++ b/app/Presenters/ConsumablePresenter.php @@ -67,35 +67,6 @@ class ConsumablePresenter extends Presenter 'searchable' => true, 'sortable' => true, 'title' => trans('general.model_no'), - ], [ - 'field' => 'item_no', - 'searchable' => true, - 'sortable' => true, - 'title' => trans('admin/consumables/general.item_no'), - ], [ - 'field' => 'qty', - 'searchable' => false, - 'sortable' => true, - 'title' => trans('admin/components/general.total'), - 'visible' => true, - 'class' => 'text-right text-padding-number-cell', - 'footerFormatter' => 'qtySumFormatter', - ], [ - 'field' => 'remaining', - 'searchable' => false, - 'sortable' => true, - 'title' => trans('admin/components/general.remaining'), - 'visible' => true, - 'class' => 'text-right text-padding-number-cell', - 'footerFormatter' => 'qtySumFormatter', - ], [ - 'field' => 'min_amt', - 'searchable' => false, - 'sortable' => true, - 'title' => trans('general.min_amt'), - 'visible' => true, - 'formatter' => 'minAmtFormatter', - 'class' => 'text-right text-padding-number-cell', ], [ 'field' => 'location', 'searchable' => true, @@ -103,6 +74,12 @@ class ConsumablePresenter extends Presenter 'title' => trans('general.location'), 'formatter' => 'locationsLinkObjFormatter', ], [ + 'field' => 'item_no', + 'searchable' => true, + 'sortable' => true, + 'title' => trans('admin/consumables/general.item_no'), + ], [ + 'field' => 'manufacturer', 'searchable' => true, 'sortable' => true, @@ -122,12 +99,42 @@ class ConsumablePresenter extends Presenter 'title' => trans('general.purchase_date'), 'visible' => true, 'formatter' => 'dateDisplayFormatter', + ], [ + 'field' => 'min_amt', + 'searchable' => false, + 'sortable' => true, + 'title' => trans('general.min_amt'), + 'visible' => true, + 'formatter' => 'minAmtFormatter', + 'class' => 'text-right text-padding-number-cell', + ], [ + 'field' => 'qty', + 'searchable' => false, + 'sortable' => true, + 'title' => trans('admin/components/general.total'), + 'visible' => true, + 'class' => 'text-right text-padding-number-cell', + 'footerFormatter' => 'qtySumFormatter', + ], [ + 'field' => 'remaining', + 'searchable' => false, + 'sortable' => true, + 'title' => trans('admin/components/general.remaining'), + 'visible' => true, + 'class' => 'text-right text-padding-number-cell', + 'footerFormatter' => 'qtySumFormatter', ], [ 'field' => 'purchase_cost', 'searchable' => true, 'sortable' => true, - 'title' => trans('general.purchase_cost'), + 'title' => trans('general.unit_cost'), 'visible' => true, + 'class' => 'text-right text-padding-number-cell', + ], [ + 'field' => 'total_cost', + 'searchable' => true, + 'sortable' => true, + 'title' => trans('general.total_cost'), 'footerFormatter' => 'sumFormatterQuantity', 'class' => 'text-right text-padding-number-cell', ], [ diff --git a/app/Presenters/LicensePresenter.php b/app/Presenters/LicensePresenter.php index 773f5f5547..ea5c3b5d73 100644 --- a/app/Presenters/LicensePresenter.php +++ b/app/Presenters/LicensePresenter.php @@ -48,11 +48,19 @@ class LicensePresenter extends Presenter 'sortable' => true, 'title' => trans('admin/licenses/form.expiration'), 'formatter' => 'dateDisplayFormatter', + ], [ + 'field' => 'termination_date', + 'searchable' => true, + 'sortable' => true, + 'visible' => false, + 'title' => trans('admin/licenses/form.termination_date'), + 'formatter' => 'dateDisplayFormatter', ], [ 'field' => 'license_email', 'searchable' => true, 'sortable' => true, 'title' => trans('admin/licenses/form.to_email'), + 'formatter' => 'emailFormatter', ], [ 'field' => 'license_name', 'searchable' => true, @@ -109,14 +117,6 @@ class LicensePresenter extends Presenter 'title' => trans('general.purchase_date'), 'formatter' => 'dateDisplayFormatter', ], - [ - 'field' => 'termination_date', - 'searchable' => true, - 'sortable' => true, - 'visible' => false, - 'title' => trans('admin/licenses/form.termination_date'), - 'formatter' => 'dateDisplayFormatter', - ], [ 'field' => 'depreciation', 'searchable' => true, @@ -201,7 +201,7 @@ class LicensePresenter extends Presenter 'switchable' => false, 'title' => trans('general.checkin').'/'.trans('general.checkout'), 'visible' => true, - 'formatter' => 'licensesInOutFormatter', + 'formatter' => 'licenseInOutFormatter', 'printIgnore' => true, ]; diff --git a/app/Presenters/LocationPresenter.php b/app/Presenters/LocationPresenter.php index 31d2f05f77..30225460dc 100644 --- a/app/Presenters/LocationPresenter.php +++ b/app/Presenters/LocationPresenter.php @@ -61,6 +61,15 @@ class LocationPresenter extends Presenter 'title' => trans('admin/locations/table.parent'), 'visible' => true, 'formatter' => 'locationsLinkObjFormatter', + ], [ + 'field' => 'users_count', + 'searchable' => false, + 'sortable' => true, + 'switchable' => true, + 'title' => trans('general.people'), + 'titleTooltip' => trans('general.people'), + 'visible' => true, + 'class' => 'css-house-user', ], [ 'field' => 'assets_count', 'searchable' => false, @@ -98,7 +107,7 @@ class LocationPresenter extends Presenter 'titleTooltip' => trans('general.accessories'), 'visible' => true, 'class' => 'css-accessory', - ], [ + ],[ 'field' => 'assigned_accessories_count', 'searchable' => false, 'sortable' => true, @@ -108,14 +117,34 @@ class LocationPresenter extends Presenter 'visible' => true, 'class' => 'css-accessory-alt', ], [ - 'field' => 'users_count', + 'field' => 'components_count', 'searchable' => false, 'sortable' => true, 'switchable' => true, - 'title' => trans('general.people'), - 'titleTooltip' => trans('general.people'), + 'title' => trans('general.components'), + 'titleTooltip' => trans('general.components'), 'visible' => true, - 'class' => 'css-house-user', + 'class' => 'css-component', + ], + [ + 'field' => 'consumables_count', + 'searchable' => false, + 'sortable' => true, + 'switchable' => true, + 'title' => trans('general.consumables'), + 'titleTooltip' => trans('general.consumables'), + 'visible' => true, + 'class' => 'css-consumable', + ], + [ + 'field' => 'children_count', + 'searchable' => false, + 'sortable' => true, + 'switchable' => true, + 'title' => trans('general.child_locations'), + 'titleTooltip' => trans('general.child_locations'), + 'visible' => true, + 'class' => 'css-child-locations', ], [ 'field' => 'currency', 'searchable' => true, diff --git a/app/Presenters/MaintenancesPresenter.php b/app/Presenters/MaintenancesPresenter.php index 41ff927f67..9edd0f5035 100644 --- a/app/Presenters/MaintenancesPresenter.php +++ b/app/Presenters/MaintenancesPresenter.php @@ -111,6 +111,12 @@ class MaintenancesPresenter extends Presenter 'sortable' => true, 'title' => trans('admin/maintenances/form.completion_date'), 'formatter' => 'dateDisplayFormatter', + ], [ + 'field' => 'url', + 'searchable' => true, + 'sortable' => true, + 'title' => trans('general.url'), + 'formatter' => 'externalLinkFormatter', ], [ 'field' => 'notes', 'searchable' => true, diff --git a/app/Presenters/Presenter.php b/app/Presenters/Presenter.php index 85fe2338ae..13bae66ecd 100644 --- a/app/Presenters/Presenter.php +++ b/app/Presenters/Presenter.php @@ -3,6 +3,7 @@ namespace App\Presenters; use App\Models\SnipeModel; +use Illuminate\Database\Eloquent\Casts\Attribute; abstract class Presenter { @@ -69,10 +70,30 @@ abstract class Presenter return ''; } - public function name() - { - return $this->model->name; - } +// public function name() +// { +// return $this->model->name; +// } +// +// public function display_name() +// { +// return $this->model->display_name; +// } + + +// protected function displayName(): Attribute +// { +// // This override should only kick in if the model has a display_name prope +// if ($this->getRawOriginal('display_name')) { +// return Attribute:: make ( +// get: fn(mixed $value) => 'Poop:'.$this->display_name +// ); +// } +// +// return Attribute:: make( +// get: fn(mixed $value) => 'Fart: '.$this->name, +// ); +// } public function __get($property) { @@ -80,7 +101,7 @@ abstract class Presenter return $this->{$property}(); } - return e($this->model->{$property}); + return $this->model->{$property}; } public function __call($method, $args) diff --git a/app/Presenters/UserPresenter.php b/app/Presenters/UserPresenter.php index c60457ea05..b02a6e4fcd 100644 --- a/app/Presenters/UserPresenter.php +++ b/app/Presenters/UserPresenter.php @@ -60,18 +60,14 @@ class UserPresenter extends Presenter 'title' => trans('admin/users/table.name'), 'visible' => true, 'formatter' => 'usersLinkFormatter', - ], - - [ + ], [ 'field' => 'first_name', 'searchable' => true, 'sortable' => true, 'title' => trans('general.first_name'), 'visible' => false, 'formatter' => 'usersLinkFormatter', - ], - - [ + ], [ 'field' => 'last_name', 'searchable' => true, 'sortable' => true, @@ -79,6 +75,30 @@ class UserPresenter extends Presenter 'visible' => false, 'formatter' => 'usersLinkFormatter', ], + [ + 'field' => 'display_name', + 'searchable' => true, + 'sortable' => true, + 'switchable' => false, + 'title' => trans('admin/users/table.display_name'), + 'visible' => false, + ], [ + 'field' => 'username', + 'searchable' => true, + 'sortable' => true, + 'switchable' => false, + 'title' => trans('admin/users/table.username'), + 'visible' => true, + 'formatter' => 'usernameRoleLinkFormatter', + ], + [ + 'field' => 'employee_num', + 'searchable' => true, + 'sortable' => true, + 'switchable' => true, + 'title' => trans('general.employee_number'), + 'visible' => false, + ], [ 'field' => 'jobtitle', 'searchable' => true, @@ -121,7 +141,7 @@ class UserPresenter extends Presenter 'sortable' => true, 'switchable' => true, 'title' => trans('admin/users/table.phone'), - 'visible' => true, + 'visible' => false, 'formatter' => 'phoneFormatter', ], [ @@ -182,23 +202,7 @@ class UserPresenter extends Presenter 'title' => trans('general.zip'), 'visible' => false, ], - [ - 'field' => 'username', - 'searchable' => true, - 'sortable' => true, - 'switchable' => false, - 'title' => trans('admin/users/table.username'), - 'visible' => true, - 'formatter' => 'usernameRoleLinkFormatter', - ], - [ - 'field' => 'employee_num', - 'searchable' => true, - 'sortable' => true, - 'switchable' => true, - 'title' => trans('general.employee_number'), - 'visible' => false, - ], + [ 'field' => 'locale', 'searchable' => true, @@ -222,7 +226,7 @@ class UserPresenter extends Presenter 'sortable' => true, 'switchable' => true, 'title' => trans('admin/users/general.department_manager'), - 'visible' => true, + 'visible' => false, 'formatter' => 'usersLinkObjFormatter', ], [ @@ -239,7 +243,7 @@ class UserPresenter extends Presenter 'searchable' => true, 'sortable' => true, 'title' => trans('admin/users/table.manager'), - 'visible' => true, + 'visible' => false, 'formatter' => 'usersLinkObjFormatter', ], [ @@ -447,20 +451,23 @@ class UserPresenter extends Presenter * * @return string */ - public function fullName() - { - return html_entity_decode($this->first_name.' '.$this->last_name, ENT_QUOTES | ENT_XML1, 'UTF-8'); - } +// public function fullName() +// { +// if ($this->display_name) { +// return 'kjdfh'.html_entity_decode($this->display_name, ENT_QUOTES | ENT_XML1, 'UTF-8'); +// } +// return 'roieuoe'.html_entity_decode($this->first_name.' '.$this->last_name, ENT_QUOTES | ENT_XML1, 'UTF-8'); +// } - /** - * Standard accessor. - * @TODO Remove presenter::fullName() entirely? - * @return string - */ - public function name() - { - return $this->fullName(); - } +// /** +// * Standard accessor. +// * @TODO Remove presenter::fullName() entirely? +// * @return string +// */ +// public function name() +// { +// return $this->fullName(); +// } diff --git a/app/Providers/AppServiceProvider.php b/app/Providers/AppServiceProvider.php index ba81ffb721..2ebcb9b035 100644 --- a/app/Providers/AppServiceProvider.php +++ b/app/Providers/AppServiceProvider.php @@ -85,6 +85,12 @@ class AppServiceProvider extends ServiceProvider */ public function register() { + + if ($this->app->environment('local')) { + $this->app->register(\Laravel\Telescope\TelescopeServiceProvider::class); + $this->app->register(TelescopeServiceProvider::class); + } + // Only load rollbar if there is a rollbar key and the app is in production if (($this->app->environment('production')) && (config('logging.channels.rollbar.access_token'))) { $this->app->register(\Rollbar\Laravel\RollbarServiceProvider::class); diff --git a/app/Providers/BreadcrumbsServiceProvider.php b/app/Providers/BreadcrumbsServiceProvider.php index e7b41a8fca..23fb88a96f 100644 --- a/app/Providers/BreadcrumbsServiceProvider.php +++ b/app/Providers/BreadcrumbsServiceProvider.php @@ -74,12 +74,12 @@ class BreadcrumbsServiceProvider extends ServiceProvider Breadcrumbs::for('hardware.show', fn (Trail $trail, Asset $asset) => $trail->parent('hardware.index', route('hardware.index')) - ->push($asset->present()->fullName(), route('hardware.show', $asset)) + ->push($asset->display_name, route('hardware.show', $asset)) ); Breadcrumbs::for('hardware.edit', fn (Trail $trail, Asset $asset) => $trail->parent('hardware.index', route('hardware.index')) - ->push($asset->present()->fullName(), route('hardware.show', $asset)) + ->push($asset->display_name, route('hardware.show', $asset)) ->push(trans('admin/hardware/general.edit')) ); @@ -349,10 +349,24 @@ class BreadcrumbsServiceProvider extends ServiceProvider /** * Licenses Breadcrumbs */ - Breadcrumbs::for('licenses.index', fn (Trail $trail) => - $trail->parent('home', route('home')) - ->push(trans('general.licenses'), route('licenses.index')) - ); + if ((request()->is('licenses*')) && (request()->status=='inactive')) { + Breadcrumbs::for('licenses.index', fn(Trail $trail) => $trail->parent('home', route('home')) + ->push(trans('general.licenses'), route('licenses.index')) + ->push(trans('general.show_inactive'), route('licenses.index')) + ); + } elseif ((request()->is('licenses*')) && (request()->status=='expiring')) { + Breadcrumbs::for('licenses.index', fn (Trail $trail) => + $trail->parent('home', route('home')) + ->push(trans('general.licenses'), route('licenses.index')) + ->push(trans('general.show_expiring'), route('licenses.index')) + ); + } else { + Breadcrumbs::for('licenses.index', fn (Trail $trail) => + $trail->parent('home', route('home')) + ->push(trans('general.licenses'), route('licenses.index')) + ); + } + Breadcrumbs::for('licenses.create', fn (Trail $trail) => $trail->parent('licenses.index', route('licenses.index')) @@ -579,7 +593,7 @@ class BreadcrumbsServiceProvider extends ServiceProvider Breadcrumbs::for('users.show', fn (Trail $trail, User $user) => $trail->parent('users.index', route('users.index')) - ->push($user->getFullNameAttribute() ?? 'Missing Username!', route('users.show', $user)) + ->push($user->display_name ?? 'Missing Username!', route('users.show', $user)) ); Breadcrumbs::for('users.edit', fn (Trail $trail, User $user) => diff --git a/app/Providers/TelescopeServiceProvider.php b/app/Providers/TelescopeServiceProvider.php new file mode 100644 index 0000000000..414cd2467e --- /dev/null +++ b/app/Providers/TelescopeServiceProvider.php @@ -0,0 +1,66 @@ +hideSensitiveRequestDetails(); + + $isLocal = $this->app->environment('local'); + + Telescope::filter(function (IncomingEntry $entry) use ($isLocal) { + return $isLocal || + $entry->isReportableException() || + $entry->isFailedRequest() || + $entry->isFailedJob() || + $entry->isScheduledTask() || + $entry->hasMonitoredTag(); + }); + } + + /** + * Prevent sensitive request details from being logged by Telescope. + */ + protected function hideSensitiveRequestDetails(): void + { + if ($this->app->environment('local')) { + return; + } + + Telescope::hideRequestParameters(['_token']); + + Telescope::hideRequestHeaders([ + 'cookie', + 'x-csrf-token', + 'x-xsrf-token', + ]); + } + + /** + * Register the Telescope gate. + * + * This gate determines who can access Telescope in NON-LOCAL environments. + */ + protected function gate(): void + { + Gate::define('viewTelescope', function ($user) { + if ($user->isSuperUser()) { + return true; + } + + return false; + }); + } +} diff --git a/app/View/Label.php b/app/View/Label.php index ee9a1ae2fd..96f88e0f5f 100644 --- a/app/View/Label.php +++ b/app/View/Label.php @@ -74,6 +74,10 @@ class Label implements View [0 => $template->getWidth(), 1 => $template->getHeight(), 'Rotate' => $template->getRotation()] ); + // Required for CJK languages, otherwise the embedded font can get too massive + $pdf->SetFontSubsetting(true); + + // Reset parameters $pdf->SetPrintHeader(false); $pdf->SetPrintFooter(false); @@ -176,14 +180,14 @@ class Label implements View // For fields that have multiple options, we need to combine them // into a single field so all values are displayed. ->reduce(function ($previous, $current) { - // On the first iteration we simply return the item. + // On the first iteration, we simply return the item. // If there is only one item to be processed for the row // then this effectively skips everything below this if block. if (is_null($previous)) { return $current; } - // At this point we are dealing with a row with multiple items being displayed. + // At this point, we are dealing with a row with multiple items being displayed. // We need to combine the label and value of the current item with the previous item. // The end result of this will be in this format: diff --git a/composer.json b/composer.json index a2803fed44..76a59a22f2 100644 --- a/composer.json +++ b/composer.json @@ -32,12 +32,12 @@ "arietimmerman/laravel-scim-server": "dev-laravel_11_compatibility", "bacon/bacon-qr-code": "^2.0", "barryvdh/laravel-debugbar": "^3.13", - "barryvdh/laravel-dompdf": "^2.0", "doctrine/cache": "^1.10", "doctrine/dbal": "^3.1", "doctrine/instantiator": "^1.3", "eduardokum/laravel-mail-auto-embed": "^2.0", - "enshrined/svg-sanitize": "^0.16.0", + "elibyy/tcpdf-laravel": "^11.5", + "enshrined/svg-sanitize": "^0.22.0", "erusev/parsedown": "^1.7", "fakerphp/faker": "^1.24", "guzzlehttp/guzzle": "^7.0.1", @@ -73,6 +73,7 @@ "spatie/laravel-ignition": "^2.0", "tabuna/breadcrumbs": "^4.2", "tecnickcom/tc-lib-barcode": "^1.15", + "tecnickcom/tc-lib-pdf-font": "^2.6", "tecnickcom/tcpdf": "^6.5", "unicodeveloper/laravel-password": "^1.0", "watson/validating": "^8.1" @@ -84,6 +85,7 @@ }, "require-dev": { "larastan/larastan": "^2.9", + "laravel/telescope": "^5.11", "mockery/mockery": "^1.4", "nunomaduro/phpinsights": "^2.11", "php-mock/php-mock-phpunit": "^2.10", @@ -95,7 +97,8 @@ "extra": { "laravel": { "dont-discover": [ - "rollbar/rollbar-laravel" + "rollbar/rollbar-laravel", + "laravel/telescope" ] } }, diff --git a/composer.lock b/composer.lock index e9a312f542..76e8fb86b6 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "75fb4f46ea0a488c2dd45d73eb2a9b9d", + "content-hash": "553ce69c21704905c568769de08fffe4", "packages": [ { "name": "alek13/slack", @@ -190,16 +190,16 @@ }, { "name": "aws/aws-sdk-php", - "version": "3.351.7", + "version": "3.356.17", "source": { "type": "git", "url": "https://github.com/aws/aws-sdk-php.git", - "reference": "9506d7fdb3cb84f8d7b175c594db9993264814be" + "reference": "d0357fbe2535bb7d832e594a4ff2ff8da29d229c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/9506d7fdb3cb84f8d7b175c594db9993264814be", - "reference": "9506d7fdb3cb84f8d7b175c594db9993264814be", + "url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/d0357fbe2535bb7d832e594a4ff2ff8da29d229c", + "reference": "d0357fbe2535bb7d832e594a4ff2ff8da29d229c", "shasum": "" }, "require": { @@ -212,7 +212,7 @@ "guzzlehttp/psr7": "^2.4.5", "mtdowling/jmespath.php": "^2.8.0", "php": ">=8.1", - "psr/http-message": "^2.0" + "psr/http-message": "^1.0 || ^2.0" }, "require-dev": { "andrewsville/php-token-reflection": "^1.4", @@ -281,9 +281,9 @@ "support": { "forum": "https://github.com/aws/aws-sdk-php/discussions", "issues": "https://github.com/aws/aws-sdk-php/issues", - "source": "https://github.com/aws/aws-sdk-php/tree/3.351.7" + "source": "https://github.com/aws/aws-sdk-php/tree/3.356.17" }, - "time": "2025-07-25T18:06:34+00:00" + "time": "2025-09-12T18:07:37+00:00" }, { "name": "bacon/bacon-qr-code", @@ -424,104 +424,27 @@ ], "time": "2025-07-14T11:56:43+00:00" }, - { - "name": "barryvdh/laravel-dompdf", - "version": "v2.2.0", - "source": { - "type": "git", - "url": "https://github.com/barryvdh/laravel-dompdf.git", - "reference": "c96f90c97666cebec154ca1ffb67afed372114d8" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/barryvdh/laravel-dompdf/zipball/c96f90c97666cebec154ca1ffb67afed372114d8", - "reference": "c96f90c97666cebec154ca1ffb67afed372114d8", - "shasum": "" - }, - "require": { - "dompdf/dompdf": "^2.0.7", - "illuminate/support": "^6|^7|^8|^9|^10|^11", - "php": "^7.2 || ^8.0" - }, - "require-dev": { - "larastan/larastan": "^1.0|^2.7.0", - "orchestra/testbench": "^4|^5|^6|^7|^8|^9", - "phpro/grumphp": "^1 || ^2.5", - "squizlabs/php_codesniffer": "^3.5" - }, - "type": "library", - "extra": { - "laravel": { - "aliases": { - "PDF": "Barryvdh\\DomPDF\\Facade\\Pdf", - "Pdf": "Barryvdh\\DomPDF\\Facade\\Pdf" - }, - "providers": [ - "Barryvdh\\DomPDF\\ServiceProvider" - ] - }, - "branch-alias": { - "dev-master": "2.0-dev" - } - }, - "autoload": { - "psr-4": { - "Barryvdh\\DomPDF\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Barry vd. Heuvel", - "email": "barryvdh@gmail.com" - } - ], - "description": "A DOMPDF Wrapper for Laravel", - "keywords": [ - "dompdf", - "laravel", - "pdf" - ], - "support": { - "issues": "https://github.com/barryvdh/laravel-dompdf/issues", - "source": "https://github.com/barryvdh/laravel-dompdf/tree/v2.2.0" - }, - "funding": [ - { - "url": "https://fruitcake.nl", - "type": "custom" - }, - { - "url": "https://github.com/barryvdh", - "type": "github" - } - ], - "time": "2024-04-25T13:16:04+00:00" - }, { "name": "brick/math", - "version": "0.12.3", + "version": "0.14.0", "source": { "type": "git", "url": "https://github.com/brick/math.git", - "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba" + "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/brick/math/zipball/866551da34e9a618e64a819ee1e01c20d8a588ba", - "reference": "866551da34e9a618e64a819ee1e01c20d8a588ba", + "url": "https://api.github.com/repos/brick/math/zipball/113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2", + "reference": "113a8ee2656b882d4c3164fa31aa6e12cbb7aaa2", "shasum": "" }, "require": { - "php": "^8.1" + "php": "^8.2" }, "require-dev": { "php-coveralls/php-coveralls": "^2.2", - "phpunit/phpunit": "^10.1", - "vimeo/psalm": "6.8.8" + "phpstan/phpstan": "2.1.22", + "phpunit/phpunit": "^11.5" }, "type": "library", "autoload": { @@ -551,7 +474,7 @@ ], "support": { "issues": "https://github.com/brick/math/issues", - "source": "https://github.com/brick/math/tree/0.12.3" + "source": "https://github.com/brick/math/tree/0.14.0" }, "funding": [ { @@ -559,7 +482,7 @@ "type": "github" } ], - "time": "2025-02-28T13:11:00+00:00" + "time": "2025-08-29T12:40:03+00:00" }, { "name": "carbonphp/carbon-doctrine-types", @@ -923,16 +846,16 @@ }, { "name": "doctrine/dbal", - "version": "3.10.0", + "version": "3.10.2", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "1cf840d696373ea0d58ad0a8875c0fadcfc67214" + "reference": "c6c16cf787eaba3112203dfcd715fa2059c62282" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/1cf840d696373ea0d58ad0a8875c0fadcfc67214", - "reference": "1cf840d696373ea0d58ad0a8875c0fadcfc67214", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/c6c16cf787eaba3112203dfcd715fa2059c62282", + "reference": "c6c16cf787eaba3112203dfcd715fa2059c62282", "shasum": "" }, "require": { @@ -948,10 +871,10 @@ }, "require-dev": { "doctrine/cache": "^1.11|^2.0", - "doctrine/coding-standard": "13.0.0", + "doctrine/coding-standard": "13.0.1", "fig/log-test": "^1", "jetbrains/phpstorm-stubs": "2023.1", - "phpstan/phpstan": "2.1.17", + "phpstan/phpstan": "2.1.22", "phpstan/phpstan-strict-rules": "^2", "phpunit/phpunit": "9.6.23", "slevomat/coding-standard": "8.16.2", @@ -1017,7 +940,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.10.0" + "source": "https://github.com/doctrine/dbal/tree/3.10.2" }, "funding": [ { @@ -1033,7 +956,7 @@ "type": "tidelift" } ], - "time": "2025-07-10T21:11:04+00:00" + "time": "2025-09-04T23:51:27+00:00" }, { "name": "doctrine/deprecations", @@ -1176,33 +1099,32 @@ }, { "name": "doctrine/inflector", - "version": "2.0.10", + "version": "2.1.0", "source": { "type": "git", "url": "https://github.com/doctrine/inflector.git", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", - "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/6d6c96277ea252fc1304627204c3d5e6e15faa3b", + "reference": "6d6c96277ea252fc1304627204c3d5e6e15faa3b", "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" + "doctrine/coding-standard": "^12.0 || ^13.0", + "phpstan/phpstan": "^1.12 || ^2.0", + "phpstan/phpstan-phpunit": "^1.4 || ^2.0", + "phpstan/phpstan-strict-rules": "^1.6 || ^2.0", + "phpunit/phpunit": "^8.5 || ^12.2" }, "type": "library", "autoload": { "psr-4": { - "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + "Doctrine\\Inflector\\": "src" } }, "notification-url": "https://packagist.org/downloads/", @@ -1247,7 +1169,7 @@ ], "support": { "issues": "https://github.com/doctrine/inflector/issues", - "source": "https://github.com/doctrine/inflector/tree/2.0.10" + "source": "https://github.com/doctrine/inflector/tree/2.1.0" }, "funding": [ { @@ -1263,7 +1185,7 @@ "type": "tidelift" } ], - "time": "2024-02-18T20:23:39+00:00" + "time": "2025-08-10T19:31:58+00:00" }, { "name": "doctrine/instantiator", @@ -1412,68 +1334,6 @@ ], "time": "2024-02-05T11:56:58+00:00" }, - { - "name": "dompdf/dompdf", - "version": "v2.0.8", - "source": { - "type": "git", - "url": "https://github.com/dompdf/dompdf.git", - "reference": "c20247574601700e1f7c8dab39310fca1964dc52" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/dompdf/zipball/c20247574601700e1f7c8dab39310fca1964dc52", - "reference": "c20247574601700e1f7c8dab39310fca1964dc52", - "shasum": "" - }, - "require": { - "ext-dom": "*", - "ext-mbstring": "*", - "masterminds/html5": "^2.0", - "phenx/php-font-lib": ">=0.5.4 <1.0.0", - "phenx/php-svg-lib": ">=0.5.2 <1.0.0", - "php": "^7.1 || ^8.0" - }, - "require-dev": { - "ext-json": "*", - "ext-zip": "*", - "mockery/mockery": "^1.3", - "phpunit/phpunit": "^7.5 || ^8 || ^9", - "squizlabs/php_codesniffer": "^3.5" - }, - "suggest": { - "ext-gd": "Needed to process images", - "ext-gmagick": "Improves image processing performance", - "ext-imagick": "Improves image processing performance", - "ext-zlib": "Needed for pdf stream compression" - }, - "type": "library", - "autoload": { - "psr-4": { - "Dompdf\\": "src/" - }, - "classmap": [ - "lib/" - ] - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1" - ], - "authors": [ - { - "name": "The Dompdf Community", - "homepage": "https://github.com/dompdf/dompdf/blob/master/AUTHORS.md" - } - ], - "description": "DOMPDF is a CSS 2.1 compliant HTML to PDF converter", - "homepage": "https://github.com/dompdf/dompdf", - "support": { - "issues": "https://github.com/dompdf/dompdf/issues", - "source": "https://github.com/dompdf/dompdf/tree/v2.0.8" - }, - "time": "2024-04-29T13:06:17+00:00" - }, { "name": "dragonmantank/cron-expression", "version": "v3.4.0", @@ -1677,27 +1537,82 @@ "time": "2025-03-06T22:45:56+00:00" }, { - "name": "enshrined/svg-sanitize", - "version": "0.16.0", + "name": "elibyy/tcpdf-laravel", + "version": "11.5.0", "source": { "type": "git", - "url": "https://github.com/darylldoyle/svg-sanitizer.git", - "reference": "239e257605e2141265b429e40987b2ee51bba4b4" + "url": "https://github.com/elibyy/tcpdf-laravel.git", + "reference": "25d076d5f50eef9702dfa1ae889b1a599250f951" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/239e257605e2141265b429e40987b2ee51bba4b4", - "reference": "239e257605e2141265b429e40987b2ee51bba4b4", + "url": "https://api.github.com/repos/elibyy/tcpdf-laravel/zipball/25d076d5f50eef9702dfa1ae889b1a599250f951", + "reference": "25d076d5f50eef9702dfa1ae889b1a599250f951", + "shasum": "" + }, + "require": { + "illuminate/support": "^6.0|^7.0|^8.0|^9.0|^10.0|^11.0|^12.0", + "tecnickcom/tcpdf": "6.2.*|6.3.*|6.4.*|6.5.*|6.6.*|6.7.*|6.8.*|6.9.*|6.10.*|dev-main" + }, + "type": "library", + "extra": { + "laravel": { + "aliases": { + "PDF": "Elibyy\\TCPDF\\Facades\\TCPDF" + }, + "providers": [ + "Elibyy\\TCPDF\\ServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Elibyy\\TCPDF\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "eli y", + "email": "elibyy@gmail.com" + } + ], + "description": "tcpdf support for Laravel 6, 7, 8, 9, 10, 11", + "keywords": [ + "TCPDF", + "laravel", + "pdf" + ], + "support": { + "issues": "https://github.com/elibyy/tcpdf-laravel/issues", + "source": "https://github.com/elibyy/tcpdf-laravel/tree/11.5.0" + }, + "time": "2025-06-06T08:27:48+00:00" + }, + { + "name": "enshrined/svg-sanitize", + "version": "0.22.0", + "source": { + "type": "git", + "url": "https://github.com/darylldoyle/svg-sanitizer.git", + "reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/darylldoyle/svg-sanitizer/zipball/0afa95ea74be155a7bcd6c6fb60c276c39984500", + "reference": "0afa95ea74be155a7bcd6c6fb60c276c39984500", "shasum": "" }, "require": { "ext-dom": "*", "ext-libxml": "*", - "ezyang/htmlpurifier": "^4.16", - "php": "^5.6 || ^7.0 || ^8.0" + "php": "^7.1 || ^8.0" }, "require-dev": { - "phpunit/phpunit": "^5.7 || ^6.5 || ^8.5" + "phpunit/phpunit": "^6.5 || ^8.5" }, "type": "library", "autoload": { @@ -1718,9 +1633,9 @@ "description": "An SVG sanitizer for PHP", "support": { "issues": "https://github.com/darylldoyle/svg-sanitizer/issues", - "source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.16.0" + "source": "https://github.com/darylldoyle/svg-sanitizer/tree/0.22.0" }, - "time": "2023-03-20T10:51:12+00:00" + "time": "2025-08-12T10:13:48+00:00" }, { "name": "erusev/parsedown", @@ -1772,67 +1687,6 @@ }, "time": "2019-12-30T22:54:17+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": "fakerphp/faker", "version": "v1.24.1", @@ -1898,16 +1752,16 @@ }, { "name": "filp/whoops", - "version": "2.18.3", + "version": "2.18.4", "source": { "type": "git", "url": "https://github.com/filp/whoops.git", - "reference": "59a123a3d459c5a23055802237cb317f609867e5" + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/filp/whoops/zipball/59a123a3d459c5a23055802237cb317f609867e5", - "reference": "59a123a3d459c5a23055802237cb317f609867e5", + "url": "https://api.github.com/repos/filp/whoops/zipball/d2102955e48b9fd9ab24280a7ad12ed552752c4d", + "reference": "d2102955e48b9fd9ab24280a7ad12ed552752c4d", "shasum": "" }, "require": { @@ -1957,7 +1811,7 @@ ], "support": { "issues": "https://github.com/filp/whoops/issues", - "source": "https://github.com/filp/whoops/tree/2.18.3" + "source": "https://github.com/filp/whoops/tree/2.18.4" }, "funding": [ { @@ -1965,7 +1819,7 @@ "type": "github" } ], - "time": "2025-06-16T00:02:10+00:00" + "time": "2025-08-08T12:00:00+00:00" }, { "name": "firebase/php-jwt", @@ -2165,22 +2019,22 @@ }, { "name": "guzzlehttp/guzzle", - "version": "7.9.3", + "version": "7.10.0", "source": { "type": "git", "url": "https://github.com/guzzle/guzzle.git", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77" + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/guzzle/zipball/7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", - "reference": "7b2f29fe81dc4da0ca0ea7d42107a0845946ea77", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", + "reference": "b51ac707cfa420b7bfd4e4d5e510ba8008e822b4", "shasum": "" }, "require": { "ext-json": "*", - "guzzlehttp/promises": "^1.5.3 || ^2.0.3", - "guzzlehttp/psr7": "^2.7.0", + "guzzlehttp/promises": "^2.3", + "guzzlehttp/psr7": "^2.8", "php": "^7.2.5 || ^8.0", "psr/http-client": "^1.0", "symfony/deprecation-contracts": "^2.2 || ^3.0" @@ -2271,7 +2125,7 @@ ], "support": { "issues": "https://github.com/guzzle/guzzle/issues", - "source": "https://github.com/guzzle/guzzle/tree/7.9.3" + "source": "https://github.com/guzzle/guzzle/tree/7.10.0" }, "funding": [ { @@ -2287,20 +2141,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:37:11+00:00" + "time": "2025-08-23T22:36:01+00:00" }, { "name": "guzzlehttp/promises", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/guzzle/promises.git", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c" + "reference": "481557b130ef3790cf82b713667b43030dc9c957" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/promises/zipball/7c69f28996b0a6920945dd20b3857e499d9ca96c", - "reference": "7c69f28996b0a6920945dd20b3857e499d9ca96c", + "url": "https://api.github.com/repos/guzzle/promises/zipball/481557b130ef3790cf82b713667b43030dc9c957", + "reference": "481557b130ef3790cf82b713667b43030dc9c957", "shasum": "" }, "require": { @@ -2308,7 +2162,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "type": "library", "extra": { @@ -2354,7 +2208,7 @@ ], "support": { "issues": "https://github.com/guzzle/promises/issues", - "source": "https://github.com/guzzle/promises/tree/2.2.0" + "source": "https://github.com/guzzle/promises/tree/2.3.0" }, "funding": [ { @@ -2370,20 +2224,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T13:27:01+00:00" + "time": "2025-08-22T14:34:08+00:00" }, { "name": "guzzlehttp/psr7", - "version": "2.7.1", + "version": "2.8.0", "source": { "type": "git", "url": "https://github.com/guzzle/psr7.git", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16" + "reference": "21dc724a0583619cd1652f673303492272778051" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/psr7/zipball/c2270caaabe631b3b44c85f99e5a04bbb8060d16", - "reference": "c2270caaabe631b3b44c85f99e5a04bbb8060d16", + "url": "https://api.github.com/repos/guzzle/psr7/zipball/21dc724a0583619cd1652f673303492272778051", + "reference": "21dc724a0583619cd1652f673303492272778051", "shasum": "" }, "require": { @@ -2399,7 +2253,7 @@ "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" + "phpunit/phpunit": "^8.5.44 || ^9.6.25" }, "suggest": { "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses" @@ -2470,7 +2324,7 @@ ], "support": { "issues": "https://github.com/guzzle/psr7/issues", - "source": "https://github.com/guzzle/psr7/tree/2.7.1" + "source": "https://github.com/guzzle/psr7/tree/2.8.0" }, "funding": [ { @@ -2486,20 +2340,20 @@ "type": "tidelift" } ], - "time": "2025-03-27T12:30:47+00:00" + "time": "2025-08-23T21:21:41+00:00" }, { "name": "guzzlehttp/uri-template", - "version": "v1.0.4", + "version": "v1.0.5", "source": { "type": "git", "url": "https://github.com/guzzle/uri-template.git", - "reference": "30e286560c137526eccd4ce21b2de477ab0676d2" + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/uri-template/zipball/30e286560c137526eccd4ce21b2de477ab0676d2", - "reference": "30e286560c137526eccd4ce21b2de477ab0676d2", + "url": "https://api.github.com/repos/guzzle/uri-template/zipball/4f4bbd4e7172148801e76e3decc1e559bdee34e1", + "reference": "4f4bbd4e7172148801e76e3decc1e559bdee34e1", "shasum": "" }, "require": { @@ -2508,7 +2362,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.36 || ^9.6.15", + "phpunit/phpunit": "^8.5.44 || ^9.6.25", "uri-template/tests": "1.0.0" }, "type": "library", @@ -2556,7 +2410,7 @@ ], "support": { "issues": "https://github.com/guzzle/uri-template/issues", - "source": "https://github.com/guzzle/uri-template/tree/v1.0.4" + "source": "https://github.com/guzzle/uri-template/tree/v1.0.5" }, "funding": [ { @@ -2572,7 +2426,7 @@ "type": "tidelift" } ], - "time": "2025-02-03T10:55:03+00:00" + "time": "2025-08-22T14:27:06+00:00" }, { "name": "intervention/image", @@ -2694,27 +2548,27 @@ }, { "name": "laravel-notification-channels/google-chat", - "version": "3.2.0", + "version": "3.3.0", "source": { "type": "git", "url": "https://github.com/laravel-notification-channels/google-chat.git", - "reference": "39ec6d130044066c46b891e5620220be5fa166d1" + "reference": "425714f90750a10c400bee72ecc406c6c7f05056" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel-notification-channels/google-chat/zipball/39ec6d130044066c46b891e5620220be5fa166d1", - "reference": "39ec6d130044066c46b891e5620220be5fa166d1", + "url": "https://api.github.com/repos/laravel-notification-channels/google-chat/zipball/425714f90750a10c400bee72ecc406c6c7f05056", + "reference": "425714f90750a10c400bee72ecc406c6c7f05056", "shasum": "" }, "require": { "guzzlehttp/guzzle": "^6.3 || ^7.0", - "illuminate/notifications": "^9.0.2 || ^10.0 || ^11.0", - "illuminate/support": "^9.0.2 || ^10.0 || ^11.0", + "illuminate/notifications": "^9.0.2 || ^10.0 || ^11.0 || ^12.0", + "illuminate/support": "^9.0.2 || ^10.0 || ^11.0 || ^12.0", "php": ">=8.0" }, "require-dev": { - "orchestra/testbench": "^7.0 || ^9.0", - "phpunit/phpunit": "^9.5.10 || ^10.5" + "orchestra/testbench": "^7.0 || ^9.0 || ^10.0", + "phpunit/phpunit": "^9.5.10 || ^10.5 || ^11.5.3" }, "type": "library", "extra": { @@ -2745,9 +2599,9 @@ "homepage": "https://github.com/laravel-notification-channels/google-chat", "support": { "issues": "https://github.com/laravel-notification-channels/google-chat/issues", - "source": "https://github.com/laravel-notification-channels/google-chat/tree/3.2.0" + "source": "https://github.com/laravel-notification-channels/google-chat/tree/3.3.0" }, - "time": "2024-03-19T06:42:00+00:00" + "time": "2025-08-11T01:53:01+00:00" }, { "name": "laravel-notification-channels/microsoft-teams", @@ -2808,20 +2662,20 @@ }, { "name": "laravel/framework", - "version": "v11.45.1", + "version": "v11.46.0", "source": { "type": "git", "url": "https://github.com/laravel/framework.git", - "reference": "b09ba32795b8e71df10856a2694706663984a239" + "reference": "2c6d85f22d08123ad45aa3a6726b16f06e68eecd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/framework/zipball/b09ba32795b8e71df10856a2694706663984a239", - "reference": "b09ba32795b8e71df10856a2694706663984a239", + "url": "https://api.github.com/repos/laravel/framework/zipball/2c6d85f22d08123ad45aa3a6726b16f06e68eecd", + "reference": "2c6d85f22d08123ad45aa3a6726b16f06e68eecd", "shasum": "" }, "require": { - "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12", + "brick/math": "^0.9.3|^0.10.2|^0.11|^0.12|^0.13|^0.14", "composer-runtime-api": "^2.2", "doctrine/inflector": "^2.0.5", "dragonmantank/cron-expression": "^3.4", @@ -2925,7 +2779,7 @@ "league/flysystem-read-only": "^3.25.1", "league/flysystem-sftp-v3": "^3.25.1", "mockery/mockery": "^1.6.10", - "orchestra/testbench-core": "^9.13.2", + "orchestra/testbench-core": "^9.16.1", "pda/pheanstalk": "^5.0.6", "php-http/discovery": "^1.15", "phpstan/phpstan": "^2.0", @@ -3019,20 +2873,20 @@ "issues": "https://github.com/laravel/framework/issues", "source": "https://github.com/laravel/framework" }, - "time": "2025-06-03T14:01:40+00:00" + "time": "2025-09-08T21:54:34+00:00" }, { "name": "laravel/helpers", - "version": "v1.7.2", + "version": "v1.8.1", "source": { "type": "git", "url": "https://github.com/laravel/helpers.git", - "reference": "672d79d5b5f65dc821e57783fa11f22c4d762d70" + "reference": "d0094b4bc4364560c8ee3a9e956596d760d4afab" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/laravel/helpers/zipball/672d79d5b5f65dc821e57783fa11f22c4d762d70", - "reference": "672d79d5b5f65dc821e57783fa11f22c4d762d70", + "url": "https://api.github.com/repos/laravel/helpers/zipball/d0094b4bc4364560c8ee3a9e956596d760d4afab", + "reference": "d0094b4bc4364560c8ee3a9e956596d760d4afab", "shasum": "" }, "require": { @@ -3074,9 +2928,9 @@ "laravel" ], "support": { - "source": "https://github.com/laravel/helpers/tree/v1.7.2" + "source": "https://github.com/laravel/helpers/tree/v1.8.1" }, - "time": "2025-01-24T15:41:25+00:00" + "time": "2025-09-02T15:31:25+00:00" }, { "name": "laravel/passport", @@ -3877,16 +3731,16 @@ }, { "name": "league/csv", - "version": "9.24.1", + "version": "9.25.0", "source": { "type": "git", "url": "https://github.com/thephpleague/csv.git", - "reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8" + "reference": "f856f532866369fb1debe4e7c5a1db185f40ef86" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/thephpleague/csv/zipball/e0221a3f16aa2a823047d59fab5809d552e29bc8", - "reference": "e0221a3f16aa2a823047d59fab5809d552e29bc8", + "url": "https://api.github.com/repos/thephpleague/csv/zipball/f856f532866369fb1debe4e7c5a1db185f40ef86", + "reference": "f856f532866369fb1debe4e7c5a1db185f40ef86", "shasum": "" }, "require": { @@ -3902,7 +3756,7 @@ "phpstan/phpstan-deprecation-rules": "^1.2.1", "phpstan/phpstan-phpunit": "^1.4.2", "phpstan/phpstan-strict-rules": "^1.6.2", - "phpunit/phpunit": "^10.5.16 || ^11.5.22", + "phpunit/phpunit": "^10.5.16 || ^11.5.22 || ^12.3.6", "symfony/var-dumper": "^6.4.8 || ^7.3.0" }, "suggest": { @@ -3964,7 +3818,7 @@ "type": "github" } ], - "time": "2025-06-25T14:53:51+00:00" + "time": "2025-09-11T08:29:08+00:00" }, { "name": "league/event", @@ -4956,16 +4810,16 @@ }, { "name": "nesbot/carbon", - "version": "3.10.1", + "version": "3.10.3", "source": { "type": "git", "url": "https://github.com/CarbonPHP/carbon.git", - "reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00" + "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/1fd1935b2d90aef2f093c5e35f7ae1257c448d00", - "reference": "1fd1935b2d90aef2f093c5e35f7ae1257c448d00", + "url": "https://api.github.com/repos/CarbonPHP/carbon/zipball/8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", + "reference": "8e3643dcd149ae0fe1d2ff4f2c8e4bbfad7c165f", "shasum": "" }, "require": { @@ -4983,13 +4837,13 @@ "require-dev": { "doctrine/dbal": "^3.6.3 || ^4.0", "doctrine/orm": "^2.15.2 || ^3.0", - "friendsofphp/php-cs-fixer": "^3.75.0", + "friendsofphp/php-cs-fixer": "^v3.87.1", "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" + "phpstan/phpstan": "^2.1.22", + "phpunit/phpunit": "^10.5.53", + "squizlabs/php_codesniffer": "^3.13.4" }, "bin": [ "bin/carbon" @@ -5057,7 +4911,7 @@ "type": "tidelift" } ], - "time": "2025-06-21T15:19:35+00:00" + "time": "2025-09-06T13:39:36+00:00" }, { "name": "nette/schema", @@ -5123,29 +4977,29 @@ }, { "name": "nette/utils", - "version": "v4.0.7", + "version": "v4.0.8", "source": { "type": "git", "url": "https://github.com/nette/utils.git", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2" + "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nette/utils/zipball/e67c4061eb40b9c113b218214e42cb5a0dda28f2", - "reference": "e67c4061eb40b9c113b218214e42cb5a0dda28f2", + "url": "https://api.github.com/repos/nette/utils/zipball/c930ca4e3cf4f17dcfb03037703679d2396d2ede", + "reference": "c930ca4e3cf4f17dcfb03037703679d2396d2ede", "shasum": "" }, "require": { - "php": "8.0 - 8.4" + "php": "8.0 - 8.5" }, "conflict": { "nette/finder": "<3", "nette/schema": "<1.2.2" }, "require-dev": { - "jetbrains/phpstorm-attributes": "dev-master", + "jetbrains/phpstorm-attributes": "^1.2", "nette/tester": "^2.5", - "phpstan/phpstan": "^1.0", + "phpstan/phpstan-nette": "^2.0@stable", "tracy/tracy": "^2.9" }, "suggest": { @@ -5163,6 +5017,9 @@ } }, "autoload": { + "psr-4": { + "Nette\\": "src" + }, "classmap": [ "src/" ] @@ -5203,22 +5060,22 @@ ], "support": { "issues": "https://github.com/nette/utils/issues", - "source": "https://github.com/nette/utils/tree/v4.0.7" + "source": "https://github.com/nette/utils/tree/v4.0.8" }, - "time": "2025-06-03T04:55:08+00:00" + "time": "2025-08-06T21:43:34+00:00" }, { "name": "nikic/php-parser", - "version": "v5.6.0", + "version": "v5.6.1", "source": { "type": "git", "url": "https://github.com/nikic/PHP-Parser.git", - "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56" + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/221b0d0fdf1369c71047ad1d18bb5880017bbc56", - "reference": "221b0d0fdf1369c71047ad1d18bb5880017bbc56", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", + "reference": "f103601b29efebd7ff4a1ca7b3eeea9e3336a2a2", "shasum": "" }, "require": { @@ -5237,7 +5094,7 @@ "type": "library", "extra": { "branch-alias": { - "dev-master": "5.0-dev" + "dev-master": "5.x-dev" } }, "autoload": { @@ -5261,9 +5118,9 @@ ], "support": { "issues": "https://github.com/nikic/PHP-Parser/issues", - "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.0" + "source": "https://github.com/nikic/PHP-Parser/tree/v5.6.1" }, - "time": "2025-07-27T20:03:57+00:00" + "time": "2025-08-13T20:13:15+00:00" }, { "name": "nunomaduro/collision", @@ -5982,96 +5839,6 @@ }, "time": "2024-04-22T22:05:04+00:00" }, - { - "name": "phenx/php-font-lib", - "version": "0.5.6", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-font-lib.git", - "reference": "a1681e9793040740a405ac5b189275059e2a9863" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-font-lib/zipball/a1681e9793040740a405ac5b189275059e2a9863", - "reference": "a1681e9793040740a405ac5b189275059e2a9863", - "shasum": "" - }, - "require": { - "ext-mbstring": "*" - }, - "require-dev": { - "symfony/phpunit-bridge": "^3 || ^4 || ^5 || ^6" - }, - "type": "library", - "autoload": { - "psr-4": { - "FontLib\\": "src/FontLib" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-2.1-or-later" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse, export and make subsets of different types of font files.", - "homepage": "https://github.com/PhenX/php-font-lib", - "support": { - "issues": "https://github.com/dompdf/php-font-lib/issues", - "source": "https://github.com/dompdf/php-font-lib/tree/0.5.6" - }, - "time": "2024-01-29T14:45:26+00:00" - }, - { - "name": "phenx/php-svg-lib", - "version": "0.5.4", - "source": { - "type": "git", - "url": "https://github.com/dompdf/php-svg-lib.git", - "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/dompdf/php-svg-lib/zipball/46b25da81613a9cf43c83b2a8c2c1bdab27df691", - "reference": "46b25da81613a9cf43c83b2a8c2c1bdab27df691", - "shasum": "" - }, - "require": { - "ext-mbstring": "*", - "php": "^7.1 || ^8.0", - "sabberworm/php-css-parser": "^8.4" - }, - "require-dev": { - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.5" - }, - "type": "library", - "autoload": { - "psr-4": { - "Svg\\": "src/Svg" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "LGPL-3.0-or-later" - ], - "authors": [ - { - "name": "Fabien Ménager", - "email": "fabien.menager@gmail.com" - } - ], - "description": "A library to read, parse and export to PDF SVG files.", - "homepage": "https://github.com/PhenX/php-svg-lib", - "support": { - "issues": "https://github.com/dompdf/php-svg-lib/issues", - "source": "https://github.com/dompdf/php-svg-lib/tree/0.5.4" - }, - "time": "2024-04-08T12:52:34+00:00" - }, { "name": "php-debugbar/php-debugbar", "version": "v2.2.4", @@ -6200,16 +5967,16 @@ }, { "name": "phpdocumentor/reflection-docblock", - "version": "5.6.2", + "version": "5.6.3", "source": { "type": "git", "url": "https://github.com/phpDocumentor/ReflectionDocBlock.git", - "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62" + "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/92dde6a5919e34835c506ac8c523ef095a95ed62", - "reference": "92dde6a5919e34835c506ac8c523ef095a95ed62", + "url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/94f8051919d1b0369a6bcc7931d679a511c03fe9", + "reference": "94f8051919d1b0369a6bcc7931d679a511c03fe9", "shasum": "" }, "require": { @@ -6258,9 +6025,9 @@ "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "support": { "issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues", - "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.2" + "source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/5.6.3" }, - "time": "2025-04-13T19:20:35+00:00" + "time": "2025-08-01T19:43:32+00:00" }, { "name": "phpdocumentor/type-resolver", @@ -6322,16 +6089,16 @@ }, { "name": "phpoption/phpoption", - "version": "1.9.3", + "version": "1.9.4", "source": { "type": "git", "url": "https://github.com/schmittjoh/php-option.git", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54" + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/e3fac8b24f56113f7cb96af14958c0dd16330f54", - "reference": "e3fac8b24f56113f7cb96af14958c0dd16330f54", + "url": "https://api.github.com/repos/schmittjoh/php-option/zipball/638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", + "reference": "638a154f8d4ee6a5cfa96d6a34dfbe0cffa9566d", "shasum": "" }, "require": { @@ -6339,7 +6106,7 @@ }, "require-dev": { "bamarni/composer-bin-plugin": "^1.8.2", - "phpunit/phpunit": "^8.5.39 || ^9.6.20 || ^10.5.28" + "phpunit/phpunit": "^8.5.44 || ^9.6.25 || ^10.5.53 || ^11.5.34" }, "type": "library", "extra": { @@ -6381,7 +6148,7 @@ ], "support": { "issues": "https://github.com/schmittjoh/php-option/issues", - "source": "https://github.com/schmittjoh/php-option/tree/1.9.3" + "source": "https://github.com/schmittjoh/php-option/tree/1.9.4" }, "funding": [ { @@ -6393,7 +6160,7 @@ "type": "tidelift" } ], - "time": "2024-07-20T21:41:07+00:00" + "time": "2025-08-21T11:53:16+00:00" }, { "name": "phpseclib/phpseclib", @@ -6577,16 +6344,16 @@ }, { "name": "phpstan/phpdoc-parser", - "version": "2.2.0", + "version": "2.3.0", "source": { "type": "git", "url": "https://github.com/phpstan/phpdoc-parser.git", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8" + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/b9e61a61e39e02dd90944e9115241c7f7e76bfd8", - "reference": "b9e61a61e39e02dd90944e9115241c7f7e76bfd8", + "url": "https://api.github.com/repos/phpstan/phpdoc-parser/zipball/1e0cd5370df5dd2e556a36b9c62f62e555870495", + "reference": "1e0cd5370df5dd2e556a36b9c62f62e555870495", "shasum": "" }, "require": { @@ -6618,9 +6385,9 @@ "description": "PHPDoc parser with support for nullable, intersection and generic types", "support": { "issues": "https://github.com/phpstan/phpdoc-parser/issues", - "source": "https://github.com/phpstan/phpdoc-parser/tree/2.2.0" + "source": "https://github.com/phpstan/phpdoc-parser/tree/2.3.0" }, - "time": "2025-07-13T07:04:09+00:00" + "time": "2025-08-30T15:50:23+00:00" }, { "name": "pragmarx/google2fa", @@ -7274,16 +7041,16 @@ }, { "name": "psy/psysh", - "version": "v0.12.9", + "version": "v0.12.10", "source": { "type": "git", "url": "https://github.com/bobthecow/psysh.git", - "reference": "1b801844becfe648985372cb4b12ad6840245ace" + "reference": "6e80abe6f2257121f1eb9a4c55bf29d921025b22" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/bobthecow/psysh/zipball/1b801844becfe648985372cb4b12ad6840245ace", - "reference": "1b801844becfe648985372cb4b12ad6840245ace", + "url": "https://api.github.com/repos/bobthecow/psysh/zipball/6e80abe6f2257121f1eb9a4c55bf29d921025b22", + "reference": "6e80abe6f2257121f1eb9a4c55bf29d921025b22", "shasum": "" }, "require": { @@ -7333,12 +7100,11 @@ "authors": [ { "name": "Justin Hileman", - "email": "justin@justinhileman.info", - "homepage": "http://justinhileman.com" + "email": "justin@justinhileman.info" } ], "description": "An interactive shell for modern PHP.", - "homepage": "http://psysh.org", + "homepage": "https://psysh.org", "keywords": [ "REPL", "console", @@ -7347,9 +7113,9 @@ ], "support": { "issues": "https://github.com/bobthecow/psysh/issues", - "source": "https://github.com/bobthecow/psysh/tree/v0.12.9" + "source": "https://github.com/bobthecow/psysh/tree/v0.12.10" }, - "time": "2025-06-23T02:35:06+00:00" + "time": "2025-08-04T12:39:37+00:00" }, { "name": "ralouphie/getallheaders", @@ -7473,20 +7239,20 @@ }, { "name": "ramsey/uuid", - "version": "4.9.0", + "version": "4.9.1", "source": { "type": "git", "url": "https://github.com/ramsey/uuid.git", - "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0" + "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/ramsey/uuid/zipball/4e0e23cc785f0724a0e838279a9eb03f28b092a0", - "reference": "4e0e23cc785f0724a0e838279a9eb03f28b092a0", + "url": "https://api.github.com/repos/ramsey/uuid/zipball/81f941f6f729b1e3ceea61d9d014f8b6c6800440", + "reference": "81f941f6f729b1e3ceea61d9d014f8b6c6800440", "shasum": "" }, "require": { - "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13", + "brick/math": "^0.8.8 || ^0.9 || ^0.10 || ^0.11 || ^0.12 || ^0.13 || ^0.14", "php": "^8.0", "ramsey/collection": "^1.2 || ^2.0" }, @@ -7545,9 +7311,9 @@ ], "support": { "issues": "https://github.com/ramsey/uuid/issues", - "source": "https://github.com/ramsey/uuid/tree/4.9.0" + "source": "https://github.com/ramsey/uuid/tree/4.9.1" }, - "time": "2025-06-25T14:20:11+00:00" + "time": "2025-09-04T20:59:21+00:00" }, { "name": "robrichards/xmlseclibs", @@ -7726,84 +7492,18 @@ }, "time": "2025-05-02T20:10:54+00:00" }, - { - "name": "sabberworm/php-css-parser", - "version": "v8.9.0", - "source": { - "type": "git", - "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git", - "reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d8e916507b88e389e26d4ab03c904a082aa66bb9", - "reference": "d8e916507b88e389e26d4ab03c904a082aa66bb9", - "shasum": "" - }, - "require": { - "ext-iconv": "*", - "php": "^5.6.20 || ^7.0.0 || ~8.0.0 || ~8.1.0 || ~8.2.0 || ~8.3.0 || ~8.4.0" - }, - "require-dev": { - "phpunit/phpunit": "5.7.27 || 6.5.14 || 7.5.20 || 8.5.41", - "rawr/cross-data-providers": "^2.0.0" - }, - "suggest": { - "ext-mbstring": "for parsing UTF-8 CSS" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-main": "9.0.x-dev" - } - }, - "autoload": { - "psr-4": { - "Sabberworm\\CSS\\": "src/" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Raphael Schweikert" - }, - { - "name": "Oliver Klee", - "email": "github@oliverklee.de" - }, - { - "name": "Jake Hotson", - "email": "jake.github@qzdesign.co.uk" - } - ], - "description": "Parser for CSS Files written in PHP", - "homepage": "https://www.sabberworm.com/blog/2010/6/10/php-css-parser", - "keywords": [ - "css", - "parser", - "stylesheet" - ], - "support": { - "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues", - "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.9.0" - }, - "time": "2025-07-11T13:20:48+00:00" - }, { "name": "sebastian/comparator", - "version": "5.0.3", + "version": "5.0.4", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/comparator.git", - "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e" + "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", - "reference": "a18251eb0b7a2dcd2f7aa3d6078b18545ef0558e", + "url": "https://api.github.com/repos/sebastianbergmann/comparator/zipball/e8e53097718d2b53cfb2aa859b06a41abf58c62e", + "reference": "e8e53097718d2b53cfb2aa859b06a41abf58c62e", "shasum": "" }, "require": { @@ -7859,15 +7559,27 @@ "support": { "issues": "https://github.com/sebastianbergmann/comparator/issues", "security": "https://github.com/sebastianbergmann/comparator/security/policy", - "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.3" + "source": "https://github.com/sebastianbergmann/comparator/tree/5.0.4" }, "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/comparator", + "type": "tidelift" } ], - "time": "2024-10-18T14:56:07+00:00" + "time": "2025-09-07T05:25:07+00:00" }, { "name": "sebastian/diff", @@ -8016,23 +7728,23 @@ }, { "name": "sebastian/recursion-context", - "version": "5.0.0", + "version": "5.0.1", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/recursion-context.git", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712" + "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/05909fb5bc7df4c52992396d0116aed689f93712", - "reference": "05909fb5bc7df4c52992396d0116aed689f93712", + "url": "https://api.github.com/repos/sebastianbergmann/recursion-context/zipball/47e34210757a2f37a97dcd207d032e1b01e64c7a", + "reference": "47e34210757a2f37a97dcd207d032e1b01e64c7a", "shasum": "" }, "require": { "php": ">=8.1" }, "require-dev": { - "phpunit/phpunit": "^10.0" + "phpunit/phpunit": "^10.5" }, "type": "library", "extra": { @@ -8067,28 +7779,41 @@ "homepage": "https://github.com/sebastianbergmann/recursion-context", "support": { "issues": "https://github.com/sebastianbergmann/recursion-context/issues", - "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.0" + "security": "https://github.com/sebastianbergmann/recursion-context/security/policy", + "source": "https://github.com/sebastianbergmann/recursion-context/tree/5.0.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/recursion-context", + "type": "tidelift" } ], - "time": "2023-02-03T07:05:40+00:00" + "time": "2025-08-10T07:50:56+00:00" }, { "name": "spatie/backtrace", - "version": "1.7.4", + "version": "1.8.1", "source": { "type": "git", "url": "https://github.com/spatie/backtrace.git", - "reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe" + "reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/spatie/backtrace/zipball/cd37a49fce7137359ac30ecc44ef3e16404cccbe", - "reference": "cd37a49fce7137359ac30ecc44ef3e16404cccbe", + "url": "https://api.github.com/repos/spatie/backtrace/zipball/8c0f16a59ae35ec8c62d85c3c17585158f430110", + "reference": "8c0f16a59ae35ec8c62d85c3c17585158f430110", "shasum": "" }, "require": { @@ -8126,7 +7851,8 @@ "spatie" ], "support": { - "source": "https://github.com/spatie/backtrace/tree/1.7.4" + "issues": "https://github.com/spatie/backtrace/issues", + "source": "https://github.com/spatie/backtrace/tree/1.8.1" }, "funding": [ { @@ -8138,7 +7864,7 @@ "type": "other" } ], - "time": "2025-05-08T15:41:09+00:00" + "time": "2025-08-26T08:22:30+00:00" }, { "name": "spatie/db-dumper", @@ -8892,16 +8618,16 @@ }, { "name": "symfony/console", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101" + "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/9e27aecde8f506ba0fd1d9989620c04a87697101", - "reference": "9e27aecde8f506ba0fd1d9989620c04a87697101", + "url": "https://api.github.com/repos/symfony/console/zipball/cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", + "reference": "cb0102a1c5ac3807cf3fdf8bea96007df7fdbea7", "shasum": "" }, "require": { @@ -8966,7 +8692,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v7.3.1" + "source": "https://github.com/symfony/console/tree/v7.3.3" }, "funding": [ { @@ -8977,12 +8703,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-08-25T06:35:40+00:00" }, { "name": "symfony/css-selector", @@ -9119,16 +8849,16 @@ }, { "name": "symfony/error-handler", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/error-handler.git", - "reference": "35b55b166f6752d6aaf21aa042fc5ed280fce235" + "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/error-handler/zipball/35b55b166f6752d6aaf21aa042fc5ed280fce235", - "reference": "35b55b166f6752d6aaf21aa042fc5ed280fce235", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/0b31a944fcd8759ae294da4d2808cbc53aebd0c3", + "reference": "0b31a944fcd8759ae294da4d2808cbc53aebd0c3", "shasum": "" }, "require": { @@ -9176,7 +8906,7 @@ "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.1" + "source": "https://github.com/symfony/error-handler/tree/v7.3.2" }, "funding": [ { @@ -9187,25 +8917,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-13T07:48:40+00:00" + "time": "2025-07-07T08:17:57+00:00" }, { "name": "symfony/event-dispatcher", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/event-dispatcher.git", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d" + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/497f73ac996a598c92409b44ac43b6690c4f666d", - "reference": "497f73ac996a598c92409b44ac43b6690c4f666d", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/b7dc69e71de420ac04bc9ab830cf3ffebba48191", + "reference": "b7dc69e71de420ac04bc9ab830cf3ffebba48191", "shasum": "" }, "require": { @@ -9256,7 +8990,7 @@ "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" + "source": "https://github.com/symfony/event-dispatcher/tree/v7.3.3" }, "funding": [ { @@ -9267,12 +9001,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-22T09:11:45+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "symfony/event-dispatcher-contracts", @@ -9352,16 +9090,16 @@ }, { "name": "symfony/finder", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/finder.git", - "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d" + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/finder/zipball/ec2344cf77a48253bbca6939aa3d2477773ea63d", - "reference": "ec2344cf77a48253bbca6939aa3d2477773ea63d", + "url": "https://api.github.com/repos/symfony/finder/zipball/2a6614966ba1074fa93dae0bc804227422df4dfe", + "reference": "2a6614966ba1074fa93dae0bc804227422df4dfe", "shasum": "" }, "require": { @@ -9396,7 +9134,7 @@ "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" + "source": "https://github.com/symfony/finder/tree/v7.3.2" }, "funding": [ { @@ -9407,25 +9145,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-12-30T19:00:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/http-foundation", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/http-foundation.git", - "reference": "23dd60256610c86a3414575b70c596e5deff6ed9" + "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-foundation/zipball/23dd60256610c86a3414575b70c596e5deff6ed9", - "reference": "23dd60256610c86a3414575b70c596e5deff6ed9", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/7475561ec27020196c49bb7c4f178d33d7d3dc00", + "reference": "7475561ec27020196c49bb7c4f178d33d7d3dc00", "shasum": "" }, "require": { @@ -9475,7 +9217,7 @@ "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.1" + "source": "https://github.com/symfony/http-foundation/tree/v7.3.3" }, "funding": [ { @@ -9486,25 +9228,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-23T15:07:14+00:00" + "time": "2025-08-20T08:04:18+00:00" }, { "name": "symfony/http-kernel", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/http-kernel.git", - "reference": "1644879a66e4aa29c36fe33dfa6c54b450ce1831" + "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-kernel/zipball/1644879a66e4aa29c36fe33dfa6c54b450ce1831", - "reference": "1644879a66e4aa29c36fe33dfa6c54b450ce1831", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/72c304de37e1a1cec6d5d12b81187ebd4850a17b", + "reference": "72c304de37e1a1cec6d5d12b81187ebd4850a17b", "shasum": "" }, "require": { @@ -9589,7 +9335,7 @@ "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.1" + "source": "https://github.com/symfony/http-kernel/tree/v7.3.3" }, "funding": [ { @@ -9600,25 +9346,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-28T08:24:55+00:00" + "time": "2025-08-29T08:23:45+00:00" }, { "name": "symfony/mailer", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/mailer.git", - "reference": "b5db5105b290bdbea5ab27b89c69effcf1cb3368" + "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mailer/zipball/b5db5105b290bdbea5ab27b89c69effcf1cb3368", - "reference": "b5db5105b290bdbea5ab27b89c69effcf1cb3368", + "url": "https://api.github.com/repos/symfony/mailer/zipball/a32f3f45f1990db8c4341d5122a7d3a381c7e575", + "reference": "a32f3f45f1990db8c4341d5122a7d3a381c7e575", "shasum": "" }, "require": { @@ -9669,7 +9419,7 @@ "description": "Helps sending emails", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/mailer/tree/v7.3.1" + "source": "https://github.com/symfony/mailer/tree/v7.3.3" }, "funding": [ { @@ -9680,25 +9430,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "symfony/mime", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/mime.git", - "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9" + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/mime/zipball/0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", - "reference": "0e7b19b2f399c31df0cdbe5d8cbf53f02f6cfcd9", + "url": "https://api.github.com/repos/symfony/mime/zipball/e0a0f859148daf1edf6c60b398eb40bfc96697d1", + "reference": "e0a0f859148daf1edf6c60b398eb40bfc96697d1", "shasum": "" }, "require": { @@ -9753,7 +9507,7 @@ "mime-type" ], "support": { - "source": "https://github.com/symfony/mime/tree/v7.3.0" + "source": "https://github.com/symfony/mime/tree/v7.3.2" }, "funding": [ { @@ -9764,16 +9518,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-02-19T08:51:26+00:00" + "time": "2025-07-15T13:41:35+00:00" }, { "name": "symfony/polyfill-ctype", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-ctype.git", @@ -9832,7 +9590,7 @@ "portable" ], "support": { - "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.33.0" }, "funding": [ { @@ -9843,6 +9601,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -9852,16 +9614,16 @@ }, { "name": "symfony/polyfill-intl-grapheme", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-grapheme.git", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", - "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/380872130d3a5dd3ace2f4010d95125fde5d5c70", + "reference": "380872130d3a5dd3ace2f4010d95125fde5d5c70", "shasum": "" }, "require": { @@ -9910,7 +9672,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.33.0" }, "funding": [ { @@ -9921,16 +9683,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-06-27T09:58:17+00:00" }, { "name": "symfony/polyfill-intl-idn", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-idn.git", @@ -9993,7 +9759,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-idn/tree/v1.33.0" }, "funding": [ { @@ -10004,6 +9770,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -10013,7 +9783,7 @@ }, { "name": "symfony/polyfill-intl-normalizer", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-intl-normalizer.git", @@ -10074,7 +9844,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.33.0" }, "funding": [ { @@ -10085,6 +9855,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -10094,7 +9868,7 @@ }, { "name": "symfony/polyfill-mbstring", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-mbstring.git", @@ -10155,7 +9929,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.33.0" }, "funding": [ { @@ -10166,6 +9940,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -10175,7 +9953,7 @@ }, { "name": "symfony/polyfill-php80", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php80.git", @@ -10235,7 +10013,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php80/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php80/tree/v1.33.0" }, "funding": [ { @@ -10246,6 +10024,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -10255,16 +10037,16 @@ }, { "name": "symfony/polyfill-php83", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php83.git", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", - "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/17f6f9a6b1735c0f163024d959f700cfbc5155e5", + "reference": "17f6f9a6b1735c0f163024d959f700cfbc5155e5", "shasum": "" }, "require": { @@ -10311,7 +10093,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php83/tree/v1.33.0" }, "funding": [ { @@ -10322,16 +10104,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-09-09T11:45:10+00:00" + "time": "2025-07-08T02:45:35+00:00" }, { "name": "symfony/polyfill-uuid", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-uuid.git", @@ -10390,7 +10176,7 @@ "uuid" ], "support": { - "source": "https://github.com/symfony/polyfill-uuid/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-uuid/tree/v1.33.0" }, "funding": [ { @@ -10401,6 +10187,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -10410,16 +10200,16 @@ }, { "name": "symfony/process", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/process.git", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af" + "reference": "32241012d521e2e8a9d713adb0812bb773b907f1" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/process/zipball/40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", - "reference": "40c295f2deb408d5e9d2d32b8ba1dd61e36f05af", + "url": "https://api.github.com/repos/symfony/process/zipball/32241012d521e2e8a9d713adb0812bb773b907f1", + "reference": "32241012d521e2e8a9d713adb0812bb773b907f1", "shasum": "" }, "require": { @@ -10451,7 +10241,7 @@ "description": "Executes commands in sub-processes", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/process/tree/v7.3.0" + "source": "https://github.com/symfony/process/tree/v7.3.3" }, "funding": [ { @@ -10462,12 +10252,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-17T09:11:12+00:00" + "time": "2025-08-18T09:42:54+00:00" }, { "name": "symfony/psr-http-message-bridge", @@ -10554,16 +10348,16 @@ }, { "name": "symfony/routing", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/routing.git", - "reference": "8e213820c5fea844ecea29203d2a308019007c15" + "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/routing/zipball/8e213820c5fea844ecea29203d2a308019007c15", - "reference": "8e213820c5fea844ecea29203d2a308019007c15", + "url": "https://api.github.com/repos/symfony/routing/zipball/7614b8ca5fa89b9cd233e21b627bfc5774f586e4", + "reference": "7614b8ca5fa89b9cd233e21b627bfc5774f586e4", "shasum": "" }, "require": { @@ -10615,7 +10409,7 @@ "url" ], "support": { - "source": "https://github.com/symfony/routing/tree/v7.3.0" + "source": "https://github.com/symfony/routing/tree/v7.3.2" }, "funding": [ { @@ -10626,12 +10420,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-24T20:43:28+00:00" + "time": "2025-07-15T11:36:08+00:00" }, { "name": "symfony/service-contracts", @@ -10718,16 +10516,16 @@ }, { "name": "symfony/string", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125" + "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/f3570b8c61ca887a9e2938e85cb6458515d2b125", - "reference": "f3570b8c61ca887a9e2938e85cb6458515d2b125", + "url": "https://api.github.com/repos/symfony/string/zipball/17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", + "reference": "17a426cce5fd1f0901fefa9b2a490d0038fd3c9c", "shasum": "" }, "require": { @@ -10785,7 +10583,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v7.3.0" + "source": "https://github.com/symfony/string/tree/v7.3.3" }, "funding": [ { @@ -10796,25 +10594,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-20T20:19:01+00:00" + "time": "2025-08-25T06:35:40+00:00" }, { "name": "symfony/translation", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "241d5ac4910d256660238a7ecf250deba4c73063" + "reference": "e0837b4cbcef63c754d89a4806575cada743a38d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/241d5ac4910d256660238a7ecf250deba4c73063", - "reference": "241d5ac4910d256660238a7ecf250deba4c73063", + "url": "https://api.github.com/repos/symfony/translation/zipball/e0837b4cbcef63c754d89a4806575cada743a38d", + "reference": "e0837b4cbcef63c754d89a4806575cada743a38d", "shasum": "" }, "require": { @@ -10881,7 +10683,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v7.3.1" + "source": "https://github.com/symfony/translation/tree/v7.3.3" }, "funding": [ { @@ -10892,12 +10694,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-08-01T21:02:37+00:00" }, { "name": "symfony/translation-contracts", @@ -11053,16 +10859,16 @@ }, { "name": "symfony/var-dumper", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/var-dumper.git", - "reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42" + "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-dumper/zipball/6e209fbe5f5a7b6043baba46fe5735a4b85d0d42", - "reference": "6e209fbe5f5a7b6043baba46fe5735a4b85d0d42", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", + "reference": "34d8d4c4b9597347306d1ec8eb4e1319b1e6986f", "shasum": "" }, "require": { @@ -11074,7 +10880,6 @@ "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", @@ -11117,7 +10922,7 @@ "dump" ], "support": { - "source": "https://github.com/symfony/var-dumper/tree/v7.3.1" + "source": "https://github.com/symfony/var-dumper/tree/v7.3.3" }, "funding": [ { @@ -11128,12 +10933,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-08-13T11:49:31+00:00" }, { "name": "tabuna/breadcrumbs", @@ -11372,6 +11181,271 @@ ], "time": "2023-10-23T09:28:20+00:00" }, + { + "name": "tecnickcom/tc-lib-file", + "version": "2.2.2", + "source": { + "type": "git", + "url": "https://github.com/tecnickcom/tc-lib-file.git", + "reference": "ec6989700b77baa8a8d88952ad4fd8f53211c370" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tecnickcom/tc-lib-file/zipball/ec6989700b77baa8a8d88952ad4fd8f53211c370", + "reference": "ec6989700b77baa8a8d88952ad4fd8f53211c370", + "shasum": "" + }, + "require": { + "ext-curl": "*", + "ext-pcre": "*", + "php": ">=8.1" + }, + "require-dev": { + "pdepend/pdepend": "2.16.2", + "phpmd/phpmd": "2.15.0", + "phpunit/phpunit": "12.2.0 || 11.5.7 || 10.5.40", + "squizlabs/php_codesniffer": "3.13.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Com\\Tecnick\\File\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "role": "lead" + } + ], + "description": "PHP library to read byte-level data from files", + "homepage": "http://www.tecnick.com", + "keywords": [ + "Double", + "bit", + "byte", + "file", + "long", + "read", + "short", + "tc-lib-file" + ], + "support": { + "issues": "https://github.com/tecnickcom/tc-lib-file/issues", + "source": "https://github.com/tecnickcom/tc-lib-file/tree/2.2.2" + }, + "funding": [ + { + "url": "https://www.paypal.com/donate/?hosted_button_id=NZUEC5XS8MFBJ", + "type": "custom" + } + ], + "time": "2025-06-06T11:33:32+00:00" + }, + { + "name": "tecnickcom/tc-lib-pdf-encrypt", + "version": "2.1.16", + "source": { + "type": "git", + "url": "https://github.com/tecnickcom/tc-lib-pdf-encrypt.git", + "reference": "4e154df154e586523033187dfc54a2a8e113a7db" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tecnickcom/tc-lib-pdf-encrypt/zipball/4e154df154e586523033187dfc54a2a8e113a7db", + "reference": "4e154df154e586523033187dfc54a2a8e113a7db", + "shasum": "" + }, + "require": { + "ext-date": "*", + "ext-hash": "*", + "ext-openssl": "*", + "ext-pcre": "*", + "php": ">=8.1" + }, + "require-dev": { + "pdepend/pdepend": "2.16.2", + "phpmd/phpmd": "2.15.0", + "phpunit/phpunit": "12.2.0 || 11.5.7 || 10.5.40", + "squizlabs/php_codesniffer": "3.13.0" + }, + "suggest": { + "ext-posix": "*" + }, + "type": "library", + "autoload": { + "psr-4": { + "Com\\Tecnick\\Pdf\\Encrypt\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "role": "lead" + } + ], + "description": "PHP library to encrypt data for PDF", + "homepage": "http://www.tecnick.com", + "keywords": [ + "aes", + "encrypt", + "encryption", + "pdf", + "rc4", + "tc-lib-pdf-encrypt" + ], + "support": { + "issues": "https://github.com/tecnickcom/tc-lib-pdf-encrypt/issues", + "source": "https://github.com/tecnickcom/tc-lib-pdf-encrypt/tree/2.1.16" + }, + "funding": [ + { + "url": "https://www.paypal.com/donate/?hosted_button_id=NZUEC5XS8MFBJ", + "type": "custom" + } + ], + "time": "2025-06-06T11:33:45+00:00" + }, + { + "name": "tecnickcom/tc-lib-pdf-font", + "version": "2.6.12", + "source": { + "type": "git", + "url": "https://github.com/tecnickcom/tc-lib-pdf-font.git", + "reference": "961ddeb8f02c7186e9efcf37693cbd1f21af1dc1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tecnickcom/tc-lib-pdf-font/zipball/961ddeb8f02c7186e9efcf37693cbd1f21af1dc1", + "reference": "961ddeb8f02c7186e9efcf37693cbd1f21af1dc1", + "shasum": "" + }, + "require": { + "ext-json": "*", + "ext-pcre": "*", + "ext-zlib": "*", + "php": ">=8.1", + "tecnickcom/tc-lib-file": "^2.2", + "tecnickcom/tc-lib-pdf-encrypt": "^2.1", + "tecnickcom/tc-lib-unicode-data": "^2.0" + }, + "require-dev": { + "pdepend/pdepend": "2.16.2", + "phpmd/phpmd": "2.15.0", + "phpunit/phpunit": "12.2.0 || 11.5.7 || 10.5.40", + "squizlabs/php_codesniffer": "3.13.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Com\\Tecnick\\Pdf\\Font\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "role": "lead" + } + ], + "description": "PHP library containing PDF page formats and definitions", + "homepage": "http://www.tecnick.com", + "keywords": [ + "PFB", + "afm", + "font", + "import", + "pdf", + "tc-lib-pdf-font", + "ttf" + ], + "support": { + "issues": "https://github.com/tecnickcom/tc-lib-pdf-font/issues", + "source": "https://github.com/tecnickcom/tc-lib-pdf-font/tree/2.6.12" + }, + "funding": [ + { + "url": "https://www.paypal.com/donate/?hosted_button_id=NZUEC5XS8MFBJ", + "type": "custom" + } + ], + "time": "2025-06-06T12:19:35+00:00" + }, + { + "name": "tecnickcom/tc-lib-unicode-data", + "version": "2.0.24", + "source": { + "type": "git", + "url": "https://github.com/tecnickcom/tc-lib-unicode-data.git", + "reference": "cc0ac553b70ecfda9ffeda71ca2f490bfaff5036" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/tecnickcom/tc-lib-unicode-data/zipball/cc0ac553b70ecfda9ffeda71ca2f490bfaff5036", + "reference": "cc0ac553b70ecfda9ffeda71ca2f490bfaff5036", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "require-dev": { + "pdepend/pdepend": "2.16.2", + "phpmd/phpmd": "2.15.0", + "phpunit/phpunit": "12.2.0 || 11.5.7 || 10.5.40", + "squizlabs/php_codesniffer": "3.13.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Com\\Tecnick\\Unicode\\Data\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "LGPL-3.0-or-later" + ], + "authors": [ + { + "name": "Nicola Asuni", + "email": "info@tecnick.com", + "role": "lead" + } + ], + "description": "PHP library containing Unicode definitions", + "homepage": "http://www.tecnick.com", + "keywords": [ + "font", + "pdf", + "tc-lib-unicode-data", + "unicode", + "utf-8" + ], + "support": { + "issues": "https://github.com/tecnickcom/tc-lib-unicode-data/issues", + "source": "https://github.com/tecnickcom/tc-lib-unicode-data/tree/2.0.24" + }, + "funding": [ + { + "url": "https://www.paypal.com/donate/?hosted_button_id=NZUEC5XS8MFBJ", + "type": "custom" + } + ], + "time": "2025-06-06T11:34:15+00:00" + }, { "name": "tecnickcom/tcpdf", "version": "6.10.0", @@ -12235,16 +12309,16 @@ }, { "name": "composer/semver", - "version": "3.4.3", + "version": "3.4.4", "source": { "type": "git", "url": "https://github.com/composer/semver.git", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", - "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "url": "https://api.github.com/repos/composer/semver/zipball/198166618906cb2de69b95d7d47e5fa8aa1b2b95", + "reference": "198166618906cb2de69b95d7d47e5fa8aa1b2b95", "shasum": "" }, "require": { @@ -12296,7 +12370,7 @@ "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" + "source": "https://github.com/composer/semver/tree/3.4.4" }, "funding": [ { @@ -12306,13 +12380,9 @@ { "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" + "time": "2025-08-20T19:15:30+00:00" }, { "name": "composer/xdebug-handler", @@ -12525,16 +12595,16 @@ }, { "name": "fidry/cpu-core-counter", - "version": "1.2.0", + "version": "1.3.0", "source": { "type": "git", "url": "https://github.com/theofidry/cpu-core-counter.git", - "reference": "8520451a140d3f46ac33042715115e290cf5785f" + "reference": "db9508f7b1474469d9d3c53b86f817e344732678" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/8520451a140d3f46ac33042715115e290cf5785f", - "reference": "8520451a140d3f46ac33042715115e290cf5785f", + "url": "https://api.github.com/repos/theofidry/cpu-core-counter/zipball/db9508f7b1474469d9d3c53b86f817e344732678", + "reference": "db9508f7b1474469d9d3c53b86f817e344732678", "shasum": "" }, "require": { @@ -12544,10 +12614,10 @@ "fidry/makefile": "^0.2.0", "fidry/php-cs-fixer-config": "^1.1.2", "phpstan/extension-installer": "^1.2.0", - "phpstan/phpstan": "^1.9.2", - "phpstan/phpstan-deprecation-rules": "^1.0.0", - "phpstan/phpstan-phpunit": "^1.2.2", - "phpstan/phpstan-strict-rules": "^1.4.4", + "phpstan/phpstan": "^2.0", + "phpstan/phpstan-deprecation-rules": "^2.0.0", + "phpstan/phpstan-phpunit": "^2.0", + "phpstan/phpstan-strict-rules": "^2.0", "phpunit/phpunit": "^8.5.31 || ^9.5.26", "webmozarts/strict-phpunit": "^7.5" }, @@ -12574,7 +12644,7 @@ ], "support": { "issues": "https://github.com/theofidry/cpu-core-counter/issues", - "source": "https://github.com/theofidry/cpu-core-counter/tree/1.2.0" + "source": "https://github.com/theofidry/cpu-core-counter/tree/1.3.0" }, "funding": [ { @@ -12582,63 +12652,62 @@ "type": "github" } ], - "time": "2024-08-06T10:04:20+00:00" + "time": "2025-08-14T07:29:31+00:00" }, { "name": "friendsofphp/php-cs-fixer", - "version": "v3.84.0", + "version": "v3.87.2", "source": { "type": "git", "url": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer.git", - "reference": "38dad0767bf2a9b516b976852200ae722fe984ca" + "reference": "da5f0a7858c79b56fc0b8c36d3efcfe5f37f0992" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/38dad0767bf2a9b516b976852200ae722fe984ca", - "reference": "38dad0767bf2a9b516b976852200ae722fe984ca", + "url": "https://api.github.com/repos/PHP-CS-Fixer/PHP-CS-Fixer/zipball/da5f0a7858c79b56fc0b8c36d3efcfe5f37f0992", + "reference": "da5f0a7858c79b56fc0b8c36d3efcfe5f37f0992", "shasum": "" }, "require": { - "clue/ndjson-react": "^1.0", + "clue/ndjson-react": "^1.3", "composer/semver": "^3.4", "composer/xdebug-handler": "^3.0.5", "ext-filter": "*", "ext-hash": "*", "ext-json": "*", "ext-tokenizer": "*", - "fidry/cpu-core-counter": "^1.2", + "fidry/cpu-core-counter": "^1.3", "php": "^7.4 || ^8.0", "react/child-process": "^0.6.6", - "react/event-loop": "^1.0", - "react/promise": "^2.11 || ^3.0", - "react/socket": "^1.0", - "react/stream": "^1.0", + "react/event-loop": "^1.5", + "react/promise": "^3.3", + "react/socket": "^1.16", + "react/stream": "^1.4", "sebastian/diff": "^4.0.6 || ^5.1.1 || ^6.0.2 || ^7.0", - "symfony/console": "^5.4.45 || ^6.4.13 || ^7.0", - "symfony/event-dispatcher": "^5.4.45 || ^6.4.13 || ^7.0", - "symfony/filesystem": "^5.4.45 || ^6.4.13 || ^7.0", - "symfony/finder": "^5.4.45 || ^6.4.17 || ^7.0", - "symfony/options-resolver": "^5.4.45 || ^6.4.16 || ^7.0", - "symfony/polyfill-mbstring": "^1.32", - "symfony/polyfill-php80": "^1.32", - "symfony/polyfill-php81": "^1.32", - "symfony/process": "^5.4.47 || ^6.4.20 || ^7.2", - "symfony/stopwatch": "^5.4.45 || ^6.4.19 || ^7.0" + "symfony/console": "^5.4.47 || ^6.4.24 || ^7.0", + "symfony/event-dispatcher": "^5.4.45 || ^6.4.24 || ^7.0", + "symfony/filesystem": "^5.4.45 || ^6.4.24 || ^7.0", + "symfony/finder": "^5.4.45 || ^6.4.24 || ^7.0", + "symfony/options-resolver": "^5.4.45 || ^6.4.24 || ^7.0", + "symfony/polyfill-mbstring": "^1.33", + "symfony/polyfill-php80": "^1.33", + "symfony/polyfill-php81": "^1.33", + "symfony/process": "^5.4.47 || ^6.4.24 || ^7.2", + "symfony/stopwatch": "^5.4.45 || ^6.4.24 || ^7.0" }, "require-dev": { - "facile-it/paraunit": "^1.3.1 || ^2.6", + "facile-it/paraunit": "^1.3.1 || ^2.7", "infection/infection": "^0.29.14", - "justinrainbow/json-schema": "^5.3 || ^6.4", + "justinrainbow/json-schema": "^6.5", "keradus/cli-executor": "^2.2", "mikey179/vfsstream": "^1.6.12", "php-coveralls/php-coveralls": "^2.8", - "php-cs-fixer/accessible-object": "^1.1", "php-cs-fixer/phpunit-constraint-isidenticalstring": "^1.6", "php-cs-fixer/phpunit-constraint-xmlmatchesxsd": "^1.6", - "phpunit/phpunit": "^9.6.23 || ^10.5.47 || ^11.5.25", - "symfony/polyfill-php84": "^1.32", - "symfony/var-dumper": "^5.4.48 || ^6.4.23 || ^7.3.1", - "symfony/yaml": "^5.4.45 || ^6.4.23 || ^7.3.1" + "phpunit/phpunit": "^9.6.25 || ^10.5.53 || ^11.5.34", + "symfony/polyfill-php84": "^1.33", + "symfony/var-dumper": "^5.4.48 || ^6.4.24 || ^7.3.2", + "symfony/yaml": "^5.4.45 || ^6.4.24 || ^7.3.2" }, "suggest": { "ext-dom": "For handling output formats in XML", @@ -12679,7 +12748,7 @@ ], "support": { "issues": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues", - "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.84.0" + "source": "https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/tree/v3.87.2" }, "funding": [ { @@ -12687,7 +12756,7 @@ "type": "github" } ], - "time": "2025-07-15T18:21:57+00:00" + "time": "2025-09-10T09:51:40+00:00" }, { "name": "hamcrest/hamcrest-php", @@ -12783,16 +12852,16 @@ }, { "name": "justinrainbow/json-schema", - "version": "6.4.2", + "version": "6.5.2", "source": { "type": "git", "url": "https://github.com/jsonrainbow/json-schema.git", - "reference": "ce1fd2d47799bb60668643bc6220f6278a4c1d02" + "reference": "ac0d369c09653cf7af561f6d91a705bc617a87b8" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/ce1fd2d47799bb60668643bc6220f6278a4c1d02", - "reference": "ce1fd2d47799bb60668643bc6220f6278a4c1d02", + "url": "https://api.github.com/repos/jsonrainbow/json-schema/zipball/ac0d369c09653cf7af561f6d91a705bc617a87b8", + "reference": "ac0d369c09653cf7af561f6d91a705bc617a87b8", "shasum": "" }, "require": { @@ -12802,7 +12871,7 @@ }, "require-dev": { "friendsofphp/php-cs-fixer": "3.3.0", - "json-schema/json-schema-test-suite": "1.2.0", + "json-schema/json-schema-test-suite": "^23.2", "marc-mabe/php-enum-phpstan": "^2.0", "phpspec/prophecy": "^1.19", "phpstan/phpstan": "^1.12", @@ -12852,9 +12921,9 @@ ], "support": { "issues": "https://github.com/jsonrainbow/json-schema/issues", - "source": "https://github.com/jsonrainbow/json-schema/tree/6.4.2" + "source": "https://github.com/jsonrainbow/json-schema/tree/6.5.2" }, - "time": "2025-06-03T18:27:04+00:00" + "time": "2025-09-09T09:42:27+00:00" }, { "name": "larastan/larastan", @@ -12945,6 +13014,75 @@ ], "time": "2025-06-10T22:06:33+00:00" }, + { + "name": "laravel/telescope", + "version": "v5.11.3", + "source": { + "type": "git", + "url": "https://github.com/laravel/telescope.git", + "reference": "7684604e104e7755b70dcacfeee06888e2470689" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/laravel/telescope/zipball/7684604e104e7755b70dcacfeee06888e2470689", + "reference": "7684604e104e7755b70dcacfeee06888e2470689", + "shasum": "" + }, + "require": { + "ext-json": "*", + "laravel/framework": "^8.37|^9.0|^10.0|^11.0|^12.0", + "php": "^8.0", + "symfony/console": "^5.3|^6.0|^7.0", + "symfony/var-dumper": "^5.0|^6.0|^7.0" + }, + "require-dev": { + "ext-gd": "*", + "guzzlehttp/guzzle": "^6.0|^7.0", + "laravel/octane": "^1.4|^2.0|dev-develop", + "orchestra/testbench": "^6.40|^7.37|^8.17|^9.0|^10.0", + "phpstan/phpstan": "^1.10", + "phpunit/phpunit": "^9.0|^10.5|^11.5" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Laravel\\Telescope\\TelescopeServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Laravel\\Telescope\\": "src/", + "Laravel\\Telescope\\Database\\Factories\\": "database/factories/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Taylor Otwell", + "email": "taylor@laravel.com" + }, + { + "name": "Mohamed Said", + "email": "mohamed@laravel.com" + } + ], + "description": "An elegant debug assistant for the Laravel framework.", + "keywords": [ + "debugging", + "laravel", + "monitoring" + ], + "support": { + "issues": "https://github.com/laravel/telescope/issues", + "source": "https://github.com/laravel/telescope/tree/v5.11.3" + }, + "time": "2025-08-21T14:25:40+00:00" + }, { "name": "league/container", "version": "5.1.0", @@ -13030,16 +13168,16 @@ }, { "name": "marc-mabe/php-enum", - "version": "v4.7.1", + "version": "v4.7.2", "source": { "type": "git", "url": "https://github.com/marc-mabe/php-enum.git", - "reference": "7159809e5cfa041dca28e61f7f7ae58063aae8ed" + "reference": "bb426fcdd65c60fb3638ef741e8782508fda7eef" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/marc-mabe/php-enum/zipball/7159809e5cfa041dca28e61f7f7ae58063aae8ed", - "reference": "7159809e5cfa041dca28e61f7f7ae58063aae8ed", + "url": "https://api.github.com/repos/marc-mabe/php-enum/zipball/bb426fcdd65c60fb3638ef741e8782508fda7eef", + "reference": "bb426fcdd65c60fb3638ef741e8782508fda7eef", "shasum": "" }, "require": { @@ -13097,9 +13235,9 @@ ], "support": { "issues": "https://github.com/marc-mabe/php-enum/issues", - "source": "https://github.com/marc-mabe/php-enum/tree/v4.7.1" + "source": "https://github.com/marc-mabe/php-enum/tree/v4.7.2" }, - "time": "2024-11-28T04:54:44+00:00" + "time": "2025-09-14T11:18:39+00:00" }, { "name": "mockery/mockery", @@ -13186,16 +13324,16 @@ }, { "name": "myclabs/deep-copy", - "version": "1.13.3", + "version": "1.13.4", "source": { "type": "git", "url": "https://github.com/myclabs/DeepCopy.git", - "reference": "faed855a7b5f4d4637717c2b3863e277116beb36" + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/faed855a7b5f4d4637717c2b3863e277116beb36", - "reference": "faed855a7b5f4d4637717c2b3863e277116beb36", + "url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/07d290f0c47959fd5eed98c95ee5602db07e0b6a", + "reference": "07d290f0c47959fd5eed98c95ee5602db07e0b6a", "shasum": "" }, "require": { @@ -13234,7 +13372,7 @@ ], "support": { "issues": "https://github.com/myclabs/DeepCopy/issues", - "source": "https://github.com/myclabs/DeepCopy/tree/1.13.3" + "source": "https://github.com/myclabs/DeepCopy/tree/1.13.4" }, "funding": [ { @@ -13242,7 +13380,7 @@ "type": "tidelift" } ], - "time": "2025-07-05T12:25:42+00:00" + "time": "2025-08-01T08:46:24+00:00" }, { "name": "nunomaduro/phpinsights", @@ -13459,16 +13597,16 @@ }, { "name": "php-mock/php-mock", - "version": "2.6.1", + "version": "2.6.2", "source": { "type": "git", "url": "https://github.com/php-mock/php-mock.git", - "reference": "c7b6789056dfc3c45389cabbe9930dc33aeb2bf0" + "reference": "e134d210e4707c29724ebc7fe50d220123f0fdd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/php-mock/php-mock/zipball/c7b6789056dfc3c45389cabbe9930dc33aeb2bf0", - "reference": "c7b6789056dfc3c45389cabbe9930dc33aeb2bf0", + "url": "https://api.github.com/repos/php-mock/php-mock/zipball/e134d210e4707c29724ebc7fe50d220123f0fdd9", + "reference": "e134d210e4707c29724ebc7fe50d220123f0fdd9", "shasum": "" }, "require": { @@ -13523,7 +13661,7 @@ ], "support": { "issues": "https://github.com/php-mock/php-mock/issues", - "source": "https://github.com/php-mock/php-mock/tree/2.6.1" + "source": "https://github.com/php-mock/php-mock/tree/2.6.2" }, "funding": [ { @@ -13531,7 +13669,7 @@ "type": "github" } ], - "time": "2025-02-28T18:11:56+00:00" + "time": "2025-08-18T19:59:14+00:00" }, { "name": "php-mock/php-mock-integration", @@ -14106,16 +14244,16 @@ }, { "name": "phpunit/phpunit", - "version": "10.5.48", + "version": "10.5.55", "source": { "type": "git", "url": "https://github.com/sebastianbergmann/phpunit.git", - "reference": "6e0a2bc39f6fae7617989d690d76c48e6d2eb541" + "reference": "4b2d546b336876bd9562f24641b08a25335b06b6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/6e0a2bc39f6fae7617989d690d76c48e6d2eb541", - "reference": "6e0a2bc39f6fae7617989d690d76c48e6d2eb541", + "url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/4b2d546b336876bd9562f24641b08a25335b06b6", + "reference": "4b2d546b336876bd9562f24641b08a25335b06b6", "shasum": "" }, "require": { @@ -14125,7 +14263,7 @@ "ext-mbstring": "*", "ext-xml": "*", "ext-xmlwriter": "*", - "myclabs/deep-copy": "^1.13.3", + "myclabs/deep-copy": "^1.13.4", "phar-io/manifest": "^2.0.4", "phar-io/version": "^3.2.1", "php": ">=8.1", @@ -14136,13 +14274,13 @@ "phpunit/php-timer": "^6.0.0", "sebastian/cli-parser": "^2.0.1", "sebastian/code-unit": "^2.0.0", - "sebastian/comparator": "^5.0.3", + "sebastian/comparator": "^5.0.4", "sebastian/diff": "^5.1.1", "sebastian/environment": "^6.1.0", "sebastian/exporter": "^5.1.2", "sebastian/global-state": "^6.0.2", "sebastian/object-enumerator": "^5.0.0", - "sebastian/recursion-context": "^5.0.0", + "sebastian/recursion-context": "^5.0.1", "sebastian/type": "^4.0.0", "sebastian/version": "^4.0.1" }, @@ -14187,7 +14325,7 @@ "support": { "issues": "https://github.com/sebastianbergmann/phpunit/issues", "security": "https://github.com/sebastianbergmann/phpunit/security/policy", - "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.48" + "source": "https://github.com/sebastianbergmann/phpunit/tree/10.5.55" }, "funding": [ { @@ -14211,7 +14349,7 @@ "type": "tidelift" } ], - "time": "2025-07-11T04:07:17+00:00" + "time": "2025-09-14T06:19:20+00:00" }, { "name": "react/cache", @@ -14510,23 +14648,23 @@ }, { "name": "react/promise", - "version": "v3.2.0", + "version": "v3.3.0", "source": { "type": "git", "url": "https://github.com/reactphp/promise.git", - "reference": "8a164643313c71354582dc850b42b33fa12a4b63" + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/reactphp/promise/zipball/8a164643313c71354582dc850b42b33fa12a4b63", - "reference": "8a164643313c71354582dc850b42b33fa12a4b63", + "url": "https://api.github.com/repos/reactphp/promise/zipball/23444f53a813a3296c1368bb104793ce8d88f04a", + "reference": "23444f53a813a3296c1368bb104793ce8d88f04a", "shasum": "" }, "require": { "php": ">=7.1.0" }, "require-dev": { - "phpstan/phpstan": "1.10.39 || 1.4.10", + "phpstan/phpstan": "1.12.28 || 1.4.10", "phpunit/phpunit": "^9.6 || ^7.5" }, "type": "library", @@ -14571,7 +14709,7 @@ ], "support": { "issues": "https://github.com/reactphp/promise/issues", - "source": "https://github.com/reactphp/promise/tree/v3.2.0" + "source": "https://github.com/reactphp/promise/tree/v3.3.0" }, "funding": [ { @@ -14579,7 +14717,7 @@ "type": "open_collective" } ], - "time": "2024-05-24T10:39:05+00:00" + "time": "2025-08-19T18:57:03+00:00" }, { "name": "react/socket", @@ -15372,32 +15510,32 @@ }, { "name": "slevomat/coding-standard", - "version": "8.20.0", + "version": "8.22.1", "source": { "type": "git", "url": "https://github.com/slevomat/coding-standard.git", - "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb" + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/b4f9f02edd4e6a586777f0cabe8d05574323f3eb", - "reference": "b4f9f02edd4e6a586777f0cabe8d05574323f3eb", + "url": "https://api.github.com/repos/slevomat/coding-standard/zipball/1dd80bf3b93692bedb21a6623c496887fad05fec", + "reference": "1dd80bf3b93692bedb21a6623c496887fad05fec", "shasum": "" }, "require": { "dealerdirect/phpcodesniffer-composer-installer": "^0.6.2 || ^0.7 || ^1.1.2", "php": "^7.4 || ^8.0", - "phpstan/phpdoc-parser": "^2.2.0", - "squizlabs/php_codesniffer": "^3.13.2" + "phpstan/phpdoc-parser": "^2.3.0", + "squizlabs/php_codesniffer": "^3.13.4" }, "require-dev": { "phing/phing": "3.0.1|3.1.0", "php-parallel-lint/php-parallel-lint": "1.4.0", - "phpstan/phpstan": "2.1.19", + "phpstan/phpstan": "2.1.24", "phpstan/phpstan-deprecation-rules": "2.0.3", "phpstan/phpstan-phpunit": "2.0.7", "phpstan/phpstan-strict-rules": "2.0.6", - "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.27|12.2.7" + "phpunit/phpunit": "9.6.8|10.5.48|11.4.4|11.5.36|12.3.10" }, "type": "phpcodesniffer-standard", "extra": { @@ -15421,7 +15559,7 @@ ], "support": { "issues": "https://github.com/slevomat/coding-standard/issues", - "source": "https://github.com/slevomat/coding-standard/tree/8.20.0" + "source": "https://github.com/slevomat/coding-standard/tree/8.22.1" }, "funding": [ { @@ -15433,20 +15571,20 @@ "type": "tidelift" } ], - "time": "2025-07-26T15:35:10+00:00" + "time": "2025-09-13T08:53:30+00:00" }, { "name": "squizlabs/php_codesniffer", - "version": "3.13.2", + "version": "3.13.4", "source": { "type": "git", "url": "https://github.com/PHPCSStandards/PHP_CodeSniffer.git", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c" + "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/5b5e3821314f947dd040c70f7992a64eac89025c", - "reference": "5b5e3821314f947dd040c70f7992a64eac89025c", + "url": "https://api.github.com/repos/PHPCSStandards/PHP_CodeSniffer/zipball/ad545ea9c1b7d270ce0fc9cbfb884161cd706119", + "reference": "ad545ea9c1b7d270ce0fc9cbfb884161cd706119", "shasum": "" }, "require": { @@ -15517,20 +15655,20 @@ "type": "thanks_dev" } ], - "time": "2025-06-17T22:17:01+00:00" + "time": "2025-09-05T05:47:09+00:00" }, { "name": "symfony/cache", - "version": "v7.3.1", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/cache.git", - "reference": "a7c6caa9d6113cebfb3020b427bcb021ebfdfc9e" + "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/cache/zipball/a7c6caa9d6113cebfb3020b427bcb021ebfdfc9e", - "reference": "a7c6caa9d6113cebfb3020b427bcb021ebfdfc9e", + "url": "https://api.github.com/repos/symfony/cache/zipball/6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", + "reference": "6621a2bee5373e3e972b2ae5dbedd5ac899d8cb6", "shasum": "" }, "require": { @@ -15599,7 +15737,7 @@ "psr6" ], "support": { - "source": "https://github.com/symfony/cache/tree/v7.3.1" + "source": "https://github.com/symfony/cache/tree/v7.3.2" }, "funding": [ { @@ -15610,12 +15748,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-27T19:55:54+00:00" + "time": "2025-07-30T17:13:41+00:00" }, { "name": "symfony/cache-contracts", @@ -15769,16 +15911,16 @@ }, { "name": "symfony/filesystem", - "version": "v7.3.0", + "version": "v7.3.2", "source": { "type": "git", "url": "https://github.com/symfony/filesystem.git", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", - "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/edcbb768a186b5c3f25d0643159a787d3e63b7fd", + "reference": "edcbb768a186b5c3f25d0643159a787d3e63b7fd", "shasum": "" }, "require": { @@ -15815,7 +15957,7 @@ "description": "Provides basic utilities for the filesystem", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/filesystem/tree/v7.3.0" + "source": "https://github.com/symfony/filesystem/tree/v7.3.2" }, "funding": [ { @@ -15826,25 +15968,29 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2024-10-25T15:15:23+00:00" + "time": "2025-07-07T08:17:47+00:00" }, { "name": "symfony/http-client", - "version": "v7.3.1", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/http-client.git", - "reference": "4403d87a2c16f33345dca93407a8714ee8c05a64" + "reference": "333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/4403d87a2c16f33345dca93407a8714ee8c05a64", - "reference": "4403d87a2c16f33345dca93407a8714ee8c05a64", + "url": "https://api.github.com/repos/symfony/http-client/zipball/333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019", + "reference": "333b9bd7639cbdaecd25a3a48a9d2dcfaa86e019", "shasum": "" }, "require": { @@ -15852,6 +15998,7 @@ "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/polyfill-php83": "^1.29", "symfony/service-contracts": "^2.5|^3" }, "conflict": { @@ -15910,7 +16057,7 @@ "http" ], "support": { - "source": "https://github.com/symfony/http-client/tree/v7.3.1" + "source": "https://github.com/symfony/http-client/tree/v7.3.3" }, "funding": [ { @@ -15921,12 +16068,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-06-28T07:58:39+00:00" + "time": "2025-08-27T07:45:05+00:00" }, { "name": "symfony/http-client-contracts", @@ -16008,16 +16159,16 @@ }, { "name": "symfony/options-resolver", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/options-resolver.git", - "reference": "afb9a8038025e5dbc657378bfab9198d75f10fca" + "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/options-resolver/zipball/afb9a8038025e5dbc657378bfab9198d75f10fca", - "reference": "afb9a8038025e5dbc657378bfab9198d75f10fca", + "url": "https://api.github.com/repos/symfony/options-resolver/zipball/0ff2f5c3df08a395232bbc3c2eb7e84912df911d", + "reference": "0ff2f5c3df08a395232bbc3c2eb7e84912df911d", "shasum": "" }, "require": { @@ -16055,7 +16206,7 @@ "options" ], "support": { - "source": "https://github.com/symfony/options-resolver/tree/v7.3.0" + "source": "https://github.com/symfony/options-resolver/tree/v7.3.3" }, "funding": [ { @@ -16066,16 +16217,20 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-04-04T13:12:05+00:00" + "time": "2025-08-05T10:16:07+00:00" }, { "name": "symfony/polyfill-php81", - "version": "v1.32.0", + "version": "v1.33.0", "source": { "type": "git", "url": "https://github.com/symfony/polyfill-php81.git", @@ -16131,7 +16286,7 @@ "shim" ], "support": { - "source": "https://github.com/symfony/polyfill-php81/tree/v1.32.0" + "source": "https://github.com/symfony/polyfill-php81/tree/v1.33.0" }, "funding": [ { @@ -16142,6 +16297,10 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" @@ -16213,16 +16372,16 @@ }, { "name": "symfony/var-exporter", - "version": "v7.3.0", + "version": "v7.3.3", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "c9a1168891b5aaadfd6332ef44393330b3498c4c" + "reference": "d4dfcd2a822cbedd7612eb6fbd260e46f87b7137" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/c9a1168891b5aaadfd6332ef44393330b3498c4c", - "reference": "c9a1168891b5aaadfd6332ef44393330b3498c4c", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/d4dfcd2a822cbedd7612eb6fbd260e46f87b7137", + "reference": "d4dfcd2a822cbedd7612eb6fbd260e46f87b7137", "shasum": "" }, "require": { @@ -16270,7 +16429,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v7.3.0" + "source": "https://github.com/symfony/var-exporter/tree/v7.3.3" }, "funding": [ { @@ -16281,12 +16440,16 @@ "url": "https://github.com/fabpot", "type": "github" }, + { + "url": "https://github.com/nicolas-grekas", + "type": "github" + }, { "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", "type": "tidelift" } ], - "time": "2025-05-15T09:04:05+00:00" + "time": "2025-08-18T13:10:53+00:00" }, { "name": "theseer/tokenizer", diff --git a/config/app.php b/config/app.php index 9de088089f..8dc0b82312 100755 --- a/config/app.php +++ b/config/app.php @@ -207,7 +207,7 @@ return [ /* |-------------------------------------------------------------------------- - | Require SAML Login + | Require SAML Login |-------------------------------------------------------------------------- | | Disable the ability to login via form login, and disables the 'nosaml' @@ -220,6 +220,23 @@ return [ 'require_saml' => env('REQUIRE_SAML', false), + /* + |-------------------------------------------------------------------------- + | SAML KEYS + |-------------------------------------------------------------------------- + | + | This is the size of the keys used by openssl_pkey_new for SAML authentication. + | The default is 2048 bits, but this can be changed to 3072 or 4096 bits + | for higher security. Note that this will increase the time it takes to + | generate the keys, so it is not recommended to set this to a very high value + | unless you have a specific need for it. + | + | The European Commission now requires at least 3072-bit keys for new SAML certificates + | @link https://github.com/grokability/snipe-it/issues/17386 + */ + + 'saml_key_size' => env('SAML_KEY_SIZE', 2048), + /* |-------------------------------------------------------------------------- @@ -283,7 +300,6 @@ return [ App\Providers\SnipeTranslationServiceProvider::class, //we REPLACE the default Laravel translator with our own Illuminate\Validation\ValidationServiceProvider::class, Illuminate\View\ViewServiceProvider::class, - Barryvdh\DomPDF\ServiceProvider::class, /* * Package Service Providers... @@ -298,6 +314,8 @@ return [ Unicodeveloper\DumbPassword\DumbPasswordServiceProvider::class, Eduardokum\LaravelMailAutoEmbed\ServiceProvider::class, Laravel\Socialite\SocialiteServiceProvider::class, + Elibyy\TCPDF\ServiceProvider::class, + /* * Application Service Providers... @@ -354,7 +372,7 @@ return [ 'Mail' => Illuminate\Support\Facades\Mail::class, 'Notification' => Illuminate\Support\Facades\Notification::class, 'Password' => Illuminate\Support\Facades\Password::class, - 'PDF' => Barryvdh\DomPDF\Facade::class, + 'PDF' => Elibyy\TCPDF\Facades\TCPDF::class, 'Queue' => Illuminate\Support\Facades\Queue::class, 'Redirect' => Illuminate\Support\Facades\Redirect::class, 'Redis' => Illuminate\Support\Facades\Redis::class, diff --git a/config/filesystems.php b/config/filesystems.php index 2aae01c055..6098438ed2 100644 --- a/config/filesystems.php +++ b/config/filesystems.php @@ -123,6 +123,9 @@ $config['allowed_upload_extensions_array'] = [ 'mov', 'mp3', 'mp4', + 'odp', + 'ods', + 'odt', 'ogg', 'pdf', 'png', @@ -140,12 +143,15 @@ $config['allowed_upload_extensions_array'] = [ ]; - +// https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/MIME_types/Common_types $config['allowed_upload_mimetypes_array'] = [ 'application/json', 'application/msword', 'application/pdf', 'application/vnd.ms-excel', + 'application/vnd.oasis.opendocument.presentation', + 'application/vnd.oasis.opendocument.spreadsheet', + 'application/vnd.oasis.opendocument.text', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', 'application/x-rar-compressed', diff --git a/config/pdf.php b/config/pdf.php new file mode 100644 index 0000000000..3a60ed1631 --- /dev/null +++ b/config/pdf.php @@ -0,0 +1,17 @@ + 'utf-8', + 'format' => 'A4', + 'author' => '', + 'subject' => '', + 'keywords' => '', + 'creator' => 'Snipe-IT', + 'display_mode' => 'fullpage', + 'tempDir' => base_path('../temp/'), + 'pdf_a' => false, + 'pdf_a_auto' => false, + 'icc_profile_path' => '', + 'defaultCssFile' => false, + 'pdfWrapper' => 'misterspelik\LaravelPdf\Wrapper\PdfWrapper', +]; \ No newline at end of file diff --git a/config/permissions.php b/config/permissions.php index 10c44a1896..eaf7b3f785 100644 --- a/config/permissions.php +++ b/config/permissions.php @@ -232,6 +232,12 @@ return [ 'note' => '', 'display' => true, ], + [ + 'permission' => 'licenses.checkin', + 'label' => 'Checkin ', + 'note' => '', + 'display' => true, + ], [ 'permission' => 'licenses.keys', 'label' => 'View License Keys', diff --git a/config/telescope.php b/config/telescope.php new file mode 100644 index 0000000000..5208137e9d --- /dev/null +++ b/config/telescope.php @@ -0,0 +1,205 @@ + env('TELESCOPE_ENABLED', false), + + /* + |-------------------------------------------------------------------------- + | Telescope Domain + |-------------------------------------------------------------------------- + | + | This is the subdomain where Telescope will be accessible from. If the + | setting is null, Telescope will reside under the same domain as the + | application. Otherwise, this value will be used as the subdomain. + | + */ + + 'domain' => env('TELESCOPE_DOMAIN'), + + /* + |-------------------------------------------------------------------------- + | Telescope Path + |-------------------------------------------------------------------------- + | + | This is the URI path where Telescope will be accessible from. Feel free + | to change this path to anything you like. Note that the URI will not + | affect the paths of its internal API that aren't exposed to users. + | + */ + + 'path' => env('TELESCOPE_PATH', 'telescope'), + + /* + |-------------------------------------------------------------------------- + | Telescope Storage Driver + |-------------------------------------------------------------------------- + | + | This configuration options determines the storage driver that will + | be used to store Telescope's data. In addition, you may set any + | custom options as needed by the particular driver you choose. + | + */ + + 'driver' => env('TELESCOPE_DRIVER', 'database'), + + 'storage' => [ + 'database' => [ + 'connection' => env('DB_CONNECTION', 'mysql'), + 'chunk' => 1000, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Telescope Queue + |-------------------------------------------------------------------------- + | + | This configuration options determines the queue connection and queue + | which will be used to process ProcessPendingUpdate jobs. This can + | be changed if you would prefer to use a non-default connection. + | + */ + + 'queue' => [ + 'connection' => env('TELESCOPE_QUEUE_CONNECTION'), + 'queue' => env('TELESCOPE_QUEUE'), + 'delay' => env('TELESCOPE_QUEUE_DELAY', 10), + ], + + /* + |-------------------------------------------------------------------------- + | Telescope Route Middleware + |-------------------------------------------------------------------------- + | + | These middleware will be assigned to every Telescope route, giving you + | the chance to add your own middleware to this list or change any of + | the existing middleware. Or, you can simply stick with this list. + | + */ + + 'middleware' => [ + 'web', + Authorize::class, + ], + + /* + |-------------------------------------------------------------------------- + | Allowed / Ignored Paths & Commands + |-------------------------------------------------------------------------- + | + | The following array lists the URI paths and Artisan commands that will + | not be watched by Telescope. In addition to this list, some Laravel + | commands, like migrations and queue commands, are always ignored. + | + */ + + 'only_paths' => [ + // 'api/*' + ], + + 'ignore_paths' => [ + 'livewire*', + ], + + 'ignore_commands' => [ + // + ], + + /* + |-------------------------------------------------------------------------- + | Telescope Watchers + |-------------------------------------------------------------------------- + | + | The following array lists the "watchers" that will be registered with + | Telescope. The watchers gather the application's profile data when + | a request or task is executed. Feel free to customize this list. + | + */ + + 'watchers' => [ + Watchers\BatchWatcher::class => env('TELESCOPE_BATCH_WATCHER', true), + + Watchers\CacheWatcher::class => [ + 'enabled' => env('TELESCOPE_CACHE_WATCHER', true), + 'hidden' => [], + 'ignore' => [], + ], + + Watchers\ClientRequestWatcher::class => env('TELESCOPE_CLIENT_REQUEST_WATCHER', true), + + Watchers\CommandWatcher::class => [ + 'enabled' => env('TELESCOPE_COMMAND_WATCHER', true), + 'ignore' => [], + ], + + Watchers\DumpWatcher::class => [ + 'enabled' => env('TELESCOPE_DUMP_WATCHER', true), + 'always' => env('TELESCOPE_DUMP_WATCHER_ALWAYS', false), + ], + + Watchers\EventWatcher::class => [ + 'enabled' => env('TELESCOPE_EVENT_WATCHER', true), + 'ignore' => [], + ], + + Watchers\ExceptionWatcher::class => env('TELESCOPE_EXCEPTION_WATCHER', true), + + Watchers\GateWatcher::class => [ + 'enabled' => env('TELESCOPE_GATE_WATCHER', true), + 'ignore_abilities' => [], + 'ignore_packages' => true, + 'ignore_paths' => [], + ], + + Watchers\JobWatcher::class => env('TELESCOPE_JOB_WATCHER', true), + + Watchers\LogWatcher::class => [ + 'enabled' => env('TELESCOPE_LOG_WATCHER', true), + 'level' => 'error', + ], + + Watchers\MailWatcher::class => env('TELESCOPE_MAIL_WATCHER', true), + + Watchers\ModelWatcher::class => [ + 'enabled' => env('TELESCOPE_MODEL_WATCHER', true), + 'events' => ['eloquent.*'], + 'hydrations' => true, + ], + + Watchers\NotificationWatcher::class => env('TELESCOPE_NOTIFICATION_WATCHER', true), + + Watchers\QueryWatcher::class => [ + 'enabled' => env('TELESCOPE_QUERY_WATCHER', true), + 'ignore_packages' => true, + 'ignore_paths' => [], + 'slow' => 100, + ], + + Watchers\RedisWatcher::class => env('TELESCOPE_REDIS_WATCHER', true), + + Watchers\RequestWatcher::class => [ + 'enabled' => env('TELESCOPE_REQUEST_WATCHER', true), + 'size_limit' => env('TELESCOPE_RESPONSE_SIZE_LIMIT', 64), + 'ignore_http_methods' => [], + 'ignore_status_codes' => [], + ], + + Watchers\ScheduleWatcher::class => env('TELESCOPE_SCHEDULE_WATCHER', true), + Watchers\ViewWatcher::class => env('TELESCOPE_VIEW_WATCHER', true), + ], +]; diff --git a/config/version.php b/config/version.php index 2e309b5797..a88f128345 100644 --- a/config/version.php +++ b/config/version.php @@ -1,10 +1,10 @@ 'v8.2.2-pre', - 'full_app_version' => 'v8.2.2-pre - build 19319-ga36afbcb2', - 'build_version' => '19319', + 'app_version' => 'v8.3.3', + 'full_app_version' => 'v8.3.3 - build 20061-g884d2a955', + 'build_version' => '20061', 'prerelease_version' => '', - 'hash_version' => 'ga36afbcb2', - 'full_hash' => 'v8.2.2-pre-249-ga36afbcb2', + 'hash_version' => 'g884d2a955', + 'full_hash' => 'v8.3.3-154-g884d2a955', 'branch' => 'develop', ); \ No newline at end of file diff --git a/database/factories/ActionlogFactory.php b/database/factories/ActionlogFactory.php index ad07f7082b..4773b39532 100644 --- a/database/factories/ActionlogFactory.php +++ b/database/factories/ActionlogFactory.php @@ -84,6 +84,28 @@ class ActionlogFactory extends Factory }); } + /** + * This sets up an ActionLog representing a manually added note tied to an Asset, + * with an optional User as the creator. If no User is provided, one is generated. + * + * @param User|null $user Optional user to associate as the creator of the note. + * @return \Illuminate\Database\Eloquent\Factories\Factory + */ + public function assetNote(?User $user=null) + { + return $this + ->state(function () use ($user) { + return [ + 'action_type' => 'note added', + 'item_type' => Asset::class, + 'target_type' => 'asset', + 'note' => 'Factory-generated manual note', + 'created_by' => $user?->id ?? User::factory(), + ]; + }) + ->for($user ?? User::factory(), 'user'); + } + public function licenseCheckoutToUser() { return $this->state(function () { diff --git a/database/factories/AssetModelFactory.php b/database/factories/AssetModelFactory.php index 3adb933e3e..ac31b57984 100644 --- a/database/factories/AssetModelFactory.php +++ b/database/factories/AssetModelFactory.php @@ -33,6 +33,7 @@ class AssetModelFactory extends Factory 'category_id' => Category::factory(), 'model_number' => $this->faker->creditCardNumber(), 'notes' => 'Created by demo seeder', + 'require_serial' => 0, ]; } diff --git a/database/factories/CheckoutAcceptanceFactory.php b/database/factories/CheckoutAcceptanceFactory.php index bb56ab2b4a..1cd139176e 100644 --- a/database/factories/CheckoutAcceptanceFactory.php +++ b/database/factories/CheckoutAcceptanceFactory.php @@ -23,23 +23,39 @@ class CheckoutAcceptanceFactory extends Factory 'assigned_to_id' => User::factory(), ]; } + protected static bool $skipActionLog = false; + + public function withoutActionLog(): static + { + // turn off for this create() call + static::$skipActionLog = true; + + // ensure it turns back on AFTER creating + return $this->afterCreating(function () { + static::$skipActionLog = false; + }); + } public function configure(): static { return $this->afterCreating(function (CheckoutAcceptance $acceptance) { + if (static::$skipActionLog) { + return; // short-circuit + } if ($acceptance->checkoutable instanceof Asset) { $this->createdAssociatedActionLogEntry($acceptance); } if ($acceptance->checkoutable instanceof Asset && $acceptance->assignedTo instanceof User) { $acceptance->checkoutable->update([ - 'assigned_to' => $acceptance->assigned_to_id, - 'assigned_type' => get_class($acceptance->assignedTo), + 'assigned_to' => $acceptance->assigned_to_id, + 'assigned_type'=> get_class($acceptance->assignedTo), ]); } }); } + public function forAccessory() { return $this->state([ diff --git a/database/factories/LicenseFactory.php b/database/factories/LicenseFactory.php index 1f5b105f42..591a36da1f 100644 --- a/database/factories/LicenseFactory.php +++ b/database/factories/LicenseFactory.php @@ -33,9 +33,9 @@ class LicenseFactory extends Factory 'seats' => $this->faker->numberBetween(1, 10), 'purchase_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get())->format('Y-m-d'), 'order_number' => $this->faker->numberBetween(1000000, 50000000), - 'expiration_date' => $this->faker->dateTimeBetween('now', '+3 years', date_default_timezone_get())->format('Y-m-d H:i:s'), + 'expiration_date' => null, 'reassignable' => $this->faker->boolean(), - 'termination_date' => $this->faker->dateTimeBetween('-1 years', 'now', date_default_timezone_get())->format('Y-m-d H:i:s'), + 'termination_date' => null, 'supplier_id' => Supplier::factory(), 'category_id' => Category::factory(), ]; diff --git a/database/factories/LicenseSeatFactory.php b/database/factories/LicenseSeatFactory.php index aaf75bdc2d..ee516b6dac 100644 --- a/database/factories/LicenseSeatFactory.php +++ b/database/factories/LicenseSeatFactory.php @@ -14,6 +14,7 @@ class LicenseSeatFactory extends Factory { return [ 'license_id' => License::factory(), + 'unreassignable_seat' => false, ]; } diff --git a/database/factories/MaintenanceFactory.php b/database/factories/MaintenanceFactory.php index e07de8d24d..01adf08560 100644 --- a/database/factories/MaintenanceFactory.php +++ b/database/factories/MaintenanceFactory.php @@ -31,6 +31,7 @@ class MaintenanceFactory extends Factory 'start_date' => $this->faker->date(), 'is_warranty' => $this->faker->boolean(), 'notes' => $this->faker->paragraph(), + 'url' => $this->faker->url(), ]; } } diff --git a/database/factories/UserFactory.php b/database/factories/UserFactory.php index 565621ca95..989fad08f2 100644 --- a/database/factories/UserFactory.php +++ b/database/factories/UserFactory.php @@ -28,8 +28,9 @@ class UserFactory extends Factory 'email' => $this->faker->safeEmail(), 'employee_num' => $this->faker->numberBetween(3500, 35050), 'first_name' => $this->faker->firstName(), - 'jobtitle' => $this->faker->jobTitle(), 'last_name' => $this->faker->lastName(), + 'display_name' => null, + 'jobtitle' => $this->faker->jobTitle(), 'locale' => 'en-US', 'notes' => 'Created by DB seeder', 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password @@ -351,6 +352,17 @@ class UserFactory extends Factory return $this->appendPermission(['import' => '1']); } + public function createCustomFields() + { + return $this->appendPermission(['customfields.create' => '1']); + } + + public function viewCustomFields() + { + return $this->appendPermission(['customfields.view' => '1']); + } + + public function deleteCustomFields() { return $this->appendPermission(['customfields.delete' => '1']); diff --git a/database/migrations/2018_08_08_100000_create_telescope_entries_table.php b/database/migrations/2018_08_08_100000_create_telescope_entries_table.php new file mode 100644 index 0000000000..91b753b6a7 --- /dev/null +++ b/database/migrations/2018_08_08_100000_create_telescope_entries_table.php @@ -0,0 +1,76 @@ +getConnection()); + + if (! Schema::hasTable('telescope_entries') ) { + $schema->create('telescope_entries', function (Blueprint $table) { + $table->bigIncrements('sequence'); + $table->uuid('uuid'); + $table->uuid('batch_id'); + $table->string('family_hash')->nullable(); + $table->boolean('should_display_on_index')->default(true); + $table->string('type', 20); + $table->longText('content'); + $table->dateTime('created_at')->nullable(); + + $table->unique('uuid'); + $table->index('batch_id'); + $table->index('family_hash'); + $table->index('created_at'); + $table->index(['type', 'should_display_on_index']); + }); + } + + if (! Schema::hasTable('telescope_entries_tags') ) { + $schema->create('telescope_entries_tags', function (Blueprint $table) { + $table->uuid('entry_uuid'); + $table->string('tag'); + + $table->primary(['entry_uuid', 'tag']); + $table->index('tag'); + + $table->foreign('entry_uuid') + ->references('uuid') + ->on('telescope_entries') + ->onDelete('cascade'); + }); + } + + if (! Schema::hasTable('telescope_monitoring') ) { + $schema->create('telescope_monitoring', function (Blueprint $table) { + $table->string('tag')->primary(); + }); + } + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + $schema = Schema::connection($this->getConnection()); + + $schema->dropIfExists('telescope_entries_tags'); + $schema->dropIfExists('telescope_entries'); + $schema->dropIfExists('telescope_monitoring'); + } +}; diff --git a/database/migrations/2025_01_15_190348_adds_unavailable_to_license_seats_tables.php b/database/migrations/2025_01_15_190348_adds_unavailable_to_license_seats_tables.php new file mode 100644 index 0000000000..40c8ad5367 --- /dev/null +++ b/database/migrations/2025_01_15_190348_adds_unavailable_to_license_seats_tables.php @@ -0,0 +1,26 @@ +addColumn('boolean', 'unreassignable_seat')->default(false)->after('assigned_to'); + }); + } + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('license_seats', function (Blueprint $table) { + $table->dropColumn('unreassignable_seat'); + }); + } +}; diff --git a/database/migrations/2025_05_12_183803_add_req_serial_bool_to_models_table.php b/database/migrations/2025_05_12_183803_add_req_serial_bool_to_models_table.php new file mode 100644 index 0000000000..ee0e37a628 --- /dev/null +++ b/database/migrations/2025_05_12_183803_add_req_serial_bool_to_models_table.php @@ -0,0 +1,28 @@ +boolean( 'require_serial')->after('category_id')->default(0); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('models', function (Blueprint $table) { + $table->dropColumn('require_serial'); + }); + } +}; diff --git a/database/migrations/2025_06_04_101736_add_deleted_at_index_to_action_logs.php b/database/migrations/2025_06_04_101736_add_deleted_at_index_to_action_logs.php index c9f853599b..1a50a33779 100644 --- a/database/migrations/2025_06_04_101736_add_deleted_at_index_to_action_logs.php +++ b/database/migrations/2025_06_04_101736_add_deleted_at_index_to_action_logs.php @@ -22,7 +22,7 @@ return new class extends Migration public function down(): void { Schema::table('action_logs', function (Blueprint $table) { - $table->dropIndex('deleted_at'); + $table->dropIndex(['deleted_at']); }); } }; diff --git a/database/migrations/2025_08_12_225214_add_qty_to_checkout_acceptances_table.php b/database/migrations/2025_08_12_225214_add_qty_to_checkout_acceptances_table.php new file mode 100644 index 0000000000..c5c7726213 --- /dev/null +++ b/database/migrations/2025_08_12_225214_add_qty_to_checkout_acceptances_table.php @@ -0,0 +1,31 @@ +unsignedInteger('qty')->nullable()->after('assigned_to_id')->default(null); + }); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::whenTableHasColumn('checkout_acceptances', 'qty', function () { + Schema::table('checkout_acceptances', function (Blueprint $table) { + $table->dropColumn('qty'); + }); + }); + } +}; diff --git a/database/migrations/2025_08_19_114742_add_display_name_to_users.php b/database/migrations/2025_08_19_114742_add_display_name_to_users.php new file mode 100644 index 0000000000..d55e755d3a --- /dev/null +++ b/database/migrations/2025_08_19_114742_add_display_name_to_users.php @@ -0,0 +1,32 @@ +text('display_name')->after('last_name')->nullable()->default(null); + } + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + if (Schema::hasColumn('users', 'display_name')) { + $table->dropColumn('display_name'); + } + }); + } +}; diff --git a/database/migrations/2025_08_19_122533_add_category_indexes.php b/database/migrations/2025_08_19_122533_add_category_indexes.php new file mode 100644 index 0000000000..530a1f4398 --- /dev/null +++ b/database/migrations/2025_08_19_122533_add_category_indexes.php @@ -0,0 +1,59 @@ +index(['deleted_at']); + }); + Schema::table('accessories', function (Blueprint $table) { + $table->index(['deleted_at','category_id']); + }); + Schema::table('consumables', function (Blueprint $table) { + $table->index(['deleted_at','category_id']); + }); + Schema::table('components', function (Blueprint $table) { + $table->index(['deleted_at','category_id']); + }); + Schema::table('licenses', function (Blueprint $table) { + $table->index(['deleted_at','category_id']); + }); + Schema::table('models', function (Blueprint $table) { + $table->index(['deleted_at','category_id']); + }); + + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('categories', function (Blueprint $table) { + $table->dropIndex(['deleted_at']); + }); + Schema::table('accessories', function (Blueprint $table) { + $table->dropIndex(['deleted_at','category_id']); + }); + Schema::table('consumables', function (Blueprint $table) { + $table->dropIndex(['deleted_at','category_id']); + }); + Schema::table('components', function (Blueprint $table) { + $table->dropIndex(['deleted_at','category_id']); + }); + Schema::table('licenses', function (Blueprint $table) { + $table->dropIndex(['deleted_at','category_id']); + }); + Schema::table('models', function (Blueprint $table) { + $table->dropIndex(['deleted_at','category_id']); + }); + } +}; diff --git a/database/migrations/2025_08_19_174823_add_display_name_to_ldap_settings.php b/database/migrations/2025_08_19_174823_add_display_name_to_ldap_settings.php new file mode 100644 index 0000000000..fb980af6dd --- /dev/null +++ b/database/migrations/2025_08_19_174823_add_display_name_to_ldap_settings.php @@ -0,0 +1,82 @@ +string('ldap_display_name', 191)->after('ldap_fname_field')->nullable()->default(null); + } + + if (!Schema::hasColumn('settings', 'ldap_zip')) { + $table->string('ldap_zip', 191)->after('ldap_manager')->nullable()->default(null); + } + + if (!Schema::hasColumn('settings', 'ldap_state')) { + $table->string('ldap_state', 191)->after('ldap_manager')->nullable()->default(null); + } + + if (!Schema::hasColumn('settings', 'ldap_city')) { + $table->string('ldap_city', 191)->after('ldap_manager')->nullable()->default(null); + } + + if (!Schema::hasColumn('settings', 'ldap_address')) { + $table->string('ldap_address', 191)->after('ldap_manager')->nullable()->default(null); + } + + if (!Schema::hasColumn('settings', 'ldap_mobile')) { + $table->string('ldap_mobile', 191)->after('ldap_phone_field')->nullable()->default(null); + } + + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('settings', function (Blueprint $table) { + if (Schema::hasColumn('settings', 'ldap_display_name')) { + $table->dropColumn('ldap_display_name'); + } + }); + + Schema::table('settings', function (Blueprint $table) { + if (Schema::hasColumn('settings', 'ldap_zip')) { + $table->dropColumn('ldap_zip'); + } + }); + Schema::table('settings', function (Blueprint $table) { + if (Schema::hasColumn('settings', 'ldap_address')) { + $table->dropColumn('ldap_address'); + } + }); + Schema::table('settings', function (Blueprint $table) { + if (Schema::hasColumn('settings', 'ldap_city')) { + $table->dropColumn('ldap_city'); + } + }); + Schema::table('settings', function (Blueprint $table) { + if (Schema::hasColumn('settings', 'ldap_state')) { + $table->dropColumn('ldap_state'); + } + }); + Schema::table('settings', function (Blueprint $table) { + if (Schema::hasColumn('settings', 'ldap_mobile')) { + $table->dropColumn('ldap_mobile'); + } + }); + + + } +}; diff --git a/database/migrations/2025_08_20_190617_add_created_at_index_to_models.php b/database/migrations/2025_08_20_190617_add_created_at_index_to_models.php new file mode 100644 index 0000000000..5a73a94f3b --- /dev/null +++ b/database/migrations/2025_08_20_190617_add_created_at_index_to_models.php @@ -0,0 +1,28 @@ +index(['created_at']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('models', function (Blueprint $table) { + $table->dropIndex(['created_at']); + }); + } +}; diff --git a/database/migrations/2025_09_16_104604_create_users_deleted_at_location_id_index.php b/database/migrations/2025_09_16_104604_create_users_deleted_at_location_id_index.php new file mode 100644 index 0000000000..05b8474a4b --- /dev/null +++ b/database/migrations/2025_09_16_104604_create_users_deleted_at_location_id_index.php @@ -0,0 +1,31 @@ +index(['deleted_at','location_id']); + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('users', function (Blueprint $table) { + $table->dropIndex(['deleted_at','location_id']); + }); + } +}; diff --git a/database/migrations/2025_10_07_113331_add_url_to_maintenances.php b/database/migrations/2025_10_07_113331_add_url_to_maintenances.php new file mode 100644 index 0000000000..53b0e30dd4 --- /dev/null +++ b/database/migrations/2025_10_07_113331_add_url_to_maintenances.php @@ -0,0 +1,32 @@ +text('url')->after('name')->nullable()->default(null); + } + }); + } + + /** + * Reverse the migrations. + */ + public function down(): void + { + Schema::table('maintenances', function (Blueprint $table) { + if (Schema::hasColumn('maintenances', 'url')) { + $table->dropColumn('url'); + } + }); + } +}; diff --git a/database/migrations/2025_10_13_102956_move_assetmodels_files.php b/database/migrations/2025_10_13_102956_move_assetmodels_files.php new file mode 100644 index 0000000000..699a761b1f --- /dev/null +++ b/database/migrations/2025_10_13_102956_move_assetmodels_files.php @@ -0,0 +1,30 @@ +header_color = null; $settings->label2_2d_type = 'QRCODE'; $settings->default_currency = 'USD'; - $settings->brand = 3; + $settings->brand = 2; $settings->ldap_enabled = 0; $settings->full_multiple_companies_support = 0; $settings->label2_1d_type = 'C128'; - $settings->skin = ''; + $settings->skin = 'blue'; $settings->email_domain = 'example.org'; $settings->email_format = 'filastname'; $settings->username_format = 'filastname'; @@ -41,6 +41,8 @@ class SettingsSeeder extends Seeder if ($user = User::where('username', '=', 'admin')->first()) { $user->locale = 'en-US'; + $user->enable_sound = 1; + $user->enable_confetti = 1; $user->save(); } diff --git a/package-lock.json b/package-lock.json index c43d68251f..0c75163a74 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "jquery-ui": "^1.14.1", "jquery-validation": "^1.21.0", "jquery.iframe-transport": "^1.0.0", + "jspdf": "^3.0.3", "jspdf-autotable": "^5.0.2", "less": "^4.2.2", "less-loader": "^6.0", @@ -2193,6 +2194,12 @@ "@types/node": "*" } }, + "node_modules/@types/pako": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/pako/-/pako-2.0.4.tgz", + "integrity": "sha512-VWDCbrLeVXJM9fihYodcLiIv0ku+AlOa/TQ1SvYOaBuyrSKgEcro95LJyIsJ4vSo6BXIxOKxiJAat04CmST9Fw==", + "license": "MIT" + }, "node_modules/@types/parse-json": { "version": "4.0.2", "dev": true, @@ -2258,6 +2265,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@types/ws": { "version": "8.5.10", "dev": true, @@ -2742,16 +2756,6 @@ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, - "node_modules/atob": { - "version": "2.1.2", - "license": "(MIT OR Apache-2.0)", - "bin": { - "atob": "bin/atob.js" - }, - "engines": { - "node": ">= 4.5.0" - } - }, "node_modules/autoprefixer": { "version": "10.4.19", "dev": true, @@ -3343,16 +3347,6 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/btoa": { - "version": "1.2.1", - "license": "(MIT OR Apache-2.0)", - "bin": { - "btoa": "bin/btoa.js" - }, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/buffer": { "version": "4.9.2", "dev": true, @@ -4617,10 +4611,14 @@ } }, "node_modules/dompurify": { - "version": "2.5.8", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.8.tgz", - "integrity": "sha512-o1vSNgrmYMQObbSSvF/1brBYEQPHhV1+gsmrusO7/GXtp1T9rCS8cXFqVxK/9crT1jA6Ccv+5MTSjBNqr7Sovw==", - "optional": true + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optional": true, + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } }, "node_modules/domutils": { "version": "2.8.0", @@ -5106,6 +5104,23 @@ "version": "2.1.0", "license": "MIT" }, + "node_modules/fast-png": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/fast-png/-/fast-png-6.4.0.tgz", + "integrity": "sha512-kAqZq1TlgBjZcLr5mcN6NP5Rv4V2f22z00c3g8vRrwkcqjerx7BEhPbOnWCPqaHUl2XWQBJQvOT/FQhdMT7X/Q==", + "license": "MIT", + "dependencies": { + "@types/pako": "^2.0.3", + "iobuffer": "^5.3.2", + "pako": "^2.1.0" + } + }, + "node_modules/fast-png/node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, "node_modules/fast-safe-stringify": { "version": "2.1.1", "license": "MIT" @@ -6233,6 +6248,12 @@ "node": ">= 0.10" } }, + "node_modules/iobuffer": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/iobuffer/-/iobuffer-5.4.0.tgz", + "integrity": "sha512-DRebOWuqDvxunfkNJAlc3IzWIPD5xVxwUNbHr7xKB8E6aLJxIPfNX3CoMJghcFjpv6RWQsrcJbghtEwSPoJqMA==", + "license": "MIT" + }, "node_modules/ion-rangeslider": { "version": "2.3.1", "license": "MIT", @@ -6769,19 +6790,19 @@ } }, "node_modules/jspdf": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.2.tgz", - "integrity": "sha512-myeX9c+p7znDWPk0eTrujCzNjT+CXdXyk7YmJq5nD5V7uLLKmSXnlQ/Jn/kuo3X09Op70Apm0rQSnFWyGK8uEQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-3.0.3.tgz", + "integrity": "sha512-eURjAyz5iX1H8BOYAfzvdPfIKK53V7mCpBTe7Kb16PaM8JSXEcUQNBQaiWMI8wY5RvNOPj4GccMjTlfwRBd+oQ==", + "license": "MIT", "dependencies": { - "@babel/runtime": "^7.23.2", - "atob": "^2.1.2", - "btoa": "^1.2.1", + "@babel/runtime": "^7.26.9", + "fast-png": "^6.2.0", "fflate": "^0.8.1" }, "optionalDependencies": { - "canvg": "^3.0.6", + "canvg": "^3.0.11", "core-js": "^3.6.0", - "dompurify": "^2.5.4", + "dompurify": "^3.2.4", "html2canvas": "^1.0.0-rc.5" } }, diff --git a/package.json b/package.json index 3237ef285a..a1dd60f3f5 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "jquery-ui": "^1.14.1", "jquery-validation": "^1.21.0", "jquery.iframe-transport": "^1.0.0", + "jspdf": "^3.0.3", "jspdf-autotable": "^5.0.2", "less": "^4.2.2", "less-loader": "^6.0", diff --git a/public/css/build/app.css b/public/css/build/app.css index 2d169880e9..c98f550291 100644 --- a/public/css/build/app.css +++ b/public/css/build/app.css @@ -306,9 +306,6 @@ a.accordion-header { padding: 0px; /* adjust based on your layout */ } -.skin-blue .main-header .navbar .dropdown-menu li a { - color: #333; -} a.logo.no-hover a:hover { background-color: transparent; } @@ -1052,6 +1049,7 @@ th.css-license > .th-inner, th.css-location > .th-inner, th.css-users > .th-inner, th.css-currency > .th-inner, +th.css-child-locations > .th-inner, th.css-history > .th-inner { font-size: 0px; line-height: 0.75 !important; @@ -1072,9 +1070,9 @@ th.css-house-laptop > .th-inner::before, th.css-house-user > .th-inner::before, th.css-license > .th-inner::before, th.css-location > .th-inner::before, -th.css-padlock > .th-inner::before, th.css-users > .th-inner::before, th.css-currency > .th-inner::before, +th.css-child-locations > .th-inner::before, th.css-history > .th-inner::before { display: inline-block; font-size: 20px; @@ -1129,7 +1127,8 @@ th.css-component > .th-inner::before { th.css-padlock > .th-inner::before { content: "\f023"; font-family: "Font Awesome 5 Free"; - font-weight: 900; + font-weight: 800; + padding-right: 3px; } th.css-house-user > .th-inner::before { content: "\e1b0"; @@ -1155,6 +1154,12 @@ th.css-accessory-alt > .th-inner::before { font-size: 19px; margin-bottom: 0px; } +th.css-child-locations > .th-inner::before { + content: "\f64f"; + font-family: "Font Awesome 5 Free"; + font-size: 19px; + margin-bottom: 0px; +} th.css-currency > .th-inner::before { content: "\24"; font-family: "Font Awesome 5 Free"; @@ -1480,6 +1485,25 @@ caption.tableCaption { margin-left: -47px; margin-top: 2px; } +.popover.help-popover, +.popover.help-popover .popover-content, +.popover.help-popover .popover-body, +.popover.help-popover .popover-title, +.popover.help-popover .popover-header { + color: #000; +} +.visually-hidden { + width: 1px; + height: 1px; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: preserve; + display: inline-block; +} +input[name="columnsSearch"] { + width: 120px; +} /*# sourceMappingURL=app.css.map*/ \ No newline at end of file diff --git a/public/css/build/app.css.map b/public/css/build/app.css.map index c3f787a507..c6083d3cb8 100644 --- a/public/css/build/app.css.map +++ b/public/css/build/app.css.map @@ -1 +1 @@ -{"version":3,"file":"css/build/app.css","mappings":"AACA;EACE;EAGA;AAFF;AAKA;EACE;IACE;EAHF;EAMA;IACE;EAJF;AACF;AAOA;EACE;AALF;AAOA;EACE;EACA;EACA;EACA;EACA;AALF;AASA;EACE;AAPF;AAUA;EACE;EACA;AARF;AAWA;EACE;AATF;AAYA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AAVF;AAaA;EACE;EACA;EACA;EACA;EACA;AAXF;AAcA;EACE;AAZF;AAeA;EACE;AAbF;AAgBA;EACE;EACA;AAdF;AAiBA;EACE;AAfF;AAkBA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAhBF;AAmBA;EACE;AAjBF;AAoBA;EACE;AAlBF;AAqBA;EACE;AAnBF;AAsBA;EACE;AApBF;AAuBA;EACE;EACA;EACA;AArBF;AAwBA;EACE;EACA;EACA;AAtBF;AA6BA;EACE;AA3BF;AA8BA;EACE;EACA;AA5BF;AA+BA;EACE;AA7BF;AA+BA;EACE;EACA;AA7BF;AAgCA;;EAEE;EACA;AA9BF;AAiCA;EACE;EACA;AA/BF;AAiCA;EACE;AA/BF;AAkCA;EACE;EACA;EACA;AAhCF;AAmCA;EACE;AAjCF;AAoCA;EACE;AAlCF;AAqCA;EACE;AAnCF;AAsCA;EACE;AApCF;AAuCA;EACE;AArCF;AAwCA;;;;;EAKE;AAtCF;AAyCA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAvCF;AA0CA;EACE;EACA;EACA;EACA;EACA;EACA;AAxCF;AA2CA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAzCF;AA4CA;EACE;AA1CF;AA6CA;EACE;EACA;EACA;EACA;AA3CF;AA8CA;EACE;EACA;AA5CF;AA+CA;EACE;EACA;EACA;EACA;EACA;AA7CF;AAgDA;EACE;EACA;AA9CF;AAiDA;EACE;EACA;EACA;EACA;AA/CF;AAkDA;EACE;EACA;AAhDF;AACA,cAAc;AAmDd;EACE;EACA;EACA;AAjDF;AAmDA;EACE;EACA;AAjDF;AAsDA;EACE;EACA;EACA;AApDF;AAuDA;EACE;EACA;AArDF;AAwDA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAtDF;AAyDA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAvDF;AA0DA;EACE;EACA;EACA;EACA;EACA;AAxDF;AA2DA;EACE;EACA;EACA;AAzDF;AA4DA;EACE;AA1DF;AA6DA;EACE;AA3DF;AA8DA;EACE;AA5DF;AA+DA;EACE;AA7DF;AAgEA;EACE;AA9DF;AAiEA;EACE;AA/DF;AAkEA;EACE;EACA;AAhEF;AAmEA;EACE;AAjEF;AAoEA;EACE;AAlEF;AACA,kBAAkB;AAqElB;EACE;EAEA;EACA;EACA;EApEA,gCAAgC;AAClC;AAuEA;EACE;AArEF;AAwEA;EACE;AAtEF;AAyEA;EACE;EACA;EACA;AAvEF;AAyEA;EACE;EACA;EACA;AAvEF;AA0EA;;;EACE;AAtEF;AAyEA;EACE;EACA;AAvEF;AA0EA;EACE;IACE;EAxEF;EA2EA;IACE;IACA;IACA;EAzEF;AACF;AA4EA;;EAEE;EACA;EACA;AA1EF;AA6EA;EACE;AA3EF;AA8EA;;EAEE;AA5EF;AA+EA;EACE;AA7EF;AAgFA;EACE;AA9EF;AAiFA;EACE;EACA;EACA;AA/EF;AAkFA;EACE;EACA;AAhFF;AAmFA;EACE;EACA;EACA;AAjFF;AAoFA;EACE;AAlFF;AC1XA;EAkBE;AD2WF;ACzWA;EACE;EACA;EACA;EACA;EACA;AD2WF;AC1WE;;;EACE;AD8WJ;AC3WA;EACE;AD6WF;AC1WA;EACE;EACA;AD4WF;ACzWA;EACE;AD2WF;ACvWA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;ADyWF;ACtWA;EACE;EACA;EACA;EACA;EACA;ADwWF;ACrWA;EACE;ADuWF;ACpWA;EACE;ADsWF;ACnWA;EACE;EACA;ADqWF;ACjWA;EACE;ADmWF;AChWA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ADkWF;AChWA;EACE;ADkWF;AChWA;EACE;ADkWF;AC9VA;EACE;ADgWF;AC9VA;EACE;ADgWF;AC5VA;EACE;EACA;EACA;AD8VF;AC3VA;EACE;EACA;EACA;AD6VF;ACtUA;EACE;ADwUF;ACrUA;EACE;EACA;EACA;ADuUF;ACpUA;EACE;EACA;ADsUF;ACnUA;EACE;ADqUF;AClUA;EACE;EACA;ADoUF;ACjUA;;EACE;EACA;ADoUF;ACjUA;EACE;EACA;ADmUF;ACjUA;EACE;ADmUF;AChUA;EACE;EACA;EACA;ADkUF;AC/TA;EACE;ADiUF;AC9TA;EACE;ADgUF;AC7TA;EACE;AD+TF;AC7TA;EACE;AD+TF;AC5TA;EACE;AD8TF;AC3TA;;;;EACE;ADgUF;AC7TA;;;;;EACE;ADmUF;AChUA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ADkUF;AChUA;EACE;EACA;EACA;EACA;EACA;EACA;ADkUF;AChUA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ADkUF;AChUA;EACE;ADkUF;AChUA;EACE;EACA;EACA;EACA;ADkUF;AChUA;EACE;EACA;ADkUF;AChUA;EACE;EACA;EACA;EACA;EACA;ADkUF;AChUA;EACE;EACA;ADkUF;AChUA;EACE;EACA;EACA;EACA;ADkUF;AC/TA;EACE;EACA;ADiUF;AC5TA;EAAY;AD+TZ;AACA,cAAc;AC7Td;EAAY;EAAkC;ADiU9C;AChUA;EAA8B;EAAY;ADoU1C;AClUA;EAAiD;EAAgB;EAAiB;ADuUlF;ACtUA;EAA8C;EAAa;AD0U3D;ACzUA;EAA+C;EAAoB;EAAa;EAAc;EAAgB;EAAqB;EAAW;EAAW;EAAmB;EAAoB;ADqVhM;ACpVA;EAAqD;EAAc;EAAa;EAAc;EAAqB;EAAqB;EAAoB;EAAU;AD8VtK;AC7VA;EAA0C;EAAoB;EAAoB;EAAa;EAAkB;ADoWjH;ACnWA;EAA0D;EAAW;EAAkB;ADwWvF;ACvWA;EAAmE;AD0WnE;ACzWA;EAAiE;AD4WjE;AC3WA;EAA6E;AD8W7E;AC7WA;EAA4E;ADgX5E;AC/WA;EAAwD;ADkXxD;ACjXA;EAA8D;ADoX9D;ACnXA;EAAuD;EAAW;ADuXlE;ACtXA;EAAsD;ADyXtD;ACxXA;EAAuD;AD2XvD;AACA,kBAAkB;ACzXlB;EACE;EACA;EACA;EACA;EACA;ED2XA,gCAAgC;AAClC;ACxXA;EAkBE;ADyWF;ACtWA;EACE;ADwWF;ACpWA;;EACE;ADuWF;ACrWA;;EACE;ADwWF;ACrWA;EACE;EAIA;ADoWF;ACjWA;EACE;EACA;ADmWF;AChWA;EACE;ADkWF;AC/VA;EACE;ADiWF;AC9VA;EAEE;IACE;IACA;ED+VF;EC5VA;IACE;IACA;IACA;ED8VF;EC3VA;IACE;ED6VF;EC1VA;;IACE;ED6VF;EC1VA;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;ED4VF;EACA,+CAA+C;ECzV/C;IACE;ED2VF;ECxVA;IACE;ED0VF;ECvVA;IACE;EDyVF;ECtVA;IACE;EDwVF;EACA,qCAAqC;ECrVrC;;IACE;EDwVF;EACA,QAAQ;ECrVR;;IACE;IACA;IACA;EDwVF;ECrVA;IACE;EDuVF;ECpVA;IACE;EDsVF;ECnVA;IACE;IACA;IACA;EDqVF;EClVA;IACE;IACA;EDoVF;ECjVA;;IACE;EDoVF;EClVA;;;;;;;;;;;;IACE;ED+VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;EC5VA;IACE;ED8VF;AACF;ACzVA;EACE;AD2VF;ACxVA;EACI;EACA;AD0VJ;ACvVA;EACE;ADyVF;ACtVA;EACE;EACA;EACA;ADwVF;ACnVA;EACE;EACA;OAAA;EACA;EACA;ADqVF;AClVA;;EACE;EACA;EACA;ADqVF;AClVA;;;EACE;ADsVF;ACnVA;;EACE;ADsVF;ACnVA;EACE;ADqVF;AClVA;EACE;ADoVF;ACjVA;EACE;EACA;EACA;ADmVF;AChVA;EACE;EACA;ADkVF;AC/UA;EACE;EACA;EACA;ADiVF;AC7UA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AD+UF;AC7UA;;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ADgVF;AC7UA;EACE;AD+UF;AC5UA;EACE;AD8UF;AC3UA;EACE;AD6UF;AC1UA;EACE;AD4UF;ACzUA;EACE;AD2UF;ACvUA;EACE;EACA;EACA;EACA;EACA;EAGA;ADuUF;ACpUA;EACE;EACA;EACA;EACA;ADsUF;ACnUA;EACE;EACA;EACA;EACA;ADqUF;ACjUA;EACE;EACA;EACA;EACA;EACA;EACA;ADmUF;AACA;;;;EAIE;AChUF;EACE;EACA;EACA;EACA;ADkUF;AC/TA;EACE;EACA;EACA;EACA;EACA;ADiUF;AC9TA;EACE;EACA;EACA;ADgUF;AC7TA;EACE;EACA;EACA;AD+TF;AC3TA;EACE;AD6TF;AACA;;EAEE;ACxTF;EACE;IACE;IACA;ED0TF;ECvTA;IACE;EDyTF;ECtTA;IACE;EDwTF;ECrTA;IACE;EDuTF;AACF;ACpTA;EACE;EACA;EACA;ADsTF;ACnTA;EACE;EACA;ADqTF;AACA;;;;;;;;;;;EAWE;AChTF;;;;;;;;;;;;;;EAeE;EACA;EACA;EACA;EACA;EACA;ADiTF;AC7SA;;;;;;;;;;;;;;;;EAiBE;EACA;EACA;EACA;AD8SF;AACA;;;EAGE;AC3SF;EAEE;EAAkB;EAAoC;AD8SxD;AC3SA;EAEE;EAAkB;EAAoC;AD8SxD;AC3SA;EAEE;EAAkB;EAAoC;AD8SxD;AC3SA;EAEE;EAAkB;EAAoC;AD8SxD;AC3SA;EAEE;EAAkB;EAAoC;AD8SxD;AC3SA;EACE;EAAkB;EAAoC;AD+SxD;AC5SA;EACE;EAAkB;EAAoC;EAAiB;ADiTzE;AC9SA;EAEE;EAAkB;EAAoC;ADiTxD;AC9SA;EAEE;EAAkB;EAAoC;ADiTxD;AC9SA;EACE;EACA;EACA;EACA;ADgTF;AC9SA;EACE;EACA;EACA;EACA;ADgTF;AC9SA;EACE;EACA;EACA;EACA;ADgTF;AC9SA;EACE;EACA;EACA;EACA;ADgTF;AC7SA;EACE;EACA;EACA;EACA;AD+SF;AC5SA;EACE;EACA;EACA;EACA;AD8SF;AC1SA;EACE;EACA;EACA;EACA;AD4SF;ACxSA;;;EACE;AD4SF;ACzSA;;EACE;EACA;EACA;EACA;AD4SF;ACzSA;;EACE;AD4SF;ACzSA;EACE;AD2SF;ACxSA;EACE;IACE;ED0SF;ECxSA;IACE;ED0SF;AACF;ACxSA;EACE;IACE;ED0SF;ECxSA;IACE;ED0SF;ECxSA;IACE;ED0SF;AACF;ACvSA;EACE;IACE;EDySF;AACF;ACvSA;EACE;IACE;EDySF;ECvSA;IACE;IACA;EDySF;ECvSA;IACE;IACA;EDySF;ECvSA;IACE;IACA;EDySF;AACF;ACvSA;EACE;IACE;EDySF;AACF;ACtSA;EACE;IACE;EDwSF;AACF;ACtSA;EACE;IACE;IACA;IACA;IACA;IACA;EDwSF;AACF;AACA,oDAAoD;ACpSpD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ADsSF;ACnSA;EACE;EACA;ADqSF;AACA,8CAA8C;AAC9C,8CAA8C;AAC9C,8CAA8C;ACjS9C;EDmSE,kCAAkC;ECjSlC;EACA;OAAA;EDmSA,+CAA+C;ECjS/C;EDmSA,+BAA+B;ECjS/B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EDmSA,6BAA6B;AAC/B;AACA,yFAAyF;AC/RzF;EDiSE,2EAA2E;ECzR3E;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ED0RA,+BAA+B;ECxR/B;AD0RF;AACA,wEAAwE;ACvRxE;EACE;ADyRF;AACA,wEAAwE;ACtRxE;;EACE;EACA;EACA;EACA;EACA;ADyRF;AACA,6EAA6E;ACtR7E;;EACE;EACA;EACA;EACA;ADyRF;AACA,+EAA+E;ACtR/E;;EACE;EACA;EACA;EACA;ADyRF;AACA,qCAAqC;ACpRrC;EACE;KAAA;UAAA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ADsRF;ACnRA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;ADqRF;AClRA;EACE;ADoRF;AACA;;;;EAIE;AChRF;EACE;ADkRF;AC/QA;EACE;EACA;EACA;EACA;ADiRF;AC9QA;EACE;ADgRF;AC7QA;EACE;AD+QF;AC5QA;EACE;AD8QF;AC3QA;EACE;AD6QF;AACA,8CAA8C;AAC9C,8CAA8C;AAC9C,8CAA8C;AAC9C;;;EAGE;ACxQF;EACE;EACA;EACA;EACA;EACA;AD0QF;ACvQA;;EAEE;EACA;EACA;ADyQF;ACtQA;EACE;ADwQF;ACrQA;EACE;ADuQF;ACrQA;EACE;ADuQF;ACpQA;EACE;EACA;EACA;ADsQF;AACA,kEAAkE;ACnQlE;EACE;ADqQF;AClQA;EACE;ADoQF;AChQA;EACE;EACA;ADkQF;AC/PA;EACE;EACA;ADiQF;AC9PA;EACE;EACA;EACA;EACA;EACA;EACA;ADgQF;AC7PA;;EACE;ADgQF;AC7PA;EACE;EAQA;EACA;EACA;ADwPF;ACrPA;EACE;EACA;ADuPF;ACpPA;EACE;ADsPF;ACnPA;EACE;EACA;ADqPF;ACjPA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ADmPF","sources":["webpack:///./resources/assets/less/app.less","webpack:///./resources/assets/less/overrides.less"],"sourcesContent":["\nbody {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n font-size: 13px;\n}\n// Moved from default.blade.php\n@media (max-width: 400px) {\n .navbar-left {\n margin: 2px;\n }\n\n .nav::after {\n clear: none;\n }\n}\n\n.skin-blue .main-header .logo {\n background-color: inherit !important;\n}\n.main-header .logo {\n width: 100% !important;\n white-space: nowrap;\n text-align: left;\n display: block;\n clear: both;\n //text-overflow: hidden;\n}\n\n.huge {\n font-size: 40px;\n}\n\n.btn-file {\n position: relative;\n overflow: hidden;\n}\n\n.dropdown-menu > li > a {\n color: #354044;\n}\n\n#sort tr.cansort {\n border-radius: 2px;\n padding: 10px;\n background: #f4f4f4;\n margin-bottom: 3px;\n border-left: 2px solid #e6e7e8;\n color: #444;\n cursor: move;\n}\n\n.user-image-inline {\n float: left;\n width: 25px;\n height: 25px;\n border-radius: 50%;\n margin-right: 10px;\n}\n\n.input-group .input-group-addon {\n background-color: #f4f4f4;\n}\n\na.accordion-header {\n color: #333;\n}\n\n.dynamic-form-row {\n padding: 10px;\n margin: 20px;\n}\n\n.handle {\n padding-left: 10px;\n}\n\n.btn-file input[type=\"file\"] {\n position: absolute;\n top: 0;\n right: 0;\n min-width: 100%;\n min-height: 100%;\n font-size: 100px;\n text-align: right;\n filter: alpha(opacity=0);\n opacity: 0;\n outline: none;\n background: white;\n cursor: inherit;\n display: block;\n}\n\n.main-footer {\n font-size: 13px;\n}\n\n.main-header {\n max-height: 150px;\n}\n\n.navbar-nav > .user-menu > .dropdown-menu {\n width: inherit;\n}\n\n.main-header .logo {\n padding: 0px 5px 0px 15px;\n}\n\n.sidebar-toggle {\n margin-left: -48px;\n z-index: 100;\n background-color: inherit;\n}\n\n.sidebar-toggle-mobile {\n z-index: 100;\n width: 50px;\n padding-top: 10px;\n}\n\n// .skin-blue .main-header .navbar .dropdown-menu li a {\n// //color: inherit;\n// }\n\n.main-header .sidebar-toggle:before {\n content: \"\\f0c9\";\n}\n\n.direct-chat-contacts {\n padding: 10px;\n height: 150px;\n}\n\n.select2-container {\n width: 100%;\n}\n.error input {\n color: #a94442;\n border: 2px solid #a94442 !important;\n}\n\n.error label,\n.alert-msg {\n color: #a94442;\n display: block;\n}\n\n.input-group[class*=\"col-\"] {\n padding-right: 15px;\n padding-left: 15px;\n}\n.control-label.multiline {\n padding-top: 10px;\n}\n\n.btn-outline {\n color: inherit;\n background-color: transparent;\n transition: all 0.5s;\n}\n\n.btn-primary.btn-outline {\n color: #428bca;\n}\n\n.btn-success.btn-outline {\n color: #5cb85c;\n}\n\n.btn-info.btn-outline {\n color: #5bc0de;\n}\n\n.btn-warning.btn-outline {\n color: #f0ad4e;\n}\n\n.btn-danger.btn-outline {\n color: #d9534f;\n}\n\n.btn-primary.btn-outline:hover,\n.btn-success.btn-outline:hover,\n.btn-info.btn-outline:hover,\n.btn-warning.btn-outline:hover,\n.btn-danger.btn-outline:hover {\n color: #fff;\n}\n\n.slideout-menu {\n position: fixed;\n top: 0;\n right: -250px;\n width: 250px;\n height: 100%;\n background: #333;\n z-index: 100;\n margin-top: 100px;\n color: white;\n padding: 10px;\n}\n\n.slideout-menu h3 {\n position: relative;\n padding: 5px 5px;\n color: #fff;\n font-size: 1.2em;\n font-weight: 400;\n border-bottom: 4px solid #222;\n}\n\n.slideout-menu .slideout-menu-toggle {\n position: absolute;\n top: 12px;\n right: 10px;\n display: inline-block;\n padding: 6px 9px 5px;\n font-family: Arial, sans-serif;\n font-weight: bold;\n line-height: 1;\n background: #222;\n color: #999;\n text-decoration: none;\n vertical-align: top;\n}\n\n.slideout-menu .slideout-menu-toggle:hover {\n color: #fff;\n}\n\n.slideout-menu ul {\n list-style: none;\n font-weight: 300;\n border-top: 1px solid #151515;\n border-bottom: 1px solid #454545;\n}\n\n.slideout-menu ul li {\n border-top: 1px solid #454545;\n border-bottom: 1px solid #151515;\n}\n\n.slideout-menu ul li a {\n position: relative;\n display: block;\n padding: 10px;\n color: #999;\n text-decoration: none;\n}\n\n.slideout-menu ul li a:hover {\n background: #000;\n color: #fff;\n}\n\n.slideout-menu ul li a i {\n position: absolute;\n top: 15px;\n right: 10px;\n opacity: 0.5;\n}\n\n.btn-box-tool-lg {\n font-size: 16px;\n color: orange;\n}\n\n/*Form Wizard*/\n.bs-wizard {\n margin-top: 20px;\n border-bottom: solid 1px #e0e0e0;\n padding: 0 0 10px 0;\n}\n.bs-wizard > .bs-wizard-step {\n padding: 0;\n position: relative;\n}\n\n// .bs-wizard > .bs-wizard-step + .bs-wizard-step {}\n\n.bs-wizard > .bs-wizard-step .bs-wizard-stepnum {\n color: #595959;\n font-size: 16px;\n margin-bottom: 5px;\n}\n\n.bs-wizard > .bs-wizard-step .bs-wizard-info {\n color: #999;\n font-size: 14px;\n}\n\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot {\n position: absolute;\n width: 30px;\n height: 30px;\n display: block;\n background: #fbe8aa;\n top: 45px;\n left: 50%;\n margin-top: -15px;\n margin-left: -15px;\n border-radius: 50%;\n}\n\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot:after {\n content: \" \";\n width: 14px;\n height: 14px;\n background: #fbbd19;\n border-radius: 50px;\n position: absolute;\n top: 8px;\n left: 8px;\n}\n\n.bs-wizard > .bs-wizard-step > .progress {\n position: relative;\n border-radius: 0px;\n height: 8px;\n box-shadow: none;\n margin: 20px 0;\n}\n\n.bs-wizard > .bs-wizard-step > .progress > .progress-bar {\n width: 0px;\n box-shadow: none;\n background: #fbe8aa;\n}\n\n.bs-wizard > .bs-wizard-step.complete > .progress > .progress-bar {\n width: 100%;\n}\n\n.bs-wizard > .bs-wizard-step.active > .progress > .progress-bar {\n width: 50%;\n}\n\n.bs-wizard > .bs-wizard-step:first-child.active > .progress > .progress-bar {\n width: 0%;\n}\n\n.bs-wizard > .bs-wizard-step:last-child.active > .progress > .progress-bar {\n width: 100%;\n}\n\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot {\n background-color: #f5f5f5;\n}\n\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot:after {\n opacity: 0;\n}\n\n.bs-wizard > .bs-wizard-step:first-child > .progress {\n left: 50%;\n width: 50%;\n}\n\n.bs-wizard > .bs-wizard-step:last-child > .progress {\n width: 50%;\n}\n\n.bs-wizard > .bs-wizard-step.disabled a.bs-wizard-dot {\n pointer-events: none;\n}\n/*END Form Wizard*/\n\n.left-navblock {\n display: inline-block;\n // float: left;\n text-align: left;\n color: white;\n padding: 0px;\n /* adjust based on your layout */\n}\n\n.skin-blue .main-header .navbar .dropdown-menu li a {\n color: #333;\n}\n\na.logo.no-hover a:hover {\n background-color: transparent;\n}\n\n.index-block {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.index-block:hover{\n overflow: visible;\n white-space: normal;\n height:auto;\n}\n\ninput:required, select:required, textarea:required {\n border-right: 6px solid orange;\n}\n\n.sidebar-menu {\n font-size: 14px;\n white-space: normal;\n}\n\n@media print {\n a[href]:after {\n content: none;\n }\n\n .tab-content > .tab-pane {\n display: block !important;\n opacity: 1 !important;\n visibility: visible !important;\n }\n}\n\nimg.navbar-brand-img,\n.navbar-brand > img {\n float: left;\n padding: 5px 5px 5px 0;\n max-height: 50px;\n}\n\n.input-daterange {\n border-radius: 0px;\n}\n\n.btn.bg-maroon,\n.btn.bg-purple {\n min-width: 90px;\n}\n\n[hidden] {\n display: none !important;\n}\n\n#toolbar {\n margin-top: 10px;\n}\n\n#uploadPreview {\n border-color: grey;\n border-width: 1px;\n border-style: solid;\n}\n\n.icon-med {\n font-size: 20px;\n color: #889195;\n}\n\n#login-logo {\n padding-top: 20px;\n padding-bottom: 10px;\n max-width: 200px;\n}\n\n.left-navblock {\n max-width: 500px;\n}\n\n@import \"overrides.less\";",".skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n\n.logo {\n background-color: inherit;\n}\n.main-header .logo {\n width: 100% !important;\n white-space: nowrap;\n text-align: left;\n display: block;\n clear: both;\n &a:link, a:hover, a:visited {\n color: #fff\n }\n}\n.huge {\n font-size: 40px;\n}\n\n.btn-file {\n position: relative;\n overflow: hidden;\n}\n\n.dropdown-menu>li>a {\n color: #354044;\n}\n\n\n#sort tr.cansort {\n border-radius: 2px;\n padding: 10px;\n background: #f4f4f4;\n margin-bottom: 3px;\n border-inline: 2px solid #e6e7e8;\n color: #444;\n cursor: move;\n}\n\n.user-image-inline {\n float: left;\n width: 25px;\n height: 25px;\n border-radius: 50%;\n margin-right: 10px;\n}\n\n.input-group .input-group-addon {\n background-color: #f4f4f4;\n}\n\na.accordion-header {\n color: #333;\n}\n\n.dynamic-form-row {\n padding: 10px;\n margin: 20px;\n}\n\n\n.handle {\n padding-left: 10px;\n}\n\n.btn-file input[type=file] {\n position: absolute;\n top: 0;\n right: 0;\n min-width: 100%;\n min-height: 100%;\n font-size: 100px;\n text-align: right;\n filter: alpha(opacity=0);\n opacity: 0;\n outline: none;\n background: white;\n cursor: inherit;\n display: block;\n}\n.main-footer {\n font-size: 13px;\n}\n.main-header {\n max-height: 150px;\n}\n\n\n.navbar-nav>.user-menu>.dropdown-menu {\n width: inherit;\n}\n.main-header .logo {\n padding: 0px 5px 0px 15px;\n}\n\n\n.sidebar-toggle {\n margin-left: -48px;\n z-index: 100;\n background-color: inherit;\n}\n\n.sidebar-toggle-mobile {\n z-index: 100;\n width: 50px;\n padding-top: 10px;\n}\n\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n //color: inherit;\n}\n.pull-text-right{\n text-align: right !important;\n}\n\n.main-header .sidebar-toggle:before {\n content: \"\\f0c9\";\n font-weight: 900;\n font-family: 'Font Awesome\\ 5 Free';\n}\n\n.direct-chat-contacts {\n padding: 10px;\n height: 150px;\n}\n\n.select2-container {\n width: 100%;\n}\n\n.error input {\n color: #a94442;\n border: 2px solid #a94442 !important;\n}\n\n.error label, .alert-msg {\n color: #a94442;\n display: block;\n}\n\n.input-group[class*=\"col-\"] {\n padding-right: 15px;\n padding-left: 15px;\n}\n.control-label.multiline {\n padding-top: 10px;\n}\n\n.btn-outline {\n color: inherit;\n background-color: transparent;\n transition: all .5s;\n}\n\n.btn-primary.btn-outline {\n color: #428bca;\n}\n\n.btn-success.btn-outline {\n color: #5cb85c;\n}\n\n.btn-info.btn-outline {\n color: #5bc0de;\n}\n.btn-warning{\n background-color:#f39c12 !important;\n}\n\n.btn-warning.btn-outline {\n color: #f0ad4e;\n}\n\n.btn-danger.btn-outline, a.link-danger:link, a.link-danger:visited, a.link-danger:hover {\n color: #dd4b39;\n}\n\n.btn-primary.btn-outline:hover, .btn-success.btn-outline:hover, .btn-info.btn-outline:hover, .btn-warning.btn-outline:hover, .btn-danger.btn-outline:hover {\n color: #fff;\n}\n\n.slideout-menu {\n position: fixed;\n top: 0;\n right: -250px;\n width: 250px;\n height: 100%;\n background: #333;\n z-index: 100;\n margin-top: 100px;\n color: white;\n padding: 10px;\n}\n.slideout-menu h3 {\n position: relative;\n padding: 5px 5px;\n color: #fff;\n font-size: 1.2em;\n font-weight: 400;\n border-bottom: 4px solid #222;\n}\n.slideout-menu .slideout-menu-toggle {\n position: absolute;\n top: 12px;\n right: 10px;\n display: inline-block;\n padding: 6px 9px 5px;\n font-family: Arial, sans-serif;\n font-weight: bold;\n line-height: 1;\n background: #222;\n color: #999;\n text-decoration: none;\n vertical-align: top;\n}\n.slideout-menu .slideout-menu-toggle:hover {\n color: #fff;\n}\n.slideout-menu ul {\n list-style: none;\n font-weight: 300;\n border-top: 1px solid #151515;\n border-bottom: 1px solid #454545;\n}\n.slideout-menu ul li {\n border-top: 1px solid #454545;\n border-bottom: 1px solid #151515;\n}\n.slideout-menu ul li a {\n position: relative;\n display: block;\n padding: 10px;\n color: #999;\n text-decoration: none;\n}\n.slideout-menu ul li a:hover {\n background: #000;\n color: #fff;\n}\n.slideout-menu ul li a i {\n position: absolute;\n top: 15px;\n right: 10px;\n opacity: .5;\n}\n\n.btn-box-tool-lg {\n font-size: 16px;\n color: orange;\n}\n\n\n\n.bs-wizard {margin-top: 20px;}\n\n/*Form Wizard*/\n.bs-wizard {border-bottom: solid 1px #e0e0e0; padding: 0 0 10px 0;}\n.bs-wizard > .bs-wizard-step {padding: 0; position: relative;}\n.bs-wizard > .bs-wizard-step + .bs-wizard-step {}\n.bs-wizard > .bs-wizard-step .bs-wizard-stepnum {color: #595959; font-size: 16px; margin-bottom: 5px;}\n.bs-wizard > .bs-wizard-step .bs-wizard-info {color: #999; font-size: 14px;}\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot {position: absolute; width: 30px; height: 30px; display: block; background: #fbe8aa; top: 45px; left: 50%; margin-top: -15px; margin-left: -15px; border-radius: 50%;}\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot:after {content: ' '; width: 14px; height: 14px; background: #fbbd19; border-radius: 50px; position: absolute; top: 8px; left: 8px; }\n.bs-wizard > .bs-wizard-step > .progress {position: relative; border-radius: 0px; height: 8px; box-shadow: none; margin: 20px 0;}\n.bs-wizard > .bs-wizard-step > .progress > .progress-bar {width:0px; box-shadow: none; background: #fbe8aa;}\n.bs-wizard > .bs-wizard-step.complete > .progress > .progress-bar {width:100%;}\n.bs-wizard > .bs-wizard-step.active > .progress > .progress-bar {width:50%;}\n.bs-wizard > .bs-wizard-step:first-child.active > .progress > .progress-bar {width:0%;}\n.bs-wizard > .bs-wizard-step:last-child.active > .progress > .progress-bar {width: 100%;}\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot {background-color: #f5f5f5;}\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot:after {opacity: 0;}\n.bs-wizard > .bs-wizard-step:first-child > .progress {left: 50%; width: 50%;}\n.bs-wizard > .bs-wizard-step:last-child > .progress {width: 50%;}\n.bs-wizard > .bs-wizard-step.disabled a.bs-wizard-dot{ pointer-events: none; }\n/*END Form Wizard*/\n\n.left-navblock {\n display: inline-block;\n float: left;\n text-align: left;\n color: white;\n padding: 0px;\n /* adjust based on your layout */\n\n}\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n color: #333;\n}\n\na.logo.no-hover a:hover {\n background-color: transparent;\n}\n\n\ninput:required, select:required {\n border-right: 5px solid orange;\n}\nselect:required + .select2-container .select2-selection, select:required + .select2-container .select2-selection .select2-selection--multiple {\n border-right: 5px solid orange !important;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont,\n \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\",\n \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n font-size: 13px;\n}\n\n.sidebar-menu {\n font-size: 14px;\n white-space: normal;\n}\n\n.modal-warning .modal-help {\n color: #fff8af;\n}\n\n.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading {\n z-index: 0 !important;\n}\n\n@media print {\n\n @page {\n size: A4;\n margin: 0mm;\n }\n\n .tab-content > .tab-pane {\n display: block !important;\n opacity: 1 !important;\n visibility: visible !important;\n }\n\n .img-responsive {\n width: 200px;\n }\n\n html, body {\n width: 1024px;\n }\n\n body {\n margin: 0 auto;\n line-height: 1em;\n word-spacing:1px;\n letter-spacing:0.2px;\n font: 15px \"Times New Roman\", Times, serif;\n background:white;\n color:black;\n width: 100%;\n float: none;\n }\n\n /* avoid page-breaks inside a listingContainer*/\n .listingContainer {\n page-break-inside: avoid;\n }\n\n h1 {\n font: 28px \"Times New Roman\", Times, serif;\n }\n\n h2 {\n font: 24px \"Times New Roman\", Times, serif;\n }\n\n h3 {\n font: 20px \"Times New Roman\", Times, serif;\n }\n\n /* Improve colour contrast of links */\n a:link, a:visited {\n color: #781351\n }\n\n /* URL */\n a:link, a:visited {\n background: transparent;\n color:#333;\n text-decoration:none;\n }\n\n a[href]:after {\n content: \"\" !important;\n }\n\n a[href^=\"http://\"] {\n color:#000;\n }\n\n #header {\n height:75px;\n font-size: 24pt;\n color:black\n }\n\n div.row-new-striped {\n margin: 0px;\n padding: 0px;\n }\n\n .pagination-detail, .fixed-table-toolbar {\n visibility: hidden;\n }\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 .col-sm-pull-3 .col-sm-push-9 {\n float: left;\n }\n\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666666666666%;\n }\n .col-sm-10 {\n width: 83.33333333333334%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666666666666%;\n }\n .col-sm-7 {\n width: 58.333333333333336%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666666666667%;\n }\n .col-sm-4 {\n width: 33.33333333333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.666666666666664%;\n }\n .col-sm-1 {\n width: 8.333333333333332%;\n }\n\n}\n\n\n.select2-selection__choice__remove {\n color: white !important;\n}\n\n.select2-selection--multiple {\n border-color: #d2d6de !important;\n overflow-y: auto;\n}\n\n.select2-selection__choice {\n border-radius: 0px !important;\n}\n\n.select2-search select2-search--inline {\n height: 35px !important;\n float: left;\n margin: 0;\n}\n\n\n\n.select2-results__option {\n padding: 5px;\n user-select: none;\n -webkit-user-select: none;\n margin: 0px;\n}\n\nimg.navbar-brand-img, .navbar-brand>img {\n float: left;\n padding: 5px 5px 5px 0;\n max-height: 50px;\n}\n\n.input-daterange, .input-daterange input:first-child, .input-daterange input:last-child {\n border-radius: 0px !important;\n}\n\n.btn.bg-maroon, .btn.bg-purple{\n min-width:90px;\n}\n\n[hidden] {\n display: none !important;\n}\n\n#toolbar {\n margin-top: 10px;\n}\n\n#uploadPreview {\n border-color: grey;\n border-width: 1px;\n border-style: solid\n}\n\n.icon-med {\n font-size: 14px;\n color: #889195;\n}\n\n#login-logo {\n padding-top: 20px;\n padding-bottom: 10px;\n max-width: 200px\n}\n\n// accessibility skip link\na.skip-main {\n left:-999px;\n position:absolute;\n top:auto;\n width:1px;\n height:1px;\n overflow:hidden;\n z-index:-999;\n}\na.skip-main:focus, a.skip-main:active {\n color: #fff;\n background-color:#000;\n left: auto;\n top: auto;\n width: 30%;\n height: auto;\n overflow:auto;\n margin: 10px 35%;\n padding:5px;\n border-radius: 15px;\n border:4px solid yellow;\n text-align:center;\n font-size:1.2em;\n z-index:999;\n}\n\nh2 {\n font-size: 22px;\n}\n\nh2.task_menu {\n font-size: 14px;\n}\n\nh2 small {\n font-size: 85%;\n}\n\nh3 {\n font-size: 20px;\n}\n\nh4 {\n font-size: 16px;\n}\n\n\n.row-striped {\n vertical-align: top;\n line-height: 2.6;\n padding: 0px;\n margin-left: 20px;\n box-sizing: border-box;\n //border-left: 1px solid #dddddd;\n //border-right: 1px solid #dddddd;\n display: table;\n}\n\n.row-striped .row:nth-of-type(odd) div {\n background-color: #f9f9f9;\n border-top: 1px solid #dddddd;\n display: table-cell;\n word-wrap: break-word;\n}\n\n.row-striped .row:nth-of-type(even) div {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n display: table-cell;\n word-wrap: break-word;\n}\n\n\n.row-new-striped {\n vertical-align: top;\n padding: 3px;\n display: table;\n width: 100%;\n word-wrap: break-word;\n table-layout:fixed;\n}\n\n/**\n* NEW STRIPING\n* This section is for the new row striping for nicer \n* display for non-table data as of v6\n**/\n.row-new-striped > .row:nth-of-type(even) {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n line-height: 1.9;\n display: table-row;\n}\n\n.row-new-striped > .row:nth-of-type(odd) {\n background-color: #F8F8F8;\n border-top: 1px solid #dddddd;\n display: table-row;\n line-height: 1.9;\n padding: 2px;\n}\n\n.row-new-striped div {\n display: table-cell;\n border-top: 1px solid #dddddd;\n padding: 6px;\n}\n\n.row-new-striped div {\n display: table-cell;\n border-top: 1px solid #dddddd;\n padding: 6px;\n}\n\n\n.row-new-striped div[class^=\"col\"]:first-child {\n font-weight: bold;\n}\n\n\n\n/**\n* This just adds a little extra padding on mobile\n**/\n@media only screen and (max-width: 520px) {\n h1.pagetitle {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n\n .firstnav {\n padding-top: 120px !important;\n }\n\n .product {\n width: 400px;\n }\n\n .product img {\n min-width: 400px;\n }\n}\n\n.card-view-title {\n min-width: 40% !important;\n line-height: 3.0!important;\n padding-right: 20px;\n}\n\n.card-view {\n display: table-row;\n flex-direction: column;\n}\n\n// ---------------\n\n/**\n\n COLUMN SELECTOR ICONS\n -----------------------------\n This is kind of weird, but it is necessary to prevent the column-selector code from barfing, since\n any HTML used in the UserPresenter \"title\" attribute breaks the column selector HTML.\n\n Instead, we use CSS to add the icon into the table header, which leaves the column selector\n \"title\" text as-is and hides the icon.\n\n See https://github.com/grokability/snipe-it/issues/7989\n */\nth.css-accessory > .th-inner,\nth.css-accessory-alt > .th-inner,\nth.css-barcode > .th-inner,\nth.css-component > .th-inner,\nth.css-consumable > .th-inner,\nth.css-envelope > .th-inner,\nth.css-house-flag > .th-inner,\nth.css-house-laptop > .th-inner,\nth.css-house-user > .th-inner,\nth.css-license > .th-inner,\nth.css-location > .th-inner,\nth.css-users > .th-inner,\nth.css-currency > .th-inner,\nth.css-history > .th-inner\n{\n font-size: 0px;\n line-height: 0.75 !important;\n text-align: left;\n text-rendering: auto;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n\nth.css-location > .th-inner::before,\nth.css-accessory > .th-inner::before,\nth.css-accessory-alt > .th-inner::before,\nth.css-barcode > .th-inner::before,\nth.css-component > .th-inner::before,\nth.css-consumable > .th-inner::before,\nth.css-envelope > .th-inner::before,\nth.css-house-flag > .th-inner::before,\nth.css-house-laptop > .th-inner::before,\nth.css-house-user > .th-inner::before,\nth.css-license > .th-inner::before,\nth.css-location > .th-inner::before,\nth.css-padlock > .th-inner::before,\nth.css-users > .th-inner::before,\nth.css-currency > .th-inner::before,\nth.css-history > .th-inner::before\n{\n display: inline-block;\n font-size: 20px;\n font-family: \"Font Awesome 5 Free\";\n font-weight: 900;\n}\n\n/**\nBEGIN ICON TABLE HEADERS\nSet the font-weight css property as 900 (For Solid), 400 (Regular or Brands), 300 (Light for pro icons).\n**/\nth.css-barcode > .th-inner::before\n{\n content: \"\\f02a\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-license > .th-inner::before\n{\n content: \"\\f0c7\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-consumable > .th-inner::before\n{\n content: \"\\f043\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-envelope > .th-inner::before\n{\n content: \"\\f0e0\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-accessory > .th-inner::before\n{\n content: \"\\f11c\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-users > .th-inner::before {\n content: \"\\f0c0\"; font-family: \"Font Awesome 5 Free\"; font-size: 15px;\n}\n\nth.css-location > .th-inner::before {\n content: \"\\f3c5\"; font-family: \"Font Awesome 5 Free\"; font-size: 19px; margin-bottom: 0px;\n}\n\nth.css-component > .th-inner::before\n{\n content: \"\\f0a0\"; font-family: \"Font Awesome 5 Free\"; font-weight: 500;\n}\n\nth.css-padlock > .th-inner::before\n{\n content: \"\\f023\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-house-user > .th-inner::before {\n content: \"\\e1b0\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-house-flag > .th-inner::before {\n content: \"\\e50d\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-house-laptop > .th-inner::before {\n content: \"\\e066\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-accessory-alt > .th-inner::before {\n content: \"\\f11c\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-currency > .th-inner::before {\n content: \"\\24\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-history > .th-inner::before {\n content: \"\\f1da\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\n\n.small-box .inner {\n padding-left: 15px;\n padding-right: 15px;\n padding-top: 15px;\n color: #fff;\n}\n\n\n.small-box > a:link, .small-box > a:visited, .small-box > a:hover {\n color: #fff;\n}\n\n.select2-container--default .select2-selection--single, .select2-selection .select2-selection--single {\n border: 1px solid #d2d6de;\n border-radius: 0;\n padding: 6px 12px;\n height: 34px;\n}\n\n.form-group.has-error label, .form-group.has-error .help-block {\n color: #a94442;\n}\n\n.select2-container--default .select2-selection--multiple {\n border-radius: 0px;\n}\n\n@media screen and (max-width: 511px){\n .tab-content .tab-pane .alert-block {\n margin-top: 120px\n }\n .sidebar-menu{\n margin-top:160px;\n }\n}\n@media screen and (max-width: 912px) and (min-width: 512px){\n .sidebar-menu {\n margin-top:100px\n }\n .navbar-custom-menu > .navbar-nav > li.dropdown.user.user-menu {\n float:right;\n }\n .navbar-custom-menu > .navbar-nav > li > .dropdown-menu {\n margin-right:-39px;\n }\n}\n\n@media screen and (max-width: 1268px) and (min-width: 912px){\n .sidebar-menu {\n margin-top:50px\n }\n}\n@media screen and (max-width: 992px){\n .info-stack-container {\n flex-direction: column;\n }\n .col-md-3.col-xs-12.col-sm-push-9.info-stack{\n left:auto;\n order:1;\n }\n .col-md-9.col-xs-12.col-sm-pull-3.info-stack{\n right:auto;\n order:2;\n }\n .info-stack-container > .col-md-9.col-xs-12.col-sm-pull-3.info-stack > .row-new-striped > .row > .col-sm-2{\n width:auto;\n float:none;\n }\n}\n@media screen and (max-width: 992px){\n .row-new-striped div{\n width:100%;\n }\n}\n\n@media screen and (max-width: 1318px) and (min-width: 1200px){\n .admin.box{\n height:170px;\n }\n}\n@media screen and (max-width: 1494px) and (min-width: 1200px){\n .dashboard.small-box{\n white-space: nowrap;\n text-overflow: ellipsis;\n max-width: 188px;\n display: block;\n overflow: hidden;\n }\n}\n\n/** Form-stuff overrides for checkboxes and stuff **/\n\nlabel.form-control {\n display: grid;\n grid-template-columns: 1.8em auto;\n gap: 0.5em;\n border: 0px;\n padding-left: 0px;\n background-color: inherit;\n color: inherit;\n font-size: inherit;\n font-weight: inherit;\n}\n\nlabel.form-control--disabled {\n color: #959495;\n cursor: not-allowed;\n}\n\n\n/** --------------------------------------- **/\n/** Start checkbox styles to replace iCheck **/\n/** --------------------------------------- **/\ninput[type=\"checkbox\"] {\n /* Add if not using autoprefixer */\n -webkit-appearance: none;\n appearance: none;\n /* For iOS < 15 to remove gradient background */\n background-color: #fff;\n /* Not removed via appearance */\n margin: 0;\n font: inherit;\n color: #959495;\n width: 1.8em;\n height: 1.8em;\n border: 0.05em solid;\n border-radius: 0em;\n transform: translateY(-0.075em);\n display: grid;\n place-content: center;\n /*Windows High Contrast Mode*/\n}\n\n/** This sets the display of a checkbox, and what the \"fill\" checkmark should look like */\n\ninput[type=\"checkbox\"]::before {\n\n /** If you want to use the non-checkbox, filled square, use this instead **/\n content: \"\";\n width: 1em;\n height: 1em;\n transform: scale(0);\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em rgb(211, 211, 211);\n\n content: \"\";\n width: 1em;\n height: 1em;\n clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);\n transform: scale(0);\n transform-origin: bottom left;\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em #428bca;\n /* Windows High Contrast Mode */\n background-color: CanvasText;\n}\n\n/** This sets the size of the scale up for the shape we defined above **/\ninput[type=\"checkbox\"]:checked::before {\n transform: scale(1);\n}\n\n/** This sets the scale and color of the DISABLED but CHECKED checkbox */\ninput[type=checkbox]:disabled::before, input[type=radio]:disabled::before {\n content: \"\";\n width: 1em;\n height: 1em;\n transform: scale(1);\n box-shadow: inset 1em 1em rgb(211, 211, 211);\n}\n\n/* This sets the scale and style of a DISABLED checkbox that is NOT checked */\ninput[type=checkbox]:disabled:not(:checked)::before, input[type=radio]:disabled:not(:checked)::before {\n content: \"\";\n transform: scale(0);\n cursor: not-allowed;\n pointer-events:none;\n}\n\n/** this is the color of the checkbox and content on a disabled, checked box **/\ninput[type=checkbox]:disabled, input[type=radio]:disabled {\n --form-control-color: rgb(211, 211, 211);\n color: #959495;\n cursor: not-allowed;\n pointer-events:none;\n}\n\n\n/** Radio styles to replace iCheck **/\n\ninput[type=\"radio\"] {\n appearance: none;\n background-color: #fff;\n margin: 0;\n font: inherit;\n color: #959495;\n width: 1.8em;\n height: 1.8em;\n border: 0.05em solid;\n border-radius: 50%;\n transform: translateY(-0.075em);\n display: grid;\n place-content: center;\n}\n\ninput[type=\"radio\"]::before {\n content: \"\";\n width: 1em;\n height: 1em;\n border-radius: 50%;\n transform: scale(0);\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em #428bca;\n}\n\ninput[type=\"radio\"]:checked::before {\n transform: scale(1);\n}\n\n\n/**\n* This addresses the column selector in bootstrap-table. Without these two lines, the\n* checkbox and the with the label text that BS tables generates will\n* end up on two different lines and it looks assy.\n */\n.dropdown-item-marker input[type=checkbox] {\n font-size: 10px;\n}\n\n.bootstrap-table .fixed-table-toolbar li.dropdown-item-marker label {\n font-weight: normal;\n display: grid;\n grid-template-columns: .1em auto;\n gap: 1.5em;\n}\n\n.container.row-striped .col-md-6 {\n overflow-wrap:anywhere;\n}\n\n.nav-tabs-custom > .nav-tabs > li {\n z-index: 1;\n}\n\n.select2-container .select2-search--inline .select2-search__field{\n padding-left:15px;\n}\n\n.nav-tabs-custom > .nav-tabs > li.active {\n font-weight: bold;\n}\n\n/** --------------------------------------- **/\n/** End checkbox styles to replace iCheck **/\n/** --------------------------------------- **/\n\n/**\n/** Separator styles with text in the middle. Currently only used by the login page but\n/** could be used elsewhere.\n */\n\n.separator {\n display: flex;\n align-items: center;\n text-align: center;\n padding-top: 20px;\n color: #959495;\n}\n\n.separator::before,\n.separator::after {\n content: '';\n flex: 1;\n border-bottom: 1px solid #959495;\n}\n\n.separator:not(:empty)::before {\n margin-right: .25em;\n}\n\n.separator:not(:empty)::after {\n margin-left: .25em;\n}\n.datepicker.dropdown-menu {\n z-index: 1030 !important;\n}\n\n.sidebar-menu > li .badge {\n margin-top: 0px;\n filter: brightness(70%);\n font-size: 70%;\n}\n\n/** this is needed to override ekko-lightboxes card view styles **/\n.bootstrap-table .fixed-table-container .table tbody tr .card-view {\n display: table-row !important;\n}\n\n.form-control-static {\n padding-top: 0px;\n}\n\n\ntd.text-right.text-padding-number-cell {\n padding-right: 30px !important;\n white-space: nowrap;\n}\n\nth.text-right.text-padding-number-footer-cell {\n padding-right: 20px !important;\n white-space: nowrap;\n}\n\ncode.single-line {\n white-space: pre-wrap;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 1;\n overflow: hidden;\n max-width: 400px;\n}\n\np.monospace, span.monospace {\n font-family: monospace, monospace;\n}\n\nlegend.highlight {\n background: repeating-linear-gradient(\n 45deg,\n #222d32,\n #222d32 10px,\n #444 10px,\n #444 11px\n );\n\n color: #fff;\n font-size: 18px;\n padding: 6px 6px 6px 10px;\n}\n\nlegend.highlight a {\n color: #fff;\n cursor: pointer;\n}\n\nfieldset.bottom-padded {\n padding-bottom: 20px;\n}\n\ncaption.tableCaption {\n font-size: 18px;\n padding-left: 8px;\n}\n\n// via https://github.com/grokability/snipe-it/issues/11754\n.sidebar-toggle.btn {\n border-radius: 3px;\n box-shadow: none;\n border-top: 0px solid transparent;\n border-bottom: 0px solid transparent;\n padding-left: 15px;\n padding-right: 15px;\n padding-top: 12px;\n padding-bottom: 12px;\n margin-left: -47px;\n margin-top: 2px;\n}\n"],"names":[],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"css/build/app.css","mappings":"AACA;EACE;EAGA;AAFF;AAKA;EACE;IACE;EAHF;EAMA;IACE;EAJF;AACF;AAOA;EACE;AALF;AAOA;EACE;EACA;EACA;EACA;EACA;AALF;AASA;EACE;AAPF;AAUA;EACE;EACA;AARF;AAWA;EACE;AATF;AAYA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AAVF;AAaA;EACE;EACA;EACA;EACA;EACA;AAXF;AAcA;EACE;AAZF;AAeA;EACE;AAbF;AAgBA;EACE;EACA;AAdF;AAiBA;EACE;AAfF;AAkBA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAhBF;AAmBA;EACE;AAjBF;AAoBA;EACE;AAlBF;AAqBA;EACE;AAnBF;AAsBA;EACE;AApBF;AAuBA;EACE;EACA;EACA;AArBF;AAwBA;EACE;EACA;EACA;AAtBF;AA6BA;EACE;AA3BF;AA8BA;EACE;EACA;AA5BF;AA+BA;EACE;AA7BF;AA+BA;EACE;EACA;AA7BF;AAgCA;;EAEE;EACA;AA9BF;AAiCA;EACE;EACA;AA/BF;AAiCA;EACE;AA/BF;AAkCA;EACE;EACA;EACA;AAhCF;AAmCA;EACE;AAjCF;AAoCA;EACE;AAlCF;AAqCA;EACE;AAnCF;AAsCA;EACE;AApCF;AAuCA;EACE;AArCF;AAwCA;;;;;EAKE;AAtCF;AAyCA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAvCF;AA0CA;EACE;EACA;EACA;EACA;EACA;EACA;AAxCF;AA2CA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAzCF;AA4CA;EACE;AA1CF;AA6CA;EACE;EACA;EACA;EACA;AA3CF;AA8CA;EACE;EACA;AA5CF;AA+CA;EACE;EACA;EACA;EACA;EACA;AA7CF;AAgDA;EACE;EACA;AA9CF;AAiDA;EACE;EACA;EACA;EACA;AA/CF;AAkDA;EACE;EACA;AAhDF;AACA,cAAc;AAmDd;EACE;EACA;EACA;AAjDF;AAmDA;EACE;EACA;AAjDF;AAsDA;EACE;EACA;EACA;AApDF;AAuDA;EACE;EACA;AArDF;AAwDA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAtDF;AAyDA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAvDF;AA0DA;EACE;EACA;EACA;EACA;EACA;AAxDF;AA2DA;EACE;EACA;EACA;AAzDF;AA4DA;EACE;AA1DF;AA6DA;EACE;AA3DF;AA8DA;EACE;AA5DF;AA+DA;EACE;AA7DF;AAgEA;EACE;AA9DF;AAiEA;EACE;AA/DF;AAkEA;EACE;EACA;AAhEF;AAmEA;EACE;AAjEF;AAoEA;EACE;AAlEF;AACA,kBAAkB;AAqElB;EACE;EAEA;EACA;EACA;EApEA,gCAAgC;AAClC;AAuEA;EACE;AArEF;AAwEA;EACE;EACA;EACA;AAtEF;AAwEA;EACE;EACA;EACA;AAtEF;AAyEA;;;EACE;AArEF;AAwEA;EACE;EACA;AAtEF;AAyEA;EACE;IACE;EAvEF;EA0EA;IACE;IACA;IACA;EAxEF;AACF;AA2EA;;EAEE;EACA;EACA;AAzEF;AA4EA;EACE;AA1EF;AA6EA;;EAEE;AA3EF;AA8EA;EACE;AA5EF;AA+EA;EACE;AA7EF;AAgFA;EACE;EACA;EACA;AA9EF;AAiFA;EACE;EACA;AA/EF;AAkFA;EACE;EACA;EACA;AAhFF;AAmFA;EACE;AAjFF;ACvXA;EAkBE;ADwWF;ACtWA;EACE;EACA;EACA;EACA;EACA;ADwWF;ACvWE;;;EACE;AD2WJ;ACxWA;EACE;AD0WF;ACvWA;EACE;EACA;ADyWF;ACtWA;EACE;ADwWF;ACpWA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;ADsWF;ACnWA;EACE;EACA;EACA;EACA;EACA;ADqWF;AClWA;EACE;ADoWF;ACjWA;EACE;ADmWF;AChWA;EACE;EACA;ADkWF;AC9VA;EACE;ADgWF;AC7VA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AD+VF;AC7VA;EACE;AD+VF;AC7VA;EACE;AD+VF;AC3VA;EACE;AD6VF;AC3VA;EACE;AD6VF;ACzVA;EACE;EACA;EACA;AD2VF;ACxVA;EACE;EACA;EACA;AD0VF;ACnUA;EACE;ADqUF;AClUA;EACE;EACA;EACA;ADoUF;ACjUA;EACE;EACA;ADmUF;AChUA;EACE;ADkUF;AC/TA;EACE;EACA;ADiUF;AC9TA;;EACE;EACA;ADiUF;AC9TA;EACE;EACA;ADgUF;AC9TA;EACE;ADgUF;AC7TA;EACE;EACA;EACA;AD+TF;AC5TA;EACE;AD8TF;AC3TA;EACE;AD6TF;AC1TA;EACE;AD4TF;AC1TA;EACE;AD4TF;ACzTA;EACE;AD2TF;ACxTA;;;;EACE;AD6TF;AC1TA;;;;;EACE;ADgUF;AC7TA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AD+TF;AC7TA;EACE;EACA;EACA;EACA;EACA;EACA;AD+TF;AC7TA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AD+TF;AC7TA;EACE;AD+TF;AC7TA;EACE;EACA;EACA;EACA;AD+TF;AC7TA;EACE;EACA;AD+TF;AC7TA;EACE;EACA;EACA;EACA;EACA;AD+TF;AC7TA;EACE;EACA;AD+TF;AC7TA;EACE;EACA;EACA;EACA;AD+TF;AC5TA;EACE;EACA;AD8TF;ACzTA;EAAY;AD4TZ;AACA,cAAc;AC1Td;EAAY;EAAkC;AD8T9C;AC7TA;EAA8B;EAAY;ADiU1C;AC/TA;EAAiD;EAAgB;EAAiB;ADoUlF;ACnUA;EAA8C;EAAa;ADuU3D;ACtUA;EAA+C;EAAoB;EAAa;EAAc;EAAgB;EAAqB;EAAW;EAAW;EAAmB;EAAoB;ADkVhM;ACjVA;EAAqD;EAAc;EAAa;EAAc;EAAqB;EAAqB;EAAoB;EAAU;AD2VtK;AC1VA;EAA0C;EAAoB;EAAoB;EAAa;EAAkB;ADiWjH;AChWA;EAA0D;EAAW;EAAkB;ADqWvF;ACpWA;EAAmE;ADuWnE;ACtWA;EAAiE;ADyWjE;ACxWA;EAA6E;AD2W7E;AC1WA;EAA4E;AD6W5E;AC5WA;EAAwD;AD+WxD;AC9WA;EAA8D;ADiX9D;AChXA;EAAuD;EAAW;ADoXlE;ACnXA;EAAsD;ADsXtD;ACrXA;EAAuD;ADwXvD;AACA,kBAAkB;ACtXlB;EACE;EACA;EACA;EACA;EACA;EDwXA,gCAAgC;AAClC;ACrXA;EAkBE;ADsWF;ACnWA;EACE;ADqWF;ACjWA;;EACE;ADoWF;AClWA;;EACE;ADqWF;AClWA;EACE;EAIA;ADiWF;AC9VA;EACE;EACA;ADgWF;AC7VA;EACE;AD+VF;AC5VA;EACE;AD8VF;AC3VA;EAEE;IACE;IACA;ED4VF;ECzVA;IACE;IACA;IACA;ED2VF;ECxVA;IACE;ED0VF;ECvVA;;IACE;ED0VF;ECvVA;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;EDyVF;EACA,+CAA+C;ECtV/C;IACE;EDwVF;ECrVA;IACE;EDuVF;ECpVA;IACE;EDsVF;ECnVA;IACE;EDqVF;EACA,qCAAqC;EClVrC;;IACE;EDqVF;EACA,QAAQ;EClVR;;IACE;IACA;IACA;EDqVF;EClVA;IACE;EDoVF;ECjVA;IACE;EDmVF;EChVA;IACE;IACA;IACA;EDkVF;EC/UA;IACE;IACA;EDiVF;EC9UA;;IACE;EDiVF;EC/UA;;;;;;;;;;;;IACE;ED4VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;ECzVA;IACE;ED2VF;AACF;ACtVA;EACE;ADwVF;ACrVA;EACI;EACA;ADuVJ;ACpVA;EACE;ADsVF;ACnVA;EACE;EACA;EACA;ADqVF;AChVA;EACE;EACA;OAAA;EACA;EACA;ADkVF;AC/UA;;EACE;EACA;EACA;ADkVF;AC/UA;;;EACE;ADmVF;AChVA;;EACE;ADmVF;AChVA;EACE;ADkVF;AC/UA;EACE;ADiVF;AC9UA;EACE;EACA;EACA;ADgVF;AC7UA;EACE;EACA;AD+UF;AC5UA;EACE;EACA;EACA;AD8UF;AC1UA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AD4UF;AC1UA;;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AD6UF;AC1UA;EACE;AD4UF;ACzUA;EACE;AD2UF;ACxUA;EACE;AD0UF;ACvUA;EACE;ADyUF;ACtUA;EACE;ADwUF;ACpUA;EACE;EACA;EACA;EACA;EACA;EAGA;ADoUF;ACjUA;EACE;EACA;EACA;EACA;ADmUF;AChUA;EACE;EACA;EACA;EACA;ADkUF;AC9TA;EACE;EACA;EACA;EACA;EACA;EACA;ADgUF;AACA;;;;EAIE;AC7TF;EACE;EACA;EACA;EACA;AD+TF;AC5TA;EACE;EACA;EACA;EACA;EACA;AD8TF;AC3TA;EACE;EACA;EACA;AD6TF;AC1TA;EACE;EACA;EACA;AD4TF;ACxTA;EACE;AD0TF;AACA;;EAEE;ACrTF;EACE;IACE;IACA;EDuTF;ECpTA;IACE;EDsTF;ECnTA;IACE;EDqTF;EClTA;IACE;EDoTF;AACF;ACjTA;EACE;EACA;EACA;ADmTF;AChTA;EACE;EACA;ADkTF;AACA;;;;;;;;;;;EAWE;AC7SF;;;;;;;;;;;;;;;EAgBE;EACA;EACA;EACA;EACA;EACA;AD8SF;AC1SA;;;;;;;;;;;;;;;;EAiBE;EACA;EACA;EACA;AD2SF;AACA;;;EAGE;ACxSF;EAEE;EAAkB;EAAoC;AD2SxD;ACxSA;EAEE;EAAkB;EAAoC;AD2SxD;ACxSA;EAEE;EAAkB;EAAoC;AD2SxD;ACxSA;EAEE;EAAkB;EAAoC;AD2SxD;ACxSA;EAEE;EAAkB;EAAoC;AD2SxD;ACxSA;EACE;EAAkB;EAAoC;AD4SxD;ACzSA;EACE;EAAkB;EAAoC;EAAiB;AD8SzE;AC3SA;EAEE;EAAkB;EAAoC;AD8SxD;AC3SA;EAEE;EAAkB;EAClB;EACA;AD6SF;AC1SA;EACE;EACA;EACA;EACA;AD4SF;AC1SA;EACE;EACA;EACA;EACA;AD4SF;AC1SA;EACE;EACA;EACA;EACA;AD4SF;AC1SA;EACE;EACA;EACA;EACA;AD4SF;ACzSA;EACE;EACA;EACA;EACA;AD2SF;ACxSA;EACE;EACA;EACA;EACA;AD0SF;ACvSA;EACE;EACA;EACA;EACA;ADySF;ACrSA;EACE;EACA;EACA;EACA;ADuSF;ACnSA;;;EACE;ADuSF;ACpSA;;EACE;EACA;EACA;EACA;ADuSF;ACpSA;;EACE;ADuSF;ACpSA;EACE;ADsSF;ACnSA;EACE;IACE;EDqSF;ECnSA;IACE;EDqSF;AACF;ACnSA;EACE;IACE;EDqSF;ECnSA;IACE;EDqSF;ECnSA;IACE;EDqSF;AACF;AClSA;EACE;IACE;EDoSF;AACF;AClSA;EACE;IACE;EDoSF;EClSA;IACE;IACA;EDoSF;EClSA;IACE;IACA;EDoSF;EClSA;IACE;IACA;EDoSF;AACF;AClSA;EACE;IACE;EDoSF;AACF;ACjSA;EACE;IACE;EDmSF;AACF;ACjSA;EACE;IACE;IACA;IACA;IACA;IACA;EDmSF;AACF;AACA,oDAAoD;AC/RpD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ADiSF;AC9RA;EACE;EACA;ADgSF;AACA,8CAA8C;AAC9C,8CAA8C;AAC9C,8CAA8C;AC5R9C;ED8RE,kCAAkC;EC5RlC;EACA;OAAA;ED8RA,+CAA+C;EC5R/C;ED8RA,+BAA+B;EC5R/B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ED8RA,6BAA6B;AAC/B;AACA,yFAAyF;AC1RzF;ED4RE,2EAA2E;ECpR3E;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EDqRA,+BAA+B;ECnR/B;ADqRF;AACA,wEAAwE;AClRxE;EACE;ADoRF;AACA,wEAAwE;ACjRxE;;EACE;EACA;EACA;EACA;EACA;ADoRF;AACA,6EAA6E;ACjR7E;;EACE;EACA;EACA;EACA;ADoRF;AACA,+EAA+E;ACjR/E;;EACE;EACA;EACA;EACA;ADoRF;AACA,qCAAqC;AC/QrC;EACE;KAAA;UAAA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;ADiRF;AC9QA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;ADgRF;AC7QA;EACE;AD+QF;AACA;;;;EAIE;AC3QF;EACE;AD6QF;AC1QA;EACE;EACA;EACA;EACA;AD4QF;ACzQA;EACE;AD2QF;ACxQA;EACE;AD0QF;ACvQA;EACE;ADyQF;ACtQA;EACE;ADwQF;AACA,8CAA8C;AAC9C,8CAA8C;AAC9C,8CAA8C;AAC9C;;;EAGE;ACnQF;EACE;EACA;EACA;EACA;EACA;ADqQF;AClQA;;EAEE;EACA;EACA;ADoQF;ACjQA;EACE;ADmQF;AChQA;EACE;ADkQF;AChQA;EACE;ADkQF;AC/PA;EACE;EACA;EACA;ADiQF;AACA,kEAAkE;AC9PlE;EACE;ADgQF;AC7PA;EACE;AD+PF;AC3PA;EACE;EACA;AD6PF;AC1PA;EACE;EACA;AD4PF;ACzPA;EACE;EACA;EACA;EACA;EACA;EACA;AD2PF;ACxPA;;EACE;AD2PF;ACxPA;EACE;EAQA;EACA;EACA;ADmPF;AChPA;EACE;EACA;ADkPF;AC/OA;EACE;ADiPF;AC9OA;EACE;EACA;ADgPF;AC5OA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AD8OF;AC5OA;;;;;EAKE;AD8OF;AC3OA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AD6OF;AC1OA;EACE;AD4OF","sources":["webpack:///./resources/assets/less/app.less","webpack:///./resources/assets/less/overrides.less"],"sourcesContent":["\nbody {\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n font-size: 13px;\n}\n// Moved from default.blade.php\n@media (max-width: 400px) {\n .navbar-left {\n margin: 2px;\n }\n\n .nav::after {\n clear: none;\n }\n}\n\n.skin-blue .main-header .logo {\n background-color: inherit !important;\n}\n.main-header .logo {\n width: 100% !important;\n white-space: nowrap;\n text-align: left;\n display: block;\n clear: both;\n //text-overflow: hidden;\n}\n\n.huge {\n font-size: 40px;\n}\n\n.btn-file {\n position: relative;\n overflow: hidden;\n}\n\n.dropdown-menu > li > a {\n color: #354044;\n}\n\n#sort tr.cansort {\n border-radius: 2px;\n padding: 10px;\n background: #f4f4f4;\n margin-bottom: 3px;\n border-left: 2px solid #e6e7e8;\n color: #444;\n cursor: move;\n}\n\n.user-image-inline {\n float: left;\n width: 25px;\n height: 25px;\n border-radius: 50%;\n margin-right: 10px;\n}\n\n.input-group .input-group-addon {\n background-color: #f4f4f4;\n}\n\na.accordion-header {\n color: #333;\n}\n\n.dynamic-form-row {\n padding: 10px;\n margin: 20px;\n}\n\n.handle {\n padding-left: 10px;\n}\n\n.btn-file input[type=\"file\"] {\n position: absolute;\n top: 0;\n right: 0;\n min-width: 100%;\n min-height: 100%;\n font-size: 100px;\n text-align: right;\n filter: alpha(opacity=0);\n opacity: 0;\n outline: none;\n background: white;\n cursor: inherit;\n display: block;\n}\n\n.main-footer {\n font-size: 13px;\n}\n\n.main-header {\n max-height: 150px;\n}\n\n.navbar-nav > .user-menu > .dropdown-menu {\n width: inherit;\n}\n\n.main-header .logo {\n padding: 0px 5px 0px 15px;\n}\n\n.sidebar-toggle {\n margin-left: -48px;\n z-index: 100;\n background-color: inherit;\n}\n\n.sidebar-toggle-mobile {\n z-index: 100;\n width: 50px;\n padding-top: 10px;\n}\n\n// .skin-blue .main-header .navbar .dropdown-menu li a {\n// //color: inherit;\n// }\n\n.main-header .sidebar-toggle:before {\n content: \"\\f0c9\";\n}\n\n.direct-chat-contacts {\n padding: 10px;\n height: 150px;\n}\n\n.select2-container {\n width: 100%;\n}\n.error input {\n color: #a94442;\n border: 2px solid #a94442 !important;\n}\n\n.error label,\n.alert-msg {\n color: #a94442;\n display: block;\n}\n\n.input-group[class*=\"col-\"] {\n padding-right: 15px;\n padding-left: 15px;\n}\n.control-label.multiline {\n padding-top: 10px;\n}\n\n.btn-outline {\n color: inherit;\n background-color: transparent;\n transition: all 0.5s;\n}\n\n.btn-primary.btn-outline {\n color: #428bca;\n}\n\n.btn-success.btn-outline {\n color: #5cb85c;\n}\n\n.btn-info.btn-outline {\n color: #5bc0de;\n}\n\n.btn-warning.btn-outline {\n color: #f0ad4e;\n}\n\n.btn-danger.btn-outline {\n color: #d9534f;\n}\n\n.btn-primary.btn-outline:hover,\n.btn-success.btn-outline:hover,\n.btn-info.btn-outline:hover,\n.btn-warning.btn-outline:hover,\n.btn-danger.btn-outline:hover {\n color: #fff;\n}\n\n.slideout-menu {\n position: fixed;\n top: 0;\n right: -250px;\n width: 250px;\n height: 100%;\n background: #333;\n z-index: 100;\n margin-top: 100px;\n color: white;\n padding: 10px;\n}\n\n.slideout-menu h3 {\n position: relative;\n padding: 5px 5px;\n color: #fff;\n font-size: 1.2em;\n font-weight: 400;\n border-bottom: 4px solid #222;\n}\n\n.slideout-menu .slideout-menu-toggle {\n position: absolute;\n top: 12px;\n right: 10px;\n display: inline-block;\n padding: 6px 9px 5px;\n font-family: Arial, sans-serif;\n font-weight: bold;\n line-height: 1;\n background: #222;\n color: #999;\n text-decoration: none;\n vertical-align: top;\n}\n\n.slideout-menu .slideout-menu-toggle:hover {\n color: #fff;\n}\n\n.slideout-menu ul {\n list-style: none;\n font-weight: 300;\n border-top: 1px solid #151515;\n border-bottom: 1px solid #454545;\n}\n\n.slideout-menu ul li {\n border-top: 1px solid #454545;\n border-bottom: 1px solid #151515;\n}\n\n.slideout-menu ul li a {\n position: relative;\n display: block;\n padding: 10px;\n color: #999;\n text-decoration: none;\n}\n\n.slideout-menu ul li a:hover {\n background: #000;\n color: #fff;\n}\n\n.slideout-menu ul li a i {\n position: absolute;\n top: 15px;\n right: 10px;\n opacity: 0.5;\n}\n\n.btn-box-tool-lg {\n font-size: 16px;\n color: orange;\n}\n\n/*Form Wizard*/\n.bs-wizard {\n margin-top: 20px;\n border-bottom: solid 1px #e0e0e0;\n padding: 0 0 10px 0;\n}\n.bs-wizard > .bs-wizard-step {\n padding: 0;\n position: relative;\n}\n\n// .bs-wizard > .bs-wizard-step + .bs-wizard-step {}\n\n.bs-wizard > .bs-wizard-step .bs-wizard-stepnum {\n color: #595959;\n font-size: 16px;\n margin-bottom: 5px;\n}\n\n.bs-wizard > .bs-wizard-step .bs-wizard-info {\n color: #999;\n font-size: 14px;\n}\n\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot {\n position: absolute;\n width: 30px;\n height: 30px;\n display: block;\n background: #fbe8aa;\n top: 45px;\n left: 50%;\n margin-top: -15px;\n margin-left: -15px;\n border-radius: 50%;\n}\n\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot:after {\n content: \" \";\n width: 14px;\n height: 14px;\n background: #fbbd19;\n border-radius: 50px;\n position: absolute;\n top: 8px;\n left: 8px;\n}\n\n.bs-wizard > .bs-wizard-step > .progress {\n position: relative;\n border-radius: 0px;\n height: 8px;\n box-shadow: none;\n margin: 20px 0;\n}\n\n.bs-wizard > .bs-wizard-step > .progress > .progress-bar {\n width: 0px;\n box-shadow: none;\n background: #fbe8aa;\n}\n\n.bs-wizard > .bs-wizard-step.complete > .progress > .progress-bar {\n width: 100%;\n}\n\n.bs-wizard > .bs-wizard-step.active > .progress > .progress-bar {\n width: 50%;\n}\n\n.bs-wizard > .bs-wizard-step:first-child.active > .progress > .progress-bar {\n width: 0%;\n}\n\n.bs-wizard > .bs-wizard-step:last-child.active > .progress > .progress-bar {\n width: 100%;\n}\n\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot {\n background-color: #f5f5f5;\n}\n\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot:after {\n opacity: 0;\n}\n\n.bs-wizard > .bs-wizard-step:first-child > .progress {\n left: 50%;\n width: 50%;\n}\n\n.bs-wizard > .bs-wizard-step:last-child > .progress {\n width: 50%;\n}\n\n.bs-wizard > .bs-wizard-step.disabled a.bs-wizard-dot {\n pointer-events: none;\n}\n/*END Form Wizard*/\n\n.left-navblock {\n display: inline-block;\n // float: left;\n text-align: left;\n color: white;\n padding: 0px;\n /* adjust based on your layout */\n}\n\na.logo.no-hover a:hover {\n background-color: transparent;\n}\n\n.index-block {\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n.index-block:hover{\n overflow: visible;\n white-space: normal;\n height:auto;\n}\n\ninput:required, select:required, textarea:required {\n border-right: 6px solid orange;\n}\n\n.sidebar-menu {\n font-size: 14px;\n white-space: normal;\n}\n\n@media print {\n a[href]:after {\n content: none;\n }\n\n .tab-content > .tab-pane {\n display: block !important;\n opacity: 1 !important;\n visibility: visible !important;\n }\n}\n\nimg.navbar-brand-img,\n.navbar-brand > img {\n float: left;\n padding: 5px 5px 5px 0;\n max-height: 50px;\n}\n\n.input-daterange {\n border-radius: 0px;\n}\n\n.btn.bg-maroon,\n.btn.bg-purple {\n min-width: 90px;\n}\n\n[hidden] {\n display: none !important;\n}\n\n#toolbar {\n margin-top: 10px;\n}\n\n#uploadPreview {\n border-color: grey;\n border-width: 1px;\n border-style: solid;\n}\n\n.icon-med {\n font-size: 20px;\n color: #889195;\n}\n\n#login-logo {\n padding-top: 20px;\n padding-bottom: 10px;\n max-width: 200px;\n}\n\n.left-navblock {\n max-width: 500px;\n}\n\n@import \"overrides.less\";",".skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n\n.logo {\n background-color: inherit;\n}\n.main-header .logo {\n width: 100% !important;\n white-space: nowrap;\n text-align: left;\n display: block;\n clear: both;\n &a:link, a:hover, a:visited {\n color: #fff\n }\n}\n.huge {\n font-size: 40px;\n}\n\n.btn-file {\n position: relative;\n overflow: hidden;\n}\n\n.dropdown-menu>li>a {\n color: #354044;\n}\n\n\n#sort tr.cansort {\n border-radius: 2px;\n padding: 10px;\n background: #f4f4f4;\n margin-bottom: 3px;\n border-inline: 2px solid #e6e7e8;\n color: #444;\n cursor: move;\n}\n\n.user-image-inline {\n float: left;\n width: 25px;\n height: 25px;\n border-radius: 50%;\n margin-right: 10px;\n}\n\n.input-group .input-group-addon {\n background-color: #f4f4f4;\n}\n\na.accordion-header {\n color: #333;\n}\n\n.dynamic-form-row {\n padding: 10px;\n margin: 20px;\n}\n\n\n.handle {\n padding-left: 10px;\n}\n\n.btn-file input[type=file] {\n position: absolute;\n top: 0;\n right: 0;\n min-width: 100%;\n min-height: 100%;\n font-size: 100px;\n text-align: right;\n filter: alpha(opacity=0);\n opacity: 0;\n outline: none;\n background: white;\n cursor: inherit;\n display: block;\n}\n.main-footer {\n font-size: 13px;\n}\n.main-header {\n max-height: 150px;\n}\n\n\n.navbar-nav>.user-menu>.dropdown-menu {\n width: inherit;\n}\n.main-header .logo {\n padding: 0px 5px 0px 15px;\n}\n\n\n.sidebar-toggle {\n margin-left: -48px;\n z-index: 100;\n background-color: inherit;\n}\n\n.sidebar-toggle-mobile {\n z-index: 100;\n width: 50px;\n padding-top: 10px;\n}\n\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n //color: inherit;\n}\n.pull-text-right{\n text-align: right !important;\n}\n\n.main-header .sidebar-toggle:before {\n content: \"\\f0c9\";\n font-weight: 900;\n font-family: 'Font Awesome\\ 5 Free';\n}\n\n.direct-chat-contacts {\n padding: 10px;\n height: 150px;\n}\n\n.select2-container {\n width: 100%;\n}\n\n.error input {\n color: #a94442;\n border: 2px solid #a94442 !important;\n}\n\n.error label, .alert-msg {\n color: #a94442;\n display: block;\n}\n\n.input-group[class*=\"col-\"] {\n padding-right: 15px;\n padding-left: 15px;\n}\n.control-label.multiline {\n padding-top: 10px;\n}\n\n.btn-outline {\n color: inherit;\n background-color: transparent;\n transition: all .5s;\n}\n\n.btn-primary.btn-outline {\n color: #428bca;\n}\n\n.btn-success.btn-outline {\n color: #5cb85c;\n}\n\n.btn-info.btn-outline {\n color: #5bc0de;\n}\n.btn-warning{\n background-color:#f39c12 !important;\n}\n\n.btn-warning.btn-outline {\n color: #f0ad4e;\n}\n\n.btn-danger.btn-outline, a.link-danger:link, a.link-danger:visited, a.link-danger:hover {\n color: #dd4b39;\n}\n\n.btn-primary.btn-outline:hover, .btn-success.btn-outline:hover, .btn-info.btn-outline:hover, .btn-warning.btn-outline:hover, .btn-danger.btn-outline:hover {\n color: #fff;\n}\n\n.slideout-menu {\n position: fixed;\n top: 0;\n right: -250px;\n width: 250px;\n height: 100%;\n background: #333;\n z-index: 100;\n margin-top: 100px;\n color: white;\n padding: 10px;\n}\n.slideout-menu h3 {\n position: relative;\n padding: 5px 5px;\n color: #fff;\n font-size: 1.2em;\n font-weight: 400;\n border-bottom: 4px solid #222;\n}\n.slideout-menu .slideout-menu-toggle {\n position: absolute;\n top: 12px;\n right: 10px;\n display: inline-block;\n padding: 6px 9px 5px;\n font-family: Arial, sans-serif;\n font-weight: bold;\n line-height: 1;\n background: #222;\n color: #999;\n text-decoration: none;\n vertical-align: top;\n}\n.slideout-menu .slideout-menu-toggle:hover {\n color: #fff;\n}\n.slideout-menu ul {\n list-style: none;\n font-weight: 300;\n border-top: 1px solid #151515;\n border-bottom: 1px solid #454545;\n}\n.slideout-menu ul li {\n border-top: 1px solid #454545;\n border-bottom: 1px solid #151515;\n}\n.slideout-menu ul li a {\n position: relative;\n display: block;\n padding: 10px;\n color: #999;\n text-decoration: none;\n}\n.slideout-menu ul li a:hover {\n background: #000;\n color: #fff;\n}\n.slideout-menu ul li a i {\n position: absolute;\n top: 15px;\n right: 10px;\n opacity: .5;\n}\n\n.btn-box-tool-lg {\n font-size: 16px;\n color: orange;\n}\n\n\n\n.bs-wizard {margin-top: 20px;}\n\n/*Form Wizard*/\n.bs-wizard {border-bottom: solid 1px #e0e0e0; padding: 0 0 10px 0;}\n.bs-wizard > .bs-wizard-step {padding: 0; position: relative;}\n.bs-wizard > .bs-wizard-step + .bs-wizard-step {}\n.bs-wizard > .bs-wizard-step .bs-wizard-stepnum {color: #595959; font-size: 16px; margin-bottom: 5px;}\n.bs-wizard > .bs-wizard-step .bs-wizard-info {color: #999; font-size: 14px;}\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot {position: absolute; width: 30px; height: 30px; display: block; background: #fbe8aa; top: 45px; left: 50%; margin-top: -15px; margin-left: -15px; border-radius: 50%;}\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot:after {content: ' '; width: 14px; height: 14px; background: #fbbd19; border-radius: 50px; position: absolute; top: 8px; left: 8px; }\n.bs-wizard > .bs-wizard-step > .progress {position: relative; border-radius: 0px; height: 8px; box-shadow: none; margin: 20px 0;}\n.bs-wizard > .bs-wizard-step > .progress > .progress-bar {width:0px; box-shadow: none; background: #fbe8aa;}\n.bs-wizard > .bs-wizard-step.complete > .progress > .progress-bar {width:100%;}\n.bs-wizard > .bs-wizard-step.active > .progress > .progress-bar {width:50%;}\n.bs-wizard > .bs-wizard-step:first-child.active > .progress > .progress-bar {width:0%;}\n.bs-wizard > .bs-wizard-step:last-child.active > .progress > .progress-bar {width: 100%;}\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot {background-color: #f5f5f5;}\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot:after {opacity: 0;}\n.bs-wizard > .bs-wizard-step:first-child > .progress {left: 50%; width: 50%;}\n.bs-wizard > .bs-wizard-step:last-child > .progress {width: 50%;}\n.bs-wizard > .bs-wizard-step.disabled a.bs-wizard-dot{ pointer-events: none; }\n/*END Form Wizard*/\n\n.left-navblock {\n display: inline-block;\n float: left;\n text-align: left;\n color: white;\n padding: 0px;\n /* adjust based on your layout */\n\n}\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n color: #333;\n}\n\na.logo.no-hover a:hover {\n background-color: transparent;\n}\n\n\ninput:required, select:required {\n border-right: 5px solid orange;\n}\nselect:required + .select2-container .select2-selection, select:required + .select2-container .select2-selection .select2-selection--multiple {\n border-right: 5px solid orange !important;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont,\n \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\",\n \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n font-size: 13px;\n}\n\n.sidebar-menu {\n font-size: 14px;\n white-space: normal;\n}\n\n.modal-warning .modal-help {\n color: #fff8af;\n}\n\n.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading {\n z-index: 0 !important;\n}\n\n@media print {\n\n @page {\n size: A4;\n margin: 0mm;\n }\n\n .tab-content > .tab-pane {\n display: block !important;\n opacity: 1 !important;\n visibility: visible !important;\n }\n\n .img-responsive {\n width: 200px;\n }\n\n html, body {\n width: 1024px;\n }\n\n body {\n margin: 0 auto;\n line-height: 1em;\n word-spacing:1px;\n letter-spacing:0.2px;\n font: 15px \"Times New Roman\", Times, serif;\n background:white;\n color:black;\n width: 100%;\n float: none;\n }\n\n /* avoid page-breaks inside a listingContainer*/\n .listingContainer {\n page-break-inside: avoid;\n }\n\n h1 {\n font: 28px \"Times New Roman\", Times, serif;\n }\n\n h2 {\n font: 24px \"Times New Roman\", Times, serif;\n }\n\n h3 {\n font: 20px \"Times New Roman\", Times, serif;\n }\n\n /* Improve colour contrast of links */\n a:link, a:visited {\n color: #781351\n }\n\n /* URL */\n a:link, a:visited {\n background: transparent;\n color:#333;\n text-decoration:none;\n }\n\n a[href]:after {\n content: \"\" !important;\n }\n\n a[href^=\"http://\"] {\n color:#000;\n }\n\n #header {\n height:75px;\n font-size: 24pt;\n color:black\n }\n\n div.row-new-striped {\n margin: 0px;\n padding: 0px;\n }\n\n .pagination-detail, .fixed-table-toolbar {\n visibility: hidden;\n }\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 .col-sm-pull-3 .col-sm-push-9 {\n float: left;\n }\n\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666666666666%;\n }\n .col-sm-10 {\n width: 83.33333333333334%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666666666666%;\n }\n .col-sm-7 {\n width: 58.333333333333336%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666666666667%;\n }\n .col-sm-4 {\n width: 33.33333333333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.666666666666664%;\n }\n .col-sm-1 {\n width: 8.333333333333332%;\n }\n\n}\n\n\n.select2-selection__choice__remove {\n color: white !important;\n}\n\n.select2-selection--multiple {\n border-color: #d2d6de !important;\n overflow-y: auto;\n}\n\n.select2-selection__choice {\n border-radius: 0px !important;\n}\n\n.select2-search select2-search--inline {\n height: 35px !important;\n float: left;\n margin: 0;\n}\n\n\n\n.select2-results__option {\n padding: 5px;\n user-select: none;\n -webkit-user-select: none;\n margin: 0px;\n}\n\nimg.navbar-brand-img, .navbar-brand>img {\n float: left;\n padding: 5px 5px 5px 0;\n max-height: 50px;\n}\n\n.input-daterange, .input-daterange input:first-child, .input-daterange input:last-child {\n border-radius: 0px !important;\n}\n\n.btn.bg-maroon, .btn.bg-purple{\n min-width:90px;\n}\n\n[hidden] {\n display: none !important;\n}\n\n#toolbar {\n margin-top: 10px;\n}\n\n#uploadPreview {\n border-color: grey;\n border-width: 1px;\n border-style: solid\n}\n\n.icon-med {\n font-size: 14px;\n color: #889195;\n}\n\n#login-logo {\n padding-top: 20px;\n padding-bottom: 10px;\n max-width: 200px\n}\n\n// accessibility skip link\na.skip-main {\n left:-999px;\n position:absolute;\n top:auto;\n width:1px;\n height:1px;\n overflow:hidden;\n z-index:-999;\n}\na.skip-main:focus, a.skip-main:active {\n color: #fff;\n background-color:#000;\n left: auto;\n top: auto;\n width: 30%;\n height: auto;\n overflow:auto;\n margin: 10px 35%;\n padding:5px;\n border-radius: 15px;\n border:4px solid yellow;\n text-align:center;\n font-size:1.2em;\n z-index:999;\n}\n\nh2 {\n font-size: 22px;\n}\n\nh2.task_menu {\n font-size: 14px;\n}\n\nh2 small {\n font-size: 85%;\n}\n\nh3 {\n font-size: 20px;\n}\n\nh4 {\n font-size: 16px;\n}\n\n\n.row-striped {\n vertical-align: top;\n line-height: 2.6;\n padding: 0px;\n margin-left: 20px;\n box-sizing: border-box;\n //border-left: 1px solid #dddddd;\n //border-right: 1px solid #dddddd;\n display: table;\n}\n\n.row-striped .row:nth-of-type(odd) div {\n background-color: #f9f9f9;\n border-top: 1px solid #dddddd;\n display: table-cell;\n word-wrap: break-word;\n}\n\n.row-striped .row:nth-of-type(even) div {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n display: table-cell;\n word-wrap: break-word;\n}\n\n\n.row-new-striped {\n vertical-align: top;\n padding: 3px;\n display: table;\n width: 100%;\n word-wrap: break-word;\n table-layout:fixed;\n}\n\n/**\n* NEW STRIPING\n* This section is for the new row striping for nicer \n* display for non-table data as of v6\n**/\n.row-new-striped > .row:nth-of-type(even) {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n line-height: 1.9;\n display: table-row;\n}\n\n.row-new-striped > .row:nth-of-type(odd) {\n background-color: #F8F8F8;\n border-top: 1px solid #dddddd;\n display: table-row;\n line-height: 1.9;\n padding: 2px;\n}\n\n.row-new-striped div {\n display: table-cell;\n border-top: 1px solid #dddddd;\n padding: 6px;\n}\n\n.row-new-striped div {\n display: table-cell;\n border-top: 1px solid #dddddd;\n padding: 6px;\n}\n\n\n.row-new-striped div[class^=\"col\"]:first-child {\n font-weight: bold;\n}\n\n\n\n/**\n* This just adds a little extra padding on mobile\n**/\n@media only screen and (max-width: 520px) {\n h1.pagetitle {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n\n .firstnav {\n padding-top: 120px !important;\n }\n\n .product {\n width: 400px;\n }\n\n .product img {\n min-width: 400px;\n }\n}\n\n.card-view-title {\n min-width: 40% !important;\n line-height: 3.0!important;\n padding-right: 20px;\n}\n\n.card-view {\n display: table-row;\n flex-direction: column;\n}\n\n// ---------------\n\n/**\n\n COLUMN SELECTOR ICONS\n -----------------------------\n This is kind of weird, but it is necessary to prevent the column-selector code from barfing, since\n any HTML used in the UserPresenter \"title\" attribute breaks the column selector HTML.\n\n Instead, we use CSS to add the icon into the table header, which leaves the column selector\n \"title\" text as-is and hides the icon.\n\n See https://github.com/grokability/snipe-it/issues/7989\n */\nth.css-accessory > .th-inner,\nth.css-accessory-alt > .th-inner,\nth.css-barcode > .th-inner,\nth.css-component > .th-inner,\nth.css-consumable > .th-inner,\nth.css-envelope > .th-inner,\nth.css-house-flag > .th-inner,\nth.css-house-laptop > .th-inner,\nth.css-house-user > .th-inner,\nth.css-license > .th-inner,\nth.css-location > .th-inner,\nth.css-users > .th-inner,\nth.css-currency > .th-inner,\nth.css-child-locations > .th-inner,\nth.css-history > .th-inner\n{\n font-size: 0px;\n line-height: 0.75 !important;\n text-align: left;\n text-rendering: auto;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n\nth.css-location > .th-inner::before,\nth.css-accessory > .th-inner::before,\nth.css-accessory-alt > .th-inner::before,\nth.css-barcode > .th-inner::before,\nth.css-component > .th-inner::before,\nth.css-consumable > .th-inner::before,\nth.css-envelope > .th-inner::before,\nth.css-house-flag > .th-inner::before,\nth.css-house-laptop > .th-inner::before,\nth.css-house-user > .th-inner::before,\nth.css-license > .th-inner::before,\nth.css-location > .th-inner::before,\nth.css-users > .th-inner::before,\nth.css-currency > .th-inner::before,\nth.css-child-locations > .th-inner::before,\nth.css-history > .th-inner::before\n{\n display: inline-block;\n font-size: 20px;\n font-family: \"Font Awesome 5 Free\";\n font-weight: 900;\n}\n\n/**\nBEGIN ICON TABLE HEADERS\nSet the font-weight css property as 900 (For Solid), 400 (Regular or Brands), 300 (Light for pro icons).\n**/\nth.css-barcode > .th-inner::before\n{\n content: \"\\f02a\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-license > .th-inner::before\n{\n content: \"\\f0c7\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-consumable > .th-inner::before\n{\n content: \"\\f043\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-envelope > .th-inner::before\n{\n content: \"\\f0e0\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-accessory > .th-inner::before\n{\n content: \"\\f11c\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-users > .th-inner::before {\n content: \"\\f0c0\"; font-family: \"Font Awesome 5 Free\"; font-size: 15px;\n}\n\nth.css-location > .th-inner::before {\n content: \"\\f3c5\"; font-family: \"Font Awesome 5 Free\"; font-size: 19px; margin-bottom: 0px;\n}\n\nth.css-component > .th-inner::before\n{\n content: \"\\f0a0\"; font-family: \"Font Awesome 5 Free\"; font-weight: 500;\n}\n\nth.css-padlock > .th-inner::before\n{\n content: \"\\f023\"; font-family: \"Font Awesome 5 Free\";\n font-weight: 800;\n padding-right: 3px;\n}\n\nth.css-house-user > .th-inner::before {\n content: \"\\e1b0\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-house-flag > .th-inner::before {\n content: \"\\e50d\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-house-laptop > .th-inner::before {\n content: \"\\e066\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-accessory-alt > .th-inner::before {\n content: \"\\f11c\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-child-locations > .th-inner::before {\n content: \"\\f64f\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-currency > .th-inner::before {\n content: \"\\24\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-history > .th-inner::before {\n content: \"\\f1da\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\n\n.small-box .inner {\n padding-left: 15px;\n padding-right: 15px;\n padding-top: 15px;\n color: #fff;\n}\n\n\n.small-box > a:link, .small-box > a:visited, .small-box > a:hover {\n color: #fff;\n}\n\n.select2-container--default .select2-selection--single, .select2-selection .select2-selection--single {\n border: 1px solid #d2d6de;\n border-radius: 0;\n padding: 6px 12px;\n height: 34px;\n}\n\n.form-group.has-error label, .form-group.has-error .help-block {\n color: #a94442;\n}\n\n.select2-container--default .select2-selection--multiple {\n border-radius: 0px;\n}\n\n@media screen and (max-width: 511px){\n .tab-content .tab-pane .alert-block {\n margin-top: 120px\n }\n .sidebar-menu{\n margin-top:160px;\n }\n}\n@media screen and (max-width: 912px) and (min-width: 512px){\n .sidebar-menu {\n margin-top:100px\n }\n .navbar-custom-menu > .navbar-nav > li.dropdown.user.user-menu {\n float:right;\n }\n .navbar-custom-menu > .navbar-nav > li > .dropdown-menu {\n margin-right:-39px;\n }\n}\n\n@media screen and (max-width: 1268px) and (min-width: 912px){\n .sidebar-menu {\n margin-top:50px\n }\n}\n@media screen and (max-width: 992px){\n .info-stack-container {\n flex-direction: column;\n }\n .col-md-3.col-xs-12.col-sm-push-9.info-stack{\n left:auto;\n order:1;\n }\n .col-md-9.col-xs-12.col-sm-pull-3.info-stack{\n right:auto;\n order:2;\n }\n .info-stack-container > .col-md-9.col-xs-12.col-sm-pull-3.info-stack > .row-new-striped > .row > .col-sm-2{\n width:auto;\n float:none;\n }\n}\n@media screen and (max-width: 992px){\n .row-new-striped div{\n width:100%;\n }\n}\n\n@media screen and (max-width: 1318px) and (min-width: 1200px){\n .admin.box{\n height:170px;\n }\n}\n@media screen and (max-width: 1494px) and (min-width: 1200px){\n .dashboard.small-box{\n white-space: nowrap;\n text-overflow: ellipsis;\n max-width: 188px;\n display: block;\n overflow: hidden;\n }\n}\n\n/** Form-stuff overrides for checkboxes and stuff **/\n\nlabel.form-control {\n display: grid;\n grid-template-columns: 1.8em auto;\n gap: 0.5em;\n border: 0px;\n padding-left: 0px;\n background-color: inherit;\n color: inherit;\n font-size: inherit;\n font-weight: inherit;\n}\n\nlabel.form-control--disabled {\n color: #959495;\n cursor: not-allowed;\n}\n\n\n/** --------------------------------------- **/\n/** Start checkbox styles to replace iCheck **/\n/** --------------------------------------- **/\ninput[type=\"checkbox\"] {\n /* Add if not using autoprefixer */\n -webkit-appearance: none;\n appearance: none;\n /* For iOS < 15 to remove gradient background */\n background-color: #fff;\n /* Not removed via appearance */\n margin: 0;\n font: inherit;\n color: #959495;\n width: 1.8em;\n height: 1.8em;\n border: 0.05em solid;\n border-radius: 0em;\n transform: translateY(-0.075em);\n display: grid;\n place-content: center;\n /*Windows High Contrast Mode*/\n}\n\n/** This sets the display of a checkbox, and what the \"fill\" checkmark should look like */\n\ninput[type=\"checkbox\"]::before {\n\n /** If you want to use the non-checkbox, filled square, use this instead **/\n content: \"\";\n width: 1em;\n height: 1em;\n transform: scale(0);\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em rgb(211, 211, 211);\n\n content: \"\";\n width: 1em;\n height: 1em;\n clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);\n transform: scale(0);\n transform-origin: bottom left;\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em #428bca;\n /* Windows High Contrast Mode */\n background-color: CanvasText;\n}\n\n/** This sets the size of the scale up for the shape we defined above **/\ninput[type=\"checkbox\"]:checked::before {\n transform: scale(1);\n}\n\n/** This sets the scale and color of the DISABLED but CHECKED checkbox */\ninput[type=checkbox]:disabled::before, input[type=radio]:disabled::before {\n content: \"\";\n width: 1em;\n height: 1em;\n transform: scale(1);\n box-shadow: inset 1em 1em rgb(211, 211, 211);\n}\n\n/* This sets the scale and style of a DISABLED checkbox that is NOT checked */\ninput[type=checkbox]:disabled:not(:checked)::before, input[type=radio]:disabled:not(:checked)::before {\n content: \"\";\n transform: scale(0);\n cursor: not-allowed;\n pointer-events:none;\n}\n\n/** this is the color of the checkbox and content on a disabled, checked box **/\ninput[type=checkbox]:disabled, input[type=radio]:disabled {\n --form-control-color: rgb(211, 211, 211);\n color: #959495;\n cursor: not-allowed;\n pointer-events:none;\n}\n\n\n/** Radio styles to replace iCheck **/\n\ninput[type=\"radio\"] {\n appearance: none;\n background-color: #fff;\n margin: 0;\n font: inherit;\n color: #959495;\n width: 1.8em;\n height: 1.8em;\n border: 0.05em solid;\n border-radius: 50%;\n transform: translateY(-0.075em);\n display: grid;\n place-content: center;\n}\n\ninput[type=\"radio\"]::before {\n content: \"\";\n width: 1em;\n height: 1em;\n border-radius: 50%;\n transform: scale(0);\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em #428bca;\n}\n\ninput[type=\"radio\"]:checked::before {\n transform: scale(1);\n}\n\n\n/**\n* This addresses the column selector in bootstrap-table. Without these two lines, the\n* checkbox and the with the label text that BS tables generates will\n* end up on two different lines and it looks assy.\n */\n.dropdown-item-marker input[type=checkbox] {\n font-size: 10px;\n}\n\n.bootstrap-table .fixed-table-toolbar li.dropdown-item-marker label {\n font-weight: normal;\n display: grid;\n grid-template-columns: .1em auto;\n gap: 1.5em;\n}\n\n.container.row-striped .col-md-6 {\n overflow-wrap:anywhere;\n}\n\n.nav-tabs-custom > .nav-tabs > li {\n z-index: 1;\n}\n\n.select2-container .select2-search--inline .select2-search__field{\n padding-left:15px;\n}\n\n.nav-tabs-custom > .nav-tabs > li.active {\n font-weight: bold;\n}\n\n/** --------------------------------------- **/\n/** End checkbox styles to replace iCheck **/\n/** --------------------------------------- **/\n\n/**\n/** Separator styles with text in the middle. Currently only used by the login page but\n/** could be used elsewhere.\n */\n\n.separator {\n display: flex;\n align-items: center;\n text-align: center;\n padding-top: 20px;\n color: #959495;\n}\n\n.separator::before,\n.separator::after {\n content: '';\n flex: 1;\n border-bottom: 1px solid #959495;\n}\n\n.separator:not(:empty)::before {\n margin-right: .25em;\n}\n\n.separator:not(:empty)::after {\n margin-left: .25em;\n}\n.datepicker.dropdown-menu {\n z-index: 1030 !important;\n}\n\n.sidebar-menu > li .badge {\n margin-top: 0px;\n filter: brightness(70%);\n font-size: 70%;\n}\n\n/** this is needed to override ekko-lightboxes card view styles **/\n.bootstrap-table .fixed-table-container .table tbody tr .card-view {\n display: table-row !important;\n}\n\n.form-control-static {\n padding-top: 0px;\n}\n\n\ntd.text-right.text-padding-number-cell {\n padding-right: 30px !important;\n white-space: nowrap;\n}\n\nth.text-right.text-padding-number-footer-cell {\n padding-right: 20px !important;\n white-space: nowrap;\n}\n\ncode.single-line {\n white-space: pre-wrap;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 1;\n overflow: hidden;\n max-width: 400px;\n}\n\np.monospace, span.monospace {\n font-family: monospace, monospace;\n}\n\nlegend.highlight {\n background: repeating-linear-gradient(\n 45deg,\n #222d32,\n #222d32 10px,\n #444 10px,\n #444 11px\n );\n\n color: #fff;\n font-size: 18px;\n padding: 6px 6px 6px 10px;\n}\n\nlegend.highlight a {\n color: #fff;\n cursor: pointer;\n}\n\nfieldset.bottom-padded {\n padding-bottom: 20px;\n}\n\ncaption.tableCaption {\n font-size: 18px;\n padding-left: 8px;\n}\n\n// via https://github.com/grokability/snipe-it/issues/11754\n.sidebar-toggle.btn {\n border-radius: 3px;\n box-shadow: none;\n border-top: 0px solid transparent;\n border-bottom: 0px solid transparent;\n padding-left: 15px;\n padding-right: 15px;\n padding-top: 12px;\n padding-bottom: 12px;\n margin-left: -47px;\n margin-top: 2px;\n}\n.popover.help-popover,\n.popover.help-popover .popover-content,\n.popover.help-popover .popover-body,\n.popover.help-popover .popover-title,\n.popover.help-popover .popover-header {\n color: #000;\n}\n\n.visually-hidden {\n width: 1px;\n height: 1px;\n margin: -1px;\n overflow: hidden;\n clip: rect(0,0,0,0);\n white-space: preserve;\n display: inline-block;\n}\n\ninput[name=\"columnsSearch\"] {\n width: 120px;\n}"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/public/css/build/overrides.css b/public/css/build/overrides.css index 311df7c6dc..1ca3a32741 100644 --- a/public/css/build/overrides.css +++ b/public/css/build/overrides.css @@ -673,6 +673,7 @@ th.css-license > .th-inner, th.css-location > .th-inner, th.css-users > .th-inner, th.css-currency > .th-inner, +th.css-child-locations > .th-inner, th.css-history > .th-inner { font-size: 0px; line-height: 0.75 !important; @@ -693,9 +694,9 @@ th.css-house-laptop > .th-inner::before, th.css-house-user > .th-inner::before, th.css-license > .th-inner::before, th.css-location > .th-inner::before, -th.css-padlock > .th-inner::before, th.css-users > .th-inner::before, th.css-currency > .th-inner::before, +th.css-child-locations > .th-inner::before, th.css-history > .th-inner::before { display: inline-block; font-size: 20px; @@ -750,7 +751,8 @@ th.css-component > .th-inner::before { th.css-padlock > .th-inner::before { content: "\f023"; font-family: "Font Awesome 5 Free"; - font-weight: 900; + font-weight: 800; + padding-right: 3px; } th.css-house-user > .th-inner::before { content: "\e1b0"; @@ -776,6 +778,12 @@ th.css-accessory-alt > .th-inner::before { font-size: 19px; margin-bottom: 0px; } +th.css-child-locations > .th-inner::before { + content: "\f64f"; + font-family: "Font Awesome 5 Free"; + font-size: 19px; + margin-bottom: 0px; +} th.css-currency > .th-inner::before { content: "\24"; font-family: "Font Awesome 5 Free"; @@ -1101,6 +1109,25 @@ caption.tableCaption { margin-left: -47px; margin-top: 2px; } +.popover.help-popover, +.popover.help-popover .popover-content, +.popover.help-popover .popover-body, +.popover.help-popover .popover-title, +.popover.help-popover .popover-header { + color: #000; +} +.visually-hidden { + width: 1px; + height: 1px; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: preserve; + display: inline-block; +} +input[name="columnsSearch"] { + width: 120px; +} /*# sourceMappingURL=overrides.css.map*/ \ No newline at end of file diff --git a/public/css/build/overrides.css.map b/public/css/build/overrides.css.map index 00424159df..66b4379a52 100644 --- a/public/css/build/overrides.css.map +++ b/public/css/build/overrides.css.map @@ -1 +1 @@ -{"version":3,"file":"css/build/overrides.css","mappings":"AAAA;EAkBE;AAhBF;AAkBA;EACE;EACA;EACA;EACA;EACA;AAhBF;AAiBE;;;EACE;AAbJ;AAgBA;EACE;AAdF;AAiBA;EACE;EACA;AAfF;AAkBA;EACE;AAhBF;AAoBA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AAlBF;AAqBA;EACE;EACA;EACA;EACA;EACA;AAnBF;AAsBA;EACE;AApBF;AAuBA;EACE;AArBF;AAwBA;EACE;EACA;AAtBF;AA0BA;EACE;AAxBF;AA2BA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAzBF;AA2BA;EACE;AAzBF;AA2BA;EACE;AAzBF;AA6BA;EACE;AA3BF;AA6BA;EACE;AA3BF;AA+BA;EACE;EACA;EACA;AA7BF;AAgCA;EACE;EACA;EACA;AA9BF;AAqDA;EACE;AAnDF;AAsDA;EACE;EACA;EACA;AApDF;AAuDA;EACE;EACA;AArDF;AAwDA;EACE;AAtDF;AAyDA;EACE;EACA;AAvDF;AA0DA;;EACE;EACA;AAvDF;AA0DA;EACE;EACA;AAxDF;AA0DA;EACE;AAxDF;AA2DA;EACE;EACA;EACA;AAzDF;AA4DA;EACE;AA1DF;AA6DA;EACE;AA3DF;AA8DA;EACE;AA5DF;AA8DA;EACE;AA5DF;AA+DA;EACE;AA7DF;AAgEA;;;;EACE;AA3DF;AA8DA;;;;;EACE;AAxDF;AA2DA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAzDF;AA2DA;EACE;EACA;EACA;EACA;EACA;EACA;AAzDF;AA2DA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAzDF;AA2DA;EACE;AAzDF;AA2DA;EACE;EACA;EACA;EACA;AAzDF;AA2DA;EACE;EACA;AAzDF;AA2DA;EACE;EACA;EACA;EACA;EACA;AAzDF;AA2DA;EACE;EACA;AAzDF;AA2DA;EACE;EACA;EACA;EACA;AAzDF;AA4DA;EACE;EACA;AA1DF;AA+DA;EAAY;AA5DZ;AACA,cAAc;AA8Dd;EAAY;EAAkC;AA1D9C;AA2DA;EAA8B;EAAY;AAvD1C;AAyDA;EAAiD;EAAgB;EAAiB;AApDlF;AAqDA;EAA8C;EAAa;AAjD3D;AAkDA;EAA+C;EAAoB;EAAa;EAAc;EAAgB;EAAqB;EAAW;EAAW;EAAmB;EAAoB;AAtChM;AAuCA;EAAqD;EAAc;EAAa;EAAc;EAAqB;EAAqB;EAAoB;EAAU;AA7BtK;AA8BA;EAA0C;EAAoB;EAAoB;EAAa;EAAkB;AAvBjH;AAwBA;EAA0D;EAAW;EAAkB;AAnBvF;AAoBA;EAAmE;AAjBnE;AAkBA;EAAiE;AAfjE;AAgBA;EAA6E;AAb7E;AAcA;EAA4E;AAX5E;AAYA;EAAwD;AATxD;AAUA;EAA8D;AAP9D;AAQA;EAAuD;EAAW;AAJlE;AAKA;EAAsD;AAFtD;AAGA;EAAuD;AAAvD;AACA,kBAAkB;AAElB;EACE;EACA;EACA;EACA;EACA;EAAA,gCAAgC;AAClC;AAGA;EAkBE;AAlBF;AAqBA;EACE;AAnBF;AAuBA;;EACE;AApBF;AAsBA;;EACE;AAnBF;AAsBA;EACE;EAIA;AAvBF;AA0BA;EACE;EACA;AAxBF;AA2BA;EACE;AAzBF;AA4BA;EACE;AA1BF;AA6BA;EAEE;IACE;IACA;EA5BF;EA+BA;IACE;IACA;IACA;EA7BF;EAgCA;IACE;EA9BF;EAiCA;;IACE;EA9BF;EAiCA;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;EA/BF;EACA,+CAA+C;EAkC/C;IACE;EAhCF;EAmCA;IACE;EAjCF;EAoCA;IACE;EAlCF;EAqCA;IACE;EAnCF;EACA,qCAAqC;EAsCrC;;IACE;EAnCF;EACA,QAAQ;EAsCR;;IACE;IACA;IACA;EAnCF;EAsCA;IACE;EApCF;EAuCA;IACE;EArCF;EAwCA;IACE;IACA;IACA;EAtCF;EAyCA;IACE;IACA;EAvCF;EA0CA;;IACE;EAvCF;EAyCA;;;;;;;;;;;;IACE;EA5BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;AACF;AAkCA;EACE;AAhCF;AAmCA;EACI;EACA;AAjCJ;AAoCA;EACE;AAlCF;AAqCA;EACE;EACA;EACA;AAnCF;AAwCA;EACE;EACA;OAAA;EACA;EACA;AAtCF;AAyCA;;EACE;EACA;EACA;AAtCF;AAyCA;;;EACE;AArCF;AAwCA;;EACE;AArCF;AAwCA;EACE;AAtCF;AAyCA;EACE;AAvCF;AA0CA;EACE;EACA;EACA;AAxCF;AA2CA;EACE;EACA;AAzCF;AA4CA;EACE;EACA;EACA;AA1CF;AA8CA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AA5CF;AA8CA;;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AA3CF;AA8CA;EACE;AA5CF;AA+CA;EACE;AA7CF;AAgDA;EACE;AA9CF;AAiDA;EACE;AA/CF;AAkDA;EACE;AAhDF;AAoDA;EACE;EACA;EACA;EACA;EACA;EAGA;AApDF;AAuDA;EACE;EACA;EACA;EACA;AArDF;AAwDA;EACE;EACA;EACA;EACA;AAtDF;AA0DA;EACE;EACA;EACA;EACA;EACA;EACA;AAxDF;AACA;;;;EAIE;AA2DF;EACE;EACA;EACA;EACA;AAzDF;AA4DA;EACE;EACA;EACA;EACA;EACA;AA1DF;AA6DA;EACE;EACA;EACA;AA3DF;AA8DA;EACE;EACA;EACA;AA5DF;AAgEA;EACE;AA9DF;AACA;;EAEE;AAmEF;EACE;IACE;IACA;EAjEF;EAoEA;IACE;EAlEF;EAqEA;IACE;EAnEF;EAsEA;IACE;EApEF;AACF;AAuEA;EACE;EACA;EACA;AArEF;AAwEA;EACE;EACA;AAtEF;AACA;;;;;;;;;;;EAWE;AA2EF;;;;;;;;;;;;;;EAeE;EACA;EACA;EACA;EACA;EACA;AA1EF;AA8EA;;;;;;;;;;;;;;;;EAiBE;EACA;EACA;EACA;AA7EF;AACA;;;EAGE;AAgFF;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EACE;EAAkB;EAAoC;AA5ExD;AA+EA;EACE;EAAkB;EAAoC;EAAiB;AA1EzE;AA6EA;EAEE;EAAkB;EAAoC;AA1ExD;AA6EA;EAEE;EAAkB;EAAoC;AA1ExD;AA6EA;EACE;EACA;EACA;EACA;AA3EF;AA6EA;EACE;EACA;EACA;EACA;AA3EF;AA6EA;EACE;EACA;EACA;EACA;AA3EF;AA6EA;EACE;EACA;EACA;EACA;AA3EF;AA8EA;EACE;EACA;EACA;EACA;AA5EF;AA+EA;EACE;EACA;EACA;EACA;AA7EF;AAiFA;EACE;EACA;EACA;EACA;AA/EF;AAmFA;;;EACE;AA/EF;AAkFA;;EACE;EACA;EACA;EACA;AA/EF;AAkFA;;EACE;AA/EF;AAkFA;EACE;AAhFF;AAmFA;EACE;IACE;EAjFF;EAmFA;IACE;EAjFF;AACF;AAmFA;EACE;IACE;EAjFF;EAmFA;IACE;EAjFF;EAmFA;IACE;EAjFF;AACF;AAoFA;EACE;IACE;EAlFF;AACF;AAoFA;EACE;IACE;EAlFF;EAoFA;IACE;IACA;EAlFF;EAoFA;IACE;IACA;EAlFF;EAoFA;IACE;IACA;EAlFF;AACF;AAoFA;EACE;IACE;EAlFF;AACF;AAqFA;EACE;IACE;EAnFF;AACF;AAqFA;EACE;IACE;IACA;IACA;IACA;IACA;EAnFF;AACF;AACA,oDAAoD;AAuFpD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AArFF;AAwFA;EACE;EACA;AAtFF;AACA,8CAA8C;AAC9C,8CAA8C;AAC9C,8CAA8C;AA0F9C;EAxFE,kCAAkC;EA0FlC;EACA;OAAA;EAxFA,+CAA+C;EA0F/C;EAxFA,+BAA+B;EA0F/B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAxFA,6BAA6B;AAC/B;AACA,yFAAyF;AA4FzF;EA1FE,2EAA2E;EAkG3E;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAjGA,+BAA+B;EAmG/B;AAjGF;AACA,wEAAwE;AAoGxE;EACE;AAlGF;AACA,wEAAwE;AAqGxE;;EACE;EACA;EACA;EACA;EACA;AAlGF;AACA,6EAA6E;AAqG7E;;EACE;EACA;EACA;EACA;AAlGF;AACA,+EAA+E;AAqG/E;;EACE;EACA;EACA;EACA;AAlGF;AACA,qCAAqC;AAuGrC;EACE;KAAA;UAAA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AArGF;AAwGA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AAtGF;AAyGA;EACE;AAvGF;AACA;;;;EAIE;AA2GF;EACE;AAzGF;AA4GA;EACE;EACA;EACA;EACA;AA1GF;AA6GA;EACE;AA3GF;AA8GA;EACE;AA5GF;AA+GA;EACE;AA7GF;AAgHA;EACE;AA9GF;AACA,8CAA8C;AAC9C,8CAA8C;AAC9C,8CAA8C;AAC9C;;;EAGE;AAmHF;EACE;EACA;EACA;EACA;EACA;AAjHF;AAoHA;;EAEE;EACA;EACA;AAlHF;AAqHA;EACE;AAnHF;AAsHA;EACE;AApHF;AAsHA;EACE;AApHF;AAuHA;EACE;EACA;EACA;AArHF;AACA,kEAAkE;AAwHlE;EACE;AAtHF;AAyHA;EACE;AAvHF;AA2HA;EACE;EACA;AAzHF;AA4HA;EACE;EACA;AA1HF;AA6HA;EACE;EACA;EACA;EACA;EACA;EACA;AA3HF;AA8HA;;EACE;AA3HF;AA8HA;EACE;EAQA;EACA;EACA;AAnIF;AAsIA;EACE;EACA;AApIF;AAuIA;EACE;AArIF;AAwIA;EACE;EACA;AAtIF;AA0IA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAxIF","sources":["webpack:///./resources/assets/less/overrides.less"],"sourcesContent":[".skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n\n.logo {\n background-color: inherit;\n}\n.main-header .logo {\n width: 100% !important;\n white-space: nowrap;\n text-align: left;\n display: block;\n clear: both;\n &a:link, a:hover, a:visited {\n color: #fff\n }\n}\n.huge {\n font-size: 40px;\n}\n\n.btn-file {\n position: relative;\n overflow: hidden;\n}\n\n.dropdown-menu>li>a {\n color: #354044;\n}\n\n\n#sort tr.cansort {\n border-radius: 2px;\n padding: 10px;\n background: #f4f4f4;\n margin-bottom: 3px;\n border-inline: 2px solid #e6e7e8;\n color: #444;\n cursor: move;\n}\n\n.user-image-inline {\n float: left;\n width: 25px;\n height: 25px;\n border-radius: 50%;\n margin-right: 10px;\n}\n\n.input-group .input-group-addon {\n background-color: #f4f4f4;\n}\n\na.accordion-header {\n color: #333;\n}\n\n.dynamic-form-row {\n padding: 10px;\n margin: 20px;\n}\n\n\n.handle {\n padding-left: 10px;\n}\n\n.btn-file input[type=file] {\n position: absolute;\n top: 0;\n right: 0;\n min-width: 100%;\n min-height: 100%;\n font-size: 100px;\n text-align: right;\n filter: alpha(opacity=0);\n opacity: 0;\n outline: none;\n background: white;\n cursor: inherit;\n display: block;\n}\n.main-footer {\n font-size: 13px;\n}\n.main-header {\n max-height: 150px;\n}\n\n\n.navbar-nav>.user-menu>.dropdown-menu {\n width: inherit;\n}\n.main-header .logo {\n padding: 0px 5px 0px 15px;\n}\n\n\n.sidebar-toggle {\n margin-left: -48px;\n z-index: 100;\n background-color: inherit;\n}\n\n.sidebar-toggle-mobile {\n z-index: 100;\n width: 50px;\n padding-top: 10px;\n}\n\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n //color: inherit;\n}\n.pull-text-right{\n text-align: right !important;\n}\n\n.main-header .sidebar-toggle:before {\n content: \"\\f0c9\";\n font-weight: 900;\n font-family: 'Font Awesome\\ 5 Free';\n}\n\n.direct-chat-contacts {\n padding: 10px;\n height: 150px;\n}\n\n.select2-container {\n width: 100%;\n}\n\n.error input {\n color: #a94442;\n border: 2px solid #a94442 !important;\n}\n\n.error label, .alert-msg {\n color: #a94442;\n display: block;\n}\n\n.input-group[class*=\"col-\"] {\n padding-right: 15px;\n padding-left: 15px;\n}\n.control-label.multiline {\n padding-top: 10px;\n}\n\n.btn-outline {\n color: inherit;\n background-color: transparent;\n transition: all .5s;\n}\n\n.btn-primary.btn-outline {\n color: #428bca;\n}\n\n.btn-success.btn-outline {\n color: #5cb85c;\n}\n\n.btn-info.btn-outline {\n color: #5bc0de;\n}\n.btn-warning{\n background-color:#f39c12 !important;\n}\n\n.btn-warning.btn-outline {\n color: #f0ad4e;\n}\n\n.btn-danger.btn-outline, a.link-danger:link, a.link-danger:visited, a.link-danger:hover {\n color: #dd4b39;\n}\n\n.btn-primary.btn-outline:hover, .btn-success.btn-outline:hover, .btn-info.btn-outline:hover, .btn-warning.btn-outline:hover, .btn-danger.btn-outline:hover {\n color: #fff;\n}\n\n.slideout-menu {\n position: fixed;\n top: 0;\n right: -250px;\n width: 250px;\n height: 100%;\n background: #333;\n z-index: 100;\n margin-top: 100px;\n color: white;\n padding: 10px;\n}\n.slideout-menu h3 {\n position: relative;\n padding: 5px 5px;\n color: #fff;\n font-size: 1.2em;\n font-weight: 400;\n border-bottom: 4px solid #222;\n}\n.slideout-menu .slideout-menu-toggle {\n position: absolute;\n top: 12px;\n right: 10px;\n display: inline-block;\n padding: 6px 9px 5px;\n font-family: Arial, sans-serif;\n font-weight: bold;\n line-height: 1;\n background: #222;\n color: #999;\n text-decoration: none;\n vertical-align: top;\n}\n.slideout-menu .slideout-menu-toggle:hover {\n color: #fff;\n}\n.slideout-menu ul {\n list-style: none;\n font-weight: 300;\n border-top: 1px solid #151515;\n border-bottom: 1px solid #454545;\n}\n.slideout-menu ul li {\n border-top: 1px solid #454545;\n border-bottom: 1px solid #151515;\n}\n.slideout-menu ul li a {\n position: relative;\n display: block;\n padding: 10px;\n color: #999;\n text-decoration: none;\n}\n.slideout-menu ul li a:hover {\n background: #000;\n color: #fff;\n}\n.slideout-menu ul li a i {\n position: absolute;\n top: 15px;\n right: 10px;\n opacity: .5;\n}\n\n.btn-box-tool-lg {\n font-size: 16px;\n color: orange;\n}\n\n\n\n.bs-wizard {margin-top: 20px;}\n\n/*Form Wizard*/\n.bs-wizard {border-bottom: solid 1px #e0e0e0; padding: 0 0 10px 0;}\n.bs-wizard > .bs-wizard-step {padding: 0; position: relative;}\n.bs-wizard > .bs-wizard-step + .bs-wizard-step {}\n.bs-wizard > .bs-wizard-step .bs-wizard-stepnum {color: #595959; font-size: 16px; margin-bottom: 5px;}\n.bs-wizard > .bs-wizard-step .bs-wizard-info {color: #999; font-size: 14px;}\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot {position: absolute; width: 30px; height: 30px; display: block; background: #fbe8aa; top: 45px; left: 50%; margin-top: -15px; margin-left: -15px; border-radius: 50%;}\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot:after {content: ' '; width: 14px; height: 14px; background: #fbbd19; border-radius: 50px; position: absolute; top: 8px; left: 8px; }\n.bs-wizard > .bs-wizard-step > .progress {position: relative; border-radius: 0px; height: 8px; box-shadow: none; margin: 20px 0;}\n.bs-wizard > .bs-wizard-step > .progress > .progress-bar {width:0px; box-shadow: none; background: #fbe8aa;}\n.bs-wizard > .bs-wizard-step.complete > .progress > .progress-bar {width:100%;}\n.bs-wizard > .bs-wizard-step.active > .progress > .progress-bar {width:50%;}\n.bs-wizard > .bs-wizard-step:first-child.active > .progress > .progress-bar {width:0%;}\n.bs-wizard > .bs-wizard-step:last-child.active > .progress > .progress-bar {width: 100%;}\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot {background-color: #f5f5f5;}\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot:after {opacity: 0;}\n.bs-wizard > .bs-wizard-step:first-child > .progress {left: 50%; width: 50%;}\n.bs-wizard > .bs-wizard-step:last-child > .progress {width: 50%;}\n.bs-wizard > .bs-wizard-step.disabled a.bs-wizard-dot{ pointer-events: none; }\n/*END Form Wizard*/\n\n.left-navblock {\n display: inline-block;\n float: left;\n text-align: left;\n color: white;\n padding: 0px;\n /* adjust based on your layout */\n\n}\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n color: #333;\n}\n\na.logo.no-hover a:hover {\n background-color: transparent;\n}\n\n\ninput:required, select:required {\n border-right: 5px solid orange;\n}\nselect:required + .select2-container .select2-selection, select:required + .select2-container .select2-selection .select2-selection--multiple {\n border-right: 5px solid orange !important;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont,\n \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\",\n \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n font-size: 13px;\n}\n\n.sidebar-menu {\n font-size: 14px;\n white-space: normal;\n}\n\n.modal-warning .modal-help {\n color: #fff8af;\n}\n\n.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading {\n z-index: 0 !important;\n}\n\n@media print {\n\n @page {\n size: A4;\n margin: 0mm;\n }\n\n .tab-content > .tab-pane {\n display: block !important;\n opacity: 1 !important;\n visibility: visible !important;\n }\n\n .img-responsive {\n width: 200px;\n }\n\n html, body {\n width: 1024px;\n }\n\n body {\n margin: 0 auto;\n line-height: 1em;\n word-spacing:1px;\n letter-spacing:0.2px;\n font: 15px \"Times New Roman\", Times, serif;\n background:white;\n color:black;\n width: 100%;\n float: none;\n }\n\n /* avoid page-breaks inside a listingContainer*/\n .listingContainer {\n page-break-inside: avoid;\n }\n\n h1 {\n font: 28px \"Times New Roman\", Times, serif;\n }\n\n h2 {\n font: 24px \"Times New Roman\", Times, serif;\n }\n\n h3 {\n font: 20px \"Times New Roman\", Times, serif;\n }\n\n /* Improve colour contrast of links */\n a:link, a:visited {\n color: #781351\n }\n\n /* URL */\n a:link, a:visited {\n background: transparent;\n color:#333;\n text-decoration:none;\n }\n\n a[href]:after {\n content: \"\" !important;\n }\n\n a[href^=\"http://\"] {\n color:#000;\n }\n\n #header {\n height:75px;\n font-size: 24pt;\n color:black\n }\n\n div.row-new-striped {\n margin: 0px;\n padding: 0px;\n }\n\n .pagination-detail, .fixed-table-toolbar {\n visibility: hidden;\n }\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 .col-sm-pull-3 .col-sm-push-9 {\n float: left;\n }\n\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666666666666%;\n }\n .col-sm-10 {\n width: 83.33333333333334%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666666666666%;\n }\n .col-sm-7 {\n width: 58.333333333333336%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666666666667%;\n }\n .col-sm-4 {\n width: 33.33333333333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.666666666666664%;\n }\n .col-sm-1 {\n width: 8.333333333333332%;\n }\n\n}\n\n\n.select2-selection__choice__remove {\n color: white !important;\n}\n\n.select2-selection--multiple {\n border-color: #d2d6de !important;\n overflow-y: auto;\n}\n\n.select2-selection__choice {\n border-radius: 0px !important;\n}\n\n.select2-search select2-search--inline {\n height: 35px !important;\n float: left;\n margin: 0;\n}\n\n\n\n.select2-results__option {\n padding: 5px;\n user-select: none;\n -webkit-user-select: none;\n margin: 0px;\n}\n\nimg.navbar-brand-img, .navbar-brand>img {\n float: left;\n padding: 5px 5px 5px 0;\n max-height: 50px;\n}\n\n.input-daterange, .input-daterange input:first-child, .input-daterange input:last-child {\n border-radius: 0px !important;\n}\n\n.btn.bg-maroon, .btn.bg-purple{\n min-width:90px;\n}\n\n[hidden] {\n display: none !important;\n}\n\n#toolbar {\n margin-top: 10px;\n}\n\n#uploadPreview {\n border-color: grey;\n border-width: 1px;\n border-style: solid\n}\n\n.icon-med {\n font-size: 14px;\n color: #889195;\n}\n\n#login-logo {\n padding-top: 20px;\n padding-bottom: 10px;\n max-width: 200px\n}\n\n// accessibility skip link\na.skip-main {\n left:-999px;\n position:absolute;\n top:auto;\n width:1px;\n height:1px;\n overflow:hidden;\n z-index:-999;\n}\na.skip-main:focus, a.skip-main:active {\n color: #fff;\n background-color:#000;\n left: auto;\n top: auto;\n width: 30%;\n height: auto;\n overflow:auto;\n margin: 10px 35%;\n padding:5px;\n border-radius: 15px;\n border:4px solid yellow;\n text-align:center;\n font-size:1.2em;\n z-index:999;\n}\n\nh2 {\n font-size: 22px;\n}\n\nh2.task_menu {\n font-size: 14px;\n}\n\nh2 small {\n font-size: 85%;\n}\n\nh3 {\n font-size: 20px;\n}\n\nh4 {\n font-size: 16px;\n}\n\n\n.row-striped {\n vertical-align: top;\n line-height: 2.6;\n padding: 0px;\n margin-left: 20px;\n box-sizing: border-box;\n //border-left: 1px solid #dddddd;\n //border-right: 1px solid #dddddd;\n display: table;\n}\n\n.row-striped .row:nth-of-type(odd) div {\n background-color: #f9f9f9;\n border-top: 1px solid #dddddd;\n display: table-cell;\n word-wrap: break-word;\n}\n\n.row-striped .row:nth-of-type(even) div {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n display: table-cell;\n word-wrap: break-word;\n}\n\n\n.row-new-striped {\n vertical-align: top;\n padding: 3px;\n display: table;\n width: 100%;\n word-wrap: break-word;\n table-layout:fixed;\n}\n\n/**\n* NEW STRIPING\n* This section is for the new row striping for nicer \n* display for non-table data as of v6\n**/\n.row-new-striped > .row:nth-of-type(even) {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n line-height: 1.9;\n display: table-row;\n}\n\n.row-new-striped > .row:nth-of-type(odd) {\n background-color: #F8F8F8;\n border-top: 1px solid #dddddd;\n display: table-row;\n line-height: 1.9;\n padding: 2px;\n}\n\n.row-new-striped div {\n display: table-cell;\n border-top: 1px solid #dddddd;\n padding: 6px;\n}\n\n.row-new-striped div {\n display: table-cell;\n border-top: 1px solid #dddddd;\n padding: 6px;\n}\n\n\n.row-new-striped div[class^=\"col\"]:first-child {\n font-weight: bold;\n}\n\n\n\n/**\n* This just adds a little extra padding on mobile\n**/\n@media only screen and (max-width: 520px) {\n h1.pagetitle {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n\n .firstnav {\n padding-top: 120px !important;\n }\n\n .product {\n width: 400px;\n }\n\n .product img {\n min-width: 400px;\n }\n}\n\n.card-view-title {\n min-width: 40% !important;\n line-height: 3.0!important;\n padding-right: 20px;\n}\n\n.card-view {\n display: table-row;\n flex-direction: column;\n}\n\n// ---------------\n\n/**\n\n COLUMN SELECTOR ICONS\n -----------------------------\n This is kind of weird, but it is necessary to prevent the column-selector code from barfing, since\n any HTML used in the UserPresenter \"title\" attribute breaks the column selector HTML.\n\n Instead, we use CSS to add the icon into the table header, which leaves the column selector\n \"title\" text as-is and hides the icon.\n\n See https://github.com/grokability/snipe-it/issues/7989\n */\nth.css-accessory > .th-inner,\nth.css-accessory-alt > .th-inner,\nth.css-barcode > .th-inner,\nth.css-component > .th-inner,\nth.css-consumable > .th-inner,\nth.css-envelope > .th-inner,\nth.css-house-flag > .th-inner,\nth.css-house-laptop > .th-inner,\nth.css-house-user > .th-inner,\nth.css-license > .th-inner,\nth.css-location > .th-inner,\nth.css-users > .th-inner,\nth.css-currency > .th-inner,\nth.css-history > .th-inner\n{\n font-size: 0px;\n line-height: 0.75 !important;\n text-align: left;\n text-rendering: auto;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n\nth.css-location > .th-inner::before,\nth.css-accessory > .th-inner::before,\nth.css-accessory-alt > .th-inner::before,\nth.css-barcode > .th-inner::before,\nth.css-component > .th-inner::before,\nth.css-consumable > .th-inner::before,\nth.css-envelope > .th-inner::before,\nth.css-house-flag > .th-inner::before,\nth.css-house-laptop > .th-inner::before,\nth.css-house-user > .th-inner::before,\nth.css-license > .th-inner::before,\nth.css-location > .th-inner::before,\nth.css-padlock > .th-inner::before,\nth.css-users > .th-inner::before,\nth.css-currency > .th-inner::before,\nth.css-history > .th-inner::before\n{\n display: inline-block;\n font-size: 20px;\n font-family: \"Font Awesome 5 Free\";\n font-weight: 900;\n}\n\n/**\nBEGIN ICON TABLE HEADERS\nSet the font-weight css property as 900 (For Solid), 400 (Regular or Brands), 300 (Light for pro icons).\n**/\nth.css-barcode > .th-inner::before\n{\n content: \"\\f02a\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-license > .th-inner::before\n{\n content: \"\\f0c7\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-consumable > .th-inner::before\n{\n content: \"\\f043\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-envelope > .th-inner::before\n{\n content: \"\\f0e0\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-accessory > .th-inner::before\n{\n content: \"\\f11c\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-users > .th-inner::before {\n content: \"\\f0c0\"; font-family: \"Font Awesome 5 Free\"; font-size: 15px;\n}\n\nth.css-location > .th-inner::before {\n content: \"\\f3c5\"; font-family: \"Font Awesome 5 Free\"; font-size: 19px; margin-bottom: 0px;\n}\n\nth.css-component > .th-inner::before\n{\n content: \"\\f0a0\"; font-family: \"Font Awesome 5 Free\"; font-weight: 500;\n}\n\nth.css-padlock > .th-inner::before\n{\n content: \"\\f023\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-house-user > .th-inner::before {\n content: \"\\e1b0\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-house-flag > .th-inner::before {\n content: \"\\e50d\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-house-laptop > .th-inner::before {\n content: \"\\e066\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-accessory-alt > .th-inner::before {\n content: \"\\f11c\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-currency > .th-inner::before {\n content: \"\\24\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-history > .th-inner::before {\n content: \"\\f1da\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\n\n.small-box .inner {\n padding-left: 15px;\n padding-right: 15px;\n padding-top: 15px;\n color: #fff;\n}\n\n\n.small-box > a:link, .small-box > a:visited, .small-box > a:hover {\n color: #fff;\n}\n\n.select2-container--default .select2-selection--single, .select2-selection .select2-selection--single {\n border: 1px solid #d2d6de;\n border-radius: 0;\n padding: 6px 12px;\n height: 34px;\n}\n\n.form-group.has-error label, .form-group.has-error .help-block {\n color: #a94442;\n}\n\n.select2-container--default .select2-selection--multiple {\n border-radius: 0px;\n}\n\n@media screen and (max-width: 511px){\n .tab-content .tab-pane .alert-block {\n margin-top: 120px\n }\n .sidebar-menu{\n margin-top:160px;\n }\n}\n@media screen and (max-width: 912px) and (min-width: 512px){\n .sidebar-menu {\n margin-top:100px\n }\n .navbar-custom-menu > .navbar-nav > li.dropdown.user.user-menu {\n float:right;\n }\n .navbar-custom-menu > .navbar-nav > li > .dropdown-menu {\n margin-right:-39px;\n }\n}\n\n@media screen and (max-width: 1268px) and (min-width: 912px){\n .sidebar-menu {\n margin-top:50px\n }\n}\n@media screen and (max-width: 992px){\n .info-stack-container {\n flex-direction: column;\n }\n .col-md-3.col-xs-12.col-sm-push-9.info-stack{\n left:auto;\n order:1;\n }\n .col-md-9.col-xs-12.col-sm-pull-3.info-stack{\n right:auto;\n order:2;\n }\n .info-stack-container > .col-md-9.col-xs-12.col-sm-pull-3.info-stack > .row-new-striped > .row > .col-sm-2{\n width:auto;\n float:none;\n }\n}\n@media screen and (max-width: 992px){\n .row-new-striped div{\n width:100%;\n }\n}\n\n@media screen and (max-width: 1318px) and (min-width: 1200px){\n .admin.box{\n height:170px;\n }\n}\n@media screen and (max-width: 1494px) and (min-width: 1200px){\n .dashboard.small-box{\n white-space: nowrap;\n text-overflow: ellipsis;\n max-width: 188px;\n display: block;\n overflow: hidden;\n }\n}\n\n/** Form-stuff overrides for checkboxes and stuff **/\n\nlabel.form-control {\n display: grid;\n grid-template-columns: 1.8em auto;\n gap: 0.5em;\n border: 0px;\n padding-left: 0px;\n background-color: inherit;\n color: inherit;\n font-size: inherit;\n font-weight: inherit;\n}\n\nlabel.form-control--disabled {\n color: #959495;\n cursor: not-allowed;\n}\n\n\n/** --------------------------------------- **/\n/** Start checkbox styles to replace iCheck **/\n/** --------------------------------------- **/\ninput[type=\"checkbox\"] {\n /* Add if not using autoprefixer */\n -webkit-appearance: none;\n appearance: none;\n /* For iOS < 15 to remove gradient background */\n background-color: #fff;\n /* Not removed via appearance */\n margin: 0;\n font: inherit;\n color: #959495;\n width: 1.8em;\n height: 1.8em;\n border: 0.05em solid;\n border-radius: 0em;\n transform: translateY(-0.075em);\n display: grid;\n place-content: center;\n /*Windows High Contrast Mode*/\n}\n\n/** This sets the display of a checkbox, and what the \"fill\" checkmark should look like */\n\ninput[type=\"checkbox\"]::before {\n\n /** If you want to use the non-checkbox, filled square, use this instead **/\n content: \"\";\n width: 1em;\n height: 1em;\n transform: scale(0);\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em rgb(211, 211, 211);\n\n content: \"\";\n width: 1em;\n height: 1em;\n clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);\n transform: scale(0);\n transform-origin: bottom left;\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em #428bca;\n /* Windows High Contrast Mode */\n background-color: CanvasText;\n}\n\n/** This sets the size of the scale up for the shape we defined above **/\ninput[type=\"checkbox\"]:checked::before {\n transform: scale(1);\n}\n\n/** This sets the scale and color of the DISABLED but CHECKED checkbox */\ninput[type=checkbox]:disabled::before, input[type=radio]:disabled::before {\n content: \"\";\n width: 1em;\n height: 1em;\n transform: scale(1);\n box-shadow: inset 1em 1em rgb(211, 211, 211);\n}\n\n/* This sets the scale and style of a DISABLED checkbox that is NOT checked */\ninput[type=checkbox]:disabled:not(:checked)::before, input[type=radio]:disabled:not(:checked)::before {\n content: \"\";\n transform: scale(0);\n cursor: not-allowed;\n pointer-events:none;\n}\n\n/** this is the color of the checkbox and content on a disabled, checked box **/\ninput[type=checkbox]:disabled, input[type=radio]:disabled {\n --form-control-color: rgb(211, 211, 211);\n color: #959495;\n cursor: not-allowed;\n pointer-events:none;\n}\n\n\n/** Radio styles to replace iCheck **/\n\ninput[type=\"radio\"] {\n appearance: none;\n background-color: #fff;\n margin: 0;\n font: inherit;\n color: #959495;\n width: 1.8em;\n height: 1.8em;\n border: 0.05em solid;\n border-radius: 50%;\n transform: translateY(-0.075em);\n display: grid;\n place-content: center;\n}\n\ninput[type=\"radio\"]::before {\n content: \"\";\n width: 1em;\n height: 1em;\n border-radius: 50%;\n transform: scale(0);\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em #428bca;\n}\n\ninput[type=\"radio\"]:checked::before {\n transform: scale(1);\n}\n\n\n/**\n* This addresses the column selector in bootstrap-table. Without these two lines, the\n* checkbox and the with the label text that BS tables generates will\n* end up on two different lines and it looks assy.\n */\n.dropdown-item-marker input[type=checkbox] {\n font-size: 10px;\n}\n\n.bootstrap-table .fixed-table-toolbar li.dropdown-item-marker label {\n font-weight: normal;\n display: grid;\n grid-template-columns: .1em auto;\n gap: 1.5em;\n}\n\n.container.row-striped .col-md-6 {\n overflow-wrap:anywhere;\n}\n\n.nav-tabs-custom > .nav-tabs > li {\n z-index: 1;\n}\n\n.select2-container .select2-search--inline .select2-search__field{\n padding-left:15px;\n}\n\n.nav-tabs-custom > .nav-tabs > li.active {\n font-weight: bold;\n}\n\n/** --------------------------------------- **/\n/** End checkbox styles to replace iCheck **/\n/** --------------------------------------- **/\n\n/**\n/** Separator styles with text in the middle. Currently only used by the login page but\n/** could be used elsewhere.\n */\n\n.separator {\n display: flex;\n align-items: center;\n text-align: center;\n padding-top: 20px;\n color: #959495;\n}\n\n.separator::before,\n.separator::after {\n content: '';\n flex: 1;\n border-bottom: 1px solid #959495;\n}\n\n.separator:not(:empty)::before {\n margin-right: .25em;\n}\n\n.separator:not(:empty)::after {\n margin-left: .25em;\n}\n.datepicker.dropdown-menu {\n z-index: 1030 !important;\n}\n\n.sidebar-menu > li .badge {\n margin-top: 0px;\n filter: brightness(70%);\n font-size: 70%;\n}\n\n/** this is needed to override ekko-lightboxes card view styles **/\n.bootstrap-table .fixed-table-container .table tbody tr .card-view {\n display: table-row !important;\n}\n\n.form-control-static {\n padding-top: 0px;\n}\n\n\ntd.text-right.text-padding-number-cell {\n padding-right: 30px !important;\n white-space: nowrap;\n}\n\nth.text-right.text-padding-number-footer-cell {\n padding-right: 20px !important;\n white-space: nowrap;\n}\n\ncode.single-line {\n white-space: pre-wrap;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 1;\n overflow: hidden;\n max-width: 400px;\n}\n\np.monospace, span.monospace {\n font-family: monospace, monospace;\n}\n\nlegend.highlight {\n background: repeating-linear-gradient(\n 45deg,\n #222d32,\n #222d32 10px,\n #444 10px,\n #444 11px\n );\n\n color: #fff;\n font-size: 18px;\n padding: 6px 6px 6px 10px;\n}\n\nlegend.highlight a {\n color: #fff;\n cursor: pointer;\n}\n\nfieldset.bottom-padded {\n padding-bottom: 20px;\n}\n\ncaption.tableCaption {\n font-size: 18px;\n padding-left: 8px;\n}\n\n// via https://github.com/grokability/snipe-it/issues/11754\n.sidebar-toggle.btn {\n border-radius: 3px;\n box-shadow: none;\n border-top: 0px solid transparent;\n border-bottom: 0px solid transparent;\n padding-left: 15px;\n padding-right: 15px;\n padding-top: 12px;\n padding-bottom: 12px;\n margin-left: -47px;\n margin-top: 2px;\n}\n"],"names":[],"sourceRoot":""} \ No newline at end of file +{"version":3,"file":"css/build/overrides.css","mappings":"AAAA;EAkBE;AAhBF;AAkBA;EACE;EACA;EACA;EACA;EACA;AAhBF;AAiBE;;;EACE;AAbJ;AAgBA;EACE;AAdF;AAiBA;EACE;EACA;AAfF;AAkBA;EACE;AAhBF;AAoBA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AAlBF;AAqBA;EACE;EACA;EACA;EACA;EACA;AAnBF;AAsBA;EACE;AApBF;AAuBA;EACE;AArBF;AAwBA;EACE;EACA;AAtBF;AA0BA;EACE;AAxBF;AA2BA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAzBF;AA2BA;EACE;AAzBF;AA2BA;EACE;AAzBF;AA6BA;EACE;AA3BF;AA6BA;EACE;AA3BF;AA+BA;EACE;EACA;EACA;AA7BF;AAgCA;EACE;EACA;EACA;AA9BF;AAqDA;EACE;AAnDF;AAsDA;EACE;EACA;EACA;AApDF;AAuDA;EACE;EACA;AArDF;AAwDA;EACE;AAtDF;AAyDA;EACE;EACA;AAvDF;AA0DA;;EACE;EACA;AAvDF;AA0DA;EACE;EACA;AAxDF;AA0DA;EACE;AAxDF;AA2DA;EACE;EACA;EACA;AAzDF;AA4DA;EACE;AA1DF;AA6DA;EACE;AA3DF;AA8DA;EACE;AA5DF;AA8DA;EACE;AA5DF;AA+DA;EACE;AA7DF;AAgEA;;;;EACE;AA3DF;AA8DA;;;;;EACE;AAxDF;AA2DA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAzDF;AA2DA;EACE;EACA;EACA;EACA;EACA;EACA;AAzDF;AA2DA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAzDF;AA2DA;EACE;AAzDF;AA2DA;EACE;EACA;EACA;EACA;AAzDF;AA2DA;EACE;EACA;AAzDF;AA2DA;EACE;EACA;EACA;EACA;EACA;AAzDF;AA2DA;EACE;EACA;AAzDF;AA2DA;EACE;EACA;EACA;EACA;AAzDF;AA4DA;EACE;EACA;AA1DF;AA+DA;EAAY;AA5DZ;AACA,cAAc;AA8Dd;EAAY;EAAkC;AA1D9C;AA2DA;EAA8B;EAAY;AAvD1C;AAyDA;EAAiD;EAAgB;EAAiB;AApDlF;AAqDA;EAA8C;EAAa;AAjD3D;AAkDA;EAA+C;EAAoB;EAAa;EAAc;EAAgB;EAAqB;EAAW;EAAW;EAAmB;EAAoB;AAtChM;AAuCA;EAAqD;EAAc;EAAa;EAAc;EAAqB;EAAqB;EAAoB;EAAU;AA7BtK;AA8BA;EAA0C;EAAoB;EAAoB;EAAa;EAAkB;AAvBjH;AAwBA;EAA0D;EAAW;EAAkB;AAnBvF;AAoBA;EAAmE;AAjBnE;AAkBA;EAAiE;AAfjE;AAgBA;EAA6E;AAb7E;AAcA;EAA4E;AAX5E;AAYA;EAAwD;AATxD;AAUA;EAA8D;AAP9D;AAQA;EAAuD;EAAW;AAJlE;AAKA;EAAsD;AAFtD;AAGA;EAAuD;AAAvD;AACA,kBAAkB;AAElB;EACE;EACA;EACA;EACA;EACA;EAAA,gCAAgC;AAClC;AAGA;EAkBE;AAlBF;AAqBA;EACE;AAnBF;AAuBA;;EACE;AApBF;AAsBA;;EACE;AAnBF;AAsBA;EACE;EAIA;AAvBF;AA0BA;EACE;EACA;AAxBF;AA2BA;EACE;AAzBF;AA4BA;EACE;AA1BF;AA6BA;EAEE;IACE;IACA;EA5BF;EA+BA;IACE;IACA;IACA;EA7BF;EAgCA;IACE;EA9BF;EAiCA;;IACE;EA9BF;EAiCA;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;EA/BF;EACA,+CAA+C;EAkC/C;IACE;EAhCF;EAmCA;IACE;EAjCF;EAoCA;IACE;EAlCF;EAqCA;IACE;EAnCF;EACA,qCAAqC;EAsCrC;;IACE;EAnCF;EACA,QAAQ;EAsCR;;IACE;IACA;IACA;EAnCF;EAsCA;IACE;EApCF;EAuCA;IACE;EArCF;EAwCA;IACE;IACA;IACA;EAtCF;EAyCA;IACE;IACA;EAvCF;EA0CA;;IACE;EAvCF;EAyCA;;;;;;;;;;;;IACE;EA5BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;EA+BA;IACE;EA7BF;AACF;AAkCA;EACE;AAhCF;AAmCA;EACI;EACA;AAjCJ;AAoCA;EACE;AAlCF;AAqCA;EACE;EACA;EACA;AAnCF;AAwCA;EACE;EACA;OAAA;EACA;EACA;AAtCF;AAyCA;;EACE;EACA;EACA;AAtCF;AAyCA;;;EACE;AArCF;AAwCA;;EACE;AArCF;AAwCA;EACE;AAtCF;AAyCA;EACE;AAvCF;AA0CA;EACE;EACA;EACA;AAxCF;AA2CA;EACE;EACA;AAzCF;AA4CA;EACE;EACA;EACA;AA1CF;AA8CA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AA5CF;AA8CA;;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AA3CF;AA8CA;EACE;AA5CF;AA+CA;EACE;AA7CF;AAgDA;EACE;AA9CF;AAiDA;EACE;AA/CF;AAkDA;EACE;AAhDF;AAoDA;EACE;EACA;EACA;EACA;EACA;EAGA;AApDF;AAuDA;EACE;EACA;EACA;EACA;AArDF;AAwDA;EACE;EACA;EACA;EACA;AAtDF;AA0DA;EACE;EACA;EACA;EACA;EACA;EACA;AAxDF;AACA;;;;EAIE;AA2DF;EACE;EACA;EACA;EACA;AAzDF;AA4DA;EACE;EACA;EACA;EACA;EACA;AA1DF;AA6DA;EACE;EACA;EACA;AA3DF;AA8DA;EACE;EACA;EACA;AA5DF;AAgEA;EACE;AA9DF;AACA;;EAEE;AAmEF;EACE;IACE;IACA;EAjEF;EAoEA;IACE;EAlEF;EAqEA;IACE;EAnEF;EAsEA;IACE;EApEF;AACF;AAuEA;EACE;EACA;EACA;AArEF;AAwEA;EACE;EACA;AAtEF;AACA;;;;;;;;;;;EAWE;AA2EF;;;;;;;;;;;;;;;EAgBE;EACA;EACA;EACA;EACA;EACA;AA1EF;AA8EA;;;;;;;;;;;;;;;;EAiBE;EACA;EACA;EACA;AA7EF;AACA;;;EAGE;AAgFF;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EAEE;EAAkB;EAAoC;AA7ExD;AAgFA;EACE;EAAkB;EAAoC;AA5ExD;AA+EA;EACE;EAAkB;EAAoC;EAAiB;AA1EzE;AA6EA;EAEE;EAAkB;EAAoC;AA1ExD;AA6EA;EAEE;EAAkB;EAClB;EACA;AA3EF;AA8EA;EACE;EACA;EACA;EACA;AA5EF;AA8EA;EACE;EACA;EACA;EACA;AA5EF;AA8EA;EACE;EACA;EACA;EACA;AA5EF;AA8EA;EACE;EACA;EACA;EACA;AA5EF;AA+EA;EACE;EACA;EACA;EACA;AA7EF;AAgFA;EACE;EACA;EACA;EACA;AA9EF;AAiFA;EACE;EACA;EACA;EACA;AA/EF;AAmFA;EACE;EACA;EACA;EACA;AAjFF;AAqFA;;;EACE;AAjFF;AAoFA;;EACE;EACA;EACA;EACA;AAjFF;AAoFA;;EACE;AAjFF;AAoFA;EACE;AAlFF;AAqFA;EACE;IACE;EAnFF;EAqFA;IACE;EAnFF;AACF;AAqFA;EACE;IACE;EAnFF;EAqFA;IACE;EAnFF;EAqFA;IACE;EAnFF;AACF;AAsFA;EACE;IACE;EApFF;AACF;AAsFA;EACE;IACE;EApFF;EAsFA;IACE;IACA;EApFF;EAsFA;IACE;IACA;EApFF;EAsFA;IACE;IACA;EApFF;AACF;AAsFA;EACE;IACE;EApFF;AACF;AAuFA;EACE;IACE;EArFF;AACF;AAuFA;EACE;IACE;IACA;IACA;IACA;IACA;EArFF;AACF;AACA,oDAAoD;AAyFpD;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAvFF;AA0FA;EACE;EACA;AAxFF;AACA,8CAA8C;AAC9C,8CAA8C;AAC9C,8CAA8C;AA4F9C;EA1FE,kCAAkC;EA4FlC;EACA;OAAA;EA1FA,+CAA+C;EA4F/C;EA1FA,+BAA+B;EA4F/B;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EA1FA,6BAA6B;AAC/B;AACA,yFAAyF;AA8FzF;EA5FE,2EAA2E;EAoG3E;EAEA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EAnGA,+BAA+B;EAqG/B;AAnGF;AACA,wEAAwE;AAsGxE;EACE;AApGF;AACA,wEAAwE;AAuGxE;;EACE;EACA;EACA;EACA;EACA;AApGF;AACA,6EAA6E;AAuG7E;;EACE;EACA;EACA;EACA;AApGF;AACA,+EAA+E;AAuG/E;;EACE;EACA;EACA;EACA;AApGF;AACA,qCAAqC;AAyGrC;EACE;KAAA;UAAA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AAvGF;AA0GA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AAxGF;AA2GA;EACE;AAzGF;AACA;;;;EAIE;AA6GF;EACE;AA3GF;AA8GA;EACE;EACA;EACA;EACA;AA5GF;AA+GA;EACE;AA7GF;AAgHA;EACE;AA9GF;AAiHA;EACE;AA/GF;AAkHA;EACE;AAhHF;AACA,8CAA8C;AAC9C,8CAA8C;AAC9C,8CAA8C;AAC9C;;;EAGE;AAqHF;EACE;EACA;EACA;EACA;EACA;AAnHF;AAsHA;;EAEE;EACA;EACA;AApHF;AAuHA;EACE;AArHF;AAwHA;EACE;AAtHF;AAwHA;EACE;AAtHF;AAyHA;EACE;EACA;EACA;AAvHF;AACA,kEAAkE;AA0HlE;EACE;AAxHF;AA2HA;EACE;AAzHF;AA6HA;EACE;EACA;AA3HF;AA8HA;EACE;EACA;AA5HF;AA+HA;EACE;EACA;EACA;EACA;EACA;EACA;AA7HF;AAgIA;;EACE;AA7HF;AAgIA;EACE;EAQA;EACA;EACA;AArIF;AAwIA;EACE;EACA;AAtIF;AAyIA;EACE;AAvIF;AA0IA;EACE;EACA;AAxIF;AA4IA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;AA1IF;AA4IA;;;;;EAKE;AA1IF;AA6IA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;AA3IF;AA8IA;EACE;AA5IF","sources":["webpack:///./resources/assets/less/overrides.less"],"sourcesContent":[".skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n\n.logo {\n background-color: inherit;\n}\n.main-header .logo {\n width: 100% !important;\n white-space: nowrap;\n text-align: left;\n display: block;\n clear: both;\n &a:link, a:hover, a:visited {\n color: #fff\n }\n}\n.huge {\n font-size: 40px;\n}\n\n.btn-file {\n position: relative;\n overflow: hidden;\n}\n\n.dropdown-menu>li>a {\n color: #354044;\n}\n\n\n#sort tr.cansort {\n border-radius: 2px;\n padding: 10px;\n background: #f4f4f4;\n margin-bottom: 3px;\n border-inline: 2px solid #e6e7e8;\n color: #444;\n cursor: move;\n}\n\n.user-image-inline {\n float: left;\n width: 25px;\n height: 25px;\n border-radius: 50%;\n margin-right: 10px;\n}\n\n.input-group .input-group-addon {\n background-color: #f4f4f4;\n}\n\na.accordion-header {\n color: #333;\n}\n\n.dynamic-form-row {\n padding: 10px;\n margin: 20px;\n}\n\n\n.handle {\n padding-left: 10px;\n}\n\n.btn-file input[type=file] {\n position: absolute;\n top: 0;\n right: 0;\n min-width: 100%;\n min-height: 100%;\n font-size: 100px;\n text-align: right;\n filter: alpha(opacity=0);\n opacity: 0;\n outline: none;\n background: white;\n cursor: inherit;\n display: block;\n}\n.main-footer {\n font-size: 13px;\n}\n.main-header {\n max-height: 150px;\n}\n\n\n.navbar-nav>.user-menu>.dropdown-menu {\n width: inherit;\n}\n.main-header .logo {\n padding: 0px 5px 0px 15px;\n}\n\n\n.sidebar-toggle {\n margin-left: -48px;\n z-index: 100;\n background-color: inherit;\n}\n\n.sidebar-toggle-mobile {\n z-index: 100;\n width: 50px;\n padding-top: 10px;\n}\n\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n //color: inherit;\n}\n.pull-text-right{\n text-align: right !important;\n}\n\n.main-header .sidebar-toggle:before {\n content: \"\\f0c9\";\n font-weight: 900;\n font-family: 'Font Awesome\\ 5 Free';\n}\n\n.direct-chat-contacts {\n padding: 10px;\n height: 150px;\n}\n\n.select2-container {\n width: 100%;\n}\n\n.error input {\n color: #a94442;\n border: 2px solid #a94442 !important;\n}\n\n.error label, .alert-msg {\n color: #a94442;\n display: block;\n}\n\n.input-group[class*=\"col-\"] {\n padding-right: 15px;\n padding-left: 15px;\n}\n.control-label.multiline {\n padding-top: 10px;\n}\n\n.btn-outline {\n color: inherit;\n background-color: transparent;\n transition: all .5s;\n}\n\n.btn-primary.btn-outline {\n color: #428bca;\n}\n\n.btn-success.btn-outline {\n color: #5cb85c;\n}\n\n.btn-info.btn-outline {\n color: #5bc0de;\n}\n.btn-warning{\n background-color:#f39c12 !important;\n}\n\n.btn-warning.btn-outline {\n color: #f0ad4e;\n}\n\n.btn-danger.btn-outline, a.link-danger:link, a.link-danger:visited, a.link-danger:hover {\n color: #dd4b39;\n}\n\n.btn-primary.btn-outline:hover, .btn-success.btn-outline:hover, .btn-info.btn-outline:hover, .btn-warning.btn-outline:hover, .btn-danger.btn-outline:hover {\n color: #fff;\n}\n\n.slideout-menu {\n position: fixed;\n top: 0;\n right: -250px;\n width: 250px;\n height: 100%;\n background: #333;\n z-index: 100;\n margin-top: 100px;\n color: white;\n padding: 10px;\n}\n.slideout-menu h3 {\n position: relative;\n padding: 5px 5px;\n color: #fff;\n font-size: 1.2em;\n font-weight: 400;\n border-bottom: 4px solid #222;\n}\n.slideout-menu .slideout-menu-toggle {\n position: absolute;\n top: 12px;\n right: 10px;\n display: inline-block;\n padding: 6px 9px 5px;\n font-family: Arial, sans-serif;\n font-weight: bold;\n line-height: 1;\n background: #222;\n color: #999;\n text-decoration: none;\n vertical-align: top;\n}\n.slideout-menu .slideout-menu-toggle:hover {\n color: #fff;\n}\n.slideout-menu ul {\n list-style: none;\n font-weight: 300;\n border-top: 1px solid #151515;\n border-bottom: 1px solid #454545;\n}\n.slideout-menu ul li {\n border-top: 1px solid #454545;\n border-bottom: 1px solid #151515;\n}\n.slideout-menu ul li a {\n position: relative;\n display: block;\n padding: 10px;\n color: #999;\n text-decoration: none;\n}\n.slideout-menu ul li a:hover {\n background: #000;\n color: #fff;\n}\n.slideout-menu ul li a i {\n position: absolute;\n top: 15px;\n right: 10px;\n opacity: .5;\n}\n\n.btn-box-tool-lg {\n font-size: 16px;\n color: orange;\n}\n\n\n\n.bs-wizard {margin-top: 20px;}\n\n/*Form Wizard*/\n.bs-wizard {border-bottom: solid 1px #e0e0e0; padding: 0 0 10px 0;}\n.bs-wizard > .bs-wizard-step {padding: 0; position: relative;}\n.bs-wizard > .bs-wizard-step + .bs-wizard-step {}\n.bs-wizard > .bs-wizard-step .bs-wizard-stepnum {color: #595959; font-size: 16px; margin-bottom: 5px;}\n.bs-wizard > .bs-wizard-step .bs-wizard-info {color: #999; font-size: 14px;}\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot {position: absolute; width: 30px; height: 30px; display: block; background: #fbe8aa; top: 45px; left: 50%; margin-top: -15px; margin-left: -15px; border-radius: 50%;}\n.bs-wizard > .bs-wizard-step > .bs-wizard-dot:after {content: ' '; width: 14px; height: 14px; background: #fbbd19; border-radius: 50px; position: absolute; top: 8px; left: 8px; }\n.bs-wizard > .bs-wizard-step > .progress {position: relative; border-radius: 0px; height: 8px; box-shadow: none; margin: 20px 0;}\n.bs-wizard > .bs-wizard-step > .progress > .progress-bar {width:0px; box-shadow: none; background: #fbe8aa;}\n.bs-wizard > .bs-wizard-step.complete > .progress > .progress-bar {width:100%;}\n.bs-wizard > .bs-wizard-step.active > .progress > .progress-bar {width:50%;}\n.bs-wizard > .bs-wizard-step:first-child.active > .progress > .progress-bar {width:0%;}\n.bs-wizard > .bs-wizard-step:last-child.active > .progress > .progress-bar {width: 100%;}\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot {background-color: #f5f5f5;}\n.bs-wizard > .bs-wizard-step.disabled > .bs-wizard-dot:after {opacity: 0;}\n.bs-wizard > .bs-wizard-step:first-child > .progress {left: 50%; width: 50%;}\n.bs-wizard > .bs-wizard-step:last-child > .progress {width: 50%;}\n.bs-wizard > .bs-wizard-step.disabled a.bs-wizard-dot{ pointer-events: none; }\n/*END Form Wizard*/\n\n.left-navblock {\n display: inline-block;\n float: left;\n text-align: left;\n color: white;\n padding: 0px;\n /* adjust based on your layout */\n\n}\n.skin-red\n.skin-purple\n.skin-blue\n.skin-black\n.skin-orange\n.skin-yellow\n.skin-green\n.skin-red-dark\n.skin-purple-dark\n.skin-blue-dark\n.skin-black-dark\n.skin-orange-dark\n.skin-yellow-dark\n.skin-green-dark\n.skin-contrast\n.main-header\n.navbar\n.dropdown-menu li a {\n color: #333;\n}\n\na.logo.no-hover a:hover {\n background-color: transparent;\n}\n\n\ninput:required, select:required {\n border-right: 5px solid orange;\n}\nselect:required + .select2-container .select2-selection, select:required + .select2-container .select2-selection .select2-selection--multiple {\n border-right: 5px solid orange !important;\n}\n\nbody {\n font-family: -apple-system, BlinkMacSystemFont,\n \"Segoe UI\", \"Roboto\", \"Oxygen\", \"Ubuntu\", \"Cantarell\",\n \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n font-size: 13px;\n}\n\n.sidebar-menu {\n font-size: 14px;\n white-space: normal;\n}\n\n.modal-warning .modal-help {\n color: #fff8af;\n}\n\n.bootstrap-table .fixed-table-container .fixed-table-body .fixed-table-loading {\n z-index: 0 !important;\n}\n\n@media print {\n\n @page {\n size: A4;\n margin: 0mm;\n }\n\n .tab-content > .tab-pane {\n display: block !important;\n opacity: 1 !important;\n visibility: visible !important;\n }\n\n .img-responsive {\n width: 200px;\n }\n\n html, body {\n width: 1024px;\n }\n\n body {\n margin: 0 auto;\n line-height: 1em;\n word-spacing:1px;\n letter-spacing:0.2px;\n font: 15px \"Times New Roman\", Times, serif;\n background:white;\n color:black;\n width: 100%;\n float: none;\n }\n\n /* avoid page-breaks inside a listingContainer*/\n .listingContainer {\n page-break-inside: avoid;\n }\n\n h1 {\n font: 28px \"Times New Roman\", Times, serif;\n }\n\n h2 {\n font: 24px \"Times New Roman\", Times, serif;\n }\n\n h3 {\n font: 20px \"Times New Roman\", Times, serif;\n }\n\n /* Improve colour contrast of links */\n a:link, a:visited {\n color: #781351\n }\n\n /* URL */\n a:link, a:visited {\n background: transparent;\n color:#333;\n text-decoration:none;\n }\n\n a[href]:after {\n content: \"\" !important;\n }\n\n a[href^=\"http://\"] {\n color:#000;\n }\n\n #header {\n height:75px;\n font-size: 24pt;\n color:black\n }\n\n div.row-new-striped {\n margin: 0px;\n padding: 0px;\n }\n\n .pagination-detail, .fixed-table-toolbar {\n visibility: hidden;\n }\n .col-sm-1, .col-sm-2, .col-sm-3, .col-sm-4, .col-sm-5, .col-sm-6, .col-sm-7, .col-sm-8, .col-sm-9, .col-sm-10, .col-sm-11, .col-sm-12 .col-sm-pull-3 .col-sm-push-9 {\n float: left;\n }\n\n .col-sm-12 {\n width: 100%;\n }\n .col-sm-11 {\n width: 91.66666666666666%;\n }\n .col-sm-10 {\n width: 83.33333333333334%;\n }\n .col-sm-9 {\n width: 75%;\n }\n .col-sm-8 {\n width: 66.66666666666666%;\n }\n .col-sm-7 {\n width: 58.333333333333336%;\n }\n .col-sm-6 {\n width: 50%;\n }\n .col-sm-5 {\n width: 41.66666666666667%;\n }\n .col-sm-4 {\n width: 33.33333333333333%;\n }\n .col-sm-3 {\n width: 25%;\n }\n .col-sm-2 {\n width: 16.666666666666664%;\n }\n .col-sm-1 {\n width: 8.333333333333332%;\n }\n\n}\n\n\n.select2-selection__choice__remove {\n color: white !important;\n}\n\n.select2-selection--multiple {\n border-color: #d2d6de !important;\n overflow-y: auto;\n}\n\n.select2-selection__choice {\n border-radius: 0px !important;\n}\n\n.select2-search select2-search--inline {\n height: 35px !important;\n float: left;\n margin: 0;\n}\n\n\n\n.select2-results__option {\n padding: 5px;\n user-select: none;\n -webkit-user-select: none;\n margin: 0px;\n}\n\nimg.navbar-brand-img, .navbar-brand>img {\n float: left;\n padding: 5px 5px 5px 0;\n max-height: 50px;\n}\n\n.input-daterange, .input-daterange input:first-child, .input-daterange input:last-child {\n border-radius: 0px !important;\n}\n\n.btn.bg-maroon, .btn.bg-purple{\n min-width:90px;\n}\n\n[hidden] {\n display: none !important;\n}\n\n#toolbar {\n margin-top: 10px;\n}\n\n#uploadPreview {\n border-color: grey;\n border-width: 1px;\n border-style: solid\n}\n\n.icon-med {\n font-size: 14px;\n color: #889195;\n}\n\n#login-logo {\n padding-top: 20px;\n padding-bottom: 10px;\n max-width: 200px\n}\n\n// accessibility skip link\na.skip-main {\n left:-999px;\n position:absolute;\n top:auto;\n width:1px;\n height:1px;\n overflow:hidden;\n z-index:-999;\n}\na.skip-main:focus, a.skip-main:active {\n color: #fff;\n background-color:#000;\n left: auto;\n top: auto;\n width: 30%;\n height: auto;\n overflow:auto;\n margin: 10px 35%;\n padding:5px;\n border-radius: 15px;\n border:4px solid yellow;\n text-align:center;\n font-size:1.2em;\n z-index:999;\n}\n\nh2 {\n font-size: 22px;\n}\n\nh2.task_menu {\n font-size: 14px;\n}\n\nh2 small {\n font-size: 85%;\n}\n\nh3 {\n font-size: 20px;\n}\n\nh4 {\n font-size: 16px;\n}\n\n\n.row-striped {\n vertical-align: top;\n line-height: 2.6;\n padding: 0px;\n margin-left: 20px;\n box-sizing: border-box;\n //border-left: 1px solid #dddddd;\n //border-right: 1px solid #dddddd;\n display: table;\n}\n\n.row-striped .row:nth-of-type(odd) div {\n background-color: #f9f9f9;\n border-top: 1px solid #dddddd;\n display: table-cell;\n word-wrap: break-word;\n}\n\n.row-striped .row:nth-of-type(even) div {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n display: table-cell;\n word-wrap: break-word;\n}\n\n\n.row-new-striped {\n vertical-align: top;\n padding: 3px;\n display: table;\n width: 100%;\n word-wrap: break-word;\n table-layout:fixed;\n}\n\n/**\n* NEW STRIPING\n* This section is for the new row striping for nicer \n* display for non-table data as of v6\n**/\n.row-new-striped > .row:nth-of-type(even) {\n background: #FFFFFF;\n border-top: 1px solid #dddddd;\n line-height: 1.9;\n display: table-row;\n}\n\n.row-new-striped > .row:nth-of-type(odd) {\n background-color: #F8F8F8;\n border-top: 1px solid #dddddd;\n display: table-row;\n line-height: 1.9;\n padding: 2px;\n}\n\n.row-new-striped div {\n display: table-cell;\n border-top: 1px solid #dddddd;\n padding: 6px;\n}\n\n.row-new-striped div {\n display: table-cell;\n border-top: 1px solid #dddddd;\n padding: 6px;\n}\n\n\n.row-new-striped div[class^=\"col\"]:first-child {\n font-weight: bold;\n}\n\n\n\n/**\n* This just adds a little extra padding on mobile\n**/\n@media only screen and (max-width: 520px) {\n h1.pagetitle {\n padding-top: 15px;\n padding-bottom: 15px;\n }\n\n .firstnav {\n padding-top: 120px !important;\n }\n\n .product {\n width: 400px;\n }\n\n .product img {\n min-width: 400px;\n }\n}\n\n.card-view-title {\n min-width: 40% !important;\n line-height: 3.0!important;\n padding-right: 20px;\n}\n\n.card-view {\n display: table-row;\n flex-direction: column;\n}\n\n// ---------------\n\n/**\n\n COLUMN SELECTOR ICONS\n -----------------------------\n This is kind of weird, but it is necessary to prevent the column-selector code from barfing, since\n any HTML used in the UserPresenter \"title\" attribute breaks the column selector HTML.\n\n Instead, we use CSS to add the icon into the table header, which leaves the column selector\n \"title\" text as-is and hides the icon.\n\n See https://github.com/grokability/snipe-it/issues/7989\n */\nth.css-accessory > .th-inner,\nth.css-accessory-alt > .th-inner,\nth.css-barcode > .th-inner,\nth.css-component > .th-inner,\nth.css-consumable > .th-inner,\nth.css-envelope > .th-inner,\nth.css-house-flag > .th-inner,\nth.css-house-laptop > .th-inner,\nth.css-house-user > .th-inner,\nth.css-license > .th-inner,\nth.css-location > .th-inner,\nth.css-users > .th-inner,\nth.css-currency > .th-inner,\nth.css-child-locations > .th-inner,\nth.css-history > .th-inner\n{\n font-size: 0px;\n line-height: 0.75 !important;\n text-align: left;\n text-rendering: auto;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n\nth.css-location > .th-inner::before,\nth.css-accessory > .th-inner::before,\nth.css-accessory-alt > .th-inner::before,\nth.css-barcode > .th-inner::before,\nth.css-component > .th-inner::before,\nth.css-consumable > .th-inner::before,\nth.css-envelope > .th-inner::before,\nth.css-house-flag > .th-inner::before,\nth.css-house-laptop > .th-inner::before,\nth.css-house-user > .th-inner::before,\nth.css-license > .th-inner::before,\nth.css-location > .th-inner::before,\nth.css-users > .th-inner::before,\nth.css-currency > .th-inner::before,\nth.css-child-locations > .th-inner::before,\nth.css-history > .th-inner::before\n{\n display: inline-block;\n font-size: 20px;\n font-family: \"Font Awesome 5 Free\";\n font-weight: 900;\n}\n\n/**\nBEGIN ICON TABLE HEADERS\nSet the font-weight css property as 900 (For Solid), 400 (Regular or Brands), 300 (Light for pro icons).\n**/\nth.css-barcode > .th-inner::before\n{\n content: \"\\f02a\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-license > .th-inner::before\n{\n content: \"\\f0c7\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-consumable > .th-inner::before\n{\n content: \"\\f043\"; font-family: \"Font Awesome 5 Free\"; font-weight: 900;\n}\n\nth.css-envelope > .th-inner::before\n{\n content: \"\\f0e0\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-accessory > .th-inner::before\n{\n content: \"\\f11c\"; font-family: \"Font Awesome 5 Free\"; font-weight: 400;\n}\n\nth.css-users > .th-inner::before {\n content: \"\\f0c0\"; font-family: \"Font Awesome 5 Free\"; font-size: 15px;\n}\n\nth.css-location > .th-inner::before {\n content: \"\\f3c5\"; font-family: \"Font Awesome 5 Free\"; font-size: 19px; margin-bottom: 0px;\n}\n\nth.css-component > .th-inner::before\n{\n content: \"\\f0a0\"; font-family: \"Font Awesome 5 Free\"; font-weight: 500;\n}\n\nth.css-padlock > .th-inner::before\n{\n content: \"\\f023\"; font-family: \"Font Awesome 5 Free\";\n font-weight: 800;\n padding-right: 3px;\n}\n\nth.css-house-user > .th-inner::before {\n content: \"\\e1b0\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-house-flag > .th-inner::before {\n content: \"\\e50d\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-house-laptop > .th-inner::before {\n content: \"\\e066\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\nth.css-accessory-alt > .th-inner::before {\n content: \"\\f11c\";\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-child-locations > .th-inner::before {\n content: \"\\f64f\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-currency > .th-inner::before {\n content: \"\\24\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\nth.css-history > .th-inner::before {\n content: \"\\f1da\"; // change this to f51e for coins\n font-family: \"Font Awesome 5 Free\";\n font-size: 19px;\n margin-bottom: 0px;\n}\n\n\n.small-box .inner {\n padding-left: 15px;\n padding-right: 15px;\n padding-top: 15px;\n color: #fff;\n}\n\n\n.small-box > a:link, .small-box > a:visited, .small-box > a:hover {\n color: #fff;\n}\n\n.select2-container--default .select2-selection--single, .select2-selection .select2-selection--single {\n border: 1px solid #d2d6de;\n border-radius: 0;\n padding: 6px 12px;\n height: 34px;\n}\n\n.form-group.has-error label, .form-group.has-error .help-block {\n color: #a94442;\n}\n\n.select2-container--default .select2-selection--multiple {\n border-radius: 0px;\n}\n\n@media screen and (max-width: 511px){\n .tab-content .tab-pane .alert-block {\n margin-top: 120px\n }\n .sidebar-menu{\n margin-top:160px;\n }\n}\n@media screen and (max-width: 912px) and (min-width: 512px){\n .sidebar-menu {\n margin-top:100px\n }\n .navbar-custom-menu > .navbar-nav > li.dropdown.user.user-menu {\n float:right;\n }\n .navbar-custom-menu > .navbar-nav > li > .dropdown-menu {\n margin-right:-39px;\n }\n}\n\n@media screen and (max-width: 1268px) and (min-width: 912px){\n .sidebar-menu {\n margin-top:50px\n }\n}\n@media screen and (max-width: 992px){\n .info-stack-container {\n flex-direction: column;\n }\n .col-md-3.col-xs-12.col-sm-push-9.info-stack{\n left:auto;\n order:1;\n }\n .col-md-9.col-xs-12.col-sm-pull-3.info-stack{\n right:auto;\n order:2;\n }\n .info-stack-container > .col-md-9.col-xs-12.col-sm-pull-3.info-stack > .row-new-striped > .row > .col-sm-2{\n width:auto;\n float:none;\n }\n}\n@media screen and (max-width: 992px){\n .row-new-striped div{\n width:100%;\n }\n}\n\n@media screen and (max-width: 1318px) and (min-width: 1200px){\n .admin.box{\n height:170px;\n }\n}\n@media screen and (max-width: 1494px) and (min-width: 1200px){\n .dashboard.small-box{\n white-space: nowrap;\n text-overflow: ellipsis;\n max-width: 188px;\n display: block;\n overflow: hidden;\n }\n}\n\n/** Form-stuff overrides for checkboxes and stuff **/\n\nlabel.form-control {\n display: grid;\n grid-template-columns: 1.8em auto;\n gap: 0.5em;\n border: 0px;\n padding-left: 0px;\n background-color: inherit;\n color: inherit;\n font-size: inherit;\n font-weight: inherit;\n}\n\nlabel.form-control--disabled {\n color: #959495;\n cursor: not-allowed;\n}\n\n\n/** --------------------------------------- **/\n/** Start checkbox styles to replace iCheck **/\n/** --------------------------------------- **/\ninput[type=\"checkbox\"] {\n /* Add if not using autoprefixer */\n -webkit-appearance: none;\n appearance: none;\n /* For iOS < 15 to remove gradient background */\n background-color: #fff;\n /* Not removed via appearance */\n margin: 0;\n font: inherit;\n color: #959495;\n width: 1.8em;\n height: 1.8em;\n border: 0.05em solid;\n border-radius: 0em;\n transform: translateY(-0.075em);\n display: grid;\n place-content: center;\n /*Windows High Contrast Mode*/\n}\n\n/** This sets the display of a checkbox, and what the \"fill\" checkmark should look like */\n\ninput[type=\"checkbox\"]::before {\n\n /** If you want to use the non-checkbox, filled square, use this instead **/\n content: \"\";\n width: 1em;\n height: 1em;\n transform: scale(0);\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em rgb(211, 211, 211);\n\n content: \"\";\n width: 1em;\n height: 1em;\n clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);\n transform: scale(0);\n transform-origin: bottom left;\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em #428bca;\n /* Windows High Contrast Mode */\n background-color: CanvasText;\n}\n\n/** This sets the size of the scale up for the shape we defined above **/\ninput[type=\"checkbox\"]:checked::before {\n transform: scale(1);\n}\n\n/** This sets the scale and color of the DISABLED but CHECKED checkbox */\ninput[type=checkbox]:disabled::before, input[type=radio]:disabled::before {\n content: \"\";\n width: 1em;\n height: 1em;\n transform: scale(1);\n box-shadow: inset 1em 1em rgb(211, 211, 211);\n}\n\n/* This sets the scale and style of a DISABLED checkbox that is NOT checked */\ninput[type=checkbox]:disabled:not(:checked)::before, input[type=radio]:disabled:not(:checked)::before {\n content: \"\";\n transform: scale(0);\n cursor: not-allowed;\n pointer-events:none;\n}\n\n/** this is the color of the checkbox and content on a disabled, checked box **/\ninput[type=checkbox]:disabled, input[type=radio]:disabled {\n --form-control-color: rgb(211, 211, 211);\n color: #959495;\n cursor: not-allowed;\n pointer-events:none;\n}\n\n\n/** Radio styles to replace iCheck **/\n\ninput[type=\"radio\"] {\n appearance: none;\n background-color: #fff;\n margin: 0;\n font: inherit;\n color: #959495;\n width: 1.8em;\n height: 1.8em;\n border: 0.05em solid;\n border-radius: 50%;\n transform: translateY(-0.075em);\n display: grid;\n place-content: center;\n}\n\ninput[type=\"radio\"]::before {\n content: \"\";\n width: 1em;\n height: 1em;\n border-radius: 50%;\n transform: scale(0);\n transition: 120ms transform ease-in-out;\n box-shadow: inset 1em 1em #428bca;\n}\n\ninput[type=\"radio\"]:checked::before {\n transform: scale(1);\n}\n\n\n/**\n* This addresses the column selector in bootstrap-table. Without these two lines, the\n* checkbox and the with the label text that BS tables generates will\n* end up on two different lines and it looks assy.\n */\n.dropdown-item-marker input[type=checkbox] {\n font-size: 10px;\n}\n\n.bootstrap-table .fixed-table-toolbar li.dropdown-item-marker label {\n font-weight: normal;\n display: grid;\n grid-template-columns: .1em auto;\n gap: 1.5em;\n}\n\n.container.row-striped .col-md-6 {\n overflow-wrap:anywhere;\n}\n\n.nav-tabs-custom > .nav-tabs > li {\n z-index: 1;\n}\n\n.select2-container .select2-search--inline .select2-search__field{\n padding-left:15px;\n}\n\n.nav-tabs-custom > .nav-tabs > li.active {\n font-weight: bold;\n}\n\n/** --------------------------------------- **/\n/** End checkbox styles to replace iCheck **/\n/** --------------------------------------- **/\n\n/**\n/** Separator styles with text in the middle. Currently only used by the login page but\n/** could be used elsewhere.\n */\n\n.separator {\n display: flex;\n align-items: center;\n text-align: center;\n padding-top: 20px;\n color: #959495;\n}\n\n.separator::before,\n.separator::after {\n content: '';\n flex: 1;\n border-bottom: 1px solid #959495;\n}\n\n.separator:not(:empty)::before {\n margin-right: .25em;\n}\n\n.separator:not(:empty)::after {\n margin-left: .25em;\n}\n.datepicker.dropdown-menu {\n z-index: 1030 !important;\n}\n\n.sidebar-menu > li .badge {\n margin-top: 0px;\n filter: brightness(70%);\n font-size: 70%;\n}\n\n/** this is needed to override ekko-lightboxes card view styles **/\n.bootstrap-table .fixed-table-container .table tbody tr .card-view {\n display: table-row !important;\n}\n\n.form-control-static {\n padding-top: 0px;\n}\n\n\ntd.text-right.text-padding-number-cell {\n padding-right: 30px !important;\n white-space: nowrap;\n}\n\nth.text-right.text-padding-number-footer-cell {\n padding-right: 20px !important;\n white-space: nowrap;\n}\n\ncode.single-line {\n white-space: pre-wrap;\n display: -webkit-box;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 1;\n overflow: hidden;\n max-width: 400px;\n}\n\np.monospace, span.monospace {\n font-family: monospace, monospace;\n}\n\nlegend.highlight {\n background: repeating-linear-gradient(\n 45deg,\n #222d32,\n #222d32 10px,\n #444 10px,\n #444 11px\n );\n\n color: #fff;\n font-size: 18px;\n padding: 6px 6px 6px 10px;\n}\n\nlegend.highlight a {\n color: #fff;\n cursor: pointer;\n}\n\nfieldset.bottom-padded {\n padding-bottom: 20px;\n}\n\ncaption.tableCaption {\n font-size: 18px;\n padding-left: 8px;\n}\n\n// via https://github.com/grokability/snipe-it/issues/11754\n.sidebar-toggle.btn {\n border-radius: 3px;\n box-shadow: none;\n border-top: 0px solid transparent;\n border-bottom: 0px solid transparent;\n padding-left: 15px;\n padding-right: 15px;\n padding-top: 12px;\n padding-bottom: 12px;\n margin-left: -47px;\n margin-top: 2px;\n}\n.popover.help-popover,\n.popover.help-popover .popover-content,\n.popover.help-popover .popover-body,\n.popover.help-popover .popover-title,\n.popover.help-popover .popover-header {\n color: #000;\n}\n\n.visually-hidden {\n width: 1px;\n height: 1px;\n margin: -1px;\n overflow: hidden;\n clip: rect(0,0,0,0);\n white-space: preserve;\n display: inline-block;\n}\n\ninput[name=\"columnsSearch\"] {\n width: 120px;\n}"],"names":[],"sourceRoot":""} \ No newline at end of file diff --git a/public/css/dist/all.css b/public/css/dist/all.css index 5ad5b3eb3a..4f0251968a 100644 --- a/public/css/dist/all.css +++ b/public/css/dist/all.css @@ -21642,9 +21642,6 @@ a.accordion-header { padding: 0px; /* adjust based on your layout */ } -.skin-blue .main-header .navbar .dropdown-menu li a { - color: #333; -} a.logo.no-hover a:hover { background-color: transparent; } @@ -22388,6 +22385,7 @@ th.css-license > .th-inner, th.css-location > .th-inner, th.css-users > .th-inner, th.css-currency > .th-inner, +th.css-child-locations > .th-inner, th.css-history > .th-inner { font-size: 0px; line-height: 0.75 !important; @@ -22408,9 +22406,9 @@ th.css-house-laptop > .th-inner::before, th.css-house-user > .th-inner::before, th.css-license > .th-inner::before, th.css-location > .th-inner::before, -th.css-padlock > .th-inner::before, th.css-users > .th-inner::before, th.css-currency > .th-inner::before, +th.css-child-locations > .th-inner::before, th.css-history > .th-inner::before { display: inline-block; font-size: 20px; @@ -22465,7 +22463,8 @@ th.css-component > .th-inner::before { th.css-padlock > .th-inner::before { content: "\f023"; font-family: "Font Awesome 5 Free"; - font-weight: 900; + font-weight: 800; + padding-right: 3px; } th.css-house-user > .th-inner::before { content: "\e1b0"; @@ -22491,6 +22490,12 @@ th.css-accessory-alt > .th-inner::before { font-size: 19px; margin-bottom: 0px; } +th.css-child-locations > .th-inner::before { + content: "\f64f"; + font-family: "Font Awesome 5 Free"; + font-size: 19px; + margin-bottom: 0px; +} th.css-currency > .th-inner::before { content: "\24"; font-family: "Font Awesome 5 Free"; @@ -22816,6 +22821,25 @@ caption.tableCaption { margin-left: -47px; margin-top: 2px; } +.popover.help-popover, +.popover.help-popover .popover-content, +.popover.help-popover .popover-body, +.popover.help-popover .popover-title, +.popover.help-popover .popover-header { + color: #000; +} +.visually-hidden { + width: 1px; + height: 1px; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: preserve; + display: inline-block; +} +input[name="columnsSearch"] { + width: 120px; +} /*# sourceMappingURL=app.css.map*/ @@ -23976,6 +24000,7 @@ th.css-license > .th-inner, th.css-location > .th-inner, th.css-users > .th-inner, th.css-currency > .th-inner, +th.css-child-locations > .th-inner, th.css-history > .th-inner { font-size: 0px; line-height: 0.75 !important; @@ -23996,9 +24021,9 @@ th.css-house-laptop > .th-inner::before, th.css-house-user > .th-inner::before, th.css-license > .th-inner::before, th.css-location > .th-inner::before, -th.css-padlock > .th-inner::before, th.css-users > .th-inner::before, th.css-currency > .th-inner::before, +th.css-child-locations > .th-inner::before, th.css-history > .th-inner::before { display: inline-block; font-size: 20px; @@ -24053,7 +24078,8 @@ th.css-component > .th-inner::before { th.css-padlock > .th-inner::before { content: "\f023"; font-family: "Font Awesome 5 Free"; - font-weight: 900; + font-weight: 800; + padding-right: 3px; } th.css-house-user > .th-inner::before { content: "\e1b0"; @@ -24079,6 +24105,12 @@ th.css-accessory-alt > .th-inner::before { font-size: 19px; margin-bottom: 0px; } +th.css-child-locations > .th-inner::before { + content: "\f64f"; + font-family: "Font Awesome 5 Free"; + font-size: 19px; + margin-bottom: 0px; +} th.css-currency > .th-inner::before { content: "\24"; font-family: "Font Awesome 5 Free"; @@ -24404,6 +24436,25 @@ caption.tableCaption { margin-left: -47px; margin-top: 2px; } +.popover.help-popover, +.popover.help-popover .popover-content, +.popover.help-popover .popover-body, +.popover.help-popover .popover-title, +.popover.help-popover .popover-header { + color: #000; +} +.visually-hidden { + width: 1px; + height: 1px; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: preserve; + display: inline-block; +} +input[name="columnsSearch"] { + width: 120px; +} /*# sourceMappingURL=overrides.css.map*/ \ No newline at end of file diff --git a/public/js/dist/all.js b/public/js/dist/all.js index 7c92716543..a8a6ca3181 100644 --- a/public/js/dist/all.js +++ b/public/js/dist/all.js @@ -9575,6 +9575,18823 @@ module.exports.TinyEmitter = E; })(jQuery); +/***/ }), + +/***/ "./node_modules/jquery-ui/dist/jquery-ui.js": +/*!**************************************************!*\ + !*** ./node_modules/jquery-ui/dist/jquery-ui.js ***! + \**************************************************/ +/***/ ((module, exports, __webpack_require__) => { + +var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! jQuery UI - v1.14.1 - 2024-10-30 +* https://jqueryui.com +* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-patch.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js +* Copyright OpenJS Foundation and other contributors; Licensed MIT */ + +( function( factory ) { + "use strict"; + + if ( true ) { + + // AMD. Register as an anonymous module. + !(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(/*! jquery */ "./node_modules/jquery/dist/jquery.js") ], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), + __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? + (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } else {} +} )( function( $ ) { +"use strict"; + +$.ui = $.ui || {}; + +var version = $.ui.version = "1.14.1"; + + +/*! + * jQuery UI Widget 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Widget +//>>group: Core +//>>description: Provides a factory for creating stateful widgets with a common API. +//>>docs: https://api.jqueryui.com/jQuery.widget/ +//>>demos: https://jqueryui.com/widget/ + + +var widgetUuid = 0; +var widgetHasOwnProperty = Array.prototype.hasOwnProperty; +var widgetSlice = Array.prototype.slice; + +$.cleanData = ( function( orig ) { + return function( elems ) { + var events, elem, i; + for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) { + + // Only trigger remove when necessary to save time + events = $._data( elem, "events" ); + if ( events && events.remove ) { + $( elem ).triggerHandler( "remove" ); + } + } + orig( elems ); + }; +} )( $.cleanData ); + +$.widget = function( name, base, prototype ) { + var existingConstructor, constructor, basePrototype; + + // ProxiedPrototype allows the provided prototype to remain unmodified + // so that it can be used as a mixin for multiple widgets (#8876) + var proxiedPrototype = {}; + + var namespace = name.split( "." )[ 0 ]; + name = name.split( "." )[ 1 ]; + if ( name === "__proto__" || name === "constructor" ) { + return $.error( "Invalid widget name: " + name ); + } + var fullName = namespace + "-" + name; + + if ( !prototype ) { + prototype = base; + base = $.Widget; + } + + if ( Array.isArray( prototype ) ) { + prototype = $.extend.apply( null, [ {} ].concat( prototype ) ); + } + + // Create selector for plugin + $.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) { + return !!$.data( elem, fullName ); + }; + + $[ namespace ] = $[ namespace ] || {}; + existingConstructor = $[ namespace ][ name ]; + constructor = $[ namespace ][ name ] = function( options, element ) { + + // Allow instantiation without "new" keyword + if ( !this || !this._createWidget ) { + return new constructor( options, element ); + } + + // Allow instantiation without initializing for simple inheritance + // must use "new" keyword (the code above always passes args) + if ( arguments.length ) { + this._createWidget( options, element ); + } + }; + + // Extend with the existing constructor to carry over any static properties + $.extend( constructor, existingConstructor, { + version: prototype.version, + + // Copy the object used to create the prototype in case we need to + // redefine the widget later + _proto: $.extend( {}, prototype ), + + // Track widgets that inherit from this widget in case this widget is + // redefined after a widget inherits from it + _childConstructors: [] + } ); + + basePrototype = new base(); + + // We need to make the options hash a property directly on the new instance + // otherwise we'll modify the options hash on the prototype that we're + // inheriting from + basePrototype.options = $.widget.extend( {}, basePrototype.options ); + $.each( prototype, function( prop, value ) { + if ( typeof value !== "function" ) { + proxiedPrototype[ prop ] = value; + return; + } + proxiedPrototype[ prop ] = ( function() { + function _super() { + return base.prototype[ prop ].apply( this, arguments ); + } + + function _superApply( args ) { + return base.prototype[ prop ].apply( this, args ); + } + + return function() { + var __super = this._super; + var __superApply = this._superApply; + var returnValue; + + this._super = _super; + this._superApply = _superApply; + + returnValue = value.apply( this, arguments ); + + this._super = __super; + this._superApply = __superApply; + + return returnValue; + }; + } )(); + } ); + constructor.prototype = $.widget.extend( basePrototype, { + + // TODO: remove support for widgetEventPrefix + // always use the name + a colon as the prefix, e.g., draggable:start + // don't prefix for widgets that aren't DOM-based + widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name + }, proxiedPrototype, { + constructor: constructor, + namespace: namespace, + widgetName: name, + widgetFullName: fullName + } ); + + // If this widget is being redefined then we need to find all widgets that + // are inheriting from it and redefine all of them so that they inherit from + // the new version of this widget. We're essentially trying to replace one + // level in the prototype chain. + if ( existingConstructor ) { + $.each( existingConstructor._childConstructors, function( i, child ) { + var childPrototype = child.prototype; + + // Redefine the child widget using the same prototype that was + // originally used, but inherit from the new version of the base + $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor, + child._proto ); + } ); + + // Remove the list of existing child constructors from the old constructor + // so the old child constructors can be garbage collected + delete existingConstructor._childConstructors; + } else { + base._childConstructors.push( constructor ); + } + + $.widget.bridge( name, constructor ); + + return constructor; +}; + +$.widget.extend = function( target ) { + var input = widgetSlice.call( arguments, 1 ); + var inputIndex = 0; + var inputLength = input.length; + var key; + var value; + + for ( ; inputIndex < inputLength; inputIndex++ ) { + for ( key in input[ inputIndex ] ) { + value = input[ inputIndex ][ key ]; + if ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) { + + // Clone objects + if ( $.isPlainObject( value ) ) { + target[ key ] = $.isPlainObject( target[ key ] ) ? + $.widget.extend( {}, target[ key ], value ) : + + // Don't extend strings, arrays, etc. with objects + $.widget.extend( {}, value ); + + // Copy everything else by reference + } else { + target[ key ] = value; + } + } + } + } + return target; +}; + +$.widget.bridge = function( name, object ) { + var fullName = object.prototype.widgetFullName || name; + $.fn[ name ] = function( options ) { + var isMethodCall = typeof options === "string"; + var args = widgetSlice.call( arguments, 1 ); + var returnValue = this; + + if ( isMethodCall ) { + + // If this is an empty collection, we need to have the instance method + // return undefined instead of the jQuery instance + if ( !this.length && options === "instance" ) { + returnValue = undefined; + } else { + this.each( function() { + var methodValue; + var instance = $.data( this, fullName ); + + if ( options === "instance" ) { + returnValue = instance; + return false; + } + + if ( !instance ) { + return $.error( "cannot call methods on " + name + + " prior to initialization; " + + "attempted to call method '" + options + "'" ); + } + + if ( typeof instance[ options ] !== "function" || + options.charAt( 0 ) === "_" ) { + return $.error( "no such method '" + options + "' for " + name + + " widget instance" ); + } + + methodValue = instance[ options ].apply( instance, args ); + + if ( methodValue !== instance && methodValue !== undefined ) { + returnValue = methodValue && methodValue.jquery ? + returnValue.pushStack( methodValue.get() ) : + methodValue; + return false; + } + } ); + } + } else { + + // Allow multiple hashes to be passed on init + if ( args.length ) { + options = $.widget.extend.apply( null, [ options ].concat( args ) ); + } + + this.each( function() { + var instance = $.data( this, fullName ); + if ( instance ) { + instance.option( options || {} ); + if ( instance._init ) { + instance._init(); + } + } else { + $.data( this, fullName, new object( options, this ) ); + } + } ); + } + + return returnValue; + }; +}; + +$.Widget = function( /* options, element */ ) {}; +$.Widget._childConstructors = []; + +$.Widget.prototype = { + widgetName: "widget", + widgetEventPrefix: "", + defaultElement: "
", + + options: { + classes: {}, + disabled: false, + + // Callbacks + create: null + }, + + _createWidget: function( options, element ) { + element = $( element || this.defaultElement || this )[ 0 ]; + this.element = $( element ); + this.uuid = widgetUuid++; + this.eventNamespace = "." + this.widgetName + this.uuid; + + this.bindings = $(); + this.hoverable = $(); + this.focusable = $(); + this.classesElementLookup = {}; + + if ( element !== this ) { + $.data( element, this.widgetFullName, this ); + this._on( true, this.element, { + remove: function( event ) { + if ( event.target === element ) { + this.destroy(); + } + } + } ); + this.document = $( element.style ? + + // Element within the document + element.ownerDocument : + + // Element is window or document + element.document || element ); + this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow ); + } + + this.options = $.widget.extend( {}, + this.options, + this._getCreateOptions(), + options ); + + this._create(); + + if ( this.options.disabled ) { + this._setOptionDisabled( this.options.disabled ); + } + + this._trigger( "create", null, this._getCreateEventData() ); + this._init(); + }, + + _getCreateOptions: function() { + return {}; + }, + + _getCreateEventData: $.noop, + + _create: $.noop, + + _init: $.noop, + + destroy: function() { + var that = this; + + this._destroy(); + $.each( this.classesElementLookup, function( key, value ) { + that._removeClass( value, key ); + } ); + + // We can probably remove the unbind calls in 2.0 + // all event bindings should go through this._on() + this.element + .off( this.eventNamespace ) + .removeData( this.widgetFullName ); + this.widget() + .off( this.eventNamespace ) + .removeAttr( "aria-disabled" ); + + // Clean up events and states + this.bindings.off( this.eventNamespace ); + }, + + _destroy: $.noop, + + widget: function() { + return this.element; + }, + + option: function( key, value ) { + var options = key; + var parts; + var curOption; + var i; + + if ( arguments.length === 0 ) { + + // Don't return a reference to the internal hash + return $.widget.extend( {}, this.options ); + } + + if ( typeof key === "string" ) { + + // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } } + options = {}; + parts = key.split( "." ); + key = parts.shift(); + if ( parts.length ) { + curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] ); + for ( i = 0; i < parts.length - 1; i++ ) { + curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {}; + curOption = curOption[ parts[ i ] ]; + } + key = parts.pop(); + if ( arguments.length === 1 ) { + return curOption[ key ] === undefined ? null : curOption[ key ]; + } + curOption[ key ] = value; + } else { + if ( arguments.length === 1 ) { + return this.options[ key ] === undefined ? null : this.options[ key ]; + } + options[ key ] = value; + } + } + + this._setOptions( options ); + + return this; + }, + + _setOptions: function( options ) { + var key; + + for ( key in options ) { + this._setOption( key, options[ key ] ); + } + + return this; + }, + + _setOption: function( key, value ) { + if ( key === "classes" ) { + this._setOptionClasses( value ); + } + + this.options[ key ] = value; + + if ( key === "disabled" ) { + this._setOptionDisabled( value ); + } + + return this; + }, + + _setOptionClasses: function( value ) { + var classKey, elements, currentElements; + + for ( classKey in value ) { + currentElements = this.classesElementLookup[ classKey ]; + if ( value[ classKey ] === this.options.classes[ classKey ] || + !currentElements || + !currentElements.length ) { + continue; + } + + // We are doing this to create a new jQuery object because the _removeClass() call + // on the next line is going to destroy the reference to the current elements being + // tracked. We need to save a copy of this collection so that we can add the new classes + // below. + elements = $( currentElements.get() ); + this._removeClass( currentElements, classKey ); + + // We don't use _addClass() here, because that uses this.options.classes + // for generating the string of classes. We want to use the value passed in from + // _setOption(), this is the new value of the classes option which was passed to + // _setOption(). We pass this value directly to _classes(). + elements.addClass( this._classes( { + element: elements, + keys: classKey, + classes: value, + add: true + } ) ); + } + }, + + _setOptionDisabled: function( value ) { + this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value ); + + // If the widget is becoming disabled, then nothing is interactive + if ( value ) { + this._removeClass( this.hoverable, null, "ui-state-hover" ); + this._removeClass( this.focusable, null, "ui-state-focus" ); + } + }, + + enable: function() { + return this._setOptions( { disabled: false } ); + }, + + disable: function() { + return this._setOptions( { disabled: true } ); + }, + + _classes: function( options ) { + var full = []; + var that = this; + + options = $.extend( { + element: this.element, + classes: this.options.classes || {} + }, options ); + + function bindRemoveEvent() { + var nodesToBind = []; + + options.element.each( function( _, element ) { + var isTracked = $.map( that.classesElementLookup, function( elements ) { + return elements; + } ) + .some( function( elements ) { + return elements.is( element ); + } ); + + if ( !isTracked ) { + nodesToBind.push( element ); + } + } ); + + that._on( $( nodesToBind ), { + remove: "_untrackClassesElement" + } ); + } + + function processClassString( classes, checkOption ) { + var current, i; + for ( i = 0; i < classes.length; i++ ) { + current = that.classesElementLookup[ classes[ i ] ] || $(); + if ( options.add ) { + bindRemoveEvent(); + current = $( $.uniqueSort( current.get().concat( options.element.get() ) ) ); + } else { + current = $( current.not( options.element ).get() ); + } + that.classesElementLookup[ classes[ i ] ] = current; + full.push( classes[ i ] ); + if ( checkOption && options.classes[ classes[ i ] ] ) { + full.push( options.classes[ classes[ i ] ] ); + } + } + } + + if ( options.keys ) { + processClassString( options.keys.match( /\S+/g ) || [], true ); + } + if ( options.extra ) { + processClassString( options.extra.match( /\S+/g ) || [] ); + } + + return full.join( " " ); + }, + + _untrackClassesElement: function( event ) { + var that = this; + $.each( that.classesElementLookup, function( key, value ) { + if ( $.inArray( event.target, value ) !== -1 ) { + that.classesElementLookup[ key ] = $( value.not( event.target ).get() ); + } + } ); + + this._off( $( event.target ) ); + }, + + _removeClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, false ); + }, + + _addClass: function( element, keys, extra ) { + return this._toggleClass( element, keys, extra, true ); + }, + + _toggleClass: function( element, keys, extra, add ) { + add = ( typeof add === "boolean" ) ? add : extra; + var shift = ( typeof element === "string" || element === null ), + options = { + extra: shift ? keys : extra, + keys: shift ? element : keys, + element: shift ? this.element : element, + add: add + }; + options.element.toggleClass( this._classes( options ), add ); + return this; + }, + + _on: function( suppressDisabledCheck, element, handlers ) { + var delegateElement; + var instance = this; + + // No suppressDisabledCheck flag, shuffle arguments + if ( typeof suppressDisabledCheck !== "boolean" ) { + handlers = element; + element = suppressDisabledCheck; + suppressDisabledCheck = false; + } + + // No element argument, shuffle and use this.element + if ( !handlers ) { + handlers = element; + element = this.element; + delegateElement = this.widget(); + } else { + element = delegateElement = $( element ); + this.bindings = this.bindings.add( element ); + } + + $.each( handlers, function( event, handler ) { + function handlerProxy() { + + // Allow widgets to customize the disabled handling + // - disabled as an array instead of boolean + // - disabled class as method for disabling individual parts + if ( !suppressDisabledCheck && + ( instance.options.disabled === true || + $( this ).hasClass( "ui-state-disabled" ) ) ) { + return; + } + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + + // Copy the guid so direct unbinding works + if ( typeof handler !== "string" ) { + handlerProxy.guid = handler.guid = + handler.guid || handlerProxy.guid || $.guid++; + } + + var match = event.match( /^([\w:-]*)\s*(.*)$/ ); + var eventName = match[ 1 ] + instance.eventNamespace; + var selector = match[ 2 ]; + + if ( selector ) { + delegateElement.on( eventName, selector, handlerProxy ); + } else { + element.on( eventName, handlerProxy ); + } + } ); + }, + + _off: function( element, eventName ) { + eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) + + this.eventNamespace; + element.off( eventName ); + + // Clear the stack to avoid memory leaks (#10056) + this.bindings = $( this.bindings.not( element ).get() ); + this.focusable = $( this.focusable.not( element ).get() ); + this.hoverable = $( this.hoverable.not( element ).get() ); + }, + + _delay: function( handler, delay ) { + function handlerProxy() { + return ( typeof handler === "string" ? instance[ handler ] : handler ) + .apply( instance, arguments ); + } + var instance = this; + return setTimeout( handlerProxy, delay || 0 ); + }, + + _hoverable: function( element ) { + this.hoverable = this.hoverable.add( element ); + this._on( element, { + mouseenter: function( event ) { + this._addClass( $( event.currentTarget ), null, "ui-state-hover" ); + }, + mouseleave: function( event ) { + this._removeClass( $( event.currentTarget ), null, "ui-state-hover" ); + } + } ); + }, + + _focusable: function( element ) { + this.focusable = this.focusable.add( element ); + this._on( element, { + focusin: function( event ) { + this._addClass( $( event.currentTarget ), null, "ui-state-focus" ); + }, + focusout: function( event ) { + this._removeClass( $( event.currentTarget ), null, "ui-state-focus" ); + } + } ); + }, + + _trigger: function( type, event, data ) { + var prop, orig; + var callback = this.options[ type ]; + + data = data || {}; + event = $.Event( event ); + event.type = ( type === this.widgetEventPrefix ? + type : + this.widgetEventPrefix + type ).toLowerCase(); + + // The original event may come from any element + // so we need to reset the target on the new event + event.target = this.element[ 0 ]; + + // Copy original event properties over to the new event + orig = event.originalEvent; + if ( orig ) { + for ( prop in orig ) { + if ( !( prop in event ) ) { + event[ prop ] = orig[ prop ]; + } + } + } + + this.element.trigger( event, data ); + return !( typeof callback === "function" && + callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false || + event.isDefaultPrevented() ); + } +}; + +$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) { + $.Widget.prototype[ "_" + method ] = function( element, options, callback ) { + if ( typeof options === "string" ) { + options = { effect: options }; + } + + var hasOptions; + var effectName = !options ? + method : + options === true || typeof options === "number" ? + defaultEffect : + options.effect || defaultEffect; + + options = options || {}; + if ( typeof options === "number" ) { + options = { duration: options }; + } else if ( options === true ) { + options = {}; + } + + hasOptions = !$.isEmptyObject( options ); + options.complete = callback; + + if ( options.delay ) { + element.delay( options.delay ); + } + + if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) { + element[ method ]( options ); + } else if ( effectName !== method && element[ effectName ] ) { + element[ effectName ]( options.duration, options.easing, callback ); + } else { + element.queue( function( next ) { + $( this )[ method ](); + if ( callback ) { + callback.call( element[ 0 ] ); + } + next(); + } ); + } + }; +} ); + +var widget = $.widget; + + +/*! + * jQuery UI Position 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + * + * https://api.jqueryui.com/position/ + */ + +//>>label: Position +//>>group: Core +//>>description: Positions elements relative to other elements. +//>>docs: https://api.jqueryui.com/position/ +//>>demos: https://jqueryui.com/position/ + + +( function() { +var cachedScrollbarWidth, + max = Math.max, + abs = Math.abs, + rhorizontal = /left|center|right/, + rvertical = /top|center|bottom/, + roffset = /[\+\-]\d+(\.[\d]+)?%?/, + rposition = /^\w+/, + rpercent = /%$/, + _position = $.fn.position; + +function getOffsets( offsets, width, height ) { + return [ + parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ), + parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 ) + ]; +} + +function parseCss( element, property ) { + return parseInt( $.css( element, property ), 10 ) || 0; +} + +function isWindow( obj ) { + return obj != null && obj === obj.window; +} + +function getDimensions( elem ) { + var raw = elem[ 0 ]; + if ( raw.nodeType === 9 ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: 0, left: 0 } + }; + } + if ( isWindow( raw ) ) { + return { + width: elem.width(), + height: elem.height(), + offset: { top: elem.scrollTop(), left: elem.scrollLeft() } + }; + } + if ( raw.preventDefault ) { + return { + width: 0, + height: 0, + offset: { top: raw.pageY, left: raw.pageX } + }; + } + return { + width: elem.outerWidth(), + height: elem.outerHeight(), + offset: elem.offset() + }; +} + +$.position = { + scrollbarWidth: function() { + if ( cachedScrollbarWidth !== undefined ) { + return cachedScrollbarWidth; + } + var w1, w2, + div = $( "
" + + "
" ), + innerDiv = div.children()[ 0 ]; + + $( "body" ).append( div ); + w1 = innerDiv.offsetWidth; + div.css( "overflow", "scroll" ); + + w2 = innerDiv.offsetWidth; + + if ( w1 === w2 ) { + w2 = div[ 0 ].clientWidth; + } + + div.remove(); + + return ( cachedScrollbarWidth = w1 - w2 ); + }, + getScrollInfo: function( within ) { + var overflowX = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-x" ), + overflowY = within.isWindow || within.isDocument ? "" : + within.element.css( "overflow-y" ), + hasOverflowX = overflowX === "scroll" || + ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ), + hasOverflowY = overflowY === "scroll" || + ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight ); + return { + width: hasOverflowY ? $.position.scrollbarWidth() : 0, + height: hasOverflowX ? $.position.scrollbarWidth() : 0 + }; + }, + getWithinInfo: function( element ) { + var withinElement = $( element || window ), + isElemWindow = isWindow( withinElement[ 0 ] ), + isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9, + hasOffset = !isElemWindow && !isDocument; + return { + element: withinElement, + isWindow: isElemWindow, + isDocument: isDocument, + offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 }, + scrollLeft: withinElement.scrollLeft(), + scrollTop: withinElement.scrollTop(), + width: withinElement.outerWidth(), + height: withinElement.outerHeight() + }; + } +}; + +$.fn.position = function( options ) { + if ( !options || !options.of ) { + return _position.apply( this, arguments ); + } + + // Make a copy, we don't want to modify arguments + options = $.extend( {}, options ); + + var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions, + + // Make sure string options are treated as CSS selectors + target = typeof options.of === "string" ? + $( document ).find( options.of ) : + $( options.of ), + + within = $.position.getWithinInfo( options.within ), + scrollInfo = $.position.getScrollInfo( within ), + collision = ( options.collision || "flip" ).split( " " ), + offsets = {}; + + dimensions = getDimensions( target ); + if ( target[ 0 ].preventDefault ) { + + // Force left top to allow flipping + options.at = "left top"; + } + targetWidth = dimensions.width; + targetHeight = dimensions.height; + targetOffset = dimensions.offset; + + // Clone to reuse original targetOffset later + basePosition = $.extend( {}, targetOffset ); + + // Force my and at to have valid horizontal and vertical positions + // if a value is missing or invalid, it will be converted to center + $.each( [ "my", "at" ], function() { + var pos = ( options[ this ] || "" ).split( " " ), + horizontalOffset, + verticalOffset; + + if ( pos.length === 1 ) { + pos = rhorizontal.test( pos[ 0 ] ) ? + pos.concat( [ "center" ] ) : + rvertical.test( pos[ 0 ] ) ? + [ "center" ].concat( pos ) : + [ "center", "center" ]; + } + pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center"; + pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center"; + + // Calculate offsets + horizontalOffset = roffset.exec( pos[ 0 ] ); + verticalOffset = roffset.exec( pos[ 1 ] ); + offsets[ this ] = [ + horizontalOffset ? horizontalOffset[ 0 ] : 0, + verticalOffset ? verticalOffset[ 0 ] : 0 + ]; + + // Reduce to just the positions without the offsets + options[ this ] = [ + rposition.exec( pos[ 0 ] )[ 0 ], + rposition.exec( pos[ 1 ] )[ 0 ] + ]; + } ); + + // Normalize collision option + if ( collision.length === 1 ) { + collision[ 1 ] = collision[ 0 ]; + } + + if ( options.at[ 0 ] === "right" ) { + basePosition.left += targetWidth; + } else if ( options.at[ 0 ] === "center" ) { + basePosition.left += targetWidth / 2; + } + + if ( options.at[ 1 ] === "bottom" ) { + basePosition.top += targetHeight; + } else if ( options.at[ 1 ] === "center" ) { + basePosition.top += targetHeight / 2; + } + + atOffset = getOffsets( offsets.at, targetWidth, targetHeight ); + basePosition.left += atOffset[ 0 ]; + basePosition.top += atOffset[ 1 ]; + + return this.each( function() { + var collisionPosition, using, + elem = $( this ), + elemWidth = elem.outerWidth(), + elemHeight = elem.outerHeight(), + marginLeft = parseCss( this, "marginLeft" ), + marginTop = parseCss( this, "marginTop" ), + collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) + + scrollInfo.width, + collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) + + scrollInfo.height, + position = $.extend( {}, basePosition ), + myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() ); + + if ( options.my[ 0 ] === "right" ) { + position.left -= elemWidth; + } else if ( options.my[ 0 ] === "center" ) { + position.left -= elemWidth / 2; + } + + if ( options.my[ 1 ] === "bottom" ) { + position.top -= elemHeight; + } else if ( options.my[ 1 ] === "center" ) { + position.top -= elemHeight / 2; + } + + position.left += myOffset[ 0 ]; + position.top += myOffset[ 1 ]; + + collisionPosition = { + marginLeft: marginLeft, + marginTop: marginTop + }; + + $.each( [ "left", "top" ], function( i, dir ) { + if ( $.ui.position[ collision[ i ] ] ) { + $.ui.position[ collision[ i ] ][ dir ]( position, { + targetWidth: targetWidth, + targetHeight: targetHeight, + elemWidth: elemWidth, + elemHeight: elemHeight, + collisionPosition: collisionPosition, + collisionWidth: collisionWidth, + collisionHeight: collisionHeight, + offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ], + my: options.my, + at: options.at, + within: within, + elem: elem + } ); + } + } ); + + if ( options.using ) { + + // Adds feedback as second argument to using callback, if present + using = function( props ) { + var left = targetOffset.left - position.left, + right = left + targetWidth - elemWidth, + top = targetOffset.top - position.top, + bottom = top + targetHeight - elemHeight, + feedback = { + target: { + element: target, + left: targetOffset.left, + top: targetOffset.top, + width: targetWidth, + height: targetHeight + }, + element: { + element: elem, + left: position.left, + top: position.top, + width: elemWidth, + height: elemHeight + }, + horizontal: right < 0 ? "left" : left > 0 ? "right" : "center", + vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle" + }; + if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) { + feedback.horizontal = "center"; + } + if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) { + feedback.vertical = "middle"; + } + if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) { + feedback.important = "horizontal"; + } else { + feedback.important = "vertical"; + } + options.using.call( this, props, feedback ); + }; + } + + elem.offset( $.extend( position, { using: using } ) ); + } ); +}; + +$.ui.position = { + fit: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollLeft : within.offset.left, + outerWidth = within.width, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = withinOffset - collisionPosLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset, + newOverRight; + + // Element is wider than within + if ( data.collisionWidth > outerWidth ) { + + // Element is initially over the left side of within + if ( overLeft > 0 && overRight <= 0 ) { + newOverRight = position.left + overLeft + data.collisionWidth - outerWidth - + withinOffset; + position.left += overLeft - newOverRight; + + // Element is initially over right side of within + } else if ( overRight > 0 && overLeft <= 0 ) { + position.left = withinOffset; + + // Element is initially over both left and right sides of within + } else { + if ( overLeft > overRight ) { + position.left = withinOffset + outerWidth - data.collisionWidth; + } else { + position.left = withinOffset; + } + } + + // Too far left -> align with left edge + } else if ( overLeft > 0 ) { + position.left += overLeft; + + // Too far right -> align with right edge + } else if ( overRight > 0 ) { + position.left -= overRight; + + // Adjust based on position and margin + } else { + position.left = max( position.left - collisionPosLeft, position.left ); + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.isWindow ? within.scrollTop : within.offset.top, + outerHeight = data.within.height, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = withinOffset - collisionPosTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset, + newOverBottom; + + // Element is taller than within + if ( data.collisionHeight > outerHeight ) { + + // Element is initially over the top of within + if ( overTop > 0 && overBottom <= 0 ) { + newOverBottom = position.top + overTop + data.collisionHeight - outerHeight - + withinOffset; + position.top += overTop - newOverBottom; + + // Element is initially over bottom of within + } else if ( overBottom > 0 && overTop <= 0 ) { + position.top = withinOffset; + + // Element is initially over both top and bottom of within + } else { + if ( overTop > overBottom ) { + position.top = withinOffset + outerHeight - data.collisionHeight; + } else { + position.top = withinOffset; + } + } + + // Too far up -> align with top + } else if ( overTop > 0 ) { + position.top += overTop; + + // Too far down -> align with bottom edge + } else if ( overBottom > 0 ) { + position.top -= overBottom; + + // Adjust based on position and margin + } else { + position.top = max( position.top - collisionPosTop, position.top ); + } + } + }, + flip: { + left: function( position, data ) { + var within = data.within, + withinOffset = within.offset.left + within.scrollLeft, + outerWidth = within.width, + offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left, + collisionPosLeft = position.left - data.collisionPosition.marginLeft, + overLeft = collisionPosLeft - offsetLeft, + overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft, + myOffset = data.my[ 0 ] === "left" ? + -data.elemWidth : + data.my[ 0 ] === "right" ? + data.elemWidth : + 0, + atOffset = data.at[ 0 ] === "left" ? + data.targetWidth : + data.at[ 0 ] === "right" ? + -data.targetWidth : + 0, + offset = -2 * data.offset[ 0 ], + newOverRight, + newOverLeft; + + if ( overLeft < 0 ) { + newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth - + outerWidth - withinOffset; + if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) { + position.left += myOffset + atOffset + offset; + } + } else if ( overRight > 0 ) { + newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset + + atOffset + offset - offsetLeft; + if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) { + position.left += myOffset + atOffset + offset; + } + } + }, + top: function( position, data ) { + var within = data.within, + withinOffset = within.offset.top + within.scrollTop, + outerHeight = within.height, + offsetTop = within.isWindow ? within.scrollTop : within.offset.top, + collisionPosTop = position.top - data.collisionPosition.marginTop, + overTop = collisionPosTop - offsetTop, + overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop, + top = data.my[ 1 ] === "top", + myOffset = top ? + -data.elemHeight : + data.my[ 1 ] === "bottom" ? + data.elemHeight : + 0, + atOffset = data.at[ 1 ] === "top" ? + data.targetHeight : + data.at[ 1 ] === "bottom" ? + -data.targetHeight : + 0, + offset = -2 * data.offset[ 1 ], + newOverTop, + newOverBottom; + if ( overTop < 0 ) { + newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight - + outerHeight - withinOffset; + if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) { + position.top += myOffset + atOffset + offset; + } + } else if ( overBottom > 0 ) { + newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset + + offset - offsetTop; + if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) { + position.top += myOffset + atOffset + offset; + } + } + } + }, + flipfit: { + left: function() { + $.ui.position.flip.left.apply( this, arguments ); + $.ui.position.fit.left.apply( this, arguments ); + }, + top: function() { + $.ui.position.flip.top.apply( this, arguments ); + $.ui.position.fit.top.apply( this, arguments ); + } + } +}; + +} )(); + +var position = $.ui.position; + + +/*! + * jQuery UI :data 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: :data Selector +//>>group: Core +//>>description: Selects elements which have data stored under the specified key. +//>>docs: https://api.jqueryui.com/data-selector/ + + +var data = $.extend( $.expr.pseudos, { + data: $.expr.createPseudo( function( dataName ) { + return function( elem ) { + return !!$.data( elem, dataName ); + }; + } ) +} ); + +/*! + * jQuery UI Disable Selection 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: disableSelection +//>>group: Core +//>>description: Disable selection of text content within the set of matched elements. +//>>docs: https://api.jqueryui.com/disableSelection/ + +// This file is deprecated + +var disableSelection = $.fn.extend( { + disableSelection: ( function() { + var eventType = "onselectstart" in document.createElement( "div" ) ? + "selectstart" : + "mousedown"; + + return function() { + return this.on( eventType + ".ui-disableSelection", function( event ) { + event.preventDefault(); + } ); + }; + } )(), + + enableSelection: function() { + return this.off( ".ui-disableSelection" ); + } +} ); + + + +// Create a local jQuery because jQuery Color relies on it and the +// global may not exist with AMD and a custom build (#10199). +// This module is a noop if used as a regular AMD module. +// eslint-disable-next-line no-unused-vars +var jQuery = $; + + +/*! + * jQuery Color Animations v3.0.0 + * https://github.com/jquery/jquery-color + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + * + * Date: Wed May 15 16:49:44 2024 +0200 + */ + + + var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " + + "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor", + + class2type = {}, + toString = class2type.toString, + + // plusequals test for += 100 -= 100 + rplusequals = /^([\-+])=\s*(\d+\.?\d*)/, + + // a set of RE's that can match strings and generate color tuples. + stringParsers = [ { + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ], + execResult[ 3 ], + execResult[ 4 ] + ]; + } + }, { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function( execResult ) { + return [ + execResult[ 1 ] * 2.55, + execResult[ 2 ] * 2.55, + execResult[ 3 ] * 2.55, + execResult[ 4 ] + ]; + } + }, { + + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})?/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ], 16 ), + execResult[ 4 ] ? + ( parseInt( execResult[ 4 ], 16 ) / 255 ).toFixed( 2 ) : + 1 + ]; + } + }, { + + // this regex ignores A-F because it's compared against an already lowercased string + re: /#([a-f0-9])([a-f0-9])([a-f0-9])([a-f0-9])?/, + parse: function( execResult ) { + return [ + parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ), + parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ), + parseInt( execResult[ 3 ] + execResult[ 3 ], 16 ), + execResult[ 4 ] ? + ( parseInt( execResult[ 4 ] + execResult[ 4 ], 16 ) / 255 ) + .toFixed( 2 ) : + 1 + ]; + } + }, { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + space: "hsla", + parse: function( execResult ) { + return [ + execResult[ 1 ], + execResult[ 2 ] / 100, + execResult[ 3 ] / 100, + execResult[ 4 ] + ]; + } + } ], + + // jQuery.Color( ) + color = jQuery.Color = function( color, green, blue, alpha ) { + return new jQuery.Color.fn.parse( color, green, blue, alpha ); + }, + spaces = { + rgba: { + props: { + red: { + idx: 0, + type: "byte" + }, + green: { + idx: 1, + type: "byte" + }, + blue: { + idx: 2, + type: "byte" + } + } + }, + + hsla: { + props: { + hue: { + idx: 0, + type: "degrees" + }, + saturation: { + idx: 1, + type: "percent" + }, + lightness: { + idx: 2, + type: "percent" + } + } + } + }, + propTypes = { + "byte": { + floor: true, + max: 255 + }, + "percent": { + max: 1 + }, + "degrees": { + mod: 360, + floor: true + } + }, + + // colors = jQuery.Color.names + colors, + + // local aliases of functions called often + each = jQuery.each; + +// define cache name and alpha properties +// for rgba and hsla spaces +each( spaces, function( spaceName, space ) { + space.cache = "_" + spaceName; + space.props.alpha = { + idx: 3, + type: "percent", + def: 1 + }; +} ); + +// Populate the class2type map +jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), + function( _i, name ) { + class2type[ "[object " + name + "]" ] = name.toLowerCase(); + } ); + +function getType( obj ) { + if ( obj == null ) { + return obj + ""; + } + + return typeof obj === "object" ? + class2type[ toString.call( obj ) ] || "object" : + typeof obj; +} + +function clamp( value, prop, allowEmpty ) { + var type = propTypes[ prop.type ] || {}; + + if ( value == null ) { + return ( allowEmpty || !prop.def ) ? null : prop.def; + } + + // ~~ is an short way of doing floor for positive numbers + value = type.floor ? ~~value : parseFloat( value ); + + if ( type.mod ) { + + // we add mod before modding to make sure that negatives values + // get converted properly: -10 -> 350 + return ( value + type.mod ) % type.mod; + } + + // for now all property types without mod have min and max + return Math.min( type.max, Math.max( 0, value ) ); +} + +function stringParse( string ) { + var inst = color(), + rgba = inst._rgba = []; + + string = string.toLowerCase(); + + each( stringParsers, function( _i, parser ) { + var parsed, + match = parser.re.exec( string ), + values = match && parser.parse( match ), + spaceName = parser.space || "rgba"; + + if ( values ) { + parsed = inst[ spaceName ]( values ); + + // if this was an rgba parse the assignment might happen twice + // oh well.... + inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ]; + rgba = inst._rgba = parsed._rgba; + + // exit each( stringParsers ) here because we matched + return false; + } + } ); + + // Found a stringParser that handled it + if ( rgba.length ) { + + // if this came from a parsed string, force "transparent" when alpha is 0 + // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0) + if ( rgba.join() === "0,0,0,0" ) { + jQuery.extend( rgba, colors.transparent ); + } + return inst; + } + + // named colors + return colors[ string ]; +} + +color.fn = jQuery.extend( color.prototype, { + parse: function( red, green, blue, alpha ) { + if ( red === undefined ) { + this._rgba = [ null, null, null, null ]; + return this; + } + if ( red.jquery || red.nodeType ) { + red = jQuery( red ).css( green ); + green = undefined; + } + + var inst = this, + type = getType( red ), + rgba = this._rgba = []; + + // more than 1 argument specified - assume ( red, green, blue, alpha ) + if ( green !== undefined ) { + red = [ red, green, blue, alpha ]; + type = "array"; + } + + if ( type === "string" ) { + return this.parse( stringParse( red ) || colors._default ); + } + + if ( type === "array" ) { + each( spaces.rgba.props, function( _key, prop ) { + rgba[ prop.idx ] = clamp( red[ prop.idx ], prop ); + } ); + return this; + } + + if ( type === "object" ) { + if ( red instanceof color ) { + each( spaces, function( _spaceName, space ) { + if ( red[ space.cache ] ) { + inst[ space.cache ] = red[ space.cache ].slice(); + } + } ); + } else { + each( spaces, function( _spaceName, space ) { + var cache = space.cache; + each( space.props, function( key, prop ) { + + // if the cache doesn't exist, and we know how to convert + if ( !inst[ cache ] && space.to ) { + + // if the value was null, we don't need to copy it + // if the key was alpha, we don't need to copy it either + if ( key === "alpha" || red[ key ] == null ) { + return; + } + inst[ cache ] = space.to( inst._rgba ); + } + + // this is the only case where we allow nulls for ALL properties. + // call clamp with alwaysAllowEmpty + inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true ); + } ); + + // everything defined but alpha? + if ( inst[ cache ] && jQuery.inArray( + null, + inst[ cache ].slice( 0, 3 ) + ) < 0 ) { + + // use the default of 1 + if ( inst[ cache ][ 3 ] == null ) { + inst[ cache ][ 3 ] = 1; + } + + if ( space.from ) { + inst._rgba = space.from( inst[ cache ] ); + } + } + } ); + } + return this; + } + }, + is: function( compare ) { + var is = color( compare ), + same = true, + inst = this; + + each( spaces, function( _, space ) { + var localCache, + isCache = is[ space.cache ]; + if ( isCache ) { + localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || []; + each( space.props, function( _, prop ) { + if ( isCache[ prop.idx ] != null ) { + same = ( isCache[ prop.idx ] === localCache[ prop.idx ] ); + return same; + } + } ); + } + return same; + } ); + return same; + }, + _space: function() { + var used = [], + inst = this; + each( spaces, function( spaceName, space ) { + if ( inst[ space.cache ] ) { + used.push( spaceName ); + } + } ); + return used.pop(); + }, + transition: function( other, distance ) { + var end = color( other ), + spaceName = end._space(), + space = spaces[ spaceName ], + startColor = this.alpha() === 0 ? color( "transparent" ) : this, + start = startColor[ space.cache ] || space.to( startColor._rgba ), + result = start.slice(); + + end = end[ space.cache ]; + each( space.props, function( _key, prop ) { + var index = prop.idx, + startValue = start[ index ], + endValue = end[ index ], + type = propTypes[ prop.type ] || {}; + + // if null, don't override start value + if ( endValue === null ) { + return; + } + + // if null - use end + if ( startValue === null ) { + result[ index ] = endValue; + } else { + if ( type.mod ) { + if ( endValue - startValue > type.mod / 2 ) { + startValue += type.mod; + } else if ( startValue - endValue > type.mod / 2 ) { + startValue -= type.mod; + } + } + result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop ); + } + } ); + return this[ spaceName ]( result ); + }, + blend: function( opaque ) { + + // if we are already opaque - return ourself + if ( this._rgba[ 3 ] === 1 ) { + return this; + } + + var rgb = this._rgba.slice(), + a = rgb.pop(), + blend = color( opaque )._rgba; + + return color( jQuery.map( rgb, function( v, i ) { + return ( 1 - a ) * blend[ i ] + a * v; + } ) ); + }, + toRgbaString: function() { + var prefix = "rgba(", + rgba = jQuery.map( this._rgba, function( v, i ) { + if ( v != null ) { + return v; + } + return i > 2 ? 1 : 0; + } ); + + if ( rgba[ 3 ] === 1 ) { + rgba.pop(); + prefix = "rgb("; + } + + return prefix + rgba.join( ", " ) + ")"; + }, + toHslaString: function() { + var prefix = "hsla(", + hsla = jQuery.map( this.hsla(), function( v, i ) { + if ( v == null ) { + v = i > 2 ? 1 : 0; + } + + // catch 1 and 2 + if ( i && i < 3 ) { + v = Math.round( v * 100 ) + "%"; + } + return v; + } ); + + if ( hsla[ 3 ] === 1 ) { + hsla.pop(); + prefix = "hsl("; + } + return prefix + hsla.join( ", " ) + ")"; + }, + toHexString: function( includeAlpha ) { + var rgba = this._rgba.slice(), + alpha = rgba.pop(); + + if ( includeAlpha ) { + rgba.push( ~~( alpha * 255 ) ); + } + + return "#" + jQuery.map( rgba, function( v ) { + + // default to 0 when nulls exist + return ( "0" + ( v || 0 ).toString( 16 ) ).substr( -2 ); + } ).join( "" ); + }, + toString: function() { + return this.toRgbaString(); + } +} ); +color.fn.parse.prototype = color.fn; + +// hsla conversions adapted from: +// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021 + +function hue2rgb( p, q, h ) { + h = ( h + 1 ) % 1; + if ( h * 6 < 1 ) { + return p + ( q - p ) * h * 6; + } + if ( h * 2 < 1 ) { + return q; + } + if ( h * 3 < 2 ) { + return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6; + } + return p; +} + +spaces.hsla.to = function( rgba ) { + if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) { + return [ null, null, null, rgba[ 3 ] ]; + } + var r = rgba[ 0 ] / 255, + g = rgba[ 1 ] / 255, + b = rgba[ 2 ] / 255, + a = rgba[ 3 ], + max = Math.max( r, g, b ), + min = Math.min( r, g, b ), + diff = max - min, + add = max + min, + l = add * 0.5, + h, s; + + if ( min === max ) { + h = 0; + } else if ( r === max ) { + h = ( 60 * ( g - b ) / diff ) + 360; + } else if ( g === max ) { + h = ( 60 * ( b - r ) / diff ) + 120; + } else { + h = ( 60 * ( r - g ) / diff ) + 240; + } + + // chroma (diff) == 0 means greyscale which, by definition, saturation = 0% + // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add) + if ( diff === 0 ) { + s = 0; + } else if ( l <= 0.5 ) { + s = diff / add; + } else { + s = diff / ( 2 - add ); + } + return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ]; +}; + +spaces.hsla.from = function( hsla ) { + if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) { + return [ null, null, null, hsla[ 3 ] ]; + } + var h = hsla[ 0 ] / 360, + s = hsla[ 1 ], + l = hsla[ 2 ], + a = hsla[ 3 ], + q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s, + p = 2 * l - q; + + return [ + Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ), + Math.round( hue2rgb( p, q, h ) * 255 ), + Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ), + a + ]; +}; + + +each( spaces, function( spaceName, space ) { + var props = space.props, + cache = space.cache, + to = space.to, + from = space.from; + + // makes rgba() and hsla() + color.fn[ spaceName ] = function( value ) { + + // generate a cache for this space if it doesn't exist + if ( to && !this[ cache ] ) { + this[ cache ] = to( this._rgba ); + } + if ( value === undefined ) { + return this[ cache ].slice(); + } + + var ret, + type = getType( value ), + arr = ( type === "array" || type === "object" ) ? value : arguments, + local = this[ cache ].slice(); + + each( props, function( key, prop ) { + var val = arr[ type === "object" ? key : prop.idx ]; + if ( val == null ) { + val = local[ prop.idx ]; + } + local[ prop.idx ] = clamp( val, prop ); + } ); + + if ( from ) { + ret = color( from( local ) ); + ret[ cache ] = local; + return ret; + } else { + return color( local ); + } + }; + + // makes red() green() blue() alpha() hue() saturation() lightness() + each( props, function( key, prop ) { + + // alpha is included in more than one space + if ( color.fn[ key ] ) { + return; + } + color.fn[ key ] = function( value ) { + var local, cur, match, fn, + vtype = getType( value ); + + if ( key === "alpha" ) { + fn = this._hsla ? "hsla" : "rgba"; + } else { + fn = spaceName; + } + local = this[ fn ](); + cur = local[ prop.idx ]; + + if ( vtype === "undefined" ) { + return cur; + } + + if ( vtype === "function" ) { + value = value.call( this, cur ); + vtype = getType( value ); + } + if ( value == null && prop.empty ) { + return this; + } + if ( vtype === "string" ) { + match = rplusequals.exec( value ); + if ( match ) { + value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 ); + } + } + local[ prop.idx ] = value; + return this[ fn ]( local ); + }; + } ); +} ); + +// add cssHook and .fx.step function for each named hook. +// accept a space separated string of properties +color.hook = function( hook ) { + var hooks = hook.split( " " ); + each( hooks, function( _i, hook ) { + jQuery.cssHooks[ hook ] = { + set: function( elem, value ) { + var parsed; + + if ( value !== "transparent" && + ( getType( value ) !== "string" || + ( parsed = stringParse( value ) ) ) ) { + value = color( parsed || value ); + value = value.toRgbaString(); + } + elem.style[ hook ] = value; + } + }; + jQuery.fx.step[ hook ] = function( fx ) { + if ( !fx.colorInit ) { + fx.start = color( fx.elem, hook ); + fx.end = color( fx.end ); + fx.colorInit = true; + } + jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) ); + }; + } ); + +}; + +color.hook( stepHooks ); + +jQuery.cssHooks.borderColor = { + expand: function( value ) { + var expanded = {}; + + each( [ "Top", "Right", "Bottom", "Left" ], function( _i, part ) { + expanded[ "border" + part + "Color" ] = value; + } ); + return expanded; + } +}; + +// Basic color names only. +// Usage of any of the other color names requires adding yourself or including +// jquery.color.svg-names.js. +colors = jQuery.Color.names = { + + // 4.1. Basic color keywords + aqua: "#00ffff", + black: "#000000", + blue: "#0000ff", + fuchsia: "#ff00ff", + gray: "#808080", + green: "#008000", + lime: "#00ff00", + maroon: "#800000", + navy: "#000080", + olive: "#808000", + purple: "#800080", + red: "#ff0000", + silver: "#c0c0c0", + teal: "#008080", + white: "#ffffff", + yellow: "#ffff00", + + // 4.2.3. "transparent" color keyword + transparent: [ null, null, null, 0 ], + + _default: "#ffffff" +}; + + +/*! + * jQuery UI Effects 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Effects Core +//>>group: Effects +/* eslint-disable max-len */ +//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects. +/* eslint-enable max-len */ +//>>docs: https://api.jqueryui.com/category/effects-core/ +//>>demos: https://jqueryui.com/effect/ + + +var dataSpace = "ui-effects-", + dataSpaceStyle = "ui-effects-style", + dataSpaceAnimated = "ui-effects-animated"; + +$.effects = { + effect: {} +}; + +/******************************************************************************/ +/****************************** CLASS ANIMATIONS ******************************/ +/******************************************************************************/ +( function() { + +var classAnimationActions = [ "add", "remove", "toggle" ], + shorthandStyles = { + border: 1, + borderBottom: 1, + borderColor: 1, + borderLeft: 1, + borderRight: 1, + borderTop: 1, + borderWidth: 1, + margin: 1, + padding: 1 + }; + +$.each( + [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ], + function( _, prop ) { + $.fx.step[ prop ] = function( fx ) { + if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) { + jQuery.style( fx.elem, prop, fx.end ); + fx.setAttr = true; + } + }; + } +); + +function camelCase( string ) { + return string.replace( /-([\da-z])/gi, function( all, letter ) { + return letter.toUpperCase(); + } ); +} + +function getElementStyles( elem ) { + var key, len, + style = elem.ownerDocument.defaultView.getComputedStyle( elem ), + styles = {}; + + len = style.length; + while ( len-- ) { + key = style[ len ]; + if ( typeof style[ key ] === "string" ) { + styles[ camelCase( key ) ] = style[ key ]; + } + } + + return styles; +} + +function styleDifference( oldStyle, newStyle ) { + var diff = {}, + name, value; + + for ( name in newStyle ) { + value = newStyle[ name ]; + if ( oldStyle[ name ] !== value ) { + if ( !shorthandStyles[ name ] ) { + if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) { + diff[ name ] = value; + } + } + } + } + + return diff; +} + +$.effects.animateClass = function( value, duration, easing, callback ) { + var o = $.speed( duration, easing, callback ); + + return this.queue( function() { + var animated = $( this ), + baseClass = animated.attr( "class" ) || "", + applyClassChange, + allAnimations = o.children ? animated.find( "*" ).addBack() : animated; + + // Map the animated objects to store the original styles. + allAnimations = allAnimations.map( function() { + var el = $( this ); + return { + el: el, + start: getElementStyles( this ) + }; + } ); + + // Apply class change + applyClassChange = function() { + $.each( classAnimationActions, function( i, action ) { + if ( value[ action ] ) { + animated[ action + "Class" ]( value[ action ] ); + } + } ); + }; + applyClassChange(); + + // Map all animated objects again - calculate new styles and diff + allAnimations = allAnimations.map( function() { + this.end = getElementStyles( this.el[ 0 ] ); + this.diff = styleDifference( this.start, this.end ); + return this; + } ); + + // Apply original class + animated.attr( "class", baseClass ); + + // Map all animated objects again - this time collecting a promise + allAnimations = allAnimations.map( function() { + var styleInfo = this, + dfd = $.Deferred(), + opts = $.extend( {}, o, { + queue: false, + complete: function() { + dfd.resolve( styleInfo ); + } + } ); + + this.el.animate( this.diff, opts ); + return dfd.promise(); + } ); + + // Once all animations have completed: + $.when.apply( $, allAnimations.get() ).done( function() { + + // Set the final class + applyClassChange(); + + // For each animated element, + // clear all css properties that were animated + $.each( arguments, function() { + var el = this.el; + $.each( this.diff, function( key ) { + el.css( key, "" ); + } ); + } ); + + // This is guarnteed to be there if you use jQuery.speed() + // it also handles dequeuing the next anim... + o.complete.call( animated[ 0 ] ); + } ); + } ); +}; + +$.fn.extend( { + addClass: ( function( orig ) { + return function( classNames, speed, easing, callback ) { + return speed ? + $.effects.animateClass.call( this, + { add: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + } )( $.fn.addClass ), + + removeClass: ( function( orig ) { + return function( classNames, speed, easing, callback ) { + return arguments.length > 1 ? + $.effects.animateClass.call( this, + { remove: classNames }, speed, easing, callback ) : + orig.apply( this, arguments ); + }; + } )( $.fn.removeClass ), + + toggleClass: ( function( orig ) { + return function( classNames, force, speed, easing, callback ) { + if ( typeof force === "boolean" || force === undefined ) { + if ( !speed ) { + + // Without speed parameter + return orig.apply( this, arguments ); + } else { + return $.effects.animateClass.call( this, + ( force ? { add: classNames } : { remove: classNames } ), + speed, easing, callback ); + } + } else { + + // Without force parameter + return $.effects.animateClass.call( this, + { toggle: classNames }, force, speed, easing ); + } + }; + } )( $.fn.toggleClass ), + + switchClass: function( remove, add, speed, easing, callback ) { + return $.effects.animateClass.call( this, { + add: add, + remove: remove + }, speed, easing, callback ); + } +} ); + +} )(); + +/******************************************************************************/ +/*********************************** EFFECTS **********************************/ +/******************************************************************************/ + +( function() { + +if ( $.expr && $.expr.pseudos && $.expr.pseudos.animated ) { + $.expr.pseudos.animated = ( function( orig ) { + return function( elem ) { + return !!$( elem ).data( dataSpaceAnimated ) || orig( elem ); + }; + } )( $.expr.pseudos.animated ); +} + +if ( $.uiBackCompat === true ) { + $.extend( $.effects, { + + // Saves a set of properties in a data storage + save: function( element, set ) { + var i = 0, length = set.length; + for ( ; i < length; i++ ) { + if ( set[ i ] !== null ) { + element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] ); + } + } + }, + + // Restores a set of previously saved properties from a data storage + restore: function( element, set ) { + var val, i = 0, length = set.length; + for ( ; i < length; i++ ) { + if ( set[ i ] !== null ) { + val = element.data( dataSpace + set[ i ] ); + element.css( set[ i ], val ); + } + } + }, + + setMode: function( el, mode ) { + if ( mode === "toggle" ) { + mode = el.is( ":hidden" ) ? "show" : "hide"; + } + return mode; + }, + + // Wraps the element around a wrapper that copies position properties + createWrapper: function( element ) { + + // If the element is already wrapped, return it + if ( element.parent().is( ".ui-effects-wrapper" ) ) { + return element.parent(); + } + + // Wrap the element + var props = { + width: element.outerWidth( true ), + height: element.outerHeight( true ), + "float": element.css( "float" ) + }, + wrapper = $( "
" ) + .addClass( "ui-effects-wrapper" ) + .css( { + fontSize: "100%", + background: "transparent", + border: "none", + margin: 0, + padding: 0 + } ), + + // Store the size in case width/height are defined in % - Fixes #5245 + size = { + width: element.width(), + height: element.height() + }, + active = document.activeElement; + + // Support: Firefox + // Firefox incorrectly exposes anonymous content + // https://bugzilla.mozilla.org/show_bug.cgi?id=561664 + try { + // eslint-disable-next-line no-unused-expressions + active.id; + } catch ( e ) { + active = document.body; + } + + element.wrap( wrapper ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).trigger( "focus" ); + } + + // Hotfix for jQuery 1.4 since some change in wrap() seems to actually + // lose the reference to the wrapped element + wrapper = element.parent(); + + // Transfer positioning properties to the wrapper + if ( element.css( "position" ) === "static" ) { + wrapper.css( { position: "relative" } ); + element.css( { position: "relative" } ); + } else { + $.extend( props, { + position: element.css( "position" ), + zIndex: element.css( "z-index" ) + } ); + $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) { + props[ pos ] = element.css( pos ); + if ( isNaN( parseInt( props[ pos ], 10 ) ) ) { + props[ pos ] = "auto"; + } + } ); + element.css( { + position: "relative", + top: 0, + left: 0, + right: "auto", + bottom: "auto" + } ); + } + element.css( size ); + + return wrapper.css( props ).show(); + }, + + removeWrapper: function( element ) { + var active = document.activeElement; + + if ( element.parent().is( ".ui-effects-wrapper" ) ) { + element.parent().replaceWith( element ); + + // Fixes #7595 - Elements lose focus when wrapped. + if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) { + $( active ).trigger( "focus" ); + } + } + + return element; + } + } ); +} + +$.extend( $.effects, { + version: "1.14.1", + + define: function( name, mode, effect ) { + if ( !effect ) { + effect = mode; + mode = "effect"; + } + + $.effects.effect[ name ] = effect; + $.effects.effect[ name ].mode = mode; + + return effect; + }, + + scaledDimensions: function( element, percent, direction ) { + if ( percent === 0 ) { + return { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0 + }; + } + + var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1, + y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1; + + return { + height: element.height() * y, + width: element.width() * x, + outerHeight: element.outerHeight() * y, + outerWidth: element.outerWidth() * x + }; + + }, + + clipToBox: function( animation ) { + return { + width: animation.clip.right - animation.clip.left, + height: animation.clip.bottom - animation.clip.top, + left: animation.clip.left, + top: animation.clip.top + }; + }, + + // Injects recently queued functions to be first in line (after "inprogress") + unshift: function( element, queueLength, count ) { + var queue = element.queue(); + + if ( queueLength > 1 ) { + queue.splice.apply( queue, + [ 1, 0 ].concat( queue.splice( queueLength, count ) ) ); + } + element.dequeue(); + }, + + saveStyle: function( element ) { + element.data( dataSpaceStyle, element[ 0 ].style.cssText ); + }, + + restoreStyle: function( element ) { + element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || ""; + element.removeData( dataSpaceStyle ); + }, + + mode: function( element, mode ) { + var hidden = element.is( ":hidden" ); + + if ( mode === "toggle" ) { + mode = hidden ? "show" : "hide"; + } + if ( hidden ? mode === "hide" : mode === "show" ) { + mode = "none"; + } + return mode; + }, + + // Translates a [top,left] array into a baseline value + getBaseline: function( origin, original ) { + var y, x; + + switch ( origin[ 0 ] ) { + case "top": + y = 0; + break; + case "middle": + y = 0.5; + break; + case "bottom": + y = 1; + break; + default: + y = origin[ 0 ] / original.height; + } + + switch ( origin[ 1 ] ) { + case "left": + x = 0; + break; + case "center": + x = 0.5; + break; + case "right": + x = 1; + break; + default: + x = origin[ 1 ] / original.width; + } + + return { + x: x, + y: y + }; + }, + + // Creates a placeholder element so that the original element can be made absolute + createPlaceholder: function( element ) { + var placeholder, + cssPosition = element.css( "position" ), + position = element.position(); + + // Lock in margins first to account for form elements, which + // will change margin if you explicitly set height + // see: https://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380 + // Support: Safari + element.css( { + marginTop: element.css( "marginTop" ), + marginBottom: element.css( "marginBottom" ), + marginLeft: element.css( "marginLeft" ), + marginRight: element.css( "marginRight" ) + } ) + .outerWidth( element.outerWidth() ) + .outerHeight( element.outerHeight() ); + + if ( /^(static|relative)/.test( cssPosition ) ) { + cssPosition = "absolute"; + + placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( { + + // Convert inline to inline block to account for inline elements + // that turn to inline block based on content (like img) + display: /^(inline|ruby)/.test( element.css( "display" ) ) ? + "inline-block" : + "block", + visibility: "hidden", + + // Margins need to be set to account for margin collapse + marginTop: element.css( "marginTop" ), + marginBottom: element.css( "marginBottom" ), + marginLeft: element.css( "marginLeft" ), + marginRight: element.css( "marginRight" ), + "float": element.css( "float" ) + } ) + .outerWidth( element.outerWidth() ) + .outerHeight( element.outerHeight() ) + .addClass( "ui-effects-placeholder" ); + + element.data( dataSpace + "placeholder", placeholder ); + } + + element.css( { + position: cssPosition, + left: position.left, + top: position.top + } ); + + return placeholder; + }, + + removePlaceholder: function( element ) { + var dataKey = dataSpace + "placeholder", + placeholder = element.data( dataKey ); + + if ( placeholder ) { + placeholder.remove(); + element.removeData( dataKey ); + } + }, + + // Removes a placeholder if it exists and restores + // properties that were modified during placeholder creation + cleanUp: function( element ) { + $.effects.restoreStyle( element ); + $.effects.removePlaceholder( element ); + }, + + setTransition: function( element, list, factor, value ) { + value = value || {}; + $.each( list, function( i, x ) { + var unit = element.cssUnit( x ); + if ( unit[ 0 ] > 0 ) { + value[ x ] = unit[ 0 ] * factor + unit[ 1 ]; + } + } ); + return value; + } +} ); + +// Return an effect options object for the given parameters: +function _normalizeArguments( effect, options, speed, callback ) { + + // Allow passing all options as the first parameter + if ( $.isPlainObject( effect ) ) { + options = effect; + effect = effect.effect; + } + + // Convert to an object + effect = { effect: effect }; + + // Catch (effect, null, ...) + if ( options == null ) { + options = {}; + } + + // Catch (effect, callback) + if ( typeof options === "function" ) { + callback = options; + speed = null; + options = {}; + } + + // Catch (effect, speed, ?) + if ( typeof options === "number" || $.fx.speeds[ options ] ) { + callback = speed; + speed = options; + options = {}; + } + + // Catch (effect, options, callback) + if ( typeof speed === "function" ) { + callback = speed; + speed = null; + } + + // Add options to effect + if ( options ) { + $.extend( effect, options ); + } + + speed = speed || options.duration; + effect.duration = $.fx.off ? 0 : + typeof speed === "number" ? speed : + speed in $.fx.speeds ? $.fx.speeds[ speed ] : + $.fx.speeds._default; + + effect.complete = callback || options.complete; + + return effect; +} + +function standardAnimationOption( option ) { + + // Valid standard speeds (nothing, number, named speed) + if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) { + return true; + } + + // Invalid strings - treat as "normal" speed + if ( typeof option === "string" && !$.effects.effect[ option ] ) { + return true; + } + + // Complete callback + if ( typeof option === "function" ) { + return true; + } + + // Options hash (but not naming an effect) + if ( typeof option === "object" && !option.effect ) { + return true; + } + + // Didn't match any standard API + return false; +} + +$.fn.extend( { + effect: function( /* effect, options, speed, callback */ ) { + var args = _normalizeArguments.apply( this, arguments ), + effectMethod = $.effects.effect[ args.effect ], + defaultMode = effectMethod.mode, + queue = args.queue, + queueName = queue || "fx", + complete = args.complete, + mode = args.mode, + modes = [], + prefilter = function( next ) { + var el = $( this ), + normalizedMode = $.effects.mode( el, mode ) || defaultMode; + + // Sentinel for duck-punching the :animated pseudo-selector + el.data( dataSpaceAnimated, true ); + + // Save effect mode for later use, + // we can't just call $.effects.mode again later, + // as the .show() below destroys the initial state + modes.push( normalizedMode ); + + // See $.uiBackCompat inside of run() for removal of defaultMode in 1.14 + if ( defaultMode && ( normalizedMode === "show" || + ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) { + el.show(); + } + + if ( !defaultMode || normalizedMode !== "none" ) { + $.effects.saveStyle( el ); + } + + if ( typeof next === "function" ) { + next(); + } + }; + + if ( $.fx.off || !effectMethod ) { + + // Delegate to the original method (e.g., .show()) if possible + if ( mode ) { + return this[ mode ]( args.duration, complete ); + } else { + return this.each( function() { + if ( complete ) { + complete.call( this ); + } + } ); + } + } + + function run( next ) { + var elem = $( this ); + + function cleanup() { + elem.removeData( dataSpaceAnimated ); + + $.effects.cleanUp( elem ); + + if ( args.mode === "hide" ) { + elem.hide(); + } + + done(); + } + + function done() { + if ( typeof complete === "function" ) { + complete.call( elem[ 0 ] ); + } + + if ( typeof next === "function" ) { + next(); + } + } + + // Override mode option on a per element basis, + // as toggle can be either show or hide depending on element state + args.mode = modes.shift(); + + if ( $.uiBackCompat === true && !defaultMode ) { + if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) { + + // Call the core method to track "olddisplay" properly + elem[ mode ](); + done(); + } else { + effectMethod.call( elem[ 0 ], args, done ); + } + } else { + if ( args.mode === "none" ) { + + // Call the core method to track "olddisplay" properly + elem[ mode ](); + done(); + } else { + effectMethod.call( elem[ 0 ], args, cleanup ); + } + } + } + + // Run prefilter on all elements first to ensure that + // any showing or hiding happens before placeholder creation, + // which ensures that any layout changes are correctly captured. + return queue === false ? + this.each( prefilter ).each( run ) : + this.queue( queueName, prefilter ).queue( queueName, run ); + }, + + show: ( function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "show"; + return this.effect.call( this, args ); + } + }; + } )( $.fn.show ), + + hide: ( function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "hide"; + return this.effect.call( this, args ); + } + }; + } )( $.fn.hide ), + + toggle: ( function( orig ) { + return function( option ) { + if ( standardAnimationOption( option ) || typeof option === "boolean" ) { + return orig.apply( this, arguments ); + } else { + var args = _normalizeArguments.apply( this, arguments ); + args.mode = "toggle"; + return this.effect.call( this, args ); + } + }; + } )( $.fn.toggle ), + + cssUnit: function( key ) { + var style = this.css( key ), + val = []; + + $.each( [ "em", "px", "%", "pt" ], function( i, unit ) { + if ( style.indexOf( unit ) > 0 ) { + val = [ parseFloat( style ), unit ]; + } + } ); + return val; + }, + + cssClip: function( clipObj ) { + if ( clipObj ) { + return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " + + clipObj.bottom + "px " + clipObj.left + "px)" ); + } + return parseClip( this.css( "clip" ), this ); + }, + + transfer: function( options, done ) { + var element = $( this ), + target = $( options.to ), + targetFixed = target.css( "position" ) === "fixed", + body = $( "body" ), + fixTop = targetFixed ? body.scrollTop() : 0, + fixLeft = targetFixed ? body.scrollLeft() : 0, + endPosition = target.offset(), + animation = { + top: endPosition.top - fixTop, + left: endPosition.left - fixLeft, + height: target.innerHeight(), + width: target.innerWidth() + }, + startPosition = element.offset(), + transfer = $( "
" ); + + transfer + .appendTo( "body" ) + .addClass( options.className ) + .css( { + top: startPosition.top - fixTop, + left: startPosition.left - fixLeft, + height: element.innerHeight(), + width: element.innerWidth(), + position: targetFixed ? "fixed" : "absolute" + } ) + .animate( animation, options.duration, options.easing, function() { + transfer.remove(); + if ( typeof done === "function" ) { + done(); + } + } ); + } +} ); + +function parseClip( str, element ) { + var outerWidth = element.outerWidth(), + outerHeight = element.outerHeight(), + clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/, + values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ]; + + return { + top: parseFloat( values[ 1 ] ) || 0, + right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ), + bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ), + left: parseFloat( values[ 4 ] ) || 0 + }; +} + +$.fx.step.clip = function( fx ) { + if ( !fx.clipInit ) { + fx.start = $( fx.elem ).cssClip(); + if ( typeof fx.end === "string" ) { + fx.end = parseClip( fx.end, fx.elem ); + } + fx.clipInit = true; + } + + $( fx.elem ).cssClip( { + top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top, + right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right, + bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom, + left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left + } ); +}; + +} )(); + +/******************************************************************************/ +/*********************************** EASING ***********************************/ +/******************************************************************************/ + +( function() { + +// Based on easing equations from Robert Penner (http://robertpenner.com/easing) + +var baseEasings = {}; + +$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) { + baseEasings[ name ] = function( p ) { + return Math.pow( p, i + 2 ); + }; +} ); + +$.extend( baseEasings, { + Sine: function( p ) { + return 1 - Math.cos( p * Math.PI / 2 ); + }, + Circ: function( p ) { + return 1 - Math.sqrt( 1 - p * p ); + }, + Elastic: function( p ) { + return p === 0 || p === 1 ? p : + -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 ); + }, + Back: function( p ) { + return p * p * ( 3 * p - 2 ); + }, + Bounce: function( p ) { + var pow2, + bounce = 4; + + while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {} + return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 ); + } +} ); + +$.each( baseEasings, function( name, easeIn ) { + $.easing[ "easeIn" + name ] = easeIn; + $.easing[ "easeOut" + name ] = function( p ) { + return 1 - easeIn( 1 - p ); + }; + $.easing[ "easeInOut" + name ] = function( p ) { + return p < 0.5 ? + easeIn( p * 2 ) / 2 : + 1 - easeIn( p * -2 + 2 ) / 2; + }; +} ); + +} )(); + +var effect = $.effects; + + +/*! + * jQuery UI Effects Blind 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Blind Effect +//>>group: Effects +//>>description: Blinds the element. +//>>docs: https://api.jqueryui.com/blind-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) { + var map = { + up: [ "bottom", "top" ], + vertical: [ "bottom", "top" ], + down: [ "top", "bottom" ], + left: [ "right", "left" ], + horizontal: [ "right", "left" ], + right: [ "left", "right" ] + }, + element = $( this ), + direction = options.direction || "up", + start = element.cssClip(), + animate = { clip: $.extend( {}, start ) }, + placeholder = $.effects.createPlaceholder( element ); + + animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ]; + + if ( options.mode === "show" ) { + element.cssClip( animate.clip ); + if ( placeholder ) { + placeholder.css( $.effects.clipToBox( animate ) ); + } + + animate.clip = start; + } + + if ( placeholder ) { + placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing ); + } + + element.animate( animate, { + queue: false, + duration: options.duration, + easing: options.easing, + complete: done + } ); +} ); + + +/*! + * jQuery UI Effects Bounce 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Bounce Effect +//>>group: Effects +//>>description: Bounces an element horizontally or vertically n times. +//>>docs: https://api.jqueryui.com/bounce-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) { + var upAnim, downAnim, refValue, + element = $( this ), + + // Defaults: + mode = options.mode, + hide = mode === "hide", + show = mode === "show", + direction = options.direction || "up", + distance = options.distance, + times = options.times || 5, + + // Number of internal animations + anims = times * 2 + ( show || hide ? 1 : 0 ), + speed = options.duration / anims, + easing = options.easing, + + // Utility: + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ), + i = 0, + + queuelen = element.queue().length; + + $.effects.createPlaceholder( element ); + + refValue = element.css( ref ); + + // Default distance for the BIGGEST bounce is the outer Distance / 3 + if ( !distance ) { + distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3; + } + + if ( show ) { + downAnim = { opacity: 1 }; + downAnim[ ref ] = refValue; + + // If we are showing, force opacity 0 and set the initial position + // then do the "first" animation + element + .css( "opacity", 0 ) + .css( ref, motion ? -distance * 2 : distance * 2 ) + .animate( downAnim, speed, easing ); + } + + // Start at the smallest distance if we are hiding + if ( hide ) { + distance = distance / Math.pow( 2, times - 1 ); + } + + downAnim = {}; + downAnim[ ref ] = refValue; + + // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here + for ( ; i < times; i++ ) { + upAnim = {}; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + + element + .animate( upAnim, speed, easing ) + .animate( downAnim, speed, easing ); + + distance = hide ? distance * 2 : distance / 2; + } + + // Last Bounce when Hiding + if ( hide ) { + upAnim = { opacity: 0 }; + upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance; + + element.animate( upAnim, speed, easing ); + } + + element.queue( done ); + + $.effects.unshift( element, queuelen, anims + 1 ); +} ); + + +/*! + * jQuery UI Effects Clip 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Clip Effect +//>>group: Effects +//>>description: Clips the element on and off like an old TV. +//>>docs: https://api.jqueryui.com/clip-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) { + var start, + animate = {}, + element = $( this ), + direction = options.direction || "vertical", + both = direction === "both", + horizontal = both || direction === "horizontal", + vertical = both || direction === "vertical"; + + start = element.cssClip(); + animate.clip = { + top: vertical ? ( start.bottom - start.top ) / 2 : start.top, + right: horizontal ? ( start.right - start.left ) / 2 : start.right, + bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom, + left: horizontal ? ( start.right - start.left ) / 2 : start.left + }; + + $.effects.createPlaceholder( element ); + + if ( options.mode === "show" ) { + element.cssClip( animate.clip ); + animate.clip = start; + } + + element.animate( animate, { + queue: false, + duration: options.duration, + easing: options.easing, + complete: done + } ); + +} ); + + +/*! + * jQuery UI Effects Drop 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Drop Effect +//>>group: Effects +//>>description: Moves an element in one direction and hides it at the same time. +//>>docs: https://api.jqueryui.com/drop-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) { + + var distance, + element = $( this ), + mode = options.mode, + show = mode === "show", + direction = options.direction || "left", + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=", + oppositeMotion = ( motion === "+=" ) ? "-=" : "+=", + animation = { + opacity: 0 + }; + + $.effects.createPlaceholder( element ); + + distance = options.distance || + element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2; + + animation[ ref ] = motion + distance; + + if ( show ) { + element.css( animation ); + + animation[ ref ] = oppositeMotion + distance; + animation.opacity = 1; + } + + // Animate + element.animate( animation, { + queue: false, + duration: options.duration, + easing: options.easing, + complete: done + } ); +} ); + + +/*! + * jQuery UI Effects Explode 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Explode Effect +//>>group: Effects +/* eslint-disable max-len */ +//>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness. +/* eslint-enable max-len */ +//>>docs: https://api.jqueryui.com/explode-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) { + + var i, j, left, top, mx, my, + rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3, + cells = rows, + element = $( this ), + mode = options.mode, + show = mode === "show", + + // Show and then visibility:hidden the element before calculating offset + offset = element.show().css( "visibility", "hidden" ).offset(), + + // Width and height of a piece + width = Math.ceil( element.outerWidth() / cells ), + height = Math.ceil( element.outerHeight() / rows ), + pieces = []; + + // Children animate complete: + function childComplete() { + pieces.push( this ); + if ( pieces.length === rows * cells ) { + animComplete(); + } + } + + // Clone the element for each row and cell. + for ( i = 0; i < rows; i++ ) { // ===> + top = offset.top + i * height; + my = i - ( rows - 1 ) / 2; + + for ( j = 0; j < cells; j++ ) { // ||| + left = offset.left + j * width; + mx = j - ( cells - 1 ) / 2; + + // Create a clone of the now hidden main element that will be absolute positioned + // within a wrapper div off the -left and -top equal to size of our pieces + element + .clone() + .appendTo( "body" ) + .wrap( "
" ) + .css( { + position: "absolute", + visibility: "visible", + left: -j * width, + top: -i * height + } ) + + // Select the wrapper - make it overflow: hidden and absolute positioned based on + // where the original was located +left and +top equal to the size of pieces + .parent() + .addClass( "ui-effects-explode" ) + .css( { + position: "absolute", + overflow: "hidden", + width: width, + height: height, + left: left + ( show ? mx * width : 0 ), + top: top + ( show ? my * height : 0 ), + opacity: show ? 0 : 1 + } ) + .animate( { + left: left + ( show ? 0 : mx * width ), + top: top + ( show ? 0 : my * height ), + opacity: show ? 1 : 0 + }, options.duration || 500, options.easing, childComplete ); + } + } + + function animComplete() { + element.css( { + visibility: "visible" + } ); + $( pieces ).remove(); + done(); + } +} ); + + +/*! + * jQuery UI Effects Fade 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Fade Effect +//>>group: Effects +//>>description: Fades the element. +//>>docs: https://api.jqueryui.com/fade-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) { + var show = options.mode === "show"; + + $( this ) + .css( "opacity", show ? 0 : 1 ) + .animate( { + opacity: show ? 1 : 0 + }, { + queue: false, + duration: options.duration, + easing: options.easing, + complete: done + } ); +} ); + + +/*! + * jQuery UI Effects Fold 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Fold Effect +//>>group: Effects +//>>description: Folds an element first horizontally and then vertically. +//>>docs: https://api.jqueryui.com/fold-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) { + + // Create element + var element = $( this ), + mode = options.mode, + show = mode === "show", + hide = mode === "hide", + size = options.size || 15, + percent = /([0-9]+)%/.exec( size ), + horizFirst = !!options.horizFirst, + ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ], + duration = options.duration / 2, + + placeholder = $.effects.createPlaceholder( element ), + + start = element.cssClip(), + animation1 = { clip: $.extend( {}, start ) }, + animation2 = { clip: $.extend( {}, start ) }, + + distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ], + + queuelen = element.queue().length; + + if ( percent ) { + size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ]; + } + animation1.clip[ ref[ 0 ] ] = size; + animation2.clip[ ref[ 0 ] ] = size; + animation2.clip[ ref[ 1 ] ] = 0; + + if ( show ) { + element.cssClip( animation2.clip ); + if ( placeholder ) { + placeholder.css( $.effects.clipToBox( animation2 ) ); + } + + animation2.clip = start; + } + + // Animate + element + .queue( function( next ) { + if ( placeholder ) { + placeholder + .animate( $.effects.clipToBox( animation1 ), duration, options.easing ) + .animate( $.effects.clipToBox( animation2 ), duration, options.easing ); + } + + next(); + } ) + .animate( animation1, duration, options.easing ) + .animate( animation2, duration, options.easing ) + .queue( done ); + + $.effects.unshift( element, queuelen, 4 ); +} ); + + +/*! + * jQuery UI Effects Highlight 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Highlight Effect +//>>group: Effects +//>>description: Highlights the background of an element in a defined color for a custom duration. +//>>docs: https://api.jqueryui.com/highlight-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) { + var element = $( this ), + animation = { + backgroundColor: element.css( "backgroundColor" ) + }; + + if ( options.mode === "hide" ) { + animation.opacity = 0; + } + + $.effects.saveStyle( element ); + + element + .css( { + backgroundImage: "none", + backgroundColor: options.color || "#ffff99" + } ) + .animate( animation, { + queue: false, + duration: options.duration, + easing: options.easing, + complete: done + } ); +} ); + + +/*! + * jQuery UI Effects Size 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Size Effect +//>>group: Effects +//>>description: Resize an element to a specified width and height. +//>>docs: https://api.jqueryui.com/size-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectSize = $.effects.define( "size", function( options, done ) { + + // Create element + var baseline, factor, temp, + element = $( this ), + + // Copy for children + cProps = [ "fontSize" ], + vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ], + hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ], + + // Set options + mode = options.mode, + restore = mode !== "effect", + scale = options.scale || "both", + origin = options.origin || [ "middle", "center" ], + position = element.css( "position" ), + pos = element.position(), + original = $.effects.scaledDimensions( element ), + from = options.from || original, + to = options.to || $.effects.scaledDimensions( element, 0 ); + + $.effects.createPlaceholder( element ); + + if ( mode === "show" ) { + temp = from; + from = to; + to = temp; + } + + // Set scaling factor + factor = { + from: { + y: from.height / original.height, + x: from.width / original.width + }, + to: { + y: to.height / original.height, + x: to.width / original.width + } + }; + + // Scale the css box + if ( scale === "box" || scale === "both" ) { + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + from = $.effects.setTransition( element, vProps, factor.from.y, from ); + to = $.effects.setTransition( element, vProps, factor.to.y, to ); + } + + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + from = $.effects.setTransition( element, hProps, factor.from.x, from ); + to = $.effects.setTransition( element, hProps, factor.to.x, to ); + } + } + + // Scale the content + if ( scale === "content" || scale === "both" ) { + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + from = $.effects.setTransition( element, cProps, factor.from.y, from ); + to = $.effects.setTransition( element, cProps, factor.to.y, to ); + } + } + + // Adjust the position properties based on the provided origin points + if ( origin ) { + baseline = $.effects.getBaseline( origin, original ); + from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top; + from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left; + to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top; + to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left; + } + delete from.outerHeight; + delete from.outerWidth; + element.css( from ); + + // Animate the children if desired + if ( scale === "content" || scale === "both" ) { + + vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps ); + hProps = hProps.concat( [ "marginLeft", "marginRight" ] ); + + // Only animate children with width attributes specified + // TODO: is this right? should we include anything with css width specified as well + element.find( "*[width]" ).each( function() { + var child = $( this ), + childOriginal = $.effects.scaledDimensions( child ), + childFrom = { + height: childOriginal.height * factor.from.y, + width: childOriginal.width * factor.from.x, + outerHeight: childOriginal.outerHeight * factor.from.y, + outerWidth: childOriginal.outerWidth * factor.from.x + }, + childTo = { + height: childOriginal.height * factor.to.y, + width: childOriginal.width * factor.to.x, + outerHeight: childOriginal.height * factor.to.y, + outerWidth: childOriginal.width * factor.to.x + }; + + // Vertical props scaling + if ( factor.from.y !== factor.to.y ) { + childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom ); + childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo ); + } + + // Horizontal props scaling + if ( factor.from.x !== factor.to.x ) { + childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom ); + childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo ); + } + + if ( restore ) { + $.effects.saveStyle( child ); + } + + // Animate children + child.css( childFrom ); + child.animate( childTo, options.duration, options.easing, function() { + + // Restore children + if ( restore ) { + $.effects.restoreStyle( child ); + } + } ); + } ); + } + + // Animate + element.animate( to, { + queue: false, + duration: options.duration, + easing: options.easing, + complete: function() { + + var offset = element.offset(); + + if ( to.opacity === 0 ) { + element.css( "opacity", from.opacity ); + } + + if ( !restore ) { + element + .css( "position", position === "static" ? "relative" : position ) + .offset( offset ); + + // Need to save style here so that automatic style restoration + // doesn't restore to the original styles from before the animation. + $.effects.saveStyle( element ); + } + + done(); + } + } ); + +} ); + + +/*! + * jQuery UI Effects Scale 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Scale Effect +//>>group: Effects +//>>description: Grows or shrinks an element and its content. +//>>docs: https://api.jqueryui.com/scale-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectScale = $.effects.define( "scale", function( options, done ) { + + // Create element + var el = $( this ), + mode = options.mode, + percent = parseInt( options.percent, 10 ) || + ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ), + + newOptions = $.extend( true, { + from: $.effects.scaledDimensions( el ), + to: $.effects.scaledDimensions( el, percent, options.direction || "both" ), + origin: options.origin || [ "middle", "center" ] + }, options ); + + // Fade option to support puff + if ( options.fade ) { + newOptions.from.opacity = 1; + newOptions.to.opacity = 0; + } + + $.effects.effect.size.call( this, newOptions, done ); +} ); + + +/*! + * jQuery UI Effects Puff 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Puff Effect +//>>group: Effects +//>>description: Creates a puff effect by scaling the element up and hiding it at the same time. +//>>docs: https://api.jqueryui.com/puff-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) { + var newOptions = $.extend( true, {}, options, { + fade: true, + percent: parseInt( options.percent, 10 ) || 150 + } ); + + $.effects.effect.scale.call( this, newOptions, done ); +} ); + + +/*! + * jQuery UI Effects Pulsate 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Pulsate Effect +//>>group: Effects +//>>description: Pulsates an element n times by changing the opacity to zero and back. +//>>docs: https://api.jqueryui.com/pulsate-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) { + var element = $( this ), + mode = options.mode, + show = mode === "show", + hide = mode === "hide", + showhide = show || hide, + + // Showing or hiding leaves off the "last" animation + anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ), + duration = options.duration / anims, + animateTo = 0, + i = 1, + queuelen = element.queue().length; + + if ( show || !element.is( ":visible" ) ) { + element.css( "opacity", 0 ).show(); + animateTo = 1; + } + + // Anims - 1 opacity "toggles" + for ( ; i < anims; i++ ) { + element.animate( { opacity: animateTo }, duration, options.easing ); + animateTo = 1 - animateTo; + } + + element.animate( { opacity: animateTo }, duration, options.easing ); + + element.queue( done ); + + $.effects.unshift( element, queuelen, anims + 1 ); +} ); + + +/*! + * jQuery UI Effects Shake 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Shake Effect +//>>group: Effects +//>>description: Shakes an element horizontally or vertically n times. +//>>docs: https://api.jqueryui.com/shake-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectShake = $.effects.define( "shake", function( options, done ) { + + var i = 1, + element = $( this ), + direction = options.direction || "left", + distance = options.distance || 20, + times = options.times || 3, + anims = times * 2 + 1, + speed = Math.round( options.duration / anims ), + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + positiveMotion = ( direction === "up" || direction === "left" ), + animation = {}, + animation1 = {}, + animation2 = {}, + + queuelen = element.queue().length; + + $.effects.createPlaceholder( element ); + + // Animation + animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance; + animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2; + animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2; + + // Animate + element.animate( animation, speed, options.easing ); + + // Shakes + for ( ; i < times; i++ ) { + element + .animate( animation1, speed, options.easing ) + .animate( animation2, speed, options.easing ); + } + + element + .animate( animation1, speed, options.easing ) + .animate( animation, speed / 2, options.easing ) + .queue( done ); + + $.effects.unshift( element, queuelen, anims + 1 ); +} ); + + +/*! + * jQuery UI Effects Slide 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Slide Effect +//>>group: Effects +//>>description: Slides an element in and out of the viewport. +//>>docs: https://api.jqueryui.com/slide-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) { + var startClip, startRef, + element = $( this ), + map = { + up: [ "bottom", "top" ], + down: [ "top", "bottom" ], + left: [ "right", "left" ], + right: [ "left", "right" ] + }, + mode = options.mode, + direction = options.direction || "left", + ref = ( direction === "up" || direction === "down" ) ? "top" : "left", + positiveMotion = ( direction === "up" || direction === "left" ), + distance = options.distance || + element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ), + animation = {}; + + $.effects.createPlaceholder( element ); + + startClip = element.cssClip(); + startRef = element.position()[ ref ]; + + // Define hide animation + animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef; + animation.clip = element.cssClip(); + animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ]; + + // Reverse the animation if we're showing + if ( mode === "show" ) { + element.cssClip( animation.clip ); + element.css( ref, animation[ ref ] ); + animation.clip = startClip; + animation[ ref ] = startRef; + } + + // Actually animate + element.animate( animation, { + queue: false, + duration: options.duration, + easing: options.easing, + complete: done + } ); +} ); + + +/*! + * jQuery UI Effects Transfer 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Transfer Effect +//>>group: Effects +//>>description: Displays a transfer effect from one element to another. +//>>docs: https://api.jqueryui.com/transfer-effect/ +//>>demos: https://jqueryui.com/effect/ + + +var effect; +if ( $.uiBackCompat === true ) { + effect = $.effects.define( "transfer", function( options, done ) { + $( this ).transfer( options, done ); + } ); +} +var effectsEffectTransfer = effect; + + +/*! + * jQuery UI Focusable 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: :focusable Selector +//>>group: Core +//>>description: Selects elements which can be focused. +//>>docs: https://api.jqueryui.com/focusable-selector/ + + +// Selectors +$.ui.focusable = function( element, hasTabindex ) { + var map, mapName, img, focusableIfVisible, fieldset, + nodeName = element.nodeName.toLowerCase(); + + if ( "area" === nodeName ) { + map = element.parentNode; + mapName = map.name; + if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) { + return false; + } + img = $( "img[usemap='#" + mapName + "']" ); + return img.length > 0 && img.is( ":visible" ); + } + + if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) { + focusableIfVisible = !element.disabled; + + if ( focusableIfVisible ) { + + // Form controls within a disabled fieldset are disabled. + // However, controls within the fieldset's legend do not get disabled. + // Since controls generally aren't placed inside legends, we skip + // this portion of the check. + fieldset = $( element ).closest( "fieldset" )[ 0 ]; + if ( fieldset ) { + focusableIfVisible = !fieldset.disabled; + } + } + } else if ( "a" === nodeName ) { + focusableIfVisible = element.href || hasTabindex; + } else { + focusableIfVisible = hasTabindex; + } + + return focusableIfVisible && $( element ).is( ":visible" ) && + $( element ).css( "visibility" ) === "visible"; +}; + +$.extend( $.expr.pseudos, { + focusable: function( element ) { + return $.ui.focusable( element, $.attr( element, "tabindex" ) != null ); + } +} ); + +var focusable = $.ui.focusable; + + +/*! + * jQuery UI Form Reset Mixin 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Form Reset Mixin +//>>group: Core +//>>description: Refresh input widgets when their form is reset +//>>docs: https://api.jqueryui.com/form-reset-mixin/ + + +var formResetMixin = $.ui.formResetMixin = { + _formResetHandler: function() { + var form = $( this ); + + // Wait for the form reset to actually happen before refreshing + setTimeout( function() { + var instances = form.data( "ui-form-reset-instances" ); + $.each( instances, function() { + this.refresh(); + } ); + } ); + }, + + _bindFormResetHandler: function() { + this.form = $( this.element.prop( "form" ) ); + if ( !this.form.length ) { + return; + } + + var instances = this.form.data( "ui-form-reset-instances" ) || []; + if ( !instances.length ) { + + // We don't use _on() here because we use a single event handler per form + this.form.on( "reset.ui-form-reset", this._formResetHandler ); + } + instances.push( this ); + this.form.data( "ui-form-reset-instances", instances ); + }, + + _unbindFormResetHandler: function() { + if ( !this.form.length ) { + return; + } + + var instances = this.form.data( "ui-form-reset-instances" ); + instances.splice( $.inArray( this, instances ), 1 ); + if ( instances.length ) { + this.form.data( "ui-form-reset-instances", instances ); + } else { + this.form + .removeData( "ui-form-reset-instances" ) + .off( "reset.ui-form-reset" ); + } + } +}; + + +/*! + * jQuery UI Legacy jQuery Core patches 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + * + */ + +//>>label: Legacy jQuery Core patches +//>>group: Core +//>>description: Backport `.even()`, `.odd()` and `$.escapeSelector` to older jQuery Core versions (deprecated) + + +// Support: jQuery 2.2.x or older. +// This method has been defined in jQuery 3.0.0. +// Code from https://github.com/jquery/jquery/blob/e539bac79e666bba95bba86d690b4e609dca2286/src/selector/escapeSelector.js +if ( !$.escapeSelector ) { + $.escapeSelector = function( id ) { + return CSS.escape( id + "" ); + }; +} + +// Support: jQuery 3.4.x or older +// These methods have been defined in jQuery 3.5.0. +if ( !$.fn.even || !$.fn.odd ) { + $.fn.extend( { + even: function() { + return this.filter( function( i ) { + return i % 2 === 0; + } ); + }, + odd: function() { + return this.filter( function( i ) { + return i % 2 === 1; + } ); + } + } ); +} + +; +/*! + * jQuery UI Keycode 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Keycode +//>>group: Core +//>>description: Provide keycodes as keynames +//>>docs: https://api.jqueryui.com/jQuery.ui.keyCode/ + + +var keycode = $.ui.keyCode = { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38 +}; + + +/*! + * jQuery UI Labels 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: labels +//>>group: Core +//>>description: Find all the labels associated with a given input +//>>docs: https://api.jqueryui.com/labels/ + + +var labels = $.fn.labels = function() { + var ancestor, selector, id, labels, ancestors; + + if ( !this.length ) { + return this.pushStack( [] ); + } + + // Check control.labels first + if ( this[ 0 ].labels && this[ 0 ].labels.length ) { + return this.pushStack( this[ 0 ].labels ); + } + + // If `control.labels` is empty - e.g. inside of document fragments - find + // the labels manually + labels = this.eq( 0 ).parents( "label" ); + + // Look for the label based on the id + id = this.attr( "id" ); + if ( id ) { + + // We don't search against the document in case the element + // is disconnected from the DOM + ancestor = this.eq( 0 ).parents().last(); + + // Get a full set of top level ancestors + ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() ); + + // Create a selector for the label based on the id + selector = "label[for='" + CSS.escape( id ) + "']"; + + labels = labels.add( ancestors.find( selector ).addBack( selector ) ); + + } + + // Return whatever we have found for labels + return this.pushStack( labels ); +}; + + +/*! + * jQuery UI Scroll Parent 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: scrollParent +//>>group: Core +//>>description: Get the closest ancestor element that is scrollable. +//>>docs: https://api.jqueryui.com/scrollParent/ + + +var scrollParent = $.fn.scrollParent = function( includeHidden ) { + var position = this.css( "position" ), + excludeStaticParent = position === "absolute", + overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/, + scrollParent = this.parents().filter( function() { + var parent = $( this ); + if ( excludeStaticParent && parent.css( "position" ) === "static" ) { + return false; + } + return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) + + parent.css( "overflow-x" ) ); + } ).eq( 0 ); + + return position === "fixed" || !scrollParent.length ? + $( this[ 0 ].ownerDocument || document ) : + scrollParent; +}; + + +/*! + * jQuery UI Tabbable 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: :tabbable Selector +//>>group: Core +//>>description: Selects elements which can be tabbed to. +//>>docs: https://api.jqueryui.com/tabbable-selector/ + + +var tabbable = $.extend( $.expr.pseudos, { + tabbable: function( element ) { + var tabIndex = $.attr( element, "tabindex" ), + hasTabindex = tabIndex != null; + return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex ); + } +} ); + + +/*! + * jQuery UI Unique ID 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: uniqueId +//>>group: Core +//>>description: Functions to generate and remove uniqueId's +//>>docs: https://api.jqueryui.com/uniqueId/ + + +var uniqueId = $.fn.extend( { + uniqueId: ( function() { + var uuid = 0; + + return function() { + return this.each( function() { + if ( !this.id ) { + this.id = "ui-id-" + ( ++uuid ); + } + } ); + }; + } )(), + + removeUniqueId: function() { + return this.each( function() { + if ( /^ui-id-\d+$/.test( this.id ) ) { + $( this ).removeAttr( "id" ); + } + } ); + } +} ); + + +/*! + * jQuery UI Accordion 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Accordion +//>>group: Widgets +/* eslint-disable max-len */ +//>>description: Displays collapsible content panels for presenting information in a limited amount of space. +/* eslint-enable max-len */ +//>>docs: https://api.jqueryui.com/accordion/ +//>>demos: https://jqueryui.com/accordion/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/accordion.css +//>>css.theme: ../../themes/base/theme.css + + +var widgetsAccordion = $.widget( "ui.accordion", { + version: "1.14.1", + options: { + active: 0, + animate: {}, + classes: { + "ui-accordion-header": "ui-corner-top", + "ui-accordion-header-collapsed": "ui-corner-all", + "ui-accordion-content": "ui-corner-bottom" + }, + collapsible: false, + event: "click", + header: function( elem ) { + return elem + .find( "> li > :first-child" ) + .add( + elem.find( "> :not(li)" ) + + // Support: jQuery <3.5 only + // We could use `.even()` but that's unavailable in older jQuery. + .filter( function( i ) { + return i % 2 === 0; + } ) + ); + }, + heightStyle: "auto", + icons: { + activeHeader: "ui-icon-triangle-1-s", + header: "ui-icon-triangle-1-e" + }, + + // Callbacks + activate: null, + beforeActivate: null + }, + + hideProps: { + borderTopWidth: "hide", + borderBottomWidth: "hide", + paddingTop: "hide", + paddingBottom: "hide", + height: "hide" + }, + + showProps: { + borderTopWidth: "show", + borderBottomWidth: "show", + paddingTop: "show", + paddingBottom: "show", + height: "show" + }, + + _create: function() { + var options = this.options; + + this.prevShow = this.prevHide = $(); + this._addClass( "ui-accordion", "ui-widget ui-helper-reset" ); + this.element.attr( "role", "tablist" ); + + // Don't allow collapsible: false and active: false / null + if ( !options.collapsible && ( options.active === false || options.active == null ) ) { + options.active = 0; + } + + this._processPanels(); + + // handle negative values + if ( options.active < 0 ) { + options.active += this.headers.length; + } + this._refresh(); + }, + + _getCreateEventData: function() { + return { + header: this.active, + panel: !this.active.length ? $() : this.active.next() + }; + }, + + _createIcons: function() { + var icon, children, + icons = this.options.icons; + + if ( icons ) { + icon = $( "" ); + this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header ); + icon.prependTo( this.headers ); + children = this.active.children( ".ui-accordion-header-icon" ); + this._removeClass( children, icons.header ) + ._addClass( children, null, icons.activeHeader ) + ._addClass( this.headers, "ui-accordion-icons" ); + } + }, + + _destroyIcons: function() { + this._removeClass( this.headers, "ui-accordion-icons" ); + this.headers.children( ".ui-accordion-header-icon" ).remove(); + }, + + _destroy: function() { + var contents; + + // Clean up main element + this.element.removeAttr( "role" ); + + // Clean up headers + this.headers + .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" ) + .removeUniqueId(); + + this._destroyIcons(); + + // Clean up content panels + contents = this.headers.next() + .css( "display", "" ) + .removeAttr( "role aria-hidden aria-labelledby" ) + .removeUniqueId(); + + if ( this.options.heightStyle !== "content" ) { + contents.css( "height", "" ); + } + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + if ( key === "event" ) { + if ( this.options.event ) { + this._off( this.headers, this.options.event ); + } + this._setupEvents( value ); + } + + this._super( key, value ); + + // Setting collapsible: false while collapsed; open first panel + if ( key === "collapsible" && !value && this.options.active === false ) { + this._activate( 0 ); + } + + if ( key === "icons" ) { + this._destroyIcons(); + if ( value ) { + this._createIcons(); + } + } + }, + + _setOptionDisabled: function( value ) { + this._super( value ); + + this.element.attr( "aria-disabled", value ); + this._toggleClass( null, "ui-state-disabled", !!value ); + }, + + _keydown: function( event ) { + if ( event.altKey || event.ctrlKey ) { + return; + } + + var keyCode = $.ui.keyCode, + length = this.headers.length, + currentIndex = this.headers.index( event.target ), + toFocus = false; + + switch ( event.keyCode ) { + case keyCode.RIGHT: + case keyCode.DOWN: + toFocus = this.headers[ ( currentIndex + 1 ) % length ]; + break; + case keyCode.LEFT: + case keyCode.UP: + toFocus = this.headers[ ( currentIndex - 1 + length ) % length ]; + break; + case keyCode.SPACE: + case keyCode.ENTER: + this._eventHandler( event ); + break; + case keyCode.HOME: + toFocus = this.headers[ 0 ]; + break; + case keyCode.END: + toFocus = this.headers[ length - 1 ]; + break; + } + + if ( toFocus ) { + $( event.target ).attr( "tabIndex", -1 ); + $( toFocus ).attr( "tabIndex", 0 ); + $( toFocus ).trigger( "focus" ); + event.preventDefault(); + } + }, + + _panelKeyDown: function( event ) { + if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) { + $( event.currentTarget ).prev().trigger( "focus" ); + } + }, + + refresh: function() { + var options = this.options; + this._processPanels(); + + // Was collapsed or no panel + if ( ( options.active === false && options.collapsible === true ) || + !this.headers.length ) { + options.active = false; + this.active = $(); + + // active false only when collapsible is true + } else if ( options.active === false ) { + this._activate( 0 ); + + // was active, but active panel is gone + } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + + // all remaining panel are disabled + if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) { + options.active = false; + this.active = $(); + + // activate previous panel + } else { + this._activate( Math.max( 0, options.active - 1 ) ); + } + + // was active, active panel still exists + } else { + + // make sure active index is correct + options.active = this.headers.index( this.active ); + } + + this._destroyIcons(); + + this._refresh(); + }, + + _processPanels: function() { + var prevHeaders = this.headers, + prevPanels = this.panels; + + if ( typeof this.options.header === "function" ) { + this.headers = this.options.header( this.element ); + } else { + this.headers = this.element.find( this.options.header ); + } + this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed", + "ui-state-default" ); + + this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide(); + this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" ); + + // Avoid memory leaks (#10056) + if ( prevPanels ) { + this._off( prevHeaders.not( this.headers ) ); + this._off( prevPanels.not( this.panels ) ); + } + }, + + _refresh: function() { + var maxHeight, + options = this.options, + heightStyle = options.heightStyle, + parent = this.element.parent(); + + this.active = this._findActive( options.active ); + this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" ) + ._removeClass( this.active, "ui-accordion-header-collapsed" ); + this._addClass( this.active.next(), "ui-accordion-content-active" ); + this.active.next().show(); + + this.headers + .attr( "role", "tab" ) + .each( function() { + var header = $( this ), + headerId = header.uniqueId().attr( "id" ), + panel = header.next(), + panelId = panel.uniqueId().attr( "id" ); + header.attr( "aria-controls", panelId ); + panel.attr( "aria-labelledby", headerId ); + } ) + .next() + .attr( "role", "tabpanel" ); + + this.headers + .not( this.active ) + .attr( { + "aria-selected": "false", + "aria-expanded": "false", + tabIndex: -1 + } ) + .next() + .attr( { + "aria-hidden": "true" + } ) + .hide(); + + // Make sure at least one header is in the tab order + if ( !this.active.length ) { + this.headers.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active.attr( { + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + } ) + .next() + .attr( { + "aria-hidden": "false" + } ); + } + + this._createIcons(); + + this._setupEvents( options.event ); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + this.element.siblings( ":visible" ).each( function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + } ); + + this.headers.each( function() { + maxHeight -= $( this ).outerHeight( true ); + } ); + + this.headers.next() + .each( function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + } ) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.headers.next() + .each( function() { + var isVisible = $( this ).is( ":visible" ); + if ( !isVisible ) { + $( this ).show(); + } + maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() ); + if ( !isVisible ) { + $( this ).hide(); + } + } ) + .height( maxHeight ); + } + }, + + _activate: function( index ) { + var active = this._findActive( index )[ 0 ]; + + // Trying to activate the already active panel + if ( active === this.active[ 0 ] ) { + return; + } + + // Trying to collapse, simulate a click on the currently active header + active = active || this.active[ 0 ]; + + this._eventHandler( { + target: active, + currentTarget: active, + preventDefault: $.noop + } ); + }, + + _findActive: function( selector ) { + return typeof selector === "number" ? this.headers.eq( selector ) : $(); + }, + + _setupEvents: function( event ) { + var events = { + keydown: "_keydown" + }; + if ( event ) { + $.each( event.split( " " ), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + } ); + } + + this._off( this.headers.add( this.headers.next() ) ); + this._on( this.headers, events ); + this._on( this.headers.next(), { keydown: "_panelKeyDown" } ); + this._hoverable( this.headers ); + this._focusable( this.headers ); + }, + + _eventHandler: function( event ) { + var activeChildren, clickedChildren, + options = this.options, + active = this.active, + clicked = $( event.currentTarget ), + clickedIsActive = clicked[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : clicked.next(), + toHide = active.next(), + eventData = { + oldHeader: active, + oldPanel: toHide, + newHeader: collapsing ? $() : clicked, + newPanel: toShow + }; + + event.preventDefault(); + + if ( + + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.headers.index( clicked ); + + // When the call to ._toggle() comes after the class changes + // it causes a very odd bug in IE 8 (see #6720) + this.active = clickedIsActive ? $() : clicked; + this._toggle( eventData ); + + // Switch classes + // corner classes on the previously active header stay after the animation + this._removeClass( active, "ui-accordion-header-active", "ui-state-active" ); + if ( options.icons ) { + activeChildren = active.children( ".ui-accordion-header-icon" ); + this._removeClass( activeChildren, null, options.icons.activeHeader ) + ._addClass( activeChildren, null, options.icons.header ); + } + + if ( !clickedIsActive ) { + this._removeClass( clicked, "ui-accordion-header-collapsed" ) + ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" ); + if ( options.icons ) { + clickedChildren = clicked.children( ".ui-accordion-header-icon" ); + this._removeClass( clickedChildren, null, options.icons.header ) + ._addClass( clickedChildren, null, options.icons.activeHeader ); + } + + this._addClass( clicked.next(), "ui-accordion-content-active" ); + } + }, + + _toggle: function( data ) { + var toShow = data.newPanel, + toHide = this.prevShow.length ? this.prevShow : data.oldPanel; + + // Handle activating a panel during the animation for another activation + this.prevShow.add( this.prevHide ).stop( true, true ); + this.prevShow = toShow; + this.prevHide = toHide; + + if ( this.options.animate ) { + this._animate( toShow, toHide, data ); + } else { + toHide.hide(); + toShow.show(); + this._toggleComplete( data ); + } + + toHide.attr( { + "aria-hidden": "true" + } ); + toHide.prev().attr( { + "aria-selected": "false", + "aria-expanded": "false" + } ); + + // if we're switching panels, remove the old header from the tab order + // if we're opening from collapsed state, remove the previous header from the tab order + // if we're collapsing, then keep the collapsing header in the tab order + if ( toShow.length && toHide.length ) { + toHide.prev().attr( { + "tabIndex": -1, + "aria-expanded": "false" + } ); + } else if ( toShow.length ) { + this.headers.filter( function() { + return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0; + } ) + .attr( "tabIndex", -1 ); + } + + toShow + .attr( "aria-hidden", "false" ) + .prev() + .attr( { + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + } ); + }, + + _animate: function( toShow, toHide, data ) { + var total, easing, duration, + that = this, + adjust = 0, + boxSizing = toShow.css( "box-sizing" ), + down = toShow.length && + ( !toHide.length || ( toShow.index() < toHide.index() ) ), + animate = this.options.animate || {}, + options = down && animate.down || animate, + complete = function() { + that._toggleComplete( data ); + }; + + if ( typeof options === "number" ) { + duration = options; + } + if ( typeof options === "string" ) { + easing = options; + } + + // fall back from options to animation in case of partial down settings + easing = easing || options.easing || animate.easing; + duration = duration || options.duration || animate.duration; + + if ( !toHide.length ) { + return toShow.animate( this.showProps, duration, easing, complete ); + } + if ( !toShow.length ) { + return toHide.animate( this.hideProps, duration, easing, complete ); + } + + total = toShow.show().outerHeight(); + toHide.animate( this.hideProps, { + duration: duration, + easing: easing, + step: function( now, fx ) { + fx.now = Math.round( now ); + } + } ); + toShow + .hide() + .animate( this.showProps, { + duration: duration, + easing: easing, + complete: complete, + step: function( now, fx ) { + fx.now = Math.round( now ); + if ( fx.prop !== "height" ) { + if ( boxSizing === "content-box" ) { + adjust += fx.now; + } + } else if ( that.options.heightStyle !== "content" ) { + fx.now = Math.round( total - toHide.outerHeight() - adjust ); + adjust = 0; + } + } + } ); + }, + + _toggleComplete: function( data ) { + var toHide = data.oldPanel, + prev = toHide.prev(); + + this._removeClass( toHide, "ui-accordion-content-active" ); + this._removeClass( prev, "ui-accordion-header-active" ) + ._addClass( prev, "ui-accordion-header-collapsed" ); + + this._trigger( "activate", null, data ); + } +} ); + + +/*! + * jQuery UI Menu 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Menu +//>>group: Widgets +//>>description: Creates nestable menus. +//>>docs: https://api.jqueryui.com/menu/ +//>>demos: https://jqueryui.com/menu/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/menu.css +//>>css.theme: ../../themes/base/theme.css + + +var widgetsMenu = $.widget( "ui.menu", { + version: "1.14.1", + defaultElement: "
    ", + delay: 300, + options: { + icons: { + submenu: "ui-icon-caret-1-e" + }, + items: "> *", + menus: "ul", + position: { + my: "left top", + at: "right top" + }, + role: "menu", + + // Callbacks + blur: null, + focus: null, + select: null + }, + + _create: function() { + this.activeMenu = this.element; + + // Flag used to prevent firing of the click handler + // as the event bubbles up through nested menus + this.mouseHandled = false; + this.lastMousePosition = { x: null, y: null }; + this.element + .uniqueId() + .attr( { + role: this.options.role, + tabIndex: 0 + } ); + + this._addClass( "ui-menu", "ui-widget ui-widget-content" ); + this._on( { + + // Prevent focus from sticking to links inside menu after clicking + // them (focus should always stay on UL during navigation). + "mousedown .ui-menu-item": function( event ) { + event.preventDefault(); + + this._activateItem( event ); + }, + "click .ui-menu-item": function( event ) { + var target = $( event.target ); + var active = $( this.document[ 0 ].activeElement ); + if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) { + this.select( event ); + + // Only set the mouseHandled flag if the event will bubble, see #9469. + if ( !event.isPropagationStopped() ) { + this.mouseHandled = true; + } + + // Open submenu on click + if ( target.has( ".ui-menu" ).length ) { + this.expand( event ); + } else if ( !this.element.is( ":focus" ) && + active.closest( ".ui-menu" ).length ) { + + // Redirect focus to the menu + this.element.trigger( "focus", [ true ] ); + + // If the active item is on the top level, let it stay active. + // Otherwise, blur the active item since it is no longer visible. + if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) { + clearTimeout( this.timer ); + } + } + } + }, + "mouseenter .ui-menu-item": "_activateItem", + "mousemove .ui-menu-item": "_activateItem", + mouseleave: "collapseAll", + "mouseleave .ui-menu": "collapseAll", + focus: function( event, keepActiveItem ) { + + // If there's already an active item, keep it active + // If not, activate the first item + var item = this.active || this._menuItems().first(); + + if ( !keepActiveItem ) { + this.focus( event, item ); + } + }, + blur: function( event ) { + this._delay( function() { + var notContained = !$.contains( + this.element[ 0 ], + this.document[ 0 ].activeElement + ); + if ( notContained ) { + this.collapseAll( event ); + } + } ); + }, + keydown: "_keydown" + } ); + + this.refresh(); + + // Clicks outside of a menu collapse any open menus + this._on( this.document, { + click: function( event ) { + if ( this._closeOnDocumentClick( event ) ) { + this.collapseAll( event, true ); + } + + // Reset the mouseHandled flag + this.mouseHandled = false; + } + } ); + }, + + _activateItem: function( event ) { + + // Ignore mouse events while typeahead is active, see #10458. + // Prevents focusing the wrong item when typeahead causes a scroll while the mouse + // is over an item in the menu + if ( this.previousFilter ) { + return; + } + + // If the mouse didn't actually move, but the page was scrolled, ignore the event (#9356) + if ( event.clientX === this.lastMousePosition.x && + event.clientY === this.lastMousePosition.y ) { + return; + } + + this.lastMousePosition = { + x: event.clientX, + y: event.clientY + }; + + var actualTarget = $( event.target ).closest( ".ui-menu-item" ), + target = $( event.currentTarget ); + + // Ignore bubbled events on parent items, see #11641 + if ( actualTarget[ 0 ] !== target[ 0 ] ) { + return; + } + + // If the item is already active, there's nothing to do + if ( target.is( ".ui-state-active" ) ) { + return; + } + + // Remove ui-state-active class from siblings of the newly focused menu item + // to avoid a jump caused by adjacent elements both having a class with a border + this._removeClass( target.siblings().children( ".ui-state-active" ), + null, "ui-state-active" ); + this.focus( event, target ); + }, + + _destroy: function() { + var items = this.element.find( ".ui-menu-item" ) + .removeAttr( "role aria-disabled" ), + submenus = items.children( ".ui-menu-item-wrapper" ) + .removeUniqueId() + .removeAttr( "tabIndex role aria-haspopup" ); + + // Destroy (sub)menus + this.element + .removeAttr( "aria-activedescendant" ) + .find( ".ui-menu" ).addBack() + .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " + + "tabIndex" ) + .removeUniqueId() + .show(); + + submenus.children().each( function() { + var elem = $( this ); + if ( elem.data( "ui-menu-submenu-caret" ) ) { + elem.remove(); + } + } ); + }, + + _keydown: function( event ) { + var match, prev, character, skip, + preventDefault = true; + + switch ( event.keyCode ) { + case $.ui.keyCode.PAGE_UP: + this.previousPage( event ); + break; + case $.ui.keyCode.PAGE_DOWN: + this.nextPage( event ); + break; + case $.ui.keyCode.HOME: + this._move( "first", "first", event ); + break; + case $.ui.keyCode.END: + this._move( "last", "last", event ); + break; + case $.ui.keyCode.UP: + this.previous( event ); + break; + case $.ui.keyCode.DOWN: + this.next( event ); + break; + case $.ui.keyCode.LEFT: + this.collapse( event ); + break; + case $.ui.keyCode.RIGHT: + if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { + this.expand( event ); + } + break; + case $.ui.keyCode.ENTER: + case $.ui.keyCode.SPACE: + this._activate( event ); + break; + case $.ui.keyCode.ESCAPE: + this.collapse( event ); + break; + default: + preventDefault = false; + prev = this.previousFilter || ""; + skip = false; + + // Support number pad values + character = event.keyCode >= 96 && event.keyCode <= 105 ? + ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode ); + + clearTimeout( this.filterTimer ); + + if ( character === prev ) { + skip = true; + } else { + character = prev + character; + } + + match = this._filterMenuItems( character ); + match = skip && match.index( this.active.next() ) !== -1 ? + this.active.nextAll( ".ui-menu-item" ) : + match; + + // If no matches on the current filter, reset to the last character pressed + // to move down the menu to the first item that starts with that character + if ( !match.length ) { + character = String.fromCharCode( event.keyCode ); + match = this._filterMenuItems( character ); + } + + if ( match.length ) { + this.focus( event, match ); + this.previousFilter = character; + this.filterTimer = this._delay( function() { + delete this.previousFilter; + }, 1000 ); + } else { + delete this.previousFilter; + } + } + + if ( preventDefault ) { + event.preventDefault(); + } + }, + + _activate: function( event ) { + if ( this.active && !this.active.is( ".ui-state-disabled" ) ) { + if ( this.active.children( "[aria-haspopup='true']" ).length ) { + this.expand( event ); + } else { + this.select( event ); + } + } + }, + + refresh: function() { + var menus, items, newSubmenus, newItems, newWrappers, + that = this, + icon = this.options.icons.submenu, + submenus = this.element.find( this.options.menus ); + + this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length ); + + // Initialize nested menus + newSubmenus = submenus.filter( ":not(.ui-menu)" ) + .hide() + .attr( { + role: this.options.role, + "aria-hidden": "true", + "aria-expanded": "false" + } ) + .each( function() { + var menu = $( this ), + item = menu.prev(), + submenuCaret = $( "" ).data( "ui-menu-submenu-caret", true ); + + that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon ); + item + .attr( "aria-haspopup", "true" ) + .prepend( submenuCaret ); + menu.attr( "aria-labelledby", item.attr( "id" ) ); + } ); + + this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" ); + + menus = submenus.add( this.element ); + items = menus.find( this.options.items ); + + // Initialize menu-items containing spaces and/or dashes only as dividers + items.not( ".ui-menu-item" ).each( function() { + var item = $( this ); + if ( that._isDivider( item ) ) { + that._addClass( item, "ui-menu-divider", "ui-widget-content" ); + } + } ); + + // Don't refresh list items that are already adapted + newItems = items.not( ".ui-menu-item, .ui-menu-divider" ); + newWrappers = newItems.children() + .not( ".ui-menu" ) + .uniqueId() + .attr( { + tabIndex: -1, + role: this._itemRole() + } ); + this._addClass( newItems, "ui-menu-item" ) + ._addClass( newWrappers, "ui-menu-item-wrapper" ); + + // Add aria-disabled attribute to any disabled menu item + items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" ); + + // If the active item has been removed, blur the menu + if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) { + this.blur(); + } + }, + + _itemRole: function() { + return { + menu: "menuitem", + listbox: "option" + }[ this.options.role ]; + }, + + _setOption: function( key, value ) { + if ( key === "icons" ) { + var icons = this.element.find( ".ui-menu-icon" ); + this._removeClass( icons, null, this.options.icons.submenu ) + ._addClass( icons, null, value.submenu ); + } + this._super( key, value ); + }, + + _setOptionDisabled: function( value ) { + this._super( value ); + + this.element.attr( "aria-disabled", String( value ) ); + this._toggleClass( null, "ui-state-disabled", !!value ); + }, + + focus: function( event, item ) { + var nested, focused, activeParent; + this.blur( event, event && event.type === "focus" ); + + this._scrollIntoView( item ); + + this.active = item.first(); + + focused = this.active.children( ".ui-menu-item-wrapper" ); + this._addClass( focused, null, "ui-state-active" ); + + // Only update aria-activedescendant if there's a role + // otherwise we assume focus is managed elsewhere + if ( this.options.role ) { + this.element.attr( "aria-activedescendant", focused.attr( "id" ) ); + } + + // Highlight active parent menu item, if any + activeParent = this.active + .parent() + .closest( ".ui-menu-item" ) + .children( ".ui-menu-item-wrapper" ); + this._addClass( activeParent, null, "ui-state-active" ); + + if ( event && event.type === "keydown" ) { + this._close(); + } else { + this.timer = this._delay( function() { + this._close(); + }, this.delay ); + } + + nested = item.children( ".ui-menu" ); + if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) { + this._startOpening( nested ); + } + this.activeMenu = item.parent(); + + this._trigger( "focus", event, { item: item } ); + }, + + _scrollIntoView: function( item ) { + var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight; + if ( this._hasScroll() ) { + borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0; + paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0; + offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop; + scroll = this.activeMenu.scrollTop(); + elementHeight = this.activeMenu.height(); + itemHeight = item.outerHeight(); + + if ( offset < 0 ) { + this.activeMenu.scrollTop( scroll + offset ); + } else if ( offset + itemHeight > elementHeight ) { + this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight ); + } + } + }, + + blur: function( event, fromFocus ) { + if ( !fromFocus ) { + clearTimeout( this.timer ); + } + + if ( !this.active ) { + return; + } + + this._removeClass( this.active.children( ".ui-menu-item-wrapper" ), + null, "ui-state-active" ); + + this._trigger( "blur", event, { item: this.active } ); + this.active = null; + }, + + _startOpening: function( submenu ) { + clearTimeout( this.timer ); + + // Don't open if already open fixes a Firefox bug that caused a .5 pixel + // shift in the submenu position when mousing over the caret icon + if ( submenu.attr( "aria-hidden" ) !== "true" ) { + return; + } + + this.timer = this._delay( function() { + this._close(); + this._open( submenu ); + }, this.delay ); + }, + + _open: function( submenu ) { + var position = $.extend( { + of: this.active + }, this.options.position ); + + clearTimeout( this.timer ); + this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) ) + .hide() + .attr( "aria-hidden", "true" ); + + submenu + .show() + .removeAttr( "aria-hidden" ) + .attr( "aria-expanded", "true" ) + .position( position ); + }, + + collapseAll: function( event, all ) { + clearTimeout( this.timer ); + this.timer = this._delay( function() { + + // If we were passed an event, look for the submenu that contains the event + var currentMenu = all ? this.element : + $( event && event.target ).closest( this.element.find( ".ui-menu" ) ); + + // If we found no valid submenu ancestor, use the main menu to close all + // sub menus anyway + if ( !currentMenu.length ) { + currentMenu = this.element; + } + + this._close( currentMenu ); + + this.blur( event ); + + // Work around active item staying active after menu is blurred + this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" ); + + this.activeMenu = currentMenu; + }, all ? 0 : this.delay ); + }, + + // With no arguments, closes the currently active menu - if nothing is active + // it closes all menus. If passed an argument, it will search for menus BELOW + _close: function( startMenu ) { + if ( !startMenu ) { + startMenu = this.active ? this.active.parent() : this.element; + } + + startMenu.find( ".ui-menu" ) + .hide() + .attr( "aria-hidden", "true" ) + .attr( "aria-expanded", "false" ); + }, + + _closeOnDocumentClick: function( event ) { + return !$( event.target ).closest( ".ui-menu" ).length; + }, + + _isDivider: function( item ) { + + // Match hyphen, em dash, en dash + return !/[^\-\u2014\u2013\s]/.test( item.text() ); + }, + + collapse: function( event ) { + var newItem = this.active && + this.active.parent().closest( ".ui-menu-item", this.element ); + if ( newItem && newItem.length ) { + this._close(); + this.focus( event, newItem ); + } + }, + + expand: function( event ) { + var newItem = this.active && this._menuItems( this.active.children( ".ui-menu" ) ).first(); + + if ( newItem && newItem.length ) { + this._open( newItem.parent() ); + + // Delay so Firefox will not hide activedescendant change in expanding submenu from AT + this._delay( function() { + this.focus( event, newItem ); + } ); + } + }, + + next: function( event ) { + this._move( "next", "first", event ); + }, + + previous: function( event ) { + this._move( "prev", "last", event ); + }, + + isFirstItem: function() { + return this.active && !this.active.prevAll( ".ui-menu-item" ).length; + }, + + isLastItem: function() { + return this.active && !this.active.nextAll( ".ui-menu-item" ).length; + }, + + _menuItems: function( menu ) { + return ( menu || this.element ) + .find( this.options.items ) + .filter( ".ui-menu-item" ); + }, + + _move: function( direction, filter, event ) { + var next; + if ( this.active ) { + if ( direction === "first" || direction === "last" ) { + next = this.active + [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" ) + .last(); + } else { + next = this.active + [ direction + "All" ]( ".ui-menu-item" ) + .first(); + } + } + if ( !next || !next.length || !this.active ) { + next = this._menuItems( this.activeMenu )[ filter ](); + } + + this.focus( event, next ); + }, + + nextPage: function( event ) { + var item, base, height; + + if ( !this.active ) { + this.next( event ); + return; + } + if ( this.isLastItem() ) { + return; + } + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.innerHeight(); + + // jQuery 3.2 doesn't include scrollbars in innerHeight, add it back. + if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) { + height += this.element[ 0 ].offsetHeight - this.element.outerHeight(); + } + + this.active.nextAll( ".ui-menu-item" ).each( function() { + item = $( this ); + return item.offset().top - base - height < 0; + } ); + + this.focus( event, item ); + } else { + this.focus( event, this._menuItems( this.activeMenu ) + [ !this.active ? "first" : "last" ]() ); + } + }, + + previousPage: function( event ) { + var item, base, height; + if ( !this.active ) { + this.next( event ); + return; + } + if ( this.isFirstItem() ) { + return; + } + if ( this._hasScroll() ) { + base = this.active.offset().top; + height = this.element.innerHeight(); + + // jQuery 3.2 doesn't include scrollbars in innerHeight, add it back. + if ( $.fn.jquery.indexOf( "3.2." ) === 0 ) { + height += this.element[ 0 ].offsetHeight - this.element.outerHeight(); + } + + this.active.prevAll( ".ui-menu-item" ).each( function() { + item = $( this ); + return item.offset().top - base + height > 0; + } ); + + this.focus( event, item ); + } else { + this.focus( event, this._menuItems( this.activeMenu ).first() ); + } + }, + + _hasScroll: function() { + return this.element.outerHeight() < this.element.prop( "scrollHeight" ); + }, + + select: function( event ) { + + // TODO: It should never be possible to not have an active item at this + // point, but the tests don't trigger mouseenter before click. + this.active = this.active || $( event.target ).closest( ".ui-menu-item" ); + var ui = { item: this.active }; + if ( !this.active.has( ".ui-menu" ).length ) { + this.collapseAll( event, true ); + } + this._trigger( "select", event, ui ); + }, + + _filterMenuItems: function( character ) { + var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ), + regex = new RegExp( "^" + escapedCharacter, "i" ); + + return this.activeMenu + .find( this.options.items ) + + // Only match on items, not dividers or other content (#10571) + .filter( ".ui-menu-item" ) + .filter( function() { + return regex.test( + String.prototype.trim.call( + $( this ).children( ".ui-menu-item-wrapper" ).text() ) ); + } ); + } +} ); + + +/*! + * jQuery UI Autocomplete 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Autocomplete +//>>group: Widgets +//>>description: Lists suggested words as the user is typing. +//>>docs: https://api.jqueryui.com/autocomplete/ +//>>demos: https://jqueryui.com/autocomplete/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/autocomplete.css +//>>css.theme: ../../themes/base/theme.css + + +$.widget( "ui.autocomplete", { + version: "1.14.1", + defaultElement: "", + options: { + appendTo: null, + autoFocus: false, + delay: 300, + minLength: 1, + position: { + my: "left top", + at: "left bottom", + collision: "none" + }, + source: null, + + // Callbacks + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null + }, + + requestIndex: 0, + pending: 0, + liveRegionTimer: null, + + _create: function() { + + // Some browsers only repeat keydown events, not keypress events, + // so we use the suppressKeyPress flag to determine if we've already + // handled the keydown event. #7269 + // Unfortunately the code for & in keypress is the same as the up arrow, + // so we use the suppressKeyPressRepeat flag to avoid handling keypress + // events when we know the keydown event was used to modify the + // search term. #7799 + var suppressKeyPress, suppressKeyPressRepeat, suppressInput, + nodeName = this.element[ 0 ].nodeName.toLowerCase(), + isTextarea = nodeName === "textarea", + isInput = nodeName === "input"; + + // Textareas are always multi-line + // Inputs are always single-line, even if inside a contentEditable element + // All other element types are determined by whether they're contentEditable + this.isMultiLine = isTextarea || + !isInput && this.element.prop( "contentEditable" ) === "true"; + + this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ]; + this.isNewMenu = true; + + this._addClass( "ui-autocomplete-input" ); + this.element.attr( "autocomplete", "off" ); + + this._on( this.element, { + keydown: function( event ) { + if ( this.element.prop( "readOnly" ) ) { + suppressKeyPress = true; + suppressInput = true; + suppressKeyPressRepeat = true; + return; + } + + suppressKeyPress = false; + suppressInput = false; + suppressKeyPressRepeat = false; + var keyCode = $.ui.keyCode; + switch ( event.keyCode ) { + case keyCode.PAGE_UP: + suppressKeyPress = true; + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + suppressKeyPress = true; + this._move( "nextPage", event ); + break; + case keyCode.UP: + suppressKeyPress = true; + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + suppressKeyPress = true; + this._keyEvent( "next", event ); + break; + case keyCode.ENTER: + + // when menu is open and has focus + if ( this.menu.active ) { + + // #6055 - Opera still allows the keypress to occur + // which causes forms to submit + suppressKeyPress = true; + event.preventDefault(); + this.menu.select( event ); + } + break; + case keyCode.TAB: + if ( this.menu.active ) { + this.menu.select( event ); + } + break; + case keyCode.ESCAPE: + if ( this.menu.element.is( ":visible" ) ) { + if ( !this.isMultiLine ) { + this._value( this.term ); + } + this.close( event ); + + // Different browsers have different default behavior for escape + // Single press can mean undo or clear + event.preventDefault(); + } + break; + default: + suppressKeyPressRepeat = true; + + // search timeout should be triggered before the input value is changed + this._searchTimeout( event ); + break; + } + }, + keypress: function( event ) { + if ( suppressKeyPress ) { + suppressKeyPress = false; + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + event.preventDefault(); + } + return; + } + if ( suppressKeyPressRepeat ) { + return; + } + + // Replicate some key handlers to allow them to repeat in Firefox and Opera + var keyCode = $.ui.keyCode; + switch ( event.keyCode ) { + case keyCode.PAGE_UP: + this._move( "previousPage", event ); + break; + case keyCode.PAGE_DOWN: + this._move( "nextPage", event ); + break; + case keyCode.UP: + this._keyEvent( "previous", event ); + break; + case keyCode.DOWN: + this._keyEvent( "next", event ); + break; + } + }, + input: function( event ) { + if ( suppressInput ) { + suppressInput = false; + event.preventDefault(); + return; + } + this._searchTimeout( event ); + }, + focus: function() { + this.selectedItem = null; + this.previous = this._value(); + }, + blur: function( event ) { + clearTimeout( this.searching ); + this.close( event ); + this._change( event ); + } + } ); + + this._initSource(); + this.menu = $( "
      " ) + .appendTo( this._appendTo() ) + .menu( { + + // disable ARIA support, the live region takes care of that + role: null + } ) + .hide() + .menu( "instance" ); + + this._addClass( this.menu.element, "ui-autocomplete", "ui-front" ); + this._on( this.menu.element, { + mousedown: function( event ) { + + // Prevent moving focus out of the text field + event.preventDefault(); + }, + menufocus: function( event, ui ) { + var label, item; + + // Support: Firefox + // Prevent accidental activation of menu items in Firefox (#7024 #9118) + if ( this.isNewMenu ) { + this.isNewMenu = false; + if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) { + this.menu.blur(); + + this.document.one( "mousemove", function() { + $( event.target ).trigger( event.originalEvent ); + } ); + + return; + } + } + + item = ui.item.data( "ui-autocomplete-item" ); + if ( false !== this._trigger( "focus", event, { item: item } ) ) { + + // use value to match what will end up in the input, if it was a key event + if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) { + this._value( item.value ); + } + } + + // Announce the value in the liveRegion + label = ui.item.attr( "aria-label" ) || item.value; + if ( label && String.prototype.trim.call( label ).length ) { + clearTimeout( this.liveRegionTimer ); + this.liveRegionTimer = this._delay( function() { + this.liveRegion.html( $( "
      " ).text( label ) ); + }, 100 ); + } + }, + menuselect: function( event, ui ) { + var item = ui.item.data( "ui-autocomplete-item" ), + previous = this.previous; + + // Only trigger when focus was lost (click on menu) + if ( this.element[ 0 ] !== this.document[ 0 ].activeElement ) { + this.element.trigger( "focus" ); + this.previous = previous; + } + + if ( false !== this._trigger( "select", event, { item: item } ) ) { + this._value( item.value ); + } + + // reset the term after the select event + // this allows custom select handling to work properly + this.term = this._value(); + + this.close( event ); + this.selectedItem = item; + } + } ); + + this.liveRegion = $( "
      ", { + role: "status", + "aria-live": "assertive", + "aria-relevant": "additions" + } ) + .appendTo( this.document[ 0 ].body ); + + this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); + + // Turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); + } + } ); + }, + + _destroy: function() { + clearTimeout( this.searching ); + this.element.removeAttr( "autocomplete" ); + this.menu.element.remove(); + this.liveRegion.remove(); + }, + + _setOption: function( key, value ) { + this._super( key, value ); + if ( key === "source" ) { + this._initSource(); + } + if ( key === "appendTo" ) { + this.menu.element.appendTo( this._appendTo() ); + } + if ( key === "disabled" && value && this.xhr ) { + this.xhr.abort(); + } + }, + + _isEventTargetInWidget: function( event ) { + var menuElement = this.menu.element[ 0 ]; + + return event.target === this.element[ 0 ] || + event.target === menuElement || + $.contains( menuElement, event.target ); + }, + + _closeOnClickOutside: function( event ) { + if ( !this._isEventTargetInWidget( event ) ) { + this.close(); + } + }, + + _appendTo: function() { + var element = this.options.appendTo; + + if ( element ) { + element = element.jquery || element.nodeType ? + $( element ) : + this.document.find( element ).eq( 0 ); + } + + if ( !element || !element[ 0 ] ) { + element = this.element.closest( ".ui-front, dialog" ); + } + + if ( !element.length ) { + element = this.document[ 0 ].body; + } + + return element; + }, + + _initSource: function() { + var array, url, + that = this; + if ( Array.isArray( this.options.source ) ) { + array = this.options.source; + this.source = function( request, response ) { + response( $.ui.autocomplete.filter( array, request.term ) ); + }; + } else if ( typeof this.options.source === "string" ) { + url = this.options.source; + this.source = function( request, response ) { + if ( that.xhr ) { + that.xhr.abort(); + } + that.xhr = $.ajax( { + url: url, + data: request, + dataType: "json", + success: function( data ) { + response( data ); + }, + error: function() { + response( [] ); + } + } ); + }; + } else { + this.source = this.options.source; + } + }, + + _searchTimeout: function( event ) { + clearTimeout( this.searching ); + this.searching = this._delay( function() { + + // Search if the value has changed, or if the user retypes the same value (see #7434) + var equalValues = this.term === this._value(), + menuVisible = this.menu.element.is( ":visible" ), + modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey; + + if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) { + this.selectedItem = null; + this.search( null, event ); + } + }, this.options.delay ); + }, + + search: function( value, event ) { + value = value != null ? value : this._value(); + + // Always save the actual value, not the one passed as an argument + this.term = this._value(); + + if ( value.length < this.options.minLength ) { + return this.close( event ); + } + + if ( this._trigger( "search", event ) === false ) { + return; + } + + return this._search( value ); + }, + + _search: function( value ) { + this.pending++; + this._addClass( "ui-autocomplete-loading" ); + this.cancelSearch = false; + + this.source( { term: value }, this._response() ); + }, + + _response: function() { + var index = ++this.requestIndex; + + return function( content ) { + if ( index === this.requestIndex ) { + this.__response( content ); + } + + this.pending--; + if ( !this.pending ) { + this._removeClass( "ui-autocomplete-loading" ); + } + }.bind( this ); + }, + + __response: function( content ) { + if ( content ) { + content = this._normalize( content ); + } + this._trigger( "response", null, { content: content } ); + if ( !this.options.disabled && content && content.length && !this.cancelSearch ) { + this._suggest( content ); + this._trigger( "open" ); + } else { + + // use ._close() instead of .close() so we don't cancel future searches + this._close(); + } + }, + + close: function( event ) { + this.cancelSearch = true; + this._close( event ); + }, + + _close: function( event ) { + + // Remove the handler that closes the menu on outside clicks + this._off( this.document, "mousedown" ); + + if ( this.menu.element.is( ":visible" ) ) { + this.menu.element.hide(); + this.menu.blur(); + this.isNewMenu = true; + this._trigger( "close", event ); + } + }, + + _change: function( event ) { + if ( this.previous !== this._value() ) { + this._trigger( "change", event, { item: this.selectedItem } ); + } + }, + + _normalize: function( items ) { + + // assume all items have the right format when the first item is complete + if ( items.length && items[ 0 ].label && items[ 0 ].value ) { + return items; + } + return $.map( items, function( item ) { + if ( typeof item === "string" ) { + return { + label: item, + value: item + }; + } + return $.extend( {}, item, { + label: item.label || item.value, + value: item.value || item.label + } ); + } ); + }, + + _suggest: function( items ) { + var ul = this.menu.element.empty(); + this._renderMenu( ul, items ); + this.isNewMenu = true; + this.menu.refresh(); + + // Size and position menu + ul.show(); + this._resizeMenu(); + ul.position( $.extend( { + of: this.element + }, this.options.position ) ); + + if ( this.options.autoFocus ) { + this.menu.next(); + } + + // Listen for interactions outside of the widget (#6642) + this._on( this.document, { + mousedown: "_closeOnClickOutside" + } ); + }, + + _resizeMenu: function() { + var ul = this.menu.element; + ul.outerWidth( Math.max( + + // Firefox wraps long text (possibly a rounding bug) + // so we add 1px to avoid the wrapping (#7513) + ul.width( "" ).outerWidth() + 1, + this.element.outerWidth() + ) ); + }, + + _renderMenu: function( ul, items ) { + var that = this; + $.each( items, function( index, item ) { + that._renderItemData( ul, item ); + } ); + }, + + _renderItemData: function( ul, item ) { + return this._renderItem( ul, item ).data( "ui-autocomplete-item", item ); + }, + + _renderItem: function( ul, item ) { + return $( "
    • " ) + .append( $( "
      " ).text( item.label ) ) + .appendTo( ul ); + }, + + _move: function( direction, event ) { + if ( !this.menu.element.is( ":visible" ) ) { + this.search( null, event ); + return; + } + if ( this.menu.isFirstItem() && /^previous/.test( direction ) || + this.menu.isLastItem() && /^next/.test( direction ) ) { + + if ( !this.isMultiLine ) { + this._value( this.term ); + } + + this.menu.blur(); + return; + } + this.menu[ direction ]( event ); + }, + + widget: function() { + return this.menu.element; + }, + + _value: function() { + return this.valueMethod.apply( this.element, arguments ); + }, + + _keyEvent: function( keyEvent, event ) { + if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) { + this._move( keyEvent, event ); + + // Prevents moving cursor to beginning/end of the text field in some browsers + event.preventDefault(); + } + } +} ); + +$.extend( $.ui.autocomplete, { + escapeRegex: function( value ) { + return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ); + }, + filter: function( array, term ) { + var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" ); + return $.grep( array, function( value ) { + return matcher.test( value.label || value.value || value ); + } ); + } +} ); + +// Live region extension, adding a `messages` option +// NOTE: This is an experimental API. We are still investigating +// a full solution for string manipulation and internationalization. +$.widget( "ui.autocomplete", $.ui.autocomplete, { + options: { + messages: { + noResults: "No search results.", + results: function( amount ) { + return amount + ( amount > 1 ? " results are" : " result is" ) + + " available, use up and down arrow keys to navigate."; + } + } + }, + + __response: function( content ) { + var message; + this._superApply( arguments ); + if ( this.options.disabled || this.cancelSearch ) { + return; + } + if ( content && content.length ) { + message = this.options.messages.results( content.length ); + } else { + message = this.options.messages.noResults; + } + clearTimeout( this.liveRegionTimer ); + this.liveRegionTimer = this._delay( function() { + this.liveRegion.html( $( "
      " ).text( message ) ); + }, 100 ); + } +} ); + +var widgetsAutocomplete = $.ui.autocomplete; + + +/*! + * jQuery UI Controlgroup 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Controlgroup +//>>group: Widgets +//>>description: Visually groups form control widgets +//>>docs: https://api.jqueryui.com/controlgroup/ +//>>demos: https://jqueryui.com/controlgroup/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/controlgroup.css +//>>css.theme: ../../themes/base/theme.css + + +var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g; + +var widgetsControlgroup = $.widget( "ui.controlgroup", { + version: "1.14.1", + defaultElement: "
      ", + options: { + direction: "horizontal", + disabled: null, + onlyVisible: true, + items: { + "button": "input[type=button], input[type=submit], input[type=reset], button, a", + "controlgroupLabel": ".ui-controlgroup-label", + "checkboxradio": "input[type='checkbox'], input[type='radio']", + "selectmenu": "select", + "spinner": ".ui-spinner-input" + } + }, + + _create: function() { + this._enhance(); + }, + + // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation + _enhance: function() { + this.element.attr( "role", "toolbar" ); + this.refresh(); + }, + + _destroy: function() { + this._callChildMethod( "destroy" ); + this.childWidgets.removeData( "ui-controlgroup-data" ); + this.element.removeAttr( "role" ); + if ( this.options.items.controlgroupLabel ) { + this.element + .find( this.options.items.controlgroupLabel ) + .find( ".ui-controlgroup-label-contents" ) + .contents().unwrap(); + } + }, + + _initWidgets: function() { + var that = this, + childWidgets = []; + + // First we iterate over each of the items options + $.each( this.options.items, function( widget, selector ) { + var labels; + var options = {}; + + // Make sure the widget has a selector set + if ( !selector ) { + return; + } + + if ( widget === "controlgroupLabel" ) { + labels = that.element.find( selector ); + labels.each( function() { + var element = $( this ); + + if ( element.children( ".ui-controlgroup-label-contents" ).length ) { + return; + } + element.contents() + .wrapAll( "" ); + } ); + that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" ); + childWidgets = childWidgets.concat( labels.get() ); + return; + } + + // Make sure the widget actually exists + if ( !$.fn[ widget ] ) { + return; + } + + // We assume everything is in the middle to start because we can't determine + // first / last elements until all enhancments are done. + if ( that[ "_" + widget + "Options" ] ) { + options = that[ "_" + widget + "Options" ]( "middle" ); + } else { + options = { classes: {} }; + } + + // Find instances of this widget inside controlgroup and init them + that.element + .find( selector ) + .each( function() { + var element = $( this ); + var instance = element[ widget ]( "instance" ); + + // We need to clone the default options for this type of widget to avoid + // polluting the variable options which has a wider scope than a single widget. + var instanceOptions = $.widget.extend( {}, options ); + + // If the button is the child of a spinner ignore it + // TODO: Find a more generic solution + if ( widget === "button" && element.parent( ".ui-spinner" ).length ) { + return; + } + + // Create the widget if it doesn't exist + if ( !instance ) { + instance = element[ widget ]()[ widget ]( "instance" ); + } + if ( instance ) { + instanceOptions.classes = + that._resolveClassesValues( instanceOptions.classes, instance ); + } + element[ widget ]( instanceOptions ); + + // Store an instance of the controlgroup to be able to reference + // from the outermost element for changing options and refresh + var widgetElement = element[ widget ]( "widget" ); + $.data( widgetElement[ 0 ], "ui-controlgroup-data", + instance ? instance : element[ widget ]( "instance" ) ); + + childWidgets.push( widgetElement[ 0 ] ); + } ); + } ); + + this.childWidgets = $( $.uniqueSort( childWidgets ) ); + this._addClass( this.childWidgets, "ui-controlgroup-item" ); + }, + + _callChildMethod: function( method ) { + this.childWidgets.each( function() { + var element = $( this ), + data = element.data( "ui-controlgroup-data" ); + if ( data && data[ method ] ) { + data[ method ](); + } + } ); + }, + + _updateCornerClass: function( element, position ) { + var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all"; + var add = this._buildSimpleOptions( position, "label" ).classes.label; + + this._removeClass( element, null, remove ); + this._addClass( element, null, add ); + }, + + _buildSimpleOptions: function( position, key ) { + var direction = this.options.direction === "vertical"; + var result = { + classes: {} + }; + result.classes[ key ] = { + "middle": "", + "first": "ui-corner-" + ( direction ? "top" : "left" ), + "last": "ui-corner-" + ( direction ? "bottom" : "right" ), + "only": "ui-corner-all" + }[ position ]; + + return result; + }, + + _spinnerOptions: function( position ) { + var options = this._buildSimpleOptions( position, "ui-spinner" ); + + options.classes[ "ui-spinner-up" ] = ""; + options.classes[ "ui-spinner-down" ] = ""; + + return options; + }, + + _buttonOptions: function( position ) { + return this._buildSimpleOptions( position, "ui-button" ); + }, + + _checkboxradioOptions: function( position ) { + return this._buildSimpleOptions( position, "ui-checkboxradio-label" ); + }, + + _selectmenuOptions: function( position ) { + var direction = this.options.direction === "vertical"; + return { + width: direction ? "auto" : false, + classes: { + middle: { + "ui-selectmenu-button-open": "", + "ui-selectmenu-button-closed": "" + }, + first: { + "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ), + "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" ) + }, + last: { + "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr", + "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" ) + }, + only: { + "ui-selectmenu-button-open": "ui-corner-top", + "ui-selectmenu-button-closed": "ui-corner-all" + } + + }[ position ] + }; + }, + + _resolveClassesValues: function( classes, instance ) { + var result = {}; + $.each( classes, function( key ) { + var current = instance.options.classes[ key ] || ""; + current = String.prototype.trim.call( current.replace( controlgroupCornerRegex, "" ) ); + result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " ); + } ); + return result; + }, + + _setOption: function( key, value ) { + if ( key === "direction" ) { + this._removeClass( "ui-controlgroup-" + this.options.direction ); + } + + this._super( key, value ); + if ( key === "disabled" ) { + this._callChildMethod( value ? "disable" : "enable" ); + return; + } + + this.refresh(); + }, + + refresh: function() { + var children, + that = this; + + this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction ); + + if ( this.options.direction === "horizontal" ) { + this._addClass( null, "ui-helper-clearfix" ); + } + this._initWidgets(); + + children = this.childWidgets; + + // We filter here because we need to track all childWidgets not just the visible ones + if ( this.options.onlyVisible ) { + children = children.filter( ":visible" ); + } + + if ( children.length ) { + + // We do this last because we need to make sure all enhancment is done + // before determining first and last + $.each( [ "first", "last" ], function( index, value ) { + var instance = children[ value ]().data( "ui-controlgroup-data" ); + + if ( instance && that[ "_" + instance.widgetName + "Options" ] ) { + var options = that[ "_" + instance.widgetName + "Options" ]( + children.length === 1 ? "only" : value + ); + options.classes = that._resolveClassesValues( options.classes, instance ); + instance.element[ instance.widgetName ]( options ); + } else { + that._updateCornerClass( children[ value ](), value ); + } + } ); + + // Finally call the refresh method on each of the child widgets. + this._callChildMethod( "refresh" ); + } + } +} ); + +/*! + * jQuery UI Checkboxradio 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Checkboxradio +//>>group: Widgets +//>>description: Enhances a form with multiple themeable checkboxes or radio buttons. +//>>docs: https://api.jqueryui.com/checkboxradio/ +//>>demos: https://jqueryui.com/checkboxradio/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/button.css +//>>css.structure: ../../themes/base/checkboxradio.css +//>>css.theme: ../../themes/base/theme.css + + +$.widget( "ui.checkboxradio", [ $.ui.formResetMixin, { + version: "1.14.1", + options: { + disabled: null, + label: null, + icon: true, + classes: { + "ui-checkboxradio-label": "ui-corner-all", + "ui-checkboxradio-icon": "ui-corner-all" + } + }, + + _getCreateOptions: function() { + var disabled, labels, labelContents; + var options = this._super() || {}; + + // We read the type here, because it makes more sense to throw a element type error first, + // rather then the error for lack of a label. Often if its the wrong type, it + // won't have a label (e.g. calling on a div, btn, etc) + this._readType(); + + labels = this.element.labels(); + + // If there are multiple labels, use the last one + this.label = $( labels[ labels.length - 1 ] ); + if ( !this.label.length ) { + $.error( "No label found for checkboxradio widget" ); + } + + this.originalLabel = ""; + + // We need to get the label text but this may also need to make sure it does not contain the + // input itself. + // The label contents could be text, html, or a mix. We wrap all elements + // and read the wrapper's `innerHTML` to get a string representation of + // the label, without the input as part of it. + labelContents = this.label.contents().not( this.element[ 0 ] ); + + if ( labelContents.length ) { + this.originalLabel += labelContents + .clone() + .wrapAll( "
      " ) + .parent() + .html(); + } + + // Set the label option if we found label text + if ( this.originalLabel ) { + options.label = this.originalLabel; + } + + disabled = this.element[ 0 ].disabled; + if ( disabled != null ) { + options.disabled = disabled; + } + return options; + }, + + _create: function() { + var checked = this.element[ 0 ].checked; + + this._bindFormResetHandler(); + + if ( this.options.disabled == null ) { + this.options.disabled = this.element[ 0 ].disabled; + } + + this._setOption( "disabled", this.options.disabled ); + this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" ); + this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" ); + + if ( this.type === "radio" ) { + this._addClass( this.label, "ui-checkboxradio-radio-label" ); + } + + if ( this.options.label && this.options.label !== this.originalLabel ) { + this._updateLabel(); + } else if ( this.originalLabel ) { + this.options.label = this.originalLabel; + } + + this._enhance(); + + if ( checked ) { + this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" ); + } + + this._on( { + change: "_toggleClasses", + focus: function() { + this._addClass( this.label, null, "ui-state-focus ui-visual-focus" ); + }, + blur: function() { + this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" ); + } + } ); + }, + + _readType: function() { + var nodeName = this.element[ 0 ].nodeName.toLowerCase(); + this.type = this.element[ 0 ].type; + if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) { + $.error( "Can't create checkboxradio on element.nodeName=" + nodeName + + " and element.type=" + this.type ); + } + }, + + // Support jQuery Mobile enhanced option + _enhance: function() { + this._updateIcon( this.element[ 0 ].checked ); + }, + + widget: function() { + return this.label; + }, + + _getRadioGroup: function() { + var group; + var name = this.element[ 0 ].name; + var nameSelector = "input[name='" + CSS.escape( name ) + "']"; + + if ( !name ) { + return $( [] ); + } + + if ( this.form.length ) { + group = $( this.form[ 0 ].elements ).filter( nameSelector ); + } else { + + // Not inside a form, check all inputs that also are not inside a form + group = $( nameSelector ).filter( function() { + return $( $( this ).prop( "form" ) ).length === 0; + } ); + } + + return group.not( this.element ); + }, + + _toggleClasses: function() { + var checked = this.element[ 0 ].checked; + this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); + + if ( this.options.icon && this.type === "checkbox" ) { + this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked ) + ._toggleClass( this.icon, null, "ui-icon-blank", !checked ); + } + + if ( this.type === "radio" ) { + this._getRadioGroup() + .each( function() { + var instance = $( this ).checkboxradio( "instance" ); + + if ( instance ) { + instance._removeClass( instance.label, + "ui-checkboxradio-checked", "ui-state-active" ); + } + } ); + } + }, + + _destroy: function() { + this._unbindFormResetHandler(); + + if ( this.icon ) { + this.icon.remove(); + this.iconSpace.remove(); + } + }, + + _setOption: function( key, value ) { + + // We don't allow the value to be set to nothing + if ( key === "label" && !value ) { + return; + } + + this._super( key, value ); + + if ( key === "disabled" ) { + this._toggleClass( this.label, null, "ui-state-disabled", value ); + this.element[ 0 ].disabled = value; + + // Don't refresh when setting disabled + return; + } + this.refresh(); + }, + + _updateIcon: function( checked ) { + var toAdd = "ui-icon ui-icon-background "; + + if ( this.options.icon ) { + if ( !this.icon ) { + this.icon = $( "" ); + this.iconSpace = $( " " ); + this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" ); + } + + if ( this.type === "checkbox" ) { + toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank"; + this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" ); + } else { + toAdd += "ui-icon-blank"; + } + this._addClass( this.icon, "ui-checkboxradio-icon", toAdd ); + if ( !checked ) { + this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" ); + } + this.icon.prependTo( this.label ).after( this.iconSpace ); + } else if ( this.icon !== undefined ) { + this.icon.remove(); + this.iconSpace.remove(); + delete this.icon; + } + }, + + _updateLabel: function() { + + // Remove the contents of the label ( minus the icon, icon space, and input ) + var contents = this.label.contents().not( this.element[ 0 ] ); + if ( this.icon ) { + contents = contents.not( this.icon[ 0 ] ); + } + if ( this.iconSpace ) { + contents = contents.not( this.iconSpace[ 0 ] ); + } + contents.remove(); + + this.label.append( this.options.label ); + }, + + refresh: function() { + var checked = this.element[ 0 ].checked, + isDisabled = this.element[ 0 ].disabled; + + this._updateIcon( checked ); + this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked ); + if ( this.options.label !== null ) { + this._updateLabel(); + } + + if ( isDisabled !== this.options.disabled ) { + this._setOptions( { "disabled": isDisabled } ); + } + } + +} ] ); + +var widgetsCheckboxradio = $.ui.checkboxradio; + + +/*! + * jQuery UI Button 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Button +//>>group: Widgets +//>>description: Enhances a form with themeable buttons. +//>>docs: https://api.jqueryui.com/button/ +//>>demos: https://jqueryui.com/button/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/button.css +//>>css.theme: ../../themes/base/theme.css + + +$.widget( "ui.button", { + version: "1.14.1", + defaultElement: "" ) + .button( { + label: $( "" ).text( this.options.closeText ).html(), + icon: "ui-icon-closethick", + showLabel: false + } ) + .appendTo( this.uiDialogTitlebar ); + + this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" ); + this._on( this.uiDialogTitlebarClose, { + click: function( event ) { + event.preventDefault(); + this.close( event ); + } + } ); + + var uiDialogHeadingLevel = Number.isInteger( this.options.uiDialogTitleHeadingLevel ) && + this.options.uiDialogTitleHeadingLevel > 0 && + this.options.uiDialogTitleHeadingLevel <= 6 ? + "h" + this.options.uiDialogTitleHeadingLevel : "span"; + + uiDialogTitle = $( "<" + uiDialogHeadingLevel + ">" ) + .uniqueId().prependTo( this.uiDialogTitlebar ); + this._addClass( uiDialogTitle, "ui-dialog-title" ); + this._title( uiDialogTitle ); + + this.uiDialogTitlebar.prependTo( this.uiDialog ); + + this.uiDialog.attr( { + "aria-labelledby": uiDialogTitle.attr( "id" ) + } ); + }, + + _title: function( title ) { + if ( this.options.title ) { + title.text( this.options.title ); + } else { + title.html( " " ); + } + }, + + _createButtonPane: function() { + this.uiDialogButtonPane = $( "
      " ); + this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane", + "ui-widget-content ui-helper-clearfix" ); + + this.uiButtonSet = $( "
      " ) + .appendTo( this.uiDialogButtonPane ); + this._addClass( this.uiButtonSet, "ui-dialog-buttonset" ); + + this._createButtons(); + }, + + _createButtons: function() { + var that = this, + buttons = this.options.buttons; + + // If we already have a button pane, remove it + this.uiDialogButtonPane.remove(); + this.uiButtonSet.empty(); + + if ( $.isEmptyObject( buttons ) || ( Array.isArray( buttons ) && !buttons.length ) ) { + this._removeClass( this.uiDialog, "ui-dialog-buttons" ); + return; + } + + $.each( buttons, function( name, props ) { + var click, buttonOptions; + props = typeof props === "function" ? + { click: props, text: name } : + props; + + // Default to a non-submitting button + props = $.extend( { type: "button" }, props ); + + // Change the context for the click callback to be the main element + click = props.click; + buttonOptions = { + icon: props.icon, + iconPosition: props.iconPosition, + showLabel: props.showLabel, + + // Deprecated options + icons: props.icons, + text: props.text + }; + + delete props.click; + delete props.icon; + delete props.iconPosition; + delete props.showLabel; + + // Deprecated options + delete props.icons; + if ( typeof props.text === "boolean" ) { + delete props.text; + } + + $( "", props ) + .button( buttonOptions ) + .appendTo( that.uiButtonSet ) + .on( "click", function() { + click.apply( that.element[ 0 ], arguments ); + } ); + } ); + this._addClass( this.uiDialog, "ui-dialog-buttons" ); + this.uiDialogButtonPane.appendTo( this.uiDialog ); + }, + + _makeDraggable: function() { + var that = this, + options = this.options; + + function filteredUi( ui ) { + return { + position: ui.position, + offset: ui.offset + }; + } + + this.uiDialog.draggable( { + cancel: ".ui-dialog-content, .ui-dialog-titlebar-close", + handle: ".ui-dialog-titlebar", + containment: "document", + start: function( event, ui ) { + that._addClass( $( this ), "ui-dialog-dragging" ); + that._blockFrames(); + that._trigger( "dragStart", event, filteredUi( ui ) ); + }, + drag: function( event, ui ) { + that._trigger( "drag", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + var left = ui.offset.left - that.document.scrollLeft(), + top = ui.offset.top - that.document.scrollTop(); + + options.position = { + my: "left top", + at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + + "top" + ( top >= 0 ? "+" : "" ) + top, + of: that.window + }; + that._removeClass( $( this ), "ui-dialog-dragging" ); + that._unblockFrames(); + that._trigger( "dragStop", event, filteredUi( ui ) ); + } + } ); + }, + + _makeResizable: function() { + var that = this, + options = this.options, + handles = options.resizable, + + // .ui-resizable has position: relative defined in the stylesheet + // but dialogs have to use absolute or fixed positioning + position = this.uiDialog.css( "position" ), + resizeHandles = typeof handles === "string" ? + handles : + "n,e,s,w,se,sw,ne,nw"; + + function filteredUi( ui ) { + return { + originalPosition: ui.originalPosition, + originalSize: ui.originalSize, + position: ui.position, + size: ui.size + }; + } + + this.uiDialog.resizable( { + cancel: ".ui-dialog-content", + containment: "document", + alsoResize: this.element, + maxWidth: options.maxWidth, + maxHeight: options.maxHeight, + minWidth: options.minWidth, + minHeight: this._minHeight(), + handles: resizeHandles, + start: function( event, ui ) { + that._addClass( $( this ), "ui-dialog-resizing" ); + that._blockFrames(); + that._trigger( "resizeStart", event, filteredUi( ui ) ); + }, + resize: function( event, ui ) { + that._trigger( "resize", event, filteredUi( ui ) ); + }, + stop: function( event, ui ) { + var offset = that.uiDialog.offset(), + left = offset.left - that.document.scrollLeft(), + top = offset.top - that.document.scrollTop(); + + options.height = that.uiDialog.height(); + options.width = that.uiDialog.width(); + options.position = { + my: "left top", + at: "left" + ( left >= 0 ? "+" : "" ) + left + " " + + "top" + ( top >= 0 ? "+" : "" ) + top, + of: that.window + }; + that._removeClass( $( this ), "ui-dialog-resizing" ); + that._unblockFrames(); + that._trigger( "resizeStop", event, filteredUi( ui ) ); + } + } ) + .css( "position", position ); + }, + + _trackFocus: function() { + this._on( this.widget(), { + focusin: function( event ) { + this._makeFocusTarget(); + this._focusedElement = $( event.target ); + } + } ); + }, + + _makeFocusTarget: function() { + this._untrackInstance(); + this._trackingInstances().unshift( this ); + }, + + _untrackInstance: function() { + var instances = this._trackingInstances(), + exists = $.inArray( this, instances ); + if ( exists !== -1 ) { + instances.splice( exists, 1 ); + } + }, + + _trackingInstances: function() { + var instances = this.document.data( "ui-dialog-instances" ); + if ( !instances ) { + instances = []; + this.document.data( "ui-dialog-instances", instances ); + } + return instances; + }, + + _minHeight: function() { + var options = this.options; + + return options.height === "auto" ? + options.minHeight : + Math.min( options.minHeight, options.height ); + }, + + _position: function() { + + // Need to show the dialog to get the actual offset in the position plugin + var isVisible = this.uiDialog.is( ":visible" ); + if ( !isVisible ) { + this.uiDialog.show(); + } + this.uiDialog.position( this.options.position ); + if ( !isVisible ) { + this.uiDialog.hide(); + } + }, + + _setOptions: function( options ) { + var that = this, + resize = false, + resizableOptions = {}; + + $.each( options, function( key, value ) { + that._setOption( key, value ); + + if ( key in that.sizeRelatedOptions ) { + resize = true; + } + if ( key in that.resizableRelatedOptions ) { + resizableOptions[ key ] = value; + } + } ); + + if ( resize ) { + this._size(); + this._position(); + } + if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { + this.uiDialog.resizable( "option", resizableOptions ); + } + }, + + _setOption: function( key, value ) { + var isDraggable, isResizable, + uiDialog = this.uiDialog; + + if ( key === "disabled" ) { + return; + } + + this._super( key, value ); + + if ( key === "appendTo" ) { + this.uiDialog.appendTo( this._appendTo() ); + } + + if ( key === "buttons" ) { + this._createButtons(); + } + + if ( key === "closeText" ) { + this.uiDialogTitlebarClose.button( { + + // Ensure that we always pass a string + label: $( "" ).text( "" + this.options.closeText ).html() + } ); + } + + if ( key === "draggable" ) { + isDraggable = uiDialog.is( ":data(ui-draggable)" ); + if ( isDraggable && !value ) { + uiDialog.draggable( "destroy" ); + } + + if ( !isDraggable && value ) { + this._makeDraggable(); + } + } + + if ( key === "position" ) { + this._position(); + } + + if ( key === "resizable" ) { + + // currently resizable, becoming non-resizable + isResizable = uiDialog.is( ":data(ui-resizable)" ); + if ( isResizable && !value ) { + uiDialog.resizable( "destroy" ); + } + + // Currently resizable, changing handles + if ( isResizable && typeof value === "string" ) { + uiDialog.resizable( "option", "handles", value ); + } + + // Currently non-resizable, becoming resizable + if ( !isResizable && value !== false ) { + this._makeResizable(); + } + } + + if ( key === "title" ) { + this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) ); + } + + if ( key === "modal" ) { + uiDialog.attr( "aria-modal", value ? "true" : null ); + } + }, + + _size: function() { + + // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content + // divs will both have width and height set, so we need to reset them + var nonContentHeight, minContentHeight, maxContentHeight, + options = this.options; + + // Reset content sizing + this.element.show().css( { + width: "auto", + minHeight: 0, + maxHeight: "none", + height: 0 + } ); + + if ( options.minWidth > options.width ) { + options.width = options.minWidth; + } + + // Reset wrapper sizing + // determine the height of all the non-content elements + nonContentHeight = this.uiDialog.css( { + height: "auto", + width: options.width + } ) + .outerHeight(); + minContentHeight = Math.max( 0, options.minHeight - nonContentHeight ); + maxContentHeight = typeof options.maxHeight === "number" ? + Math.max( 0, options.maxHeight - nonContentHeight ) : + "none"; + + if ( options.height === "auto" ) { + this.element.css( { + minHeight: minContentHeight, + maxHeight: maxContentHeight, + height: "auto" + } ); + } else { + this.element.height( Math.max( 0, options.height - nonContentHeight ) ); + } + + if ( this.uiDialog.is( ":data(ui-resizable)" ) ) { + this.uiDialog.resizable( "option", "minHeight", this._minHeight() ); + } + }, + + _blockFrames: function() { + this.iframeBlocks = this.document.find( "iframe" ).map( function() { + var iframe = $( this ); + + return $( "
      " ) + .css( { + position: "absolute", + width: iframe.outerWidth(), + height: iframe.outerHeight() + } ) + .appendTo( iframe.parent() ) + .offset( iframe.offset() )[ 0 ]; + } ); + }, + + _unblockFrames: function() { + if ( this.iframeBlocks ) { + this.iframeBlocks.remove(); + delete this.iframeBlocks; + } + }, + + _allowInteraction: function( event ) { + if ( $( event.target ).closest( ".ui-dialog" ).length ) { + return true; + } + + // TODO: Remove hack when datepicker implements + // the .ui-front logic (#8989) + return !!$( event.target ).closest( ".ui-datepicker" ).length; + }, + + _createOverlay: function() { + if ( !this.options.modal ) { + return; + } + + // We use a delay in case the overlay is created from an + // event that we're going to be cancelling (#2804) + var isOpening = true; + this._delay( function() { + isOpening = false; + } ); + + if ( !this.document.data( "ui-dialog-overlays" ) ) { + + // Prevent use of anchors and inputs + // This doesn't use `_on()` because it is a shared event handler + // across all open modal dialogs. + this.document.on( "focusin.ui-dialog", function( event ) { + if ( isOpening ) { + return; + } + + var instance = this._trackingInstances()[ 0 ]; + if ( !instance._allowInteraction( event ) ) { + event.preventDefault(); + instance._focusTabbable(); + } + }.bind( this ) ); + } + + this.overlay = $( "
      " ) + .appendTo( this._appendTo() ); + + this._addClass( this.overlay, null, "ui-widget-overlay ui-front" ); + this._on( this.overlay, { + mousedown: "_keepFocus" + } ); + this.document.data( "ui-dialog-overlays", + ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 ); + }, + + _destroyOverlay: function() { + if ( !this.options.modal ) { + return; + } + + if ( this.overlay ) { + var overlays = this.document.data( "ui-dialog-overlays" ) - 1; + + if ( !overlays ) { + this.document.off( "focusin.ui-dialog" ); + this.document.removeData( "ui-dialog-overlays" ); + } else { + this.document.data( "ui-dialog-overlays", overlays ); + } + + this.overlay.remove(); + this.overlay = null; + } + } +} ); + +// DEPRECATED +// TODO: switch return back to widget declaration at top of file when this is removed +if ( $.uiBackCompat === true ) { + + // Backcompat for dialogClass option + $.widget( "ui.dialog", $.ui.dialog, { + options: { + dialogClass: "" + }, + _createWrapper: function() { + this._super(); + this.uiDialog.addClass( this.options.dialogClass ); + }, + _setOption: function( key, value ) { + if ( key === "dialogClass" ) { + this.uiDialog + .removeClass( this.options.dialogClass ) + .addClass( value ); + } + this._superApply( arguments ); + } + } ); +} + +var widgetsDialog = $.ui.dialog; + + +/*! + * jQuery UI Droppable 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Droppable +//>>group: Interactions +//>>description: Enables drop targets for draggable elements. +//>>docs: https://api.jqueryui.com/droppable/ +//>>demos: https://jqueryui.com/droppable/ + + +$.widget( "ui.droppable", { + version: "1.14.1", + widgetEventPrefix: "drop", + options: { + accept: "*", + addClasses: true, + greedy: false, + scope: "default", + tolerance: "intersect", + + // Callbacks + activate: null, + deactivate: null, + drop: null, + out: null, + over: null + }, + _create: function() { + + var proportions, + o = this.options, + accept = o.accept; + + this.isover = false; + this.isout = true; + + this.accept = typeof accept === "function" ? accept : function( d ) { + return d.is( accept ); + }; + + this.proportions = function( /* valueToWrite */ ) { + if ( arguments.length ) { + + // Store the droppable's proportions + proportions = arguments[ 0 ]; + } else { + + // Retrieve or derive the droppable's proportions + return proportions ? + proportions : + proportions = { + width: this.element[ 0 ].offsetWidth, + height: this.element[ 0 ].offsetHeight + }; + } + }; + + this._addToManager( o.scope ); + + if ( o.addClasses ) { + this._addClass( "ui-droppable" ); + } + + }, + + _addToManager: function( scope ) { + + // Add the reference and positions to the manager + $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || []; + $.ui.ddmanager.droppables[ scope ].push( this ); + }, + + _splice: function( drop ) { + var i = 0; + for ( ; i < drop.length; i++ ) { + if ( drop[ i ] === this ) { + drop.splice( i, 1 ); + } + } + }, + + _destroy: function() { + var drop = $.ui.ddmanager.droppables[ this.options.scope ]; + + this._splice( drop ); + }, + + _setOption: function( key, value ) { + + if ( key === "accept" ) { + this.accept = typeof value === "function" ? value : function( d ) { + return d.is( value ); + }; + } else if ( key === "scope" ) { + var drop = $.ui.ddmanager.droppables[ this.options.scope ]; + + this._splice( drop ); + this._addToManager( value ); + } + + this._super( key, value ); + }, + + _activate: function( event ) { + var draggable = $.ui.ddmanager.current; + + this._addActiveClass(); + if ( draggable ) { + this._trigger( "activate", event, this.ui( draggable ) ); + } + }, + + _deactivate: function( event ) { + var draggable = $.ui.ddmanager.current; + + this._removeActiveClass(); + if ( draggable ) { + this._trigger( "deactivate", event, this.ui( draggable ) ); + } + }, + + _over: function( event ) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if ( !draggable || ( draggable.currentItem || + draggable.element )[ 0 ] === this.element[ 0 ] ) { + return; + } + + if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || + draggable.element ) ) ) { + this._addHoverClass(); + this._trigger( "over", event, this.ui( draggable ) ); + } + + }, + + _out: function( event ) { + + var draggable = $.ui.ddmanager.current; + + // Bail if draggable and droppable are same element + if ( !draggable || ( draggable.currentItem || + draggable.element )[ 0 ] === this.element[ 0 ] ) { + return; + } + + if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem || + draggable.element ) ) ) { + this._removeHoverClass(); + this._trigger( "out", event, this.ui( draggable ) ); + } + + }, + + _drop: function( event, custom ) { + + var draggable = custom || $.ui.ddmanager.current, + childrenIntersection = false; + + // Bail if draggable and droppable are same element + if ( !draggable || ( draggable.currentItem || + draggable.element )[ 0 ] === this.element[ 0 ] ) { + return false; + } + + this.element + .find( ":data(ui-droppable)" ) + .not( ".ui-draggable-dragging" ) + .each( function() { + var inst = $( this ).droppable( "instance" ); + if ( + inst.options.greedy && + !inst.options.disabled && + inst.options.scope === draggable.options.scope && + inst.accept.call( + inst.element[ 0 ], ( draggable.currentItem || draggable.element ) + ) && + $.ui.intersect( + draggable, + $.extend( inst, { offset: inst.element.offset() } ), + inst.options.tolerance, event + ) + ) { + childrenIntersection = true; + return false; + } + } ); + if ( childrenIntersection ) { + return false; + } + + if ( this.accept.call( this.element[ 0 ], + ( draggable.currentItem || draggable.element ) ) ) { + this._removeActiveClass(); + this._removeHoverClass(); + + this._trigger( "drop", event, this.ui( draggable ) ); + return this.element; + } + + return false; + + }, + + ui: function( c ) { + return { + draggable: ( c.currentItem || c.element ), + helper: c.helper, + position: c.position, + offset: c.positionAbs + }; + }, + + // Extension points just to make backcompat sane and avoid duplicating logic + // TODO: Remove in 1.14 along with call to it below + _addHoverClass: function() { + this._addClass( "ui-droppable-hover" ); + }, + + _removeHoverClass: function() { + this._removeClass( "ui-droppable-hover" ); + }, + + _addActiveClass: function() { + this._addClass( "ui-droppable-active" ); + }, + + _removeActiveClass: function() { + this._removeClass( "ui-droppable-active" ); + } +} ); + +$.ui.intersect = ( function() { + function isOverAxis( x, reference, size ) { + return ( x >= reference ) && ( x < ( reference + size ) ); + } + + return function( draggable, droppable, toleranceMode, event ) { + + if ( !droppable.offset ) { + return false; + } + + var x1 = ( draggable.positionAbs || + draggable.position.absolute ).left + draggable.margins.left, + y1 = ( draggable.positionAbs || + draggable.position.absolute ).top + draggable.margins.top, + x2 = x1 + draggable.helperProportions.width, + y2 = y1 + draggable.helperProportions.height, + l = droppable.offset.left, + t = droppable.offset.top, + r = l + droppable.proportions().width, + b = t + droppable.proportions().height; + + switch ( toleranceMode ) { + case "fit": + return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b ); + case "intersect": + return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half + x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half + t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half + y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half + case "pointer": + return isOverAxis( event.pageY, t, droppable.proportions().height ) && + isOverAxis( event.pageX, l, droppable.proportions().width ); + case "touch": + return ( + ( y1 >= t && y1 <= b ) || // Top edge touching + ( y2 >= t && y2 <= b ) || // Bottom edge touching + ( y1 < t && y2 > b ) // Surrounded vertically + ) && ( + ( x1 >= l && x1 <= r ) || // Left edge touching + ( x2 >= l && x2 <= r ) || // Right edge touching + ( x1 < l && x2 > r ) // Surrounded horizontally + ); + default: + return false; + } + }; +} )(); + +/* + This manager tracks offsets of draggables and droppables +*/ +$.ui.ddmanager = { + current: null, + droppables: { "default": [] }, + prepareOffsets: function( t, event ) { + + var i, j, + m = $.ui.ddmanager.droppables[ t.options.scope ] || [], + type = event ? event.type : null, // workaround for #2317 + list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack(); + + droppablesLoop: for ( i = 0; i < m.length; i++ ) { + + // No disabled and non-accepted + if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ], + ( t.currentItem || t.element ) ) ) ) { + continue; + } + + // Filter out elements in the current dragged item + for ( j = 0; j < list.length; j++ ) { + if ( list[ j ] === m[ i ].element[ 0 ] ) { + m[ i ].proportions().height = 0; + continue droppablesLoop; + } + } + + m[ i ].visible = m[ i ].element.css( "display" ) !== "none"; + if ( !m[ i ].visible ) { + continue; + } + + // Activate the droppable if used directly from draggables + if ( type === "mousedown" ) { + m[ i ]._activate.call( m[ i ], event ); + } + + m[ i ].offset = m[ i ].element.offset(); + m[ i ].proportions( { + width: m[ i ].element[ 0 ].offsetWidth, + height: m[ i ].element[ 0 ].offsetHeight + } ); + + } + + }, + drop: function( draggable, event ) { + + var dropped = false; + + // Create a copy of the droppables in case the list changes during the drop (#9116) + $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() { + + if ( !this.options ) { + return; + } + if ( !this.options.disabled && this.visible && + $.ui.intersect( draggable, this, this.options.tolerance, event ) ) { + dropped = this._drop.call( this, event ) || dropped; + } + + if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ], + ( draggable.currentItem || draggable.element ) ) ) { + this.isout = true; + this.isover = false; + this._deactivate.call( this, event ); + } + + } ); + return dropped; + + }, + dragStart: function( draggable, event ) { + + // Listen for scrolling so that if the dragging causes scrolling the position of the + // droppables can be recalculated (see #5003) + draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() { + if ( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + } ); + }, + drag: function( draggable, event ) { + + // If you have a highly dynamic page, you might try this option. It renders positions + // every time you move the mouse. + if ( draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + + // Run through all droppables and check their positions based on specific tolerance options + $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() { + + if ( this.options.disabled || this.greedyChild || !this.visible ) { + return; + } + + var parentInstance, scope, parent, + intersects = $.ui.intersect( draggable, this, this.options.tolerance, event ), + c = !intersects && this.isover ? + "isout" : + ( intersects && !this.isover ? "isover" : null ); + if ( !c ) { + return; + } + + if ( this.options.greedy ) { + + // find droppable parents with same scope + scope = this.options.scope; + parent = this.element.parents( ":data(ui-droppable)" ).filter( function() { + return $( this ).droppable( "instance" ).options.scope === scope; + } ); + + if ( parent.length ) { + parentInstance = $( parent[ 0 ] ).droppable( "instance" ); + parentInstance.greedyChild = ( c === "isover" ); + } + } + + // We just moved into a greedy child + if ( parentInstance && c === "isover" ) { + parentInstance.isover = false; + parentInstance.isout = true; + parentInstance._out.call( parentInstance, event ); + } + + this[ c ] = true; + this[ c === "isout" ? "isover" : "isout" ] = false; + this[ c === "isover" ? "_over" : "_out" ].call( this, event ); + + // We just moved out of a greedy child + if ( parentInstance && c === "isout" ) { + parentInstance.isout = false; + parentInstance.isover = true; + parentInstance._over.call( parentInstance, event ); + } + } ); + + }, + dragStop: function( draggable, event ) { + draggable.element.parentsUntil( "body" ).off( "scroll.droppable" ); + + // Call prepareOffsets one final time since IE does not fire return scroll events when + // overflow was caused by drag (see #5003) + if ( !draggable.options.refreshPositions ) { + $.ui.ddmanager.prepareOffsets( draggable, event ); + } + } +}; + +// DEPRECATED +// TODO: switch return back to widget declaration at top of file when this is removed +if ( $.uiBackCompat === true ) { + + // Backcompat for activeClass and hoverClass options + $.widget( "ui.droppable", $.ui.droppable, { + options: { + hoverClass: false, + activeClass: false + }, + _addActiveClass: function() { + this._super(); + if ( this.options.activeClass ) { + this.element.addClass( this.options.activeClass ); + } + }, + _removeActiveClass: function() { + this._super(); + if ( this.options.activeClass ) { + this.element.removeClass( this.options.activeClass ); + } + }, + _addHoverClass: function() { + this._super(); + if ( this.options.hoverClass ) { + this.element.addClass( this.options.hoverClass ); + } + }, + _removeHoverClass: function() { + this._super(); + if ( this.options.hoverClass ) { + this.element.removeClass( this.options.hoverClass ); + } + } + } ); +} + +var widgetsDroppable = $.ui.droppable; + + +/*! + * jQuery UI Progressbar 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Progressbar +//>>group: Widgets +/* eslint-disable max-len */ +//>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators. +/* eslint-enable max-len */ +//>>docs: https://api.jqueryui.com/progressbar/ +//>>demos: https://jqueryui.com/progressbar/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/progressbar.css +//>>css.theme: ../../themes/base/theme.css + + +var widgetsProgressbar = $.widget( "ui.progressbar", { + version: "1.14.1", + options: { + classes: { + "ui-progressbar": "ui-corner-all", + "ui-progressbar-value": "ui-corner-left", + "ui-progressbar-complete": "ui-corner-right" + }, + max: 100, + value: 0, + + change: null, + complete: null + }, + + min: 0, + + _create: function() { + + // Constrain initial value + this.oldValue = this.options.value = this._constrainedValue(); + + this.element.attr( { + + // Only set static values; aria-valuenow and aria-valuemax are + // set inside _refreshValue() + role: "progressbar", + "aria-valuemin": this.min + } ); + this._addClass( "ui-progressbar", "ui-widget ui-widget-content" ); + + this.valueDiv = $( "
      " ).appendTo( this.element ); + this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" ); + this._refreshValue(); + }, + + _destroy: function() { + this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" ); + + this.valueDiv.remove(); + }, + + value: function( newValue ) { + if ( newValue === undefined ) { + return this.options.value; + } + + this.options.value = this._constrainedValue( newValue ); + this._refreshValue(); + }, + + _constrainedValue: function( newValue ) { + if ( newValue === undefined ) { + newValue = this.options.value; + } + + this.indeterminate = newValue === false; + + // Sanitize value + if ( typeof newValue !== "number" ) { + newValue = 0; + } + + return this.indeterminate ? false : + Math.min( this.options.max, Math.max( this.min, newValue ) ); + }, + + _setOptions: function( options ) { + + // Ensure "value" option is set after other values (like max) + var value = options.value; + delete options.value; + + this._super( options ); + + this.options.value = this._constrainedValue( value ); + this._refreshValue(); + }, + + _setOption: function( key, value ) { + if ( key === "max" ) { + + // Don't allow a max less than min + value = Math.max( this.min, value ); + } + this._super( key, value ); + }, + + _setOptionDisabled: function( value ) { + this._super( value ); + + this.element.attr( "aria-disabled", value ); + this._toggleClass( null, "ui-state-disabled", !!value ); + }, + + _percentage: function() { + return this.indeterminate ? + 100 : + 100 * ( this.options.value - this.min ) / ( this.options.max - this.min ); + }, + + _refreshValue: function() { + var value = this.options.value, + percentage = this._percentage(); + + this.valueDiv + .toggle( this.indeterminate || value > this.min ) + .width( percentage.toFixed( 0 ) + "%" ); + + this + ._toggleClass( this.valueDiv, "ui-progressbar-complete", null, + value === this.options.max ) + ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate ); + + if ( this.indeterminate ) { + this.element.removeAttr( "aria-valuenow" ); + if ( !this.overlayDiv ) { + this.overlayDiv = $( "
      " ).appendTo( this.valueDiv ); + this._addClass( this.overlayDiv, "ui-progressbar-overlay" ); + } + } else { + this.element.attr( { + "aria-valuemax": this.options.max, + "aria-valuenow": value + } ); + if ( this.overlayDiv ) { + this.overlayDiv.remove(); + this.overlayDiv = null; + } + } + + if ( this.oldValue !== value ) { + this.oldValue = value; + this._trigger( "change" ); + } + if ( value === this.options.max ) { + this._trigger( "complete" ); + } + } +} ); + + +/*! + * jQuery UI Selectable 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Selectable +//>>group: Interactions +//>>description: Allows groups of elements to be selected with the mouse. +//>>docs: https://api.jqueryui.com/selectable/ +//>>demos: https://jqueryui.com/selectable/ +//>>css.structure: ../../themes/base/selectable.css + + +var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, { + version: "1.14.1", + options: { + appendTo: "body", + autoRefresh: true, + distance: 0, + filter: "*", + tolerance: "touch", + + // Callbacks + selected: null, + selecting: null, + start: null, + stop: null, + unselected: null, + unselecting: null + }, + _create: function() { + var that = this; + + this._addClass( "ui-selectable" ); + + this.dragged = false; + + // Cache selectee children based on filter + this.refresh = function() { + that.elementPos = $( that.element[ 0 ] ).offset(); + that.selectees = $( that.options.filter, that.element[ 0 ] ); + that._addClass( that.selectees, "ui-selectee" ); + that.selectees.each( function() { + var $this = $( this ), + selecteeOffset = $this.offset(), + pos = { + left: selecteeOffset.left - that.elementPos.left, + top: selecteeOffset.top - that.elementPos.top + }; + $.data( this, "selectable-item", { + element: this, + $element: $this, + left: pos.left, + top: pos.top, + right: pos.left + $this.outerWidth(), + bottom: pos.top + $this.outerHeight(), + startselected: false, + selected: $this.hasClass( "ui-selected" ), + selecting: $this.hasClass( "ui-selecting" ), + unselecting: $this.hasClass( "ui-unselecting" ) + } ); + } ); + }; + this.refresh(); + + this._mouseInit(); + + this.helper = $( "
      " ); + this._addClass( this.helper, "ui-selectable-helper" ); + }, + + _destroy: function() { + this.selectees.removeData( "selectable-item" ); + this._mouseDestroy(); + }, + + _mouseStart: function( event ) { + var that = this, + options = this.options; + + this.opos = [ event.pageX, event.pageY ]; + this.elementPos = $( this.element[ 0 ] ).offset(); + + if ( this.options.disabled ) { + return; + } + + this.selectees = $( options.filter, this.element[ 0 ] ); + + this._trigger( "start", event ); + + $( options.appendTo ).append( this.helper ); + + // position helper (lasso) + this.helper.css( { + "left": event.pageX, + "top": event.pageY, + "width": 0, + "height": 0 + } ); + + if ( options.autoRefresh ) { + this.refresh(); + } + + this.selectees.filter( ".ui-selected" ).each( function() { + var selectee = $.data( this, "selectable-item" ); + selectee.startselected = true; + if ( !event.metaKey && !event.ctrlKey ) { + that._removeClass( selectee.$element, "ui-selected" ); + selectee.selected = false; + that._addClass( selectee.$element, "ui-unselecting" ); + selectee.unselecting = true; + + // selectable UNSELECTING callback + that._trigger( "unselecting", event, { + unselecting: selectee.element + } ); + } + } ); + + $( event.target ).parents().addBack().each( function() { + var doSelect, + selectee = $.data( this, "selectable-item" ); + if ( selectee ) { + doSelect = ( !event.metaKey && !event.ctrlKey ) || + !selectee.$element.hasClass( "ui-selected" ); + that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" ) + ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" ); + selectee.unselecting = !doSelect; + selectee.selecting = doSelect; + selectee.selected = doSelect; + + // selectable (UN)SELECTING callback + if ( doSelect ) { + that._trigger( "selecting", event, { + selecting: selectee.element + } ); + } else { + that._trigger( "unselecting", event, { + unselecting: selectee.element + } ); + } + return false; + } + } ); + + }, + + _mouseDrag: function( event ) { + + this.dragged = true; + + if ( this.options.disabled ) { + return; + } + + var tmp, + that = this, + options = this.options, + x1 = this.opos[ 0 ], + y1 = this.opos[ 1 ], + x2 = event.pageX, + y2 = event.pageY; + + if ( x1 > x2 ) { + tmp = x2; x2 = x1; x1 = tmp; + } + if ( y1 > y2 ) { + tmp = y2; y2 = y1; y1 = tmp; + } + this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } ); + + this.selectees.each( function() { + var selectee = $.data( this, "selectable-item" ), + hit = false, + offset = {}; + + //prevent helper from being selected if appendTo: selectable + if ( !selectee || selectee.element === that.element[ 0 ] ) { + return; + } + + offset.left = selectee.left + that.elementPos.left; + offset.right = selectee.right + that.elementPos.left; + offset.top = selectee.top + that.elementPos.top; + offset.bottom = selectee.bottom + that.elementPos.top; + + if ( options.tolerance === "touch" ) { + hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 || + offset.bottom < y1 ) ); + } else if ( options.tolerance === "fit" ) { + hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 && + offset.bottom < y2 ); + } + + if ( hit ) { + + // SELECT + if ( selectee.selected ) { + that._removeClass( selectee.$element, "ui-selected" ); + selectee.selected = false; + } + if ( selectee.unselecting ) { + that._removeClass( selectee.$element, "ui-unselecting" ); + selectee.unselecting = false; + } + if ( !selectee.selecting ) { + that._addClass( selectee.$element, "ui-selecting" ); + selectee.selecting = true; + + // selectable SELECTING callback + that._trigger( "selecting", event, { + selecting: selectee.element + } ); + } + } else { + + // UNSELECT + if ( selectee.selecting ) { + if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) { + that._removeClass( selectee.$element, "ui-selecting" ); + selectee.selecting = false; + that._addClass( selectee.$element, "ui-selected" ); + selectee.selected = true; + } else { + that._removeClass( selectee.$element, "ui-selecting" ); + selectee.selecting = false; + if ( selectee.startselected ) { + that._addClass( selectee.$element, "ui-unselecting" ); + selectee.unselecting = true; + } + + // selectable UNSELECTING callback + that._trigger( "unselecting", event, { + unselecting: selectee.element + } ); + } + } + if ( selectee.selected ) { + if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) { + that._removeClass( selectee.$element, "ui-selected" ); + selectee.selected = false; + + that._addClass( selectee.$element, "ui-unselecting" ); + selectee.unselecting = true; + + // selectable UNSELECTING callback + that._trigger( "unselecting", event, { + unselecting: selectee.element + } ); + } + } + } + } ); + + return false; + }, + + _mouseStop: function( event ) { + var that = this; + + this.dragged = false; + + $( ".ui-unselecting", this.element[ 0 ] ).each( function() { + var selectee = $.data( this, "selectable-item" ); + that._removeClass( selectee.$element, "ui-unselecting" ); + selectee.unselecting = false; + selectee.startselected = false; + that._trigger( "unselected", event, { + unselected: selectee.element + } ); + } ); + $( ".ui-selecting", this.element[ 0 ] ).each( function() { + var selectee = $.data( this, "selectable-item" ); + that._removeClass( selectee.$element, "ui-selecting" ) + ._addClass( selectee.$element, "ui-selected" ); + selectee.selecting = false; + selectee.selected = true; + selectee.startselected = true; + that._trigger( "selected", event, { + selected: selectee.element + } ); + } ); + this._trigger( "stop", event ); + + this.helper.remove(); + + return false; + } + +} ); + + +/*! + * jQuery UI Selectmenu 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Selectmenu +//>>group: Widgets +/* eslint-disable max-len */ +//>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select. +/* eslint-enable max-len */ +//>>docs: https://api.jqueryui.com/selectmenu/ +//>>demos: https://jqueryui.com/selectmenu/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css +//>>css.theme: ../../themes/base/theme.css + + +var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, { + version: "1.14.1", + defaultElement: "", + widgetEventPrefix: "spin", + options: { + classes: { + "ui-spinner": "ui-corner-all", + "ui-spinner-down": "ui-corner-br", + "ui-spinner-up": "ui-corner-tr" + }, + culture: null, + icons: { + down: "ui-icon-triangle-1-s", + up: "ui-icon-triangle-1-n" + }, + incremental: true, + max: null, + min: null, + numberFormat: null, + page: 10, + step: 1, + + change: null, + spin: null, + start: null, + stop: null + }, + + _create: function() { + + // handle string values that need to be parsed + this._setOption( "max", this.options.max ); + this._setOption( "min", this.options.min ); + this._setOption( "step", this.options.step ); + + // Only format if there is a value, prevents the field from being marked + // as invalid in Firefox, see #9573. + if ( this.value() !== "" ) { + + // Format the value, but don't constrain. + this._value( this.element.val(), true ); + } + + this._draw(); + this._on( this._events ); + this._refresh(); + + // Turning off autocomplete prevents the browser from remembering the + // value when navigating through history, so we re-enable autocomplete + // if the page is unloaded before the widget is destroyed. #7790 + this._on( this.window, { + beforeunload: function() { + this.element.removeAttr( "autocomplete" ); + } + } ); + }, + + _getCreateOptions: function() { + var options = this._super(); + var element = this.element; + + $.each( [ "min", "max", "step" ], function( i, option ) { + var value = element.attr( option ); + if ( value != null && value.length ) { + options[ option ] = value; + } + } ); + + return options; + }, + + _events: { + keydown: function( event ) { + if ( this._start( event ) && this._keydown( event ) ) { + event.preventDefault(); + } + }, + keyup: "_stop", + focus: function() { + this.previous = this.element.val(); + }, + blur: function( event ) { + this._stop(); + this._refresh(); + if ( this.previous !== this.element.val() ) { + this._trigger( "change", event ); + } + }, + mousewheel: function( event, delta ) { + var activeElement = this.document[ 0 ].activeElement; + var isActive = this.element[ 0 ] === activeElement; + + if ( !isActive || !delta ) { + return; + } + + if ( !this.spinning && !this._start( event ) ) { + return false; + } + + this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event ); + clearTimeout( this.mousewheelTimer ); + this.mousewheelTimer = this._delay( function() { + if ( this.spinning ) { + this._stop( event ); + } + }, 100 ); + event.preventDefault(); + }, + "mousedown .ui-spinner-button": function( event ) { + var previous; + + // We never want the buttons to have focus; whenever the user is + // interacting with the spinner, the focus should be on the input. + // If the input is focused then this.previous is properly set from + // when the input first received focus. If the input is not focused + // then we need to set this.previous based on the value before spinning. + previous = this.element[ 0 ] === this.document[ 0 ].activeElement ? + this.previous : this.element.val(); + function checkFocus() { + var isActive = this.element[ 0 ] === this.document[ 0 ].activeElement; + if ( !isActive ) { + this.element.trigger( "focus" ); + this.previous = previous; + } + } + + // Ensure focus is on (or stays on) the text field + event.preventDefault(); + checkFocus.call( this ); + + if ( this._start( event ) === false ) { + return; + } + + this._repeat( null, $( event.currentTarget ) + .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + "mouseup .ui-spinner-button": "_stop", + "mouseenter .ui-spinner-button": function( event ) { + + // button will add ui-state-active if mouse was down while mouseleave and kept down + if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) { + return; + } + + if ( this._start( event ) === false ) { + return false; + } + this._repeat( null, $( event.currentTarget ) + .hasClass( "ui-spinner-up" ) ? 1 : -1, event ); + }, + + // TODO: do we really want to consider this a stop? + // shouldn't we just stop the repeater and wait until mouseup before + // we trigger the stop event? + "mouseleave .ui-spinner-button": "_stop" + }, + + // Support mobile enhanced option and make backcompat more sane + _enhance: function() { + this.uiSpinner = this.element + .attr( "autocomplete", "off" ) + .wrap( "" ) + .parent() + + // Add buttons + .append( + "" + ); + }, + + _draw: function() { + this._enhance(); + + this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" ); + this._addClass( "ui-spinner-input" ); + + this.element.attr( "role", "spinbutton" ); + + // Button bindings + this.buttons = this.uiSpinner.children( "a" ) + .attr( "tabIndex", -1 ) + .attr( "aria-hidden", true ) + .button( { + classes: { + "ui-button": "" + } + } ); + + // TODO: Right now button does not support classes this is already updated in button PR + this._removeClass( this.buttons, "ui-corner-all" ); + + this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" ); + this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" ); + this.buttons.first().button( { + "icon": this.options.icons.up, + "showLabel": false + } ); + this.buttons.last().button( { + "icon": this.options.icons.down, + "showLabel": false + } ); + + // IE 6 doesn't understand height: 50% for the buttons + // unless the wrapper has an explicit height + if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) && + this.uiSpinner.height() > 0 ) { + this.uiSpinner.height( this.uiSpinner.height() ); + } + }, + + _keydown: function( event ) { + var options = this.options, + keyCode = $.ui.keyCode; + + switch ( event.keyCode ) { + case keyCode.UP: + this._repeat( null, 1, event ); + return true; + case keyCode.DOWN: + this._repeat( null, -1, event ); + return true; + case keyCode.PAGE_UP: + this._repeat( null, options.page, event ); + return true; + case keyCode.PAGE_DOWN: + this._repeat( null, -options.page, event ); + return true; + } + + return false; + }, + + _start: function( event ) { + if ( !this.spinning && this._trigger( "start", event ) === false ) { + return false; + } + + if ( !this.counter ) { + this.counter = 1; + } + this.spinning = true; + return true; + }, + + _repeat: function( i, steps, event ) { + i = i || 500; + + clearTimeout( this.timer ); + this.timer = this._delay( function() { + this._repeat( 40, steps, event ); + }, i ); + + this._spin( steps * this.options.step, event ); + }, + + _spin: function( step, event ) { + var value = this.value() || 0; + + if ( !this.counter ) { + this.counter = 1; + } + + value = this._adjustValue( value + step * this._increment( this.counter ) ); + + if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) { + this._value( value ); + this.counter++; + } + }, + + _increment: function( i ) { + var incremental = this.options.incremental; + + if ( incremental ) { + return typeof incremental === "function" ? + incremental( i ) : + Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 ); + } + + return 1; + }, + + _precision: function() { + var precision = this._precisionOf( this.options.step ); + if ( this.options.min !== null ) { + precision = Math.max( precision, this._precisionOf( this.options.min ) ); + } + return precision; + }, + + _precisionOf: function( num ) { + var str = num.toString(), + decimal = str.indexOf( "." ); + return decimal === -1 ? 0 : str.length - decimal - 1; + }, + + _adjustValue: function( value ) { + var base, aboveMin, + options = this.options; + + // Make sure we're at a valid step + // - find out where we are relative to the base (min or 0) + base = options.min !== null ? options.min : 0; + aboveMin = value - base; + + // - round to the nearest step + aboveMin = Math.round( aboveMin / options.step ) * options.step; + + // - rounding is based on 0, so adjust back to our base + value = base + aboveMin; + + // Fix precision from bad JS floating point math + value = parseFloat( value.toFixed( this._precision() ) ); + + // Clamp the value + if ( options.max !== null && value > options.max ) { + return options.max; + } + if ( options.min !== null && value < options.min ) { + return options.min; + } + + return value; + }, + + _stop: function( event ) { + if ( !this.spinning ) { + return; + } + + clearTimeout( this.timer ); + clearTimeout( this.mousewheelTimer ); + this.counter = 0; + this.spinning = false; + this._trigger( "stop", event ); + }, + + _setOption: function( key, value ) { + var prevValue, first, last; + + if ( key === "culture" || key === "numberFormat" ) { + prevValue = this._parse( this.element.val() ); + this.options[ key ] = value; + this.element.val( this._format( prevValue ) ); + return; + } + + if ( key === "max" || key === "min" || key === "step" ) { + if ( typeof value === "string" ) { + value = this._parse( value ); + } + } + if ( key === "icons" ) { + first = this.buttons.first().find( ".ui-icon" ); + this._removeClass( first, null, this.options.icons.up ); + this._addClass( first, null, value.up ); + last = this.buttons.last().find( ".ui-icon" ); + this._removeClass( last, null, this.options.icons.down ); + this._addClass( last, null, value.down ); + } + + this._super( key, value ); + }, + + _setOptionDisabled: function( value ) { + this._super( value ); + + this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value ); + this.element.prop( "disabled", !!value ); + this.buttons.button( value ? "disable" : "enable" ); + }, + + _setOptions: spinnerModifier( function( options ) { + this._super( options ); + } ), + + _parse: function( val ) { + if ( typeof val === "string" && val !== "" ) { + val = window.Globalize && this.options.numberFormat ? + Globalize.parseFloat( val, 10, this.options.culture ) : +val; + } + return val === "" || isNaN( val ) ? null : val; + }, + + _format: function( value ) { + if ( value === "" ) { + return ""; + } + return window.Globalize && this.options.numberFormat ? + Globalize.format( value, this.options.numberFormat, this.options.culture ) : + value; + }, + + _refresh: function() { + this.element.attr( { + "aria-valuemin": this.options.min, + "aria-valuemax": this.options.max, + + // TODO: what should we do with values that can't be parsed? + "aria-valuenow": this._parse( this.element.val() ) + } ); + }, + + isValid: function() { + var value = this.value(); + + // Null is invalid + if ( value === null ) { + return false; + } + + // If value gets adjusted, it's invalid + return value === this._adjustValue( value ); + }, + + // Update the value without triggering change + _value: function( value, allowAny ) { + var parsed; + if ( value !== "" ) { + parsed = this._parse( value ); + if ( parsed !== null ) { + if ( !allowAny ) { + parsed = this._adjustValue( parsed ); + } + value = this._format( parsed ); + } + } + this.element.val( value ); + this._refresh(); + }, + + _destroy: function() { + this.element + .prop( "disabled", false ) + .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" ); + + this.uiSpinner.replaceWith( this.element ); + }, + + stepUp: spinnerModifier( function( steps ) { + this._stepUp( steps ); + } ), + _stepUp: function( steps ) { + if ( this._start() ) { + this._spin( ( steps || 1 ) * this.options.step ); + this._stop(); + } + }, + + stepDown: spinnerModifier( function( steps ) { + this._stepDown( steps ); + } ), + _stepDown: function( steps ) { + if ( this._start() ) { + this._spin( ( steps || 1 ) * -this.options.step ); + this._stop(); + } + }, + + pageUp: spinnerModifier( function( pages ) { + this._stepUp( ( pages || 1 ) * this.options.page ); + } ), + + pageDown: spinnerModifier( function( pages ) { + this._stepDown( ( pages || 1 ) * this.options.page ); + } ), + + value: function( newVal ) { + if ( !arguments.length ) { + return this._parse( this.element.val() ); + } + spinnerModifier( this._value ).call( this, newVal ); + }, + + widget: function() { + return this.uiSpinner; + } +} ); + +// DEPRECATED +// TODO: switch return back to widget declaration at top of file when this is removed +if ( $.uiBackCompat === true ) { + + // Backcompat for spinner html extension points + $.widget( "ui.spinner", $.ui.spinner, { + _enhance: function() { + this.uiSpinner = this.element + .attr( "autocomplete", "off" ) + .wrap( this._uiSpinnerHtml() ) + .parent() + + // Add buttons + .append( this._buttonHtml() ); + }, + _uiSpinnerHtml: function() { + return ""; + }, + + _buttonHtml: function() { + return ""; + } + } ); +} + +var widgetsSpinner = $.ui.spinner; + + +/*! + * jQuery UI Tabs 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Tabs +//>>group: Widgets +//>>description: Transforms a set of container elements into a tab structure. +//>>docs: https://api.jqueryui.com/tabs/ +//>>demos: https://jqueryui.com/tabs/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/tabs.css +//>>css.theme: ../../themes/base/theme.css + + +$.widget( "ui.tabs", { + version: "1.14.1", + delay: 300, + options: { + active: null, + classes: { + "ui-tabs": "ui-corner-all", + "ui-tabs-nav": "ui-corner-all", + "ui-tabs-panel": "ui-corner-bottom", + "ui-tabs-tab": "ui-corner-top" + }, + collapsible: false, + event: "click", + heightStyle: "content", + hide: null, + show: null, + + // Callbacks + activate: null, + beforeActivate: null, + beforeLoad: null, + load: null + }, + + _isLocal: ( function() { + var rhash = /#.*$/; + + return function( anchor ) { + var anchorUrl, locationUrl; + + anchorUrl = anchor.href.replace( rhash, "" ); + locationUrl = location.href.replace( rhash, "" ); + + // Decoding may throw an error if the URL isn't UTF-8 (#9518) + try { + anchorUrl = decodeURIComponent( anchorUrl ); + } catch ( error ) {} + try { + locationUrl = decodeURIComponent( locationUrl ); + } catch ( error ) {} + + return anchor.hash.length > 1 && anchorUrl === locationUrl; + }; + } )(), + + _create: function() { + var that = this, + options = this.options; + + this.running = false; + + this._addClass( "ui-tabs", "ui-widget ui-widget-content" ); + this._toggleClass( "ui-tabs-collapsible", null, options.collapsible ); + + this._processTabs(); + options.active = this._initialActive(); + + // Take disabling tabs via class attribute from HTML + // into account and update option properly. + if ( Array.isArray( options.disabled ) ) { + options.disabled = $.uniqueSort( options.disabled.concat( + $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) { + return that.tabs.index( li ); + } ) + ) ).sort(); + } + + // Check for length avoids error when initializing empty list + if ( this.options.active !== false && this.anchors.length ) { + this.active = this._findActive( options.active ); + } else { + this.active = $(); + } + + this._refresh(); + + if ( this.active.length ) { + this.load( options.active ); + } + }, + + _initialActive: function() { + var active = this.options.active, + collapsible = this.options.collapsible, + locationHashDecoded = decodeURIComponent( location.hash.substring( 1 ) ); + + if ( active === null ) { + + // check the fragment identifier in the URL + if ( locationHashDecoded ) { + this.tabs.each( function( i, tab ) { + if ( $( tab ).attr( "aria-controls" ) === locationHashDecoded ) { + active = i; + return false; + } + } ); + } + + // Check for a tab marked active via a class + if ( active === null ) { + active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) ); + } + + // No active tab, set to false + if ( active === null || active === -1 ) { + active = this.tabs.length ? 0 : false; + } + } + + // Handle numbers: negative, out of range + if ( active !== false ) { + active = this.tabs.index( this.tabs.eq( active ) ); + if ( active === -1 ) { + active = collapsible ? false : 0; + } + } + + // Don't allow collapsible: false and active: false + if ( !collapsible && active === false && this.anchors.length ) { + active = 0; + } + + return active; + }, + + _getCreateEventData: function() { + return { + tab: this.active, + panel: !this.active.length ? $() : this._getPanelForTab( this.active ) + }; + }, + + _tabKeydown: function( event ) { + var focusedTab = $( this.document[ 0 ].activeElement ).closest( "li" ), + selectedIndex = this.tabs.index( focusedTab ), + goingForward = true; + + if ( this._handlePageNav( event ) ) { + return; + } + + switch ( event.keyCode ) { + case $.ui.keyCode.RIGHT: + case $.ui.keyCode.DOWN: + selectedIndex++; + break; + case $.ui.keyCode.UP: + case $.ui.keyCode.LEFT: + goingForward = false; + selectedIndex--; + break; + case $.ui.keyCode.END: + selectedIndex = this.anchors.length - 1; + break; + case $.ui.keyCode.HOME: + selectedIndex = 0; + break; + case $.ui.keyCode.SPACE: + + // Activate only, no collapsing + event.preventDefault(); + clearTimeout( this.activating ); + this._activate( selectedIndex ); + return; + case $.ui.keyCode.ENTER: + + // Toggle (cancel delayed activation, allow collapsing) + event.preventDefault(); + clearTimeout( this.activating ); + + // Determine if we should collapse or activate + this._activate( selectedIndex === this.options.active ? false : selectedIndex ); + return; + default: + return; + } + + // Focus the appropriate tab, based on which key was pressed + event.preventDefault(); + clearTimeout( this.activating ); + selectedIndex = this._focusNextTab( selectedIndex, goingForward ); + + // Navigating with control/command key will prevent automatic activation + if ( !event.ctrlKey && !event.metaKey ) { + + // Update aria-selected immediately so that AT think the tab is already selected. + // Otherwise AT may confuse the user by stating that they need to activate the tab, + // but the tab will already be activated by the time the announcement finishes. + focusedTab.attr( "aria-selected", "false" ); + this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" ); + + this.activating = this._delay( function() { + this.option( "active", selectedIndex ); + }, this.delay ); + } + }, + + _panelKeydown: function( event ) { + if ( this._handlePageNav( event ) ) { + return; + } + + // Ctrl+up moves focus to the current tab + if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) { + event.preventDefault(); + this.active.trigger( "focus" ); + } + }, + + // Alt+page up/down moves focus to the previous/next tab (and activates) + _handlePageNav: function( event ) { + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) { + this._activate( this._focusNextTab( this.options.active - 1, false ) ); + return true; + } + if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) { + this._activate( this._focusNextTab( this.options.active + 1, true ) ); + return true; + } + }, + + _findNextTab: function( index, goingForward ) { + var lastTabIndex = this.tabs.length - 1; + + function constrain() { + if ( index > lastTabIndex ) { + index = 0; + } + if ( index < 0 ) { + index = lastTabIndex; + } + return index; + } + + while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) { + index = goingForward ? index + 1 : index - 1; + } + + return index; + }, + + _focusNextTab: function( index, goingForward ) { + index = this._findNextTab( index, goingForward ); + this.tabs.eq( index ).trigger( "focus" ); + return index; + }, + + _setOption: function( key, value ) { + if ( key === "active" ) { + + // _activate() will handle invalid values and update this.options + this._activate( value ); + return; + } + + this._super( key, value ); + + if ( key === "collapsible" ) { + this._toggleClass( "ui-tabs-collapsible", null, value ); + + // Setting collapsible: false while collapsed; open first panel + if ( !value && this.options.active === false ) { + this._activate( 0 ); + } + } + + if ( key === "event" ) { + this._setupEvents( value ); + } + + if ( key === "heightStyle" ) { + this._setupHeightStyle( value ); + } + }, + + refresh: function() { + var options = this.options, + lis = this.tablist.children( ":has(a[href])" ); + + // Get disabled tabs from class attribute from HTML + // this will get converted to a boolean if needed in _refresh() + options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) { + return lis.index( tab ); + } ); + + this._processTabs(); + + // Was collapsed or no tabs + if ( options.active === false || !this.anchors.length ) { + options.active = false; + this.active = $(); + + // was active, but active tab is gone + } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) { + + // all remaining tabs are disabled + if ( this.tabs.length === options.disabled.length ) { + options.active = false; + this.active = $(); + + // activate previous tab + } else { + this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) ); + } + + // was active, active tab still exists + } else { + + // make sure active index is correct + options.active = this.tabs.index( this.active ); + } + + this._refresh(); + }, + + _refresh: function() { + this._setOptionDisabled( this.options.disabled ); + this._setupEvents( this.options.event ); + this._setupHeightStyle( this.options.heightStyle ); + + this.tabs.not( this.active ).attr( { + "aria-selected": "false", + "aria-expanded": "false", + tabIndex: -1 + } ); + this.panels.not( this._getPanelForTab( this.active ) ) + .hide() + .attr( { + "aria-hidden": "true" + } ); + + // Make sure one tab is in the tab order + if ( !this.active.length ) { + this.tabs.eq( 0 ).attr( "tabIndex", 0 ); + } else { + this.active + .attr( { + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + } ); + this._addClass( this.active, "ui-tabs-active", "ui-state-active" ); + this._getPanelForTab( this.active ) + .show() + .attr( { + "aria-hidden": "false" + } ); + } + }, + + _processTabs: function() { + var that = this, + prevTabs = this.tabs, + prevAnchors = this.anchors, + prevPanels = this.panels; + + this.tablist = this._getList().attr( "role", "tablist" ); + this._addClass( this.tablist, "ui-tabs-nav", + "ui-helper-reset ui-helper-clearfix ui-widget-header" ); + + // Prevent users from focusing disabled tabs via click + this.tablist + .on( "mousedown" + this.eventNamespace, "> li", function( event ) { + if ( $( this ).is( ".ui-state-disabled" ) ) { + event.preventDefault(); + } + } ); + + this.tabs = this.tablist.find( "> li:has(a[href])" ) + .attr( { + role: "tab", + tabIndex: -1 + } ); + this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" ); + + this.anchors = this.tabs.map( function() { + return $( "a", this )[ 0 ]; + } ) + .attr( { + tabIndex: -1 + } ); + this._addClass( this.anchors, "ui-tabs-anchor" ); + + this.panels = $(); + + this.anchors.each( function( i, anchor ) { + var selector, panel, panelId, + anchorId = $( anchor ).uniqueId().attr( "id" ), + tab = $( anchor ).closest( "li" ), + originalAriaControls = tab.attr( "aria-controls" ); + + // Inline tab + if ( that._isLocal( anchor ) ) { + selector = decodeURIComponent( anchor.hash ); + panelId = selector.substring( 1 ); + panel = that.element.find( "#" + CSS.escape( panelId ) ); + + // remote tab + } else { + + // If the tab doesn't already have aria-controls, + // generate an id by using a throw-away element + panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id; + selector = "#" + panelId; + panel = that.element.find( selector ); + if ( !panel.length ) { + panel = that._createPanel( panelId ); + panel.insertAfter( that.panels[ i - 1 ] || that.tablist ); + } + panel.attr( "aria-live", "polite" ); + } + + if ( panel.length ) { + that.panels = that.panels.add( panel ); + } + if ( originalAriaControls ) { + tab.data( "ui-tabs-aria-controls", originalAriaControls ); + } + tab.attr( { + "aria-controls": panelId, + "aria-labelledby": anchorId + } ); + panel.attr( "aria-labelledby", anchorId ); + } ); + + this.panels.attr( "role", "tabpanel" ); + this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" ); + + // Avoid memory leaks (#10056) + if ( prevTabs ) { + this._off( prevTabs.not( this.tabs ) ); + this._off( prevAnchors.not( this.anchors ) ); + this._off( prevPanels.not( this.panels ) ); + } + }, + + // Allow overriding how to find the list for rare usage scenarios (#7715) + _getList: function() { + return this.tablist || this.element.find( "ol, ul" ).eq( 0 ); + }, + + _createPanel: function( id ) { + return $( "
      " ) + .attr( "id", id ) + .data( "ui-tabs-destroy", true ); + }, + + _setOptionDisabled: function( disabled ) { + var currentItem, li, i; + + if ( Array.isArray( disabled ) ) { + if ( !disabled.length ) { + disabled = false; + } else if ( disabled.length === this.anchors.length ) { + disabled = true; + } + } + + // Disable tabs + for ( i = 0; ( li = this.tabs[ i ] ); i++ ) { + currentItem = $( li ); + if ( disabled === true || $.inArray( i, disabled ) !== -1 ) { + currentItem.attr( "aria-disabled", "true" ); + this._addClass( currentItem, null, "ui-state-disabled" ); + } else { + currentItem.removeAttr( "aria-disabled" ); + this._removeClass( currentItem, null, "ui-state-disabled" ); + } + } + + this.options.disabled = disabled; + + this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, + disabled === true ); + }, + + _setupEvents: function( event ) { + var events = {}; + if ( event ) { + $.each( event.split( " " ), function( index, eventName ) { + events[ eventName ] = "_eventHandler"; + } ); + } + + this._off( this.anchors.add( this.tabs ).add( this.panels ) ); + + // Always prevent the default action, even when disabled + this._on( true, this.anchors, { + click: function( event ) { + event.preventDefault(); + } + } ); + this._on( this.anchors, events ); + this._on( this.tabs, { keydown: "_tabKeydown" } ); + this._on( this.panels, { keydown: "_panelKeydown" } ); + + this._focusable( this.tabs ); + this._hoverable( this.tabs ); + }, + + _setupHeightStyle: function( heightStyle ) { + var maxHeight, + parent = this.element.parent(); + + if ( heightStyle === "fill" ) { + maxHeight = parent.height(); + maxHeight -= this.element.outerHeight() - this.element.height(); + + this.element.siblings( ":visible" ).each( function() { + var elem = $( this ), + position = elem.css( "position" ); + + if ( position === "absolute" || position === "fixed" ) { + return; + } + maxHeight -= elem.outerHeight( true ); + } ); + + this.element.children().not( this.panels ).each( function() { + maxHeight -= $( this ).outerHeight( true ); + } ); + + this.panels.each( function() { + $( this ).height( Math.max( 0, maxHeight - + $( this ).innerHeight() + $( this ).height() ) ); + } ) + .css( "overflow", "auto" ); + } else if ( heightStyle === "auto" ) { + maxHeight = 0; + this.panels.each( function() { + maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() ); + } ).height( maxHeight ); + } + }, + + _eventHandler: function( event ) { + var options = this.options, + active = this.active, + anchor = $( event.currentTarget ), + tab = anchor.closest( "li" ), + clickedIsActive = tab[ 0 ] === active[ 0 ], + collapsing = clickedIsActive && options.collapsible, + toShow = collapsing ? $() : this._getPanelForTab( tab ), + toHide = !active.length ? $() : this._getPanelForTab( active ), + eventData = { + oldTab: active, + oldPanel: toHide, + newTab: collapsing ? $() : tab, + newPanel: toShow + }; + + event.preventDefault(); + + if ( tab.hasClass( "ui-state-disabled" ) || + + // tab is already loading + tab.hasClass( "ui-tabs-loading" ) || + + // can't switch durning an animation + this.running || + + // click on active header, but not collapsible + ( clickedIsActive && !options.collapsible ) || + + // allow canceling activation + ( this._trigger( "beforeActivate", event, eventData ) === false ) ) { + return; + } + + options.active = collapsing ? false : this.tabs.index( tab ); + + this.active = clickedIsActive ? $() : tab; + if ( this.xhr ) { + this.xhr.abort(); + } + + if ( !toHide.length && !toShow.length ) { + $.error( "jQuery UI Tabs: Mismatching fragment identifier." ); + } + + if ( toShow.length ) { + this.load( this.tabs.index( tab ), event ); + } + this._toggle( event, eventData ); + }, + + // Handles show/hide for selecting tabs + _toggle: function( event, eventData ) { + var that = this, + toShow = eventData.newPanel, + toHide = eventData.oldPanel; + + this.running = true; + + function complete() { + that.running = false; + that._trigger( "activate", event, eventData ); + } + + function show() { + that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" ); + + if ( toShow.length && that.options.show ) { + that._show( toShow, that.options.show, complete ); + } else { + toShow.show(); + complete(); + } + } + + // Start out by hiding, then showing, then completing + if ( toHide.length && this.options.hide ) { + this._hide( toHide, this.options.hide, function() { + that._removeClass( eventData.oldTab.closest( "li" ), + "ui-tabs-active", "ui-state-active" ); + show(); + } ); + } else { + this._removeClass( eventData.oldTab.closest( "li" ), + "ui-tabs-active", "ui-state-active" ); + toHide.hide(); + show(); + } + + toHide.attr( "aria-hidden", "true" ); + eventData.oldTab.attr( { + "aria-selected": "false", + "aria-expanded": "false" + } ); + + // If we're switching tabs, remove the old tab from the tab order. + // If we're opening from collapsed state, remove the previous tab from the tab order. + // If we're collapsing, then keep the collapsing tab in the tab order. + if ( toShow.length && toHide.length ) { + eventData.oldTab.attr( "tabIndex", -1 ); + } else if ( toShow.length ) { + this.tabs.filter( function() { + return $( this ).attr( "tabIndex" ) === 0; + } ) + .attr( "tabIndex", -1 ); + } + + toShow.attr( "aria-hidden", "false" ); + eventData.newTab.attr( { + "aria-selected": "true", + "aria-expanded": "true", + tabIndex: 0 + } ); + }, + + _activate: function( index ) { + var anchor, + active = this._findActive( index ); + + // Trying to activate the already active panel + if ( active[ 0 ] === this.active[ 0 ] ) { + return; + } + + // Trying to collapse, simulate a click on the current active header + if ( !active.length ) { + active = this.active; + } + + anchor = active.find( ".ui-tabs-anchor" )[ 0 ]; + this._eventHandler( { + target: anchor, + currentTarget: anchor, + preventDefault: $.noop + } ); + }, + + _findActive: function( index ) { + return index === false ? $() : this.tabs.eq( index ); + }, + + _getIndex: function( index ) { + + // meta-function to give users option to provide a href string instead of a numerical index. + if ( typeof index === "string" ) { + index = this.anchors.index( this.anchors.filter( "[href$='" + + CSS.escape( index ) + "']" ) ); + } + + return index; + }, + + _destroy: function() { + if ( this.xhr ) { + this.xhr.abort(); + } + + this.tablist + .removeAttr( "role" ) + .off( this.eventNamespace ); + + this.anchors + .removeAttr( "role tabIndex" ) + .removeUniqueId(); + + this.tabs.add( this.panels ).each( function() { + if ( $.data( this, "ui-tabs-destroy" ) ) { + $( this ).remove(); + } else { + $( this ).removeAttr( "role tabIndex " + + "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" ); + } + } ); + + this.tabs.each( function() { + var li = $( this ), + prev = li.data( "ui-tabs-aria-controls" ); + if ( prev ) { + li + .attr( "aria-controls", prev ) + .removeData( "ui-tabs-aria-controls" ); + } else { + li.removeAttr( "aria-controls" ); + } + } ); + + this.panels.show(); + + if ( this.options.heightStyle !== "content" ) { + this.panels.css( "height", "" ); + } + }, + + enable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === false ) { + return; + } + + if ( index === undefined ) { + disabled = false; + } else { + index = this._getIndex( index ); + if ( Array.isArray( disabled ) ) { + disabled = $.map( disabled, function( num ) { + return num !== index ? num : null; + } ); + } else { + disabled = $.map( this.tabs, function( li, num ) { + return num !== index ? num : null; + } ); + } + } + this._setOptionDisabled( disabled ); + }, + + disable: function( index ) { + var disabled = this.options.disabled; + if ( disabled === true ) { + return; + } + + if ( index === undefined ) { + disabled = true; + } else { + index = this._getIndex( index ); + if ( $.inArray( index, disabled ) !== -1 ) { + return; + } + if ( Array.isArray( disabled ) ) { + disabled = $.merge( [ index ], disabled ).sort(); + } else { + disabled = [ index ]; + } + } + this._setOptionDisabled( disabled ); + }, + + load: function( index, event ) { + index = this._getIndex( index ); + var that = this, + tab = this.tabs.eq( index ), + anchor = tab.find( ".ui-tabs-anchor" ), + panel = this._getPanelForTab( tab ), + eventData = { + tab: tab, + panel: panel + }, + complete = function( jqXHR, status ) { + if ( status === "abort" ) { + that.panels.stop( false, true ); + } + + that._removeClass( tab, "ui-tabs-loading" ); + panel.removeAttr( "aria-busy" ); + + if ( jqXHR === that.xhr ) { + delete that.xhr; + } + }; + + // Not remote + if ( this._isLocal( anchor[ 0 ] ) ) { + return; + } + + this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) ); + + if ( this.xhr.statusText !== "canceled" ) { + this._addClass( tab, "ui-tabs-loading" ); + panel.attr( "aria-busy", "true" ); + + this.xhr + .done( function( response, status, jqXHR ) { + panel.html( response ); + that._trigger( "load", event, eventData ); + + complete( jqXHR, status ); + } ) + .fail( function( jqXHR, status ) { + complete( jqXHR, status ); + } ); + } + }, + + _ajaxSettings: function( anchor, event, eventData ) { + var that = this; + return { + url: anchor.attr( "href" ), + beforeSend: function( jqXHR, settings ) { + return that._trigger( "beforeLoad", event, + $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) ); + } + }; + }, + + _getPanelForTab: function( tab ) { + var id = $( tab ).attr( "aria-controls" ); + return this.element.find( "#" + CSS.escape( id ) ); + } +} ); + +// DEPRECATED +// TODO: Switch return back to widget declaration at top of file when this is removed +if ( $.uiBackCompat === true ) { + + // Backcompat for ui-tab class (now ui-tabs-tab) + $.widget( "ui.tabs", $.ui.tabs, { + _processTabs: function() { + this._superApply( arguments ); + this._addClass( this.tabs, "ui-tab" ); + } + } ); +} + +var widgetsTabs = $.ui.tabs; + + +/*! + * jQuery UI Tooltip 1.14.1 + * https://jqueryui.com + * + * Copyright OpenJS Foundation and other contributors + * Released under the MIT license. + * https://jquery.org/license + */ + +//>>label: Tooltip +//>>group: Widgets +//>>description: Shows additional information for any element on hover or focus. +//>>docs: https://api.jqueryui.com/tooltip/ +//>>demos: https://jqueryui.com/tooltip/ +//>>css.structure: ../../themes/base/core.css +//>>css.structure: ../../themes/base/tooltip.css +//>>css.theme: ../../themes/base/theme.css + + +$.widget( "ui.tooltip", { + version: "1.14.1", + options: { + classes: { + "ui-tooltip": "ui-corner-all ui-widget-shadow" + }, + content: function() { + var title = $( this ).attr( "title" ); + + // Escape title, since we're going from an attribute to raw HTML + return $( "" ).text( title ).html(); + }, + hide: true, + + // Disabled elements have inconsistent behavior across browsers (#8661) + items: "[title]:not([disabled])", + position: { + my: "left top+15", + at: "left bottom", + collision: "flipfit flip" + }, + show: true, + track: false, + + // Callbacks + close: null, + open: null + }, + + _addDescribedBy: function( elem, id ) { + var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ); + describedby.push( id ); + elem + .data( "ui-tooltip-id", id ) + .attr( "aria-describedby", String.prototype.trim.call( describedby.join( " " ) ) ); + }, + + _removeDescribedBy: function( elem ) { + var id = elem.data( "ui-tooltip-id" ), + describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ), + index = $.inArray( id, describedby ); + + if ( index !== -1 ) { + describedby.splice( index, 1 ); + } + + elem.removeData( "ui-tooltip-id" ); + describedby = String.prototype.trim.call( describedby.join( " " ) ); + if ( describedby ) { + elem.attr( "aria-describedby", describedby ); + } else { + elem.removeAttr( "aria-describedby" ); + } + }, + + _create: function() { + this._on( { + mouseover: "open", + focusin: "open" + } ); + + // IDs of generated tooltips, needed for destroy + this.tooltips = {}; + + // IDs of parent tooltips where we removed the title attribute + this.parents = {}; + + // Append the aria-live region so tooltips announce correctly + this.liveRegion = $( "
      " ) + .attr( { + role: "log", + "aria-live": "assertive", + "aria-relevant": "additions" + } ) + .appendTo( this.document[ 0 ].body ); + this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" ); + + this.disabledTitles = $( [] ); + }, + + _setOption: function( key, value ) { + var that = this; + + this._super( key, value ); + + if ( key === "content" ) { + $.each( this.tooltips, function( id, tooltipData ) { + that._updateContent( tooltipData.element ); + } ); + } + }, + + _setOptionDisabled: function( value ) { + this[ value ? "_disable" : "_enable" ](); + }, + + _disable: function() { + var that = this; + + // Close open tooltips + $.each( this.tooltips, function( id, tooltipData ) { + var event = $.Event( "blur" ); + event.target = event.currentTarget = tooltipData.element[ 0 ]; + that.close( event, true ); + } ); + + // Remove title attributes to prevent native tooltips + this.disabledTitles = this.disabledTitles.add( + this.element.find( this.options.items ).addBack() + .filter( function() { + var element = $( this ); + if ( element.is( "[title]" ) ) { + return element + .data( "ui-tooltip-title", element.attr( "title" ) ) + .removeAttr( "title" ); + } + } ) + ); + }, + + _enable: function() { + + // restore title attributes + this.disabledTitles.each( function() { + var element = $( this ); + if ( element.data( "ui-tooltip-title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + } + } ); + this.disabledTitles = $( [] ); + }, + + open: function( event ) { + var that = this, + target = $( event ? event.target : this.element ) + + // we need closest here due to mouseover bubbling, + // but always pointing at the same event target + .closest( this.options.items ); + + // No element to show a tooltip for or the tooltip is already open + if ( !target.length || target.data( "ui-tooltip-id" ) ) { + return; + } + + if ( target.attr( "title" ) ) { + target.data( "ui-tooltip-title", target.attr( "title" ) ); + } + + target.data( "ui-tooltip-open", true ); + + // Kill parent tooltips, custom or native, for hover + if ( event && event.type === "mouseover" ) { + target.parents().each( function() { + var parent = $( this ), + blurEvent; + if ( parent.data( "ui-tooltip-open" ) ) { + blurEvent = $.Event( "blur" ); + blurEvent.target = blurEvent.currentTarget = this; + that.close( blurEvent, true ); + } + if ( parent.attr( "title" ) ) { + parent.uniqueId(); + that.parents[ this.id ] = { + element: this, + title: parent.attr( "title" ) + }; + parent.attr( "title", "" ); + } + } ); + } + + this._registerCloseHandlers( event, target ); + this._updateContent( target, event ); + }, + + _updateContent: function( target, event ) { + var content, + contentOption = this.options.content, + that = this, + eventType = event ? event.type : null; + + if ( typeof contentOption === "string" || contentOption.nodeType || + contentOption.jquery ) { + return this._open( event, target, contentOption ); + } + + content = contentOption.call( target[ 0 ], function( response ) { + + // Ignore async response if tooltip was closed already + if ( !target.data( "ui-tooltip-open" ) ) { + return; + } + + // JQuery creates a special event for focusin when it doesn't + // exist natively. To improve performance, the native event + // object is reused and the type is changed. Therefore, we can't + // rely on the type being correct after the event finished + // bubbling, so we set it back to the previous value. (#8740) + if ( event ) { + event.type = eventType; + } + that._open( event, target, response ); + } ); + if ( content ) { + this._open( event, target, content ); + } + }, + + _open: function( event, target, content ) { + var tooltipData, tooltip, delayedShow, a11yContent, + positionOption = $.extend( {}, this.options.position ); + + if ( !content ) { + return; + } + + // Content can be updated multiple times. If the tooltip already + // exists, then just update the content and bail. + tooltipData = this._find( target ); + if ( tooltipData ) { + tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content ); + return; + } + + // If we have a title, clear it to prevent the native tooltip + // we have to check first to avoid defining a title if none exists + // (we don't want to cause an element to start matching [title]) + // + // We use removeAttr only for key events, to allow IE to export the correct + // accessible attributes. For mouse events, set to empty string to avoid + // native tooltip showing up (happens only when removing inside mouseover). + if ( target.is( "[title]" ) ) { + if ( event && event.type === "mouseover" ) { + target.attr( "title", "" ); + } else { + target.removeAttr( "title" ); + } + } + + tooltipData = this._tooltip( target ); + tooltip = tooltipData.tooltip; + this._addDescribedBy( target, tooltip.attr( "id" ) ); + tooltip.find( ".ui-tooltip-content" ).html( content ); + + // Support: Voiceover on OS X, JAWS on IE <= 9 + // JAWS announces deletions even when aria-relevant="additions" + // Voiceover will sometimes re-read the entire log region's contents from the beginning + this.liveRegion.children().hide(); + a11yContent = $( "
      " ).html( tooltip.find( ".ui-tooltip-content" ).html() ); + a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" ); + a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" ); + a11yContent.appendTo( this.liveRegion ); + + function position( event ) { + positionOption.of = event; + if ( tooltip.is( ":hidden" ) ) { + return; + } + tooltip.position( positionOption ); + } + if ( this.options.track && event && /^mouse/.test( event.type ) ) { + this._on( this.document, { + mousemove: position + } ); + + // trigger once to override element-relative positioning + position( event ); + } else { + tooltip.position( $.extend( { + of: target + }, this.options.position ) ); + } + + tooltip.hide(); + + this._show( tooltip, this.options.show ); + + // Handle tracking tooltips that are shown with a delay (#8644). As soon + // as the tooltip is visible, position the tooltip using the most recent + // event. + // Adds the check to add the timers only when both delay and track options are set (#14682) + if ( this.options.track && this.options.show && this.options.show.delay ) { + delayedShow = this.delayedShow = setInterval( function() { + if ( tooltip.is( ":visible" ) ) { + position( positionOption.of ); + clearInterval( delayedShow ); + } + }, 13 ); + } + + this._trigger( "open", event, { tooltip: tooltip } ); + }, + + _registerCloseHandlers: function( event, target ) { + var events = { + keyup: function( event ) { + if ( event.keyCode === $.ui.keyCode.ESCAPE ) { + var fakeEvent = $.Event( event ); + fakeEvent.currentTarget = target[ 0 ]; + this.close( fakeEvent, true ); + } + } + }; + + // Only bind remove handler for delegated targets. Non-delegated + // tooltips will handle this in destroy. + if ( target[ 0 ] !== this.element[ 0 ] ) { + events.remove = function() { + var targetElement = this._find( target ); + if ( targetElement ) { + this._removeTooltip( targetElement.tooltip ); + } + }; + } + + if ( !event || event.type === "mouseover" ) { + events.mouseleave = "close"; + } + if ( !event || event.type === "focusin" ) { + events.focusout = "close"; + } + this._on( true, target, events ); + }, + + close: function( event ) { + var tooltip, + that = this, + target = $( event ? event.currentTarget : this.element ), + tooltipData = this._find( target ); + + // The tooltip may already be closed + if ( !tooltipData ) { + + // We set ui-tooltip-open immediately upon open (in open()), but only set the + // additional data once there's actually content to show (in _open()). So even if the + // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in + // the period between open() and _open(). + target.removeData( "ui-tooltip-open" ); + return; + } + + tooltip = tooltipData.tooltip; + + // Disabling closes the tooltip, so we need to track when we're closing + // to avoid an infinite loop in case the tooltip becomes disabled on close + if ( tooltipData.closing ) { + return; + } + + // Clear the interval for delayed tracking tooltips + clearInterval( this.delayedShow ); + + // Only set title if we had one before (see comment in _open()) + // If the title attribute has changed since open(), don't restore + if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) { + target.attr( "title", target.data( "ui-tooltip-title" ) ); + } + + this._removeDescribedBy( target ); + + tooltipData.hiding = true; + tooltip.stop( true ); + this._hide( tooltip, this.options.hide, function() { + that._removeTooltip( $( this ) ); + } ); + + target.removeData( "ui-tooltip-open" ); + this._off( target, "mouseleave focusout keyup" ); + + // Remove 'remove' binding only on delegated targets + if ( target[ 0 ] !== this.element[ 0 ] ) { + this._off( target, "remove" ); + } + this._off( this.document, "mousemove" ); + + if ( event && event.type === "mouseleave" ) { + $.each( this.parents, function( id, parent ) { + $( parent.element ).attr( "title", parent.title ); + delete that.parents[ id ]; + } ); + } + + tooltipData.closing = true; + this._trigger( "close", event, { tooltip: tooltip } ); + if ( !tooltipData.hiding ) { + tooltipData.closing = false; + } + }, + + _tooltip: function( element ) { + var tooltip = $( "
      " ).attr( "role", "tooltip" ), + content = $( "
      " ).appendTo( tooltip ), + id = tooltip.uniqueId().attr( "id" ); + + this._addClass( content, "ui-tooltip-content" ); + this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" ); + + tooltip.appendTo( this._appendTo( element ) ); + + return this.tooltips[ id ] = { + element: element, + tooltip: tooltip + }; + }, + + _find: function( target ) { + var id = target.data( "ui-tooltip-id" ); + return id ? this.tooltips[ id ] : null; + }, + + _removeTooltip: function( tooltip ) { + + // Clear the interval for delayed tracking tooltips + clearInterval( this.delayedShow ); + + tooltip.remove(); + delete this.tooltips[ tooltip.attr( "id" ) ]; + }, + + _appendTo: function( target ) { + var element = target.closest( ".ui-front, dialog" ); + + if ( !element.length ) { + element = this.document[ 0 ].body; + } + + return element; + }, + + _destroy: function() { + var that = this; + + // Close open tooltips + $.each( this.tooltips, function( id, tooltipData ) { + + // Delegate to close method to handle common cleanup + var event = $.Event( "blur" ), + element = tooltipData.element; + event.target = event.currentTarget = element[ 0 ]; + that.close( event, true ); + + // Remove immediately; destroying an open tooltip doesn't use the + // hide animation + $( "#" + id ).remove(); + + // Restore the title + if ( element.data( "ui-tooltip-title" ) ) { + + // If the title attribute has changed since open(), don't restore + if ( !element.attr( "title" ) ) { + element.attr( "title", element.data( "ui-tooltip-title" ) ); + } + element.removeData( "ui-tooltip-title" ); + } + } ); + this.liveRegion.remove(); + } +} ); + +// DEPRECATED +// TODO: Switch return back to widget declaration at top of file when this is removed +if ( $.uiBackCompat === true ) { + + // Backcompat for tooltipClass option + $.widget( "ui.tooltip", $.ui.tooltip, { + options: { + tooltipClass: null + }, + _tooltip: function() { + var tooltipData = this._superApply( arguments ); + if ( this.options.tooltipClass ) { + tooltipData.tooltip.addClass( this.options.tooltipClass ); + } + return tooltipData; + } + } ); +} + +var widgetsTooltip = $.ui.tooltip; + + + + +} ); + /***/ }), /***/ "./node_modules/jquery-ui/ui/version.js": @@ -33475,7 +52292,7 @@ window.$ = jQuery; itself *****************************************/ -__webpack_require__(/*! jquery-ui */ "./node_modules/jquery-ui/ui/widget.js"); //should we export this to the window? +__webpack_require__(/*! jquery-ui/dist/jquery-ui */ "./node_modules/jquery-ui/dist/jquery-ui.js"); jQuery.fn.uitooltip = jQuery.fn.tooltip; __webpack_require__(/*! bootstrap-less */ "./node_modules/bootstrap-less/js/bootstrap.js"); __webpack_require__(/*! select2 */ "./node_modules/select2/dist/js/select2.js"); diff --git a/public/js/dist/all.js.map b/public/js/dist/all.js.map index 6377fbf749..2e6d5bdbb6 100644 --- a/public/js/dist/all.js.map +++ b/public/js/dist/all.js.map @@ -1 +1 @@ -{"version":3,"file":"/js/dist/all.js","mappings":";;;;;;;;;;;AAAA;;;;;;;;;;;ACAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0EAA0E,aAAa,aAAa,gBAAgB,wLAAwL,mCAAmC,0BAA0B,mBAAmB,4LAA4L,wBAAwB,UAAU,iCAAiC,cAAc,4BAA4B,0BAA0B,OAAO,iBAAiB,mCAAmC,uBAAuB,uBAAuB,uDAAuD,QAAQ,EAAE,4BAA4B,oHAAoH,6IAA6I,uEAAuE,wCAAwC,4DAA4D,kCAAkC,aAAa,oCAAoC,sCAAsC,uCAAuC,2BAA2B,sBAAsB,sFAAsF,8BAA8B,gCAAgC,qBAAqB,gBAAgB,EAAE,EAAE,qBAAqB,aAAa,gBAAgB,qDAAqD,yBAAyB,wKAAwK,yPAAyP,cAAc,4BAA4B,0BAA0B,OAAO,iBAAiB,mCAAmC,uBAAuB,uBAAuB,uDAAuD,QAAQ,EAAE,8BAA8B,qDAAqD,+BAA+B,oFAAoF,gNAAgN,2BAA2B,wBAAwB,iCAAiC,oFAAoF,+KAA+K,uDAAuD,wBAAwB,+BAA+B,8BAA8B,+DAA+D,oDAAoD,wBAAwB,wCAAwC,WAAW,oEAAoE,kDAAkD,oEAAoE,kDAAkD,GAAG,qBAAqB,mFAAmF,6BAA6B,gCAAgC,qBAAqB,gBAAgB,EAAE,EAAE,qBAAqB,aAAa,gBAAgB,kEAAkE,8BAA8B,uBAAuB,iQAAiQ,cAAc,4BAA4B,0BAA0B,OAAO,iBAAiB,mCAAmC,uBAAuB,+BAA+B,EAAE,4BAA4B,8FAA8F,WAAW,aAAa,gCAAgC,2FAA2F,+BAA+B,2HAA2H,2CAA2C,sCAAsC,iCAAiC,qHAAqH,2CAA2C,qDAAqD,4BAA4B,yCAAyC,sCAAsC,OAAO,yCAAyC,GAAG,0BAA0B,kGAAkG,kCAAkC,sCAAsC,+CAA+C,EAAE,qBAAqB,aAAa,cAAc,eAAe,2GAA2G,cAAc,4BAA4B,0BAA0B,wDAAwD,EAAE,+BAA+B,qCAAqC,sBAAsB,sFAAsF,8BAA8B,sCAAsC,+CAA+C,EAAE,qBAAqB,aAAa,cAAc,2BAA2B,wBAAwB,kEAAkE,yUAAyU,cAAc,4BAA4B,0BAA0B,OAAO,iBAAiB,mCAAmC,qBAAqB,yBAAyB,EAAE,4BAA4B,oHAAoH,wFAAwF,oCAAoC,oBAAoB,EAAE,+BAA+B,iDAAiD,yFAAyF,6BAA6B,yIAAyI,8BAA8B,+IAA+I,sCAAsC,sBAAsB,oFAAoF,uBAAuB,iCAAiC,aAAa,+BAA+B,sBAAsB,qCAAqC,qCAAqC,iCAAiC,sBAAsB,qCAAqC,sCAAsC,oBAAoB,gFAAgF,4BAA4B,sCAAsC,4CAA4C,iCAAiC,aAAa,EAAE,qBAAqB,aAAa,gBAAgB,qDAAqD,wBAAwB,oBAAoB,SAAS,uBAAuB,UAAU,IAAI,iCAAiC,UAAU,cAAc,4BAA4B,0BAA0B,OAAO,iBAAiB,mCAAmC,uBAAuB,uBAAuB,uDAAuD,QAAQ,EAAE,+BAA+B,uFAAuF,+BAA+B,6BAA6B,iCAAiC,+BAA+B,wCAAwC,WAAW,kEAAkE,kBAAkB,GAAG,oBAAoB,gFAAgF,4BAA4B,gCAAgC,0BAA0B,gBAAgB,EAAE,EAAE,qBAAqB,aAAa,gBAAgB,iHAAiH,oBAAoB,oEAAoE,2JAA2J,cAAc,4BAA4B,cAAc,eAAe,iBAAiB,mCAAmC,sBAAsB,EAAE,iCAAiC,6CAA6C,mHAAmH,kCAAkC,iBAAiB,2BAA2B,oCAAoC,mBAAmB,wEAAwE,4CAA4C,aAAa,oCAAoC,iBAAiB,yEAAyE,mEAAmE,aAAa,wCAAwC,WAAW,4DAA4D,oBAAoB,GAAG,gBAAgB,oEAAoE,wBAAwB,gCAAgC,qBAAqB,gBAAgB,EAAE,EAAE,qBAAqB,aAAa,cAAc,oDAAoD,sBAAsB,6BAA6B,oOAAoO,cAAc,4BAA4B,0BAA0B,OAAO,iBAAiB,mCAAmC,qBAAqB,uBAAuB,uDAAuD,QAAQ,EAAE,gCAAgC,yGAAyG,kCAAkC,kDAAkD,0IAA0I,6BAA6B,aAAa,sEAAsE,6BAA6B,iDAAiD,6BAA6B,aAAa,4BAA4B,sCAAsC,uGAAuG,oDAAoD,KAAK,MAAM,uEAAuE,WAAW,6DAA6D,mCAAmC,mHAAmH,6CAA6C,6CAA6C,WAAW,kBAAkB,kBAAkB,yEAAyE,0BAA0B,gCAAgC,kBAAkB,EAAE;;;;;;;;;;ACZp4Z;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,CAAC;AACD;AACA,QAAQ,IAA0C;AAClD;AACA,QAAQ,iCAAO;AACf,YAAY,yEAAQ;AACpB,YAAY,uFAAqB;AACjC,SAAS,oCAAE,OAAO;AAAA;AAAA;AAAA,kGAAC;AACnB,MAAM,KAAK,EASN;AACL,CAAC;AACD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uCAAuC,kBAAkB;AACzD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA,oDAAoD,YAAY;AAChE,qBAAqB;AACrB;AACA;AACA,aAAa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;;AAEb;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA,aAAa;;AAEb;;AAEA;AACA,4CAA4C;;AAE5C;AACA,0CAA0C;;AAE1C;AACA,0CAA0C;;AAE1C;AACA,0CAA0C;;AAE1C;AACA,4CAA4C;;AAE5C;AACA,8CAA8C;;AAE9C;AACA,iDAAiD;;AAEjD;AACA,qCAAqC;;AAErC;AACA,oCAAoC;;AAEpC;AACA,4CAA4C;;AAE5C;AACA,2CAA2C;;AAE3C;AACA,0CAA0C;;AAE1C;AACA,wCAAwC;;AAExC;AACA,qDAAqD;;AAErD;AACA,+CAA+C;;AAE/C;AACA,+CAA+C;;AAE/C;AACA,+CAA+C;;AAE/C;AACA,iDAAiD;;AAEjD;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,yBAAyB;AAC5D,iBAAiB;AACjB;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA,aAAa;AACb;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAyC,kBAAkB;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,kBAAkB;AAC9D;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yCAAyC;AACzC;AACA;AACA;AACA;AACA,sEAAsE;AACtE;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB,sBAAsB;AACtB;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B,yBAAyB;AACzB;AACA,kBAAkB;AAClB;AACA;AACA,sBAAsB;AACtB;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA,qCAAqC;AACrC;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+CAA+C,kBAAkB;AACjE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,kBAAkB;AAC/D;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA,qCAAqC;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA,4BAA4B,iBAAiB;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA,4BAA4B,iBAAiB;AAC7C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA,yCAAyC;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,oCAAoC,kBAAkB;AACtD;AACA;AACA;AACA,aAAa;AACb;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB,iBAAiB;AACjB;AACA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA,qBAAqB;AACrB;AACA,cAAc;AACd;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,0BAA0B,iCAAiC;AAC3D,cAAc;AACd;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,kBAAkB;AAC7D;AACA;AACA;AACA;AACA,aAAa;AACb,SAAS;;AAET;AACA;AACA;AACA,wBAAwB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA,0CAA0C,kBAAkB;AAC5D;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6CAA6C,kBAAkB;AAC/D;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,SAAS;;AAET;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA,8BAA8B,IAAI;AAClC,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,yBAAyB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA,+BAA+B,iBAAiB;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB,cAAc;AACd;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA,gCAAgC,iBAAiB;AACjD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,KAAK;;AAEL,CAAC;;;;;;;;;;;AC9/CD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,MAAM,IAA0C;AAChD;AACA,IAAI,iCAAO,CAAC,yEAAQ,CAAC,mCAAE;AACvB;AACA,KAAK;AAAA,kGAAC;AACN,IAAI,KAAK,EAON;AACH,CAAC;AACD;AACA;AACA;AACA;AACA,aAAa,eAAe;AAC5B,aAAa,QAAQ;AACrB,aAAa,aAAa;AAC1B,aAAa,aAAa;AAC1B,aAAa,SAAS;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA,4BAA4B;;AAE5B;;AAEA;AACA,6BAA6B;;AAE7B;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,sBAAsB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,cAAc;AACd,wBAAwB;AACxB;AACA,gBAAgB;AAChB;AACA;AACA;AACA,KAAK;AACL;AACA,eAAe,QAAQ;AACvB;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,eAAe,QAAQ;AACvB,iBAAiB,SAAS;AAC1B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA,QAAQ;AACR;AACA,QAAQ;AACR;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,eAAe,QAAQ;AACvB,iBAAiB,QAAQ;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,qBAAqB;AACrB,KAAK;AACL;AACA;AACA,eAAe,QAAQ;AACvB,eAAe,SAAS;AACxB,eAAe,SAAS;AACxB,iBAAiB;AACjB;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,uBAAuB,IAAI,YAAY,IAAI,YAAY,IAAI;AAC3D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,wBAAwB,IAAI,YAAY,IAAI,YAAY,IAAI;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,0BAA0B,EAAE,cAAc,EAAE,cAAc,EAAE;AAC5D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,aAAa,eAAe;AAC5B,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA,oCAAoC;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,UAAU;AACV;AACA;AACA,WAAW;AACX;AACA;;AAEA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;;AAEA,KAAK;AACL,8BAA8B;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA,eAAe,QAAQ;AACvB,iBAAiB;AACjB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,0CAA0C;AAC1C,UAAU;AACV,0CAA0C;AAC1C,UAAU;AACV,0CAA0C;AAC1C,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,6DAA6D;;AAE7D;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,UAAU,OAAO;AACjB;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;AACL;AACA;;AAEA;;AAEA,CAAC;;;;;;;;;;;AC9yCD;AACA;AACA;AACA;AACA;;AAEA;AACA,QAAQ,IAA0C;AAClD,QAAQ,iCAAO,CAAC,yEAAQ,CAAC,oCAAE,OAAO;AAAA;AAAA;AAAA,kGAAC;AACnC,MAAM,KAAK,EAIN;AACL,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA,iCAAiC,OAAO;AACxC;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;AAGF;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,wBAAwB;AACxB;AACA,+BAA+B;;AAE/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI;AACJ,oBAAoB;AACpB;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,GAAG;AACH;AACA,6BAA6B,gBAAgB;AAC7C;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA,6BAA6B,gBAAgB;AAC7C;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;;AAEA;AACA;AACA;;AAEA,gCAAgC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,KAAK;AACL;AACA;AACA;AACA;AACA,MAAM;AACN,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,KAAK;AACL;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,KAAK;AACL;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;AACJ,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,IAAI;AACJ,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;AACJ,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA,0BAA0B,qBAAqB;AAC/C;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA,0BAA0B,iBAAiB;AAC3C;AACA;AACA;AACA,GAAG;;AAEH;AACA,0BAA0B,uCAAuC;AACjE;AACA;AACA,GAAG;;AAEH;AACA,0BAA0B,6CAA6C;AACvE;AACA;AACA,GAAG;;AAEH;AACA,0BAA0B,6BAA6B;AACvD;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,kCAAkC;AAClC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,mBAAmB,QAAQ;AAC3B;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA,uCAAuC,0BAA0B;AACjE;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP,gBAAgB;AAChB,OAAO;AACP,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA,gBAAgB;AAChB;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB,SAAS;AAC3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA,gDAAgD;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA,SAAS;AACT;AACA,SAAS;AACT;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA,GAAG;AACH;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI;AACJ,GAAG;AACH;AACA;AACA;AACA,IAAI;AACJ,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH;AACA,oCAAoC,cAAc;AAClD;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB,wBAAwB;AACxB,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,kBAAkB;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,kBAAkB;AAClB;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mCAAmC,SAAS;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc,0BAA0B;AACxC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,UAAU;AACtD;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF,CAAC;;;;;;;;;;;AC5/DD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,iBAAiB;AACjB;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,iDAAiD,eAAe;AAChE,iCAAiC;AACjC;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;;AAEA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,gCAAgC;AAChC;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;;AAEL,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,4BAA4B;AAC5B,4BAA4B;AAC5B;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,uFAAuF,cAAc;AACrG;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,kDAAkD,oDAAoD;AACtG;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA,+BAA+B;AAC/B;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,6BAA6B;AAC7B;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,oCAAoC;AACpC;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA,+BAA+B;;AAE/B;AACA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,4BAA4B;AAC5B;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,4BAA4B;;AAE5B;;AAEA;;AAEA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA,uEAAuE,qBAAqB;AAC5F;AACA;AACA;AACA;;AAEA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,0CAA0C,+BAA+B;;AAEzE;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,0CAA0C,+BAA+B;;AAEzE;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,MAAM;AACN;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,MAAM;AACN;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,4BAA4B;AAC5B;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,mDAAmD;AACnD;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA,+BAA+B;;AAE/B;AACA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA,mEAAmE,iCAAiC;;AAEpG;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;AACA,GAAG;;AAEH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,kCAAkC,IAAI;AACtC;;AAEA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,kCAAkC,kBAAkB,iCAAiC;AACrF;AACA;;AAEA;AACA;AACA;;AAEA;AACA,yBAAyB;;AAEzB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,eAAe,mCAAmC;AAClD;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;;AAEL;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,wEAAwE;AACxE,0BAA0B,YAAY,uEAAuE;AAC7G;AACA,+BAA+B,kBAAkB;AACjD,sBAAsB;AACtB,+BAA+B,uDAAuD;;AAEtF,sBAAsB;AACtB;;AAEA;AACA,qCAAqC,gFAAgF;AACrH,qCAAqC,gFAAgF;AACrH,qCAAqC,iFAAiF;AACtH,qCAAqC;;AAErC;;AAEA;AACA,kBAAkB;AAClB;;AAEA;AACA;;AAEA;AACA;AACA;AACA,oDAAoD;AACpD;AACA,QAAQ,kFAAkF;AAC1F;AACA;AACA,MAAM;AACN;AACA;AACA,sDAAsD;AACtD;AACA,QAAQ,uDAAuD;AAC/D;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA,gCAAgC;AAChC;AACA;AACA;AACA;AACA,GAAG;;;AAGH;AACA;;AAEA,iCAAiC;;AAEjC;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,qCAAqC;AACrC;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP,8BAA8B,oBAAoB;AAClD;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,6BAA6B,IAAI;AACjC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;;AAEA;AACA,8BAA8B;;AAE9B;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,KAAK;AACL,GAAG;;AAEH,CAAC;;;;;;;;;;;AChxED;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,YAAY;AACZ;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,aAAa;AACb,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA,6BAA6B,sBAAsB,sBAAsB;AACzE;AACA;AACA;AACA,6BAA6B,mBAAmB;AAChD;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,iDAAiD,QAAQ,eAAe;AACxE,SAAS;;AAET;AACA;;AAEA;AACA,6BAA6B,aAAa;;AAE1C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,kCAAkC,cAAc;AAChD,+DAA+D;AAC/D,sCAAsC;AACtC,oCAAoC;AACpC,4DAA4D;AAC5D,yCAAyC;AACzC,iCAAiC,6BAA6B,EAAE;AAChE,kBAAkB;AAClB,gBAAgB,EAAE;AAClB,eAAe,0BAA0B;AACzC,4CAA4C;AAC5C,eAAe,2BAA2B;AAC1C,kDAAkD;AAClD,oDAAoD;AACpD,eAAe,2BAA2B;AAC1C,kDAAkD;AAClD,oDAAoD;AACpD,iEAAiE;AACjE,cAAc;AACd,YAAY;AACZ;AACA;AACA;AACA,UAAU;AACV;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,SAAS;;AAET;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,6CAA6C;AAC7C;AACA;AACA,iEAAiE;AACjE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,2CAA2C,+BAA+B;AAC1E;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,sBAAsB,aAAa;AACnC,wBAAwB,aAAa;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;;AAEA;AACA,CAAC,WAAW;;;;;;;;;;;ACt3BZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI,IAAyD;AAC7D;AACA,MAAM,EAK4B;AAClC,CAAC;AACD,8BAA8B;AAC9B;;AAEA;AACA,yCAAyC,0BAAmB,EAAE,8BAAmB;;AAEjF;;AAEA;AACA,8BAAmB,GAAG,0BAAmB;AACzC,0BAA0B;AAC1B,CAAC;;AAED;AACA,mBAAmB,8BAAmB;AACtC,wCAAwC,8BAAmB;AAC3D;AACA,aAAa,8BAAmB;AAChC,kCAAkC,8BAAmB;AACrD;AACA,iBAAiB,8BAAmB;AACpC,kCAAkC,8BAAmB;AACrD,CAAC;AACD;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA,CAAC;;;AAGD;AACA;AACA,WAAW,oBAAoB;AAC/B,YAAY;AACZ;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,CAAC;AACD;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;AACA;AACA,wDAAwD;;AAExD,uCAAuC;;AAEvC;AACA;AACA,kCAAkC;;AAElC;AACA,2DAA2D;;AAE3D;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;;;AAID;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,YAAY;AACZ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,oBAAoB;AAC/B,WAAW,QAAQ;AACnB,YAAY;AACZ;;;AAGA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;AACD,wBAAwB,2BAA2B,2EAA2E,kCAAkC,wBAAwB,OAAO,kCAAkC,mIAAmI;;;;AAIpW;AACA;AACA;AACA,WAAW,QAAQ;AACnB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B;;AAE3B;AACA;AACA,IAAI;;;AAGJ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,IAAI;;;AAGJ;AACA;AACA;AACA,KAAK;AACL,IAAI;;;AAGJ;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA,CAAC;AACD,iCAAiC,2BAA2B,2EAA2E,2CAA2C,wBAAwB,OAAO,2CAA2C,mIAAmI;;AAE/X,kDAAkD,0CAA0C;;AAE5F,4CAA4C,gBAAgB,kBAAkB,OAAO,2BAA2B,wDAAwD,gCAAgC,uDAAuD;;AAE/P,8DAA8D,sEAAsE,8DAA8D;;AAElM,2CAA2C,+DAA+D,6EAA6E,yEAAyE,eAAe,uDAAuD,GAAG;;AAEzU,iCAAiC,4EAA4E,iBAAiB,aAAa;;AAE3I,iCAAiC,6DAA6D,yCAAyC,8CAA8C,iCAAiC,mDAAmD,2DAA2D,OAAO,yCAAyC;;AAEpX,kDAAkD,mFAAmF,eAAe;;AAEpJ,wCAAwC,uBAAuB,yFAAyF;;AAExJ,uCAAuC,wEAAwE,0CAA0C,8CAA8C,MAAM,uEAAuE,IAAI,eAAe,YAAY;;AAEnT,8BAA8B,gGAAgG,mDAAmD;;;;;;;AAOjL;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,SAAS;AACpB;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA;;AAEA;AACA,aAAa,4CAA4C;AACzD,aAAa,QAAQ;AACrB;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa,QAAQ;AACrB;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,4CAA4C;AAC3D;;AAEA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,eAAe,OAAO;AACtB;;AAEA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,GAAG;;AAEV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA,eAAe,SAAS;AACxB;;AAEA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,SAAS;AACxB;;AAEA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,oBAAoB;AACnC,eAAe,QAAQ;AACvB;AACA;;AAEA,GAAG;AACH;;AAEA;AACA;AACA,eAAe,SAAS;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,GAAG;AACH;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,oBAAoB;AACnC;AACA;;AAEA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,eAAe,QAAQ;AACvB;;AAEA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,GAAG;;AAEH;AACA,CAAC;;AAED;;AAEA,OAAO;;AAEP;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,SAAS;AACpB,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA,OAAO;;AAEP;AACA,kDAAkD,gCAAmB;;AAErE,cAAc,gCAAmB;;AAEjC;AACA;AACA;AACA,WAAW,SAAS;AACpB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,WAAW,SAAS;AACpB,YAAY;AACZ;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,sBAAsB;AACjC,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,WAAW,SAAS;AACpB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA,WAAW,SAAS;AACpB,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,YAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;;AAGA,OAAO;;AAEP;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;;;AAGA,OAAO;;AAEP;AACA,kDAAkD,gCAAmB;;AAErE,SAAS,gCAAmB;AAC5B,eAAe,gCAAmB;;AAElC;AACA;AACA;AACA;AACA,WAAW,4CAA4C;AACvD,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,aAAa;AACxB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,yBAAyB;AACpC,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,YAAY;AACZ;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,YAAY;AACZ;AACA;AACA;AACA;;AAEA;;;AAGA,OAAO;;AAEP;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;;AAGA,OAAO;;AAEP;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,kCAAkC;;AAElC;AACA;AACA;AACA,KAAK;;AAEL;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA,yCAAyC;AACzC;AACA;;AAEA,YAAY,SAAS;AACrB;AACA;;AAEA;AACA,GAAG;;AAEH;AACA,kCAAkC;AAClC;AACA;;AAEA;AACA,yCAAyC,SAAS;AAClD;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;;AAGA,OAAO;;AAEP,WAAW;AACX;AACA;AACA;AACA;AACA;AACA,mBAAmB,gCAAmB;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iEAAiE,gCAAmB;AACpF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,gCAAmB;AAC9B;AACA,0BAA0B,4BAA4B;AACtD,0BAA0B;AAC1B,YAAY,gCAAmB,aAAa,WAAW;AACvD;AACA;AACA,WAAW;AACX;AACA;AACA;AACA;AACA,WAAW,gCAAmB;AAC9B;AACA,gBAAgB,gCAAmB,wBAAwB,gCAAmB;AAC9E,oDAAoD,wCAAwC;AAC5F;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;AACA,WAAW,gCAAmB,2BAA2B;AACzD,WAAW;AACX;AACA;AACA;AACA;AACA;AACA,iBAAiB,gCAAmB;AACpC,UAAU;AACV;AACA,CAAC;;;;;;;;;;ACz3BD,aAAa,aAAa,gBAAgB,8EAA8E,iBAAiB,gBAAgB,YAAY,WAAW,KAAK,WAAW,+GAA+G,uBAAuB,wCAAwC,GAAG,aAAa,kCAAkC,2NAA2N,mCAAmC,kBAAkB,sHAAsH,iCAAiC,qBAAqB,oBAAoB,sBAAsB,wBAAwB,8BAA8B,cAAc,gBAAgB,WAAW,kCAAkC,2YAA2Y,6DAA6D,mJAAmJ,wPAAwP,uRAAuR,6+CAA6+C,2CAA2C,iEAAiE,4CAA4C,2HAA2H,kEAAkE,qFAAqF,oJAAoJ,oEAAoE,0CAA0C,sDAAsD,+CAA+C,2BAA2B,8DAA8D,EAAE,kBAAkB,6BAA6B,UAAU,SAAS,+BAA+B,uBAAuB,EAAE,6BAA6B,qBAAqB,EAAE,mCAAmC,kLAAkL,EAAE,oCAAoC,wDAAwD,2BAA2B,iCAAiC,gDAAgD,0BAA0B,0GAA0G,EAAE,qCAAqC,wDAAwD,sDAAsD,iCAAiC,qBAAqB,0BAA0B,2GAA2G,EAAE,wCAAwC,2BAA2B,qEAAqE,mQAAmQ,EAAE,6BAA6B,mCAAmC,EAAE,4CAA4C,wGAAwG,EAAE,4CAA4C,mQAAmQ,EAAE,iCAAiC,4FAA4F,EAAE,uCAAuC,6DAA6D,iJAAiJ,gIAAgI,+BAA+B,EAAE,+BAA+B,6BAA6B,6BAA6B,uIAAuI,oHAAoH,UAAU,oFAAoF,MAAM,0CAA0C,MAAM,wDAAwD,MAAM,oEAAoE,MAAM,sCAAsC,MAAM,qCAAqC,aAAa,EAAE,sCAAsC,eAAe,iFAAiF,qCAAqC,EAAE,oCAAoC,sCAAsC,EAAE,wCAAwC,0CAA0C,EAAE,uCAAuC,wSAAwS,EAAE,yCAAyC,OAAO,sNAAsN,EAAE,yCAAyC,OAAO,kMAAkM,EAAE,6CAA6C,4HAA4H,EAAE,6CAA6C,2EAA2E,6JAA6J,2LAA2L,EAAE,4CAA4C,4JAA4J,kGAAkG,EAAE,0CAA0C,qFAAqF,qDAAqD,EAAE,8CAA8C,+CAA+C,oSAAoS,EAAE,+CAA+C,iWAAiW,EAAE,0CAA0C,qFAAqF,yVAAyV,EAAE,6CAA6C,sIAAsI,oMAAoM,8CAA8C,wFAAwF,EAAE,oCAAoC,4EAA4E,wJAAwJ,wBAAwB,gDAAgD,EAAE,+BAA+B,mFAAmF,EAAE,+CAA+C,wBAAwB,uCAAuC,0BAA0B,4CAA4C,mIAAmI,EAAE,wCAAwC,WAAW,QAAQ,gBAAgB,sBAAsB,4BAA4B,mCAAmC,MAAM,oBAAoB,0BAA0B,mBAAmB,yNAAyN,sBAAsB,uEAAuE,cAAc,EAAE,oCAAoC,4HAA4H,EAAE,kCAAkC,gDAAgD,4PAA4P,6BAA6B,YAAY,+HAA+H,+PAA+P,sHAAsH,oCAAoC,SAAS,kBAAkB,SAAS,iBAAiB,aAAa,IAAI,yCAAyC,WAAW,cAAc,sBAAsB,wBAAwB,2CAA2C,WAAW,GAAG,KAAK,GAAG,sFAAsF,oCAAoC,GAAG,UAAU;AAC1yc;;;;;;;;;;ACDA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA,iDAAiD,oBAAoB,IAAI;AACzE;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,0DAA0D;AAC1D,aAAa;;AAEb;AACA,8BAA8B;AAC9B;AACA,aAAa;AACb;AACA,WAAW;AACX;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;AACA;AACA,SAAS;AACT;AACA,SAAS;;AAET;AACA;AACA;AACA,SAAS;AACT;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;;AAEA;AACA;AACA;AACA;AACA,oBAAoB,2CAA2C;AAC/D;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kCAAkC;AAClC;;AAEA;AACA;;AAEA;AACA;AACA;AACA,8BAA8B;;AAE9B;;AAEA;AACA,8BAA8B;AAC9B,0BAA0B;;AAE1B;AACA;AACA;AACA;AACA;;AAEA;AACA,oDAAoD;AACpD,gCAAgC;AAChC;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,sBAAsB,mBAAmB;AACzC;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,sBAAsB,uBAAuB;AAC7C;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,oBAAoB,0BAA0B;;AAE9C;AACA;AACA,oBAAoB,kBAAkB;AACtC;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B;AAC/B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;;AAEA,OAAO;;AAEP;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH,CAAC;;;;;;;;;;;ACzdD;AACA;;AAEA,MAAM,IAA0C;;AAEhD;AACA,EAAE,iCAAQ,EAAE,yEAAQ,EAAE,oCAAE,OAAO;AAAA;AAAA;AAAA,kGAAE;AACjC,GAAG,KAAK,EAIN;AACF,EAAE;AACF;;AAEA;;AAEA;;AAEA,EAAE;;;;;;;;;;;ACnBF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,MAAM,IAA0C;;AAEhD;AACA,EAAE,iCAAQ,EAAE,yEAAQ,EAAE,8EAAW,EAAE,oCAAE,OAAO;AAAA;AAAA;AAAA,kGAAE;AAC9C,GAAG,KAAK,EAIN;AACF,EAAE;AACF;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,+BAA+B;;AAE9C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,yCAAyC;AACzC;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,sBAAsB;;AAEtB;AACA;AACA;AACA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA,4CAA4C;AAC5C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,IAAI;AACJ,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAS,0BAA0B;AACnC;AACA;AACA;;AAEA;AACA;AACA;AACA,yBAAyB;;AAEzB;AACA,yBAAyB;;AAEzB;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,kCAAkC;AAClC;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,IAAI;;AAEJ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oCAAoC;AACpC;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,aAAa;AACb;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,oCAAoC;AACpC;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,6BAA6B;AAC7B;;AAEA;;AAEA,+CAA+C,OAAO;AACtD;AACA;AACA;AACA;AACA,oDAAoD;AACpD,iBAAiB,sBAAsB;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA,6BAA6B,kBAAkB;AAC/C,EAAE;;AAEF;AACA,6BAA6B,iBAAiB;AAC9C,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA,gBAAgB,oBAAoB;AACpC;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,UAAU,iCAAiC;AAC3C;AACA;AACA,eAAe;AACf;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,eAAe;AACf,IAAI;AACJ;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,EAAE;;AAEF;;AAEA,EAAE;;;;;;;;;;;ACtvBF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,IAA0C;AAChD,EAAE,iCAAQ,CAAC,yEAAQ,CAAC,oCAAE,OAAO;AAAA;AAAA;AAAA,kGAAE;AAC/B,GAAG,KAAK,EAIN;AACF,CAAC;;AAED;;AAEA;AACA;;AAEA,6CAA6C;AAC7C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,mCAAmC;AACnC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA,kDAAkD;AAClD;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,sBAAsB,iBAAiB;AACvC;;AAEA;AACA;AACA;AACA;AACA,4BAA4B,gBAAgB;AAC5C;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;;AAEA;AACA,8CAA8C;;AAE9C;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA,mCAAmC;AACnC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2CAA2C,YAAY;AACvD;AACA,IAAI;AACJ,GAAG;AACH;AACA;;AAEA;;AAEA;AACA,cAAc;AACd,YAAY;AACZ,WAAW;AACX;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,6DAA6D,GAAG;AAChE,yDAAyD,GAAG;AAC5D,kEAAkE,GAAG,KAAK,GAAG;AAC7E,4DAA4D,GAAG,KAAK,EAAE;AACtE,wEAAwE,EAAE;AAC1E,2EAA2E,EAAE;AAC7E,yDAAyD,EAAE;AAC3D,EAAE;;AAEF;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,gCAAgC;AAChC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,KAAK;AACL;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,8BAA8B;AAC9B;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,2EAA2E,eAAe;AAC1F;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;;AAEN;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA,iBAAiB,eAAe;AAChC;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA,wCAAwC;AACxC;AACA,MAAM;;AAEN;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA,mBAAmB;AACnB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,sDAAsD;AACtD;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,aAAa;AACb;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,oBAAoB,sBAAsB;AAC1C;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,qBAAqB,OAAO;AAC5B;AACA;AACA,KAAK;AACL,+DAA+D,GAAG;AAClE;;AAEA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,gBAAgB,qBAAqB;AACrC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,iBAAiB,uBAAuB;AACxC;AACA;AACA;AACA;AACA,kDAAkD,eAAe;AACjE;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,KAAK;AACL,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,MAAM;AACN;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,MAAM;AACN;;AAEA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,+CAA+C,YAAY,EAAE;AAC7D,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA,6CAA6C,iBAAiB;AAC9D,KAAK;AACL,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,EAAE;;AAEF;AACA,cAAc,gBAAgB;AAC9B,WAAW,aAAa;AACxB,SAAS,WAAW;AACpB,UAAU,YAAY;AACtB,aAAa,eAAe;AAC5B,YAAY,cAAc;AAC1B,YAAY,cAAc;AAC1B,gBAAgB;AAChB,EAAE;;AAEF;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,EAAE;;AAEF;AACA,gBAAgB;AAChB;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA,gBAAgB;AAChB;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA,gBAAgB;AAChB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA,gBAAgB;AAChB;;AAEA;AACA;AACA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,IAAI;;AAEJ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF,mCAAmC,cAAc,2BAA2B;AAC5E;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA,mEAAmE,EAAE,gCAAgC,KAAK,6CAA6C,KAAK;AAC5J,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA,kGAAkG,IAAI,KAAK,eAAe,EAAE,iCAAiC,IAAI,KAAK,eAAe,EAAE,+BAA+B,IAAI,EAAE,EAAE,iCAAiC,IAAI,EAAE,EAAE,sCAAsC,IAAI,EAAE,EAAE,gDAAgD,IAAI,oBAAoB,EAAE,6FAA6F,KAAK,iDAAiD,GAAG,YAAY,IAAI;AACriB,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA,2CAA2C,EAAE;AAC7C,GAAG;;AAEH;AACA;AACA,sDAAsD,IAAI,OAAO,EAAE;AACnE,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,0CAA0C,aAAa;AACvD,2CAA2C,aAAa;AACxD;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,iEAAiE,oCAAoC;AACrG;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA,EAAE;;AAEF;AACA,mBAAmB,oCAAoC;AACvD;AACA;;AAEA,wBAAwB;AACxB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;;;;;;;;;;ACtqDD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA,YAAY;AACZ,QAAQ;;AAER;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA,YAAY;AACZ,QAAQ;;AAER;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,UAAU;AACV;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,UAAU;AACV;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA,sCAAsC,kBAAkB;AACxD,2CAA2C;AAC3C;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB,0CAA0C;;AAE/D;AACA;AACA;AACA;AACA;AACA;AACA;AACA,+BAA+B;AAC/B;AACA;AACA;AACA;AACA,2CAA2C,0BAA0B;AACrE;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,0DAA0D;AAC1D,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;;AAEA;AACA;AACA;AACA,oDAAoD;AACpD;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;;AAEb;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA,gEAAgE;AAChE;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH,CAAC;;;;;;;;;;;ACtPD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,MAAM,KAA0B;;AAEhC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA,EAAE;AACF;AACA;;;AAGA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;;;AAGA;;;;AAIA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;AAIA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,+BAA+B;AAC/B;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,SAAS,YAAY;;AAErB;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;;AAEA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF,oBAAoB;;AAEpB;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA,EAAE;;AAEF,8CAA8C;AAC9C;AACA;AACA,mBAAmB,iCAAiC;AACpD,EAAE;;AAEF;AACA;;AAEA;AACA;AACA,WAAW,YAAY;AACvB;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;;AAEA,UAAU,SAAS;AACnB;AACA;;AAEA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU,YAAY;AACtB;AACA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,YAAY;AACvB;;AAEA;AACA;AACA;AACA;;AAEA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA,eAAe;AACf;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,UAAU,SAAS;AACnB;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,kCAAkC,IAAI;AACtC;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,2BAA2B;AAC3B;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA,gBAAgB,IAAI;;AAEpB;AACA;;AAEA;;AAEA;AACA;AACA,0CAA0C,IAAI;AAC9C;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,GAAG;AACH,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,EAAE;AACF,UAAU;;AAEV;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,MAAM;AACN;AACA;;AAEA;AACA,MAAM;AACN;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,aAAa,0BAA0B;AACvC;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,UAAU;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,UAAU;AACrB;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB,aAAa,QAAQ;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,QAAQ;AACnB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,SAAS,6BAA6B;AACjD;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,UAAU;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,GAAG;AACH;;AAEA;AACA;AACA,WAAW,iBAAiB;AAC5B,aAAa,wBAAwB;AACrC;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,gBAAgB;AAC3B,aAAa,SAAS;AACtB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,gBAAgB;AAC3B,aAAa,QAAQ;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oBAAoB;AACpB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,qBAAqB;AACrB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,mBAAmB;AACnB;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,WAAW,WAAW;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,WAAW,eAAe;AAC1B;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA,iCAAiC,MAAM;AACvC;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA,eAAe;;AAEf,SAAS;;AAET;AACA,SAAS,gCAAgC;AACzC,SAAS,mBAAmB;AAC5B,SAAS,qCAAqC;AAC9C,SAAS;AACT,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,MAAM;;AAEN;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,8DAA8D;;AAE9D;AACA;AACA;AACA,2CAA2C;;AAE3C;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,QAAQ;;AAER;AACA;;AAEA;AACA;AACA,+DAA+D;;AAE/D;AACA;AACA;AACA,4CAA4C;;AAE5C;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,mCAAmC;;AAEnC;AACA;AACA;AACA,+CAA+C;;AAE/C;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA,kEAAkE,UAAU;AAC5E,uCAAuC,2BAA2B;AAClE;AACA,iCAAiC,MAAM;AACvC;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA,IAAI;;AAEJ;AACA;AACA,IAAI;;AAEJ;AACA;AACA,WAAW,YAAY;AACvB;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA,WAAW,YAAY;AACvB;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,UAAU;AACrB;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA,WAAW,cAAc;AACzB;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;;AAEA;AACA,aAAa,uEAAuE;AACpF;AACA;AACA,aAAa,4BAA4B;AACzC;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS,SAAS;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,6DAA6D;;AAE7D;AACA;AACA;AACA,0CAA0C;;AAE1C;AACA;AACA,QAAQ;AACR;;AAEA;AACA;AACA,QAAQ;;AAER;AACA;;AAEA,oCAAoC;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA,SAAS,SAAS;AAClB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAS,SAAS;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;;AAEJ,SAAS,SAAS;AAClB;AACA;AACA,IAAI;AACJ;;AAEA;AACA;;AAEA;AACA;AACA,YAAY,SAAS;AACrB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,iBAAiB,iDAAiD;AAClE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,sBAAsB;AACtB;AACA;AACA;;AAEA;AACA;AACA,kDAAkD;AAClD,WAAW,4CAA4C;AACvD;AACA;;AAEA;AACA;AACA,uBAAuB;AACvB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,iBAAiB;AAC5B;AACA,WAAW,SAAS;AACpB,WAAW,OAAO;AAClB,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;;AAEA,EAAE;;;;AAIF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AAKA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;;AAEA,SAAS,GAAG;AACZ;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;;;;AAIA;;AAEA;;AAEA;AACA;;;;AAIA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,iBAAiB,SAAS;AAC1B;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA,eAAe,SAAS;AACxB;AACA;;AAEA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;AAGF;;;AAGA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,KAAK;AACL;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,SAAS;AACT;AACA;AACA;AACA;;AAEA;;AAEA;AACA,MAAM;AACN;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,OAAO;AAClB;AACA;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,WAAW,OAAO;AAClB,2BAA2B,wBAAwB;;AAEnD;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA,2CAA2C;AAC3C,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,CAAC;AACD;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF;;;;AAIA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,mBAAmB;;AAEnB;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,WAAW,cAAc;AACzB;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,MAAM;AACN;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA,QAAQ;AACR,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA,IAAI;AACJ;;AAEA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,yCAAyC,qCAAqC;AAC9E,qCAAqC,sCAAsC;AAC3E,qCAAqC,qCAAqC;AAC1E;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,QAAQ;AACR;AACA,OAAO;AACP,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,YAAY;;AAEZ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;;AAEZ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;;AAEN;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,qCAAqC;AACrC,sCAAsC;AACtC,qCAAqC;AACrC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;;AAGF;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;AAKA;AACA;AACA;AACA,GAAG;AACH;;;;;AAKA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;;;;;AAKA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,WAAW,SAAS;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,gCAAgC;AAChC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;AAKA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA,EAAE;AACF;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,wBAAwB,aAAa;AACrC,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;;AAEA;;;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,SAAS;AAC7B;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL,GAAG;AACH,EAAE;;AAEF;AACA;AACA;AACA,IAAI;AACJ;AACA,EAAE;;;AAGF;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;AACJ;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL,EAAE;AACF;AACA;AACA;AACA,IAAI;AACJ,EAAE;AACF;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;;AAEA;;;AAGA;;AAEA;;;;AAIA;AACA;AACA,GAAG;AACH,eAAe;;AAEf;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,SAAS,gBAAgB;AACzB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,kBAAkB,gBAAgB;AAClC;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,IAAI;AACJ;AACA,EAAE;AACF;;AAEA;;AAEA;;;;AAIA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,EAAE;;;AAGF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,GAAG;AACH;;AAEA,GAAG;AACH;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;;AAEA,SAAS,OAAO;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA,sBAAsB;;AAEtB;AACA;AACA;AACA;AACA;AACA;;AAEA,SAAS,OAAO;AAChB;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;AACL;;AAEA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;;AAEA,WAAW;;AAEX;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;;AAEA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,4CAA4C;AAC5C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,eAAe,sBAAsB;AACrC;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,0BAA0B;AAC1B;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,gEAAgE;AAChE;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAW,cAAc;;AAEzB;AACA;AACA;AACA;AACA;AACA,kBAAkB,mBAAmB;AACrC;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,2BAA2B,uCAAuC;AAClE;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,wBAAwB,uDAAuD;AAC/E;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM,+CAA+C;AACrD;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;;AAEN;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,uCAAuC;AACvC;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;;AAEA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,sCAAsC,cAAc;AACpD;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,CAAC;;AAED,eAAe,oCAAoC;AACnD;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,sCAAsC;AACtC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA,EAAE;;;AAGF;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,4CAA4C,OAAO;AACnD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,8BAA8B;;AAE9B;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,GAAG;AACH;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,OAAO;AAClB;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,iBAAiB,gBAAgB;AACjC;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,SAAS,+BAA+B;AACxC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,wCAAwC,OAAO;AAC/C;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,yCAAyC,OAAO;AAChD;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA,UAAU,qCAAqC;AAC/C;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,SAAS;AACT;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN,GAAG;AACH,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;;AAEA,UAAU,8BAA8B;AACxC;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA,6BAA6B;AAC7B;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,aAAa,OAAO;AACpB;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,MAAM;AACN;;AAEA;AACA;AACA;AACA,GAAG;AACH,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,GAAG;AACH;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA;AACA;AACA;;AAEA,UAAU,WAAW;AACrB;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;AACF;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;;;;AAIA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,+CAA+C,cAAc,WAAW;AACxE,mBAAmB,UAAU;AAC7B;AACA,sBAAsB,cAAc,sBAAsB,gBAAgB;AAC1E,gBAAgB,WAAW,YAAY;AACvC,cAAc;AACd;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,iCAAiC;AACjC;AACA;AACA;AACA;AACA;AACA;;AAEA,6CAA6C;AAC7C;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH,EAAE;;;AAGF;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB;AACnB;AACA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;;AAEA;AACA;AACA;AACA;AACA;AACA,aAAa,8DAA8D;AAC3E;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,SAAS,OAAO;;AAEhB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA,aAAa;;AAEb;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA,IAAI;;AAEJ;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,mBAAmB,eAAe;AAClC;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD;AACA;AACA;AACA,iBAAiB;;AAEjB;AACA;;AAEA,WAAW,OAAO;AAClB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA,YAAY;AACZ;;AAEA;AACA;AACA;;AAEA,YAAY,SAAS;AACrB;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA,EAAE;;;AAGF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;;AAEA;;AAEA;AACA;;;;;AAKA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;;AAEZ;AACA;AACA;AACA,SAAS,OAAO;AAChB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS,gBAAgB;AACzB;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,kDAAkD,0BAA0B;AAC5E;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,WAAW,gBAAgB;AAC3B;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA,2BAA2B;AAC3B;AACA,qBAAqB;AACrB;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY,gBAAgB;AAC5B;AACA;;AAEA,8CAA8C;AAC9C;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;;AAEA,SAAS,gBAAgB;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;;AAEA,UAAU,gBAAgB;AAC1B;AACA;AACA;AACA;AACA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA,EAAE;;AAEF;AACA,iEAAiE;AACjE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,GAAG;AACH;AACA;AACA;;AAEA,KAAK;AACL;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,qBAAqB,aAAa;AAClC,EAAE;AACF;AACA;AACA;AACA;;AAEA;AACA,iDAAiD;;AAEjD;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;;AAEA,gCAAgC,SAAS;AACzC;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,gCAAgC,SAAS;AACzC;AACA;AACA;AACA;AACA;;AAEA;AACA,oBAAoB,gBAAgB;AACpC;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,WAAW,iBAAiB;AAC5B,YAAY,iBAAiB;AAC7B,eAAe;AACf,CAAC;AACD;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA;;AAEA,SAAS,mBAAmB;AAC5B;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;;AAGA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;AAGF;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,IAAI;AACJ;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;;;AAKF;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,IAAI;AACJ;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;;;AAKF;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,EAAE;;;;;AAKF;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;AACA;;AAEA,kCAAkC;AAClC;AACA;;AAEA,KAAK;AACL;;AAEA,KAAK;AACL;AACA;AACA,MAAM;AACN;;AAEA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,MAAM;AACN;AACA;;AAEA;AACA,YAAY,SAAS;AACrB;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;;;AAKF;;;AAGA;;;AAGA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA,uCAAuC;AACvC;AACA;AACA;;AAEA;;AAEA,0BAA0B;AAC1B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,+CAA+C;AAC/C;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,4CAA4C;AAC5C;;AAEA;AACA;AACA;AACA;AACA,WAAW,KAAK;AAChB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,EAAE;;AAEF;;AAEA;AACA;AACA;AACA,IAAI;AACJ,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;AAGF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB,oCAAoC;;AAEpD;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA;;AAEA,MAAM;AACN;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA,cAAc;;AAEd;;;;AAIA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ,GAAG;;AAEH;AACA;AACA;AACA;;AAEA,GAAG;;AAEH;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,IAAI;;AAEJ,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,EAAE;AACF;AACA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,cAAc;AACd,MAAM;AACN;;AAEA,YAAY;AACZ,IAAI;AACJ;AACA,EAAE;;;AAGF;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,gBAAgB;;AAEhB;AACA;AACA;AACA;AACA;AACA,gBAAgB;;AAEhB,iDAAiD;AACjD;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,mBAAmB;AACnB;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,yDAAyD;AACzD;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,iBAAiB;;AAEjB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,UAAU;AACV;;AAEA;;AAEA;AACA;;AAEA;AACA,iBAAiB;AACjB,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA,mDAAmD;;AAEnD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,2BAA2B;;AAE3B;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,kCAAkC;;AAElC;AACA,sBAAsB;AACtB,2BAA2B;;AAE3B;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;;AAER;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,uDAAuD;AACvD;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,MAAM;AACN;;AAEA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;AAGF;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA,GAAG;AACH;;;AAGA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;AACL;;AAEA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,KAAK;AACL;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;;AAEA;AACA;AACA,IAAI;AACJ,EAAE;;AAEF;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,EAAE;;;AAGF;AACA;AACA;AACA;AACA;AACA;;;;;AAKA;AACA;AACA;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,EAAE;AACF;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;;AAEA,oDAAoD;AACpD;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY,uBAAuB;AACnC,YAAY,wBAAwB;AACpC;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,MAAM;;AAEN;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;;;AAKF;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,gCAAgC;AAChC,cAAc,uCAAuC;AACrD;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;;;AAKF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,IAAI;;AAEJ;AACA;AACA;AACA,EAAE;;;;;AAKF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;AAGF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;;AAEJ;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA,KAAK;AACL,IAAI;AACJ;;AAEA;AACA;;;;;AAKA;AACA;AACA;AACA,GAAG;AACH;;;;;AAKA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,IAAI;AACJ;AACA;AACA;;AAEA;;AAEA;AACA,qDAAqD;AACrD;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,IAAI;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,oBAAoB;;AAEpB;AACA;;AAEA;AACA;;AAEA,IAAI;AACJ;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,IAAI;AACJ;AACA,EAAE;;AAEF;AACA,eAAe,qDAAqD;AACpE;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,KAAK;AACL;AACA;AACA,GAAG;AACH;AACA,EAAE;;AAEF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;AAGF;AACA,eAAe,kCAAkC;AACjD,gBAAgB,4DAA4D;AAC5E;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,IAAI;AACJ;AACA,GAAG;AACH,EAAE;;;AAGF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,EAAE;;;;;AAKF;;AAEA;AACA;AACA,EAAE;AACF;AACA;AACA,EAAE;;AAEF;AACA;AACA,EAAE;AACF;;AAEA;AACA;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA,EAAE;;AAEF;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;;;;AAKH;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;;;AAIA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,KAAK,IAA0C;AAC/C,CAAC,iCAAkB,EAAE,mCAAE;AACvB;AACA,EAAE;AAAA,kGAAE;AACJ;;;;;AAKA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;;;;AAKA;AACA,EAAE;;;;;;;;;;;ACvnVF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;ACfA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,sCAAsC,QAAQ;AAC9C;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;;AC3BA,cAAc,mBAAO,CAAC,oEAAiB;AACvC,WAAW,mBAAO,CAAC,kEAAgB;AACnC,WAAW,mBAAO,CAAC,kEAAgB;AACnC,aAAa,mBAAO,CAAC,wEAAmB;AACxC,eAAe,mBAAO,CAAC,8EAAsB;AAC7C,UAAU,mBAAO,CAAC,gEAAe;;AAEjC;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;;;AAIH;AACA;AACA;AACA;;AAEA,8CAA8C,QAAQ;AACtD;AACA;AACA,KAAK;AACL;AACA;AACA,qBAAqB,4BAA4B;AACjD;AACA,6CAA6C,QAAQ;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA,2CAA2C;AAC3C;AACA,GAAG;;AAEH;AACA;AACA;AACA;;;;;;;;;;;AClEA,kBAAkB,mBAAO,CAAC,wFAAwB;AAClD,eAAe,mBAAO,CAAC,8EAAsB;AAC7C,WAAW,mBAAO,CAAC,kEAAgB;AACnC,YAAY,mBAAO,CAAC,sEAAkB;AACtC,WAAW,mBAAO,CAAC,kEAAgB;AACnC,aAAa,mBAAO,CAAC,wEAAmB;AACxC,YAAY,mBAAO,CAAC,oEAAiB;AACrC,iBAAiB,mBAAO,CAAC,gFAAuB;AAChD,YAAY,mBAAO,CAAC,sEAAkB;;AAEtC;;AAEA;AACA;AACA,WAAW,mBAAO,CAAC,kDAAQ;AAC3B,eAAe,mBAAO,CAAC,4DAAa;AACpC,qBAAqB,mBAAO,CAAC,8DAAc;;AAE3C;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8BAA8B;AAC9B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,iCAAiC;AACjC;;AAEA,0BAA0B,mBAAO,CAAC,oDAAS;AAC3C,0BAA0B,mBAAO,CAAC,4DAAa;AAC/C,0BAA0B,mBAAO,CAAC,sDAAU;AAC5C,0BAA0B,mBAAO,CAAC,sDAAU;AAC5C,0BAA0B,mBAAO,CAAC,kDAAQ;AAC1C,0BAA0B,mBAAO,CAAC,kEAAgB;;AAElD;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,kCAAkC;AAClC;AACA;AACA;AACA;AACA,wDAAwD,QAAQ;AAChE;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,4CAA4C,QAAQ;AACpD;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wCAAwC,QAAQ;AAChD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,4CAA4C,QAAQ;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,4CAA4C,QAAQ;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,oBAAoB,QAAQ;AAC5B;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;;;;;ACrQA;AACA;AACA;;AAEA;;AAEA,wBAAwB;AACxB,0BAA0B;;AAE1B;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;AC3DA,cAAc,mBAAO,CAAC,oEAAiB;AACvC,WAAW,mBAAO,CAAC,kEAAgB;AACnC,SAAS,mBAAO,CAAC,oDAAS;;AAE1B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,oBAAoB,YAAY;AAChC;;AAEA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;;AAEA;AACA;AACA;AACA,+DAA+D,OAAO;AACtE;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;AACA;AACA;;;;;;;;;;;AC5FA;;AAEA,aAAa,mBAAO,CAAC,kDAAQ;;AAE7B;AACA;AACA;AACA,uCAAuC,QAAQ;AAC/C;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,8CAA8C,QAAQ;AACtD;AACA;AACA;AACA;AACA,mDAAmD;AACnD;AACA;AACA;AACA;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;;;;;;;;;;AC9CA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,QAAQ;AACR;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA,4BAA4B,2BAA2B;AACvD;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,8CAA8C,QAAQ;AACtD;AACA;AACA,KAAK;AACL;AACA;AACA,2CAA2C,QAAQ;AACnD;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,mCAAmC;AACnC;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,2BAA2B;AAC3B;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;;;;;;;;;;ACvHA;;AAEA;AACA;AACA;AACA,+CAA+C,QAAQ;AACvD;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA,QAAQ;AACR;AACA,QAAQ;AACR;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;AACL;AACA,+CAA+C,QAAQ;AACvD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;;;AAGA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;;;;;ACzGA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,2CAA2C,QAAQ;AACnD;AACA;AACA,wDAAwD,QAAQ;AAChE;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,yCAAyC,QAAQ;AACjD;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,2CAA2C,QAAQ;AACnD;AACA;AACA,wDAAwD,QAAQ;AAChE;AACA;AACA,QAAQ;AACR;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,mDAAmD,QAAQ;AAC3D;AACA;AACA,4CAA4C,QAAQ;AACpD;AACA,uBAAuB;AACvB;AACA;AACA,UAAU;AACV;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;AC7KA;AACA;AACA;;AAEA,YAAY,mBAAO,CAAC,gEAAY;;AAEhC;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,WAAW,SAAS;AACpB,YAAY;AACZ;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,SAAS;AACpB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW,eAAe;AAC1B,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;;AAGA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,SAAS;AACpB,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,gCAAgC;AAChC;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA,IAAI;AACJ;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA;;;;;;;;;;;ACnKA;AACA;AACA;AACA,cAAc,mBAAO,CAAC,gEAAY;;AAElC;AACA;AACA;AACA,WAAW,SAAS;AACpB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,WAAW,SAAS;AACpB;AACA;;AAEA,YAAY;AACZ;AACA,mBAAmB,eAAe;AAClC;AACA;AACA;;AAEA;AACA;AACA;AACA,WAAW,SAAS;AACpB,WAAW,QAAQ;AACnB,WAAW,UAAU;AACrB,WAAW,SAAS;AACpB;AACA;;AAEA,cAAc;AACd;AACA,mBAAmB,eAAe;AAClC;AACA;AACA;;;;;;;;;;;ACrCA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,4BAA4B,kBAAkB;AAC9C;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;;;;;ACjBA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,uCAAuC;AACvC,2CAA2C;;AAE3C;AACA;AACA;AACA,sBAAsB;AACtB;;AAEA,wBAAwB,oBAAoB;AAC5C;AACA;;AAEA,wBAAwB,oBAAoB;AAC5C;AACA;;AAEA;AACA,SAAS;;AAET;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,+CAA+C;;AAE/C;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,oBAAoB,oBAAoB;AACxC,oCAAoC;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,6BAA6B,YAAY;AACzC;AACA;AACA;AACA,8BAA8B;AAC9B;AACA,cAAc,UAAU;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;;;;;;;;;;AC1HA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,SAAS;AACpB,WAAW,QAAQ;AACnB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,mBAAmB,YAAY;AAC/B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;ACzBA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,QAAQ;AACnB,WAAW,SAAS;AACpB,WAAW,SAAS;AACpB;AACA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,yBAAyB,YAAY;AACrC;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,MAAM;AACN;AACA;AACA;AACA,CAAC;;;;;;;;;;;AC9DD;;AAEA;AACA;AACA,kBAAkB,gBAAgB;AAClC;AACA;AACA;AACA;;;;;;;;;;;ACRA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW,eAAe;AAC1B,YAAY,OAAO;AACnB;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,kBAAkB,uBAAuB;AACzC;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;;;;;;;;;;AChCA;AACA;AACA;AACA;AACA;AACA;;;;;;;;;;;ACLA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC;AACD,MAAM,IAA0C;AAChD;AACA,IAAI,iCAAO,CAAC,yEAAQ,CAAC,oCAAE,OAAO;AAAA;AAAA;AAAA,kGAAC;AAC/B,IAAI,KAAK,EAqBN;AACH,EAAE;AACF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAe;AACtB,WAAW,WAAW,OAAO;AAC7B;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,oBAAoB;AACpB,oBAAoB;AACpB,mBAAmB;AACnB,qBAAqB;AACrB;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,eAAe,QAAQ;AACvB,eAAe,QAAQ;AACvB;AACA,iBAAiB,QAAQ;AACzB;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,wBAAwB,iBAAiB;AACzC;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sBAAsB;AACtB;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA,uCAAuC,OAAO;AAC9C;;AAEA;AACA;AACA;AACA,+CAA+C,OAAO;AACtD;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;AACA;AACA,cAAc;AACd,0CAA0C;AAC1C;AACA,SAAS;AACT;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,wBAAwB,iBAAiB;AACzC;AACA;;AAEA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA,kBAAkB;AAClB,uFAAuF;AACvF;AACA,kBAAkB;AAClB;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,cAAc;AACd;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,CAAC;;AAED,yBAAyB,qBAAqB;AAC9C;AACA,CAAC;AACD,gCAAgC;;AAEhC;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;;AAEA;AACA,sBAAsB;;AAEtB;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA,oBAAoB,yBAAyB;AAC7C;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA,oBAAoB,6BAA6B;AACjD;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,oBAAoB;AACpB;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,4CAA4C,SAAS;AACrD;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA,oBAAoB,YAAY;AAChC;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA,sBAAsB,iBAAiB;AACvC;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,kBAAkB;AAClB,iBAAiB;AACjB,gBAAgB;AAChB,gBAAgB;AAChB,kBAAkB;AAClB,kBAAkB;AAClB,iBAAiB;AACjB;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;;AAEP;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,sCAAsC;AACtC;AACA,oCAAoC;AACpC,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;;AAEA;;AAEA,oBAAoB,yBAAyB;AAC7C;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,OAAO;;AAEP;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA,OAAO;;AAEP,KAAK;AACL;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA,sBAAsB,0BAA0B;AAChD;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,OAAO;;AAEP;;AAEA;AACA;AACA,MAAM;AACN;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,gCAAgC;AAChC,QAAQ;AACR;AACA;AACA,SAAS;AACT;AACA,KAAK;;AAEL;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX,UAAU;AACV,kCAAkC;AAClC;;AAEA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,MAAM;AACN;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA,CAAC;;AAED;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,OAAO;AACP,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,cAAc,MAAM;AACpB,cAAc,OAAO;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,cAAc,MAAM;AACpB,cAAc,OAAO;AACrB;AACA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA,mCAAmC;AACnC;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA,oBAAoB,iBAAiB;AACrC;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,iBAAiB;AACrC;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,6BAA6B;AAC7B;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,gBAAgB;AAChB;AACA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,OAAO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,MAAM;AACN;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,OAAO;;AAEP;;AAEA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,2BAA2B;AAC3B;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,wBAAwB,iBAAiB;AACzC;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP,MAAM;AACN;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA,sBAAsB,wBAAwB;AAC9C;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,sBAAsB,sBAAsB;AAC5C;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,sBAAsB;AACtB;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,sBAAsB;AACtB;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,oBAAoB,iBAAiB;AACrC;;AAEA;AACA;AACA;;AAEA;AACA,uCAAuC;;AAEvC;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,0BAA0B;AAC1B;AACA,SAAS;AACT,OAAO;AACP;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA,sBAAsB;AACtB;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,SAAS;AACT,OAAO;;AAEP;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA,sBAAsB,iBAAiB;AACvC;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,sBAAsB,iBAAiB;AACvC;;AAEA;AACA;AACA;AACA;AACA,WAAW;AACX;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA,kCAAkC;AAClC;AACA,OAAO;;AAEP;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;;AAEA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,kCAAkC,QAAQ;AAC1C;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,4BAA4B,GAAG,QAAQ;;AAEvC;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;;AAEA;AACA;AACA;;AAEA,oBAAoB,iBAAiB;AACrC;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA,CAAC;;AAED;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;;AAEA;;AAEA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;;AAEA;AACA;AACA;;AAEA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA,KAAK;AACL;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,+BAA+B;;AAE/B;AACA;AACA;AACA,QAAQ;AACR;AACA,QAAQ;AACR;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,QAAQ;AACR;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA,oBAAoB,6BAA6B;AACjD;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,qCAAqC;;AAErC;AACA,+CAA+C,QAAQ;AACvD;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,kBAAkB;AAClB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,MAAM;AACN;AACA;;AAEA;;AAEA,oBAAoB,sBAAsB;AAC1C;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA,oBAAoB,sBAAsB;AAC1C;;AAEA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA,QAAQ;AACR;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA,uBAAuB,gCAAgC;AACvD;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,iCAAiC;AACjC;;AAEA;AACA,gCAAgC;;AAEhC;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA,MAAM;AACN;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA,gCAAgC;;AAEhC,wCAAwC,OAAO;AAC/C;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;AACA;AACA,OAAO;AACP,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;;AAEA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,KAAK;;AAEL;AACA;AACA,+BAA+B;AAC/B;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,UAAU;AACV,2CAA2C;;AAE3C;AACA,UAAU;AACV,2CAA2C;;AAE3C;AACA,UAAU;AACV,6CAA6C;;AAE7C;AACA,UAAU;AACV,yCAAyC;;AAEzC;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,gCAAgC;AAChC,MAAM;AACN,+BAA+B;AAC/B;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN,sBAAsB,iCAAiC;AACvD;;AAEA;AACA;AACA;AACA;AACA,MAAM;AACN;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,4BAA4B;AAC5B;;AAEA;AACA;AACA;AACA;;AAEA,4BAA4B,qBAAqB;AACjD;;AAEA;AACA;AACA;AACA;AACA,cAAc,MAAM;AACpB,cAAc,OAAO;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,cAAc,MAAM;AACpB,cAAc,OAAO;AACrB;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,4BAA4B;AAC5B;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,MAAM;AACN;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,iDAAiD;;AAEjD;AACA,SAAS;;AAET;AACA,QAAQ;AACR;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,SAAS;;AAET;AACA;AACA;AACA;;AAEA;AACA,QAAQ;AACR;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,CAAC;;;;;;;;;;;;AC39LY;;AAEb;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA,kEAAkE;AAClE;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;;AAEA;AACA,eAAe,qBAAqB;AACpC;AACA;AACA;;AAEA;;AAEA,kBAAkB,4BAA4B;AAC9C;AACA;AACA;AACA;AACA,KAAK;AACL,GAAG;AACH,CAAC;;AAED;;;;;;;;;;;AC3HA;;AAEA;AACA,MAAM,IAA0C;AAChD,IAAI,iCAAO,EAAE,oCAAE,OAAO;AAAA;AAAA;AAAA,kGAAC;AACvB,IAAI,KAAK,EAIN;AACH,CAAC;;AAED;;AAEA,kCAAkC,2CAA2C,gBAAgB,kBAAkB,OAAO,2BAA2B,wDAAwD,gCAAgC,uDAAuD,+DAA+D,yDAAyD,qEAAqE,6DAA6D,wBAAwB;;AAEljB,kDAAkD,0CAA0C;;AAE5F;AACA;AACA,iBAAiB;AACjB;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;;AAEA;AACA,kEAAkE;AAClE;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,MAAM;;AAEN;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;;AAEA,qBAAqB;AACrB;AACA;;AAEA;AACA,qEAAqE;;AAErE;;AAEA;;AAEA;AACA;AACA;AACA,eAAe;AACf;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;AACJ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL,IAAI;AACJ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA;AACA;AACA;AACA,GAAG;AACH;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,kCAAkC,wCAAwC;AAC1E;AACA,GAAG;AACH;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;;AAEA,2FAA2F,aAAa;AACxG;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;AACA,GAAG;;AAEH;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,oCAAoC,iCAAiC,eAAe,eAAe,gBAAgB,oBAAoB,MAAM,0CAA0C,+BAA+B,aAAa,qBAAqB,uCAAuC,cAAc,WAAW,YAAY,UAAU,MAAM,2CAA2C,UAAU,sBAAsB,eAAe,2BAA2B,0BAA0B,cAAc,2CAA2C,gCAAgC,OAAO,mFAAmF;;AAEtpB,kCAAkC,2CAA2C,gBAAgB,kBAAkB,OAAO,2BAA2B,wDAAwD,gCAAgC,uDAAuD,+DAA+D,yDAAyD,qEAAqE,6DAA6D,wBAAwB;;AAEljB,yCAAyC,mBAAmB,4BAA4B,kDAAkD,gBAAgB,kDAAkD,8DAA8D,0BAA0B,4CAA4C,uBAAuB,oBAAoB,OAAO,cAAc,gBAAgB,gBAAgB,eAAe,2BAA2B,wBAAwB,4BAA4B,qBAAqB,OAAO,uBAAuB,4BAA4B,oBAAoB;;AAEjnB,kDAAkD,0CAA0C;;AAE5F,2CAA2C,+DAA+D,uGAAuG,yEAAyE,eAAe,0EAA0E,GAAG;;AAEtX;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,kBAAkB,uBAAuB;AACzC;AACA;AACA;AACA;AACA;AACA,CAAC;;AAED;;AAEA;AACA;AACA;AACA,GAAG;AACH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;AACA,CAAC;;AAED;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,WAAW;AACX;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,WAAW;AACX;;AAEA;AACA,cAAc;;AAEd,qEAAqE,aAAa;AAClF;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,GAAG;;AAEH;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA,WAAW;AACX;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA,QAAQ;AACR;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA,qBAAqB;AACrB,YAAY;AACZ;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;AACA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,OAAO;AACP;AACA,GAAG;AACH;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA,OAAO;;AAEP;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,QAAQ;AACR,0BAA0B;AAC1B;;AAEA;AACA;AACA,OAAO;AACP;;AAEA;AACA,qEAAqE,8BAA8B;AACnG;;AAEA,mDAAmD,8BAA8B;AACjF;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA,sBAAsB,+BAA+B;AACrD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA,UAAU;AACV;AACA,UAAU;AACV;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;;AAET;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,WAAW;AACX;AACA;AACA,WAAW;AACX;AACA;;AAEA;AACA;AACA;AACA,WAAW;;AAEX;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;;AAEA;AACA;;AAEA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,GAAG;AACH;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;;AAEA,0BAA0B,yBAAyB;AACnD;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,kBAAkB;;AAElB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,QAAQ;AACR;AACA;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;AACA,aAAa;AACb;;AAEA;AACA;AACA,SAAS;AACT,QAAQ;AACR;AACA,qBAAqB,uBAAuB;AAC5C;;AAEA;AACA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA;AACA,GAAG;;AAEH;AACA,CAAC;;AAED;;AAEA;;AAEA;AACA;;AAEA;;AAEA,oCAAoC,iCAAiC,eAAe,eAAe,gBAAgB,oBAAoB,MAAM,0CAA0C,+BAA+B,aAAa,qBAAqB,uCAAuC,cAAc,WAAW,YAAY,UAAU,MAAM,2CAA2C,UAAU,sBAAsB,eAAe,2BAA2B,0BAA0B,cAAc,2CAA2C,gCAAgC,OAAO,mFAAmF;;AAEtpB;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA,IAAI;AACJ;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA,OAAO;AACP,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;;AAEA,+BAA+B;AAC/B,+BAA+B;;AAE/B;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA,QAAQ;AACR;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,SAAS;AACT,QAAQ;AACR;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,UAAU;AACV;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA;AACA,YAAY;AACZ;AACA;;AAEA;AACA;AACA;AACA,WAAW;AACX,SAAS;AACT;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,SAAS;AACT;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL,aAAa;AACb;AACA,CAAC;AACD;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA;AACA,KAAK;;AAEL;AACA;AACA,CAAC;AACD;;AAEA;;AAEA,oCAAoC,iCAAiC,eAAe,eAAe,gBAAgB,oBAAoB,MAAM,0CAA0C,+BAA+B,aAAa,qBAAqB,uCAAuC,cAAc,WAAW,YAAY,UAAU,MAAM,2CAA2C,UAAU,sBAAsB,eAAe,2BAA2B,0BAA0B,cAAc,2CAA2C,gCAAgC,OAAO,mFAAmF;;AAEtpB;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,8CAA8C,sBAAsB;AACpE;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;;AAEA;AACA;;AAEA;AACA;AACA,MAAM;AACN;AACA;AACA;;AAEA;AACA;;AAEA,aAAa;AACb;AACA,CAAC;AACD;;AAEA,CAAC;;;;;;;;;;;;AC3xDD;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,CAAC,UAASA,CAAC,EAAC;EAER,IAAIC,aAAa,GAAS,EAAE;IACxBC,mBAAmB,GAAG,EAAE;IACxBC,mBAAmB,GAAG,EAAE;IACxBC,mBAAmB,GAAG,EAAE;IACxBC,kBAAkB,GAAI,IAAI;;EAE9B;AACJ;AACA;AACA;AACA;EACI,IAAIC,OAAO,GAAG;IAEV;AACR;AACA;AACA;AACA;AACA;AACA;AACA;IACQC,IAAI,EAAE,SAAAA,KAASC,OAAO,EAAEC,SAAS,EACjC;MACI,IAAIC,QAAQ,GAAGV,CAAC,CAACW,MAAM,CAAC;QACpB,MAAM,EAAE,OAAO;QACf,iBAAiB,EAAE,IAAI;QACvB,gBAAgB,EAAE,IAAI;QACtB,gBAAgB,EAAE,EAAE;QACpB,WAAW,EAAE,IAAI;QACjB,WAAW,EAAE,IAAI;QACjB,SAAS,EAAI,IAAI;QACjB,cAAc,EAAE,IAAI;QACpB,wBAAwB,EAAE,EAAE;QAC5B,qBAAqB,EAAE,SAAAC,oBAASC,iBAAiB,EAAE,CAAE;MACzD,CAAC,EAAEL,OAAO,CAAC;MAEX,KAAI,IAAIM,CAAC,GAAG,EAAE,EAAEA,CAAC,GAAG,EAAE,EAAEA,CAAC,EAAE,EAAE;QACzBb,aAAa,CAACc,IAAI,CAACD,CAAC,CAAC;MACzB;MAEA,KAAIA,CAAC,GAAG,EAAE,EAAEA,CAAC,GAAG,EAAE,EAAEA,CAAC,EAAE,EAAE;QACrBZ,mBAAmB,CAACa,IAAI,CAACD,CAAC,CAAC;MAC/B;MAEA,KAAIA,CAAC,GAAG,EAAE,EAAEA,CAAC,GAAG,GAAG,EAAEA,CAAC,EAAE,EAAE;QACtBX,mBAAmB,CAACY,IAAI,CAACD,CAAC,CAAC;MAC/B;MAEAV,mBAAmB,GAAG,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,CAAC,CAACY,MAAM,CAACN,QAAQ,CAACO,sBAAsB,CAAC;MAEpI,OAAO,IAAI,CAACC,IAAI,CAAC,YAAU;QAEvBb,kBAAkB,GAAGL,CAAC,CAAC,IAAI,CAAC;QAE5BK,kBAAkB,CAACc,IAAI,CAACT,QAAQ,CAACS,IAAI,EAAE,UAASC,CAAC,EAAC;UAC9CA,CAAC,CAACC,cAAc,CAAC,CAAC;UAClBf,OAAO,CAACgB,gBAAgB,CAACZ,QAAQ,CAAC;QACtC,CAAC,CAAC;MAEN,CAAC,CAAC;IACN,CAAC;IAED;AACR;AACA;AACA;AACA;IACQY,gBAAgB,EAAE,SAAAA,iBAASZ,QAAQ,EACnC;MACI,IAAIa,QAAQ,GAAG,IAAIC,KAAK,CAAC,CAAC;QACtBC,UAAU,GAAGf,QAAQ,CAACgB,SAAS,GAAGhB,QAAQ,CAACiB,SAAS,GAAGjB,QAAQ,CAACkB,OAAO,GAAGlB,QAAQ,CAACmB,YAAY;QAC/FC,QAAQ,GAAG,CAAC;QACZC,gBAAgB,GAAG,IAAIP,KAAK,CAAC,CAAC;MAElC,IAAIQ,YAAY,GAAGC,IAAI,CAACC,KAAK,CAACxB,QAAQ,CAACyB,cAAc,GAAGV,UAAU,CAAC;MAEnE,IAAGf,QAAQ,CAACgB,SAAS,EAAE;QACnB;QACA,KAAI,IAAIZ,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGkB,YAAY,EAAElB,CAAC,EAAE,EAAE;UAClCS,QAAQ,CAACR,IAAI,CAACqB,MAAM,CAACC,YAAY,CAACnC,mBAAmB,CAACoC,kBAAkB,CAAC,CAAC,EAAEpC,mBAAmB,CAACqC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClH;QAEAR,gBAAgB,GAAGA,gBAAgB,CAACf,MAAM,CAACd,mBAAmB,CAAC;QAE/D4B,QAAQ,EAAE;MACd;MAEA,IAAGpB,QAAQ,CAACkB,OAAO,EAAE;QACjB;QACA,KAAI,IAAId,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGkB,YAAY,EAAElB,CAAC,EAAE,EAAE;UAClCS,QAAQ,CAACR,IAAI,CAACqB,MAAM,CAACC,YAAY,CAACpC,aAAa,CAACqC,kBAAkB,CAAC,CAAC,EAAErC,aAAa,CAACsC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACtG;QAEAR,gBAAgB,GAAGA,gBAAgB,CAACf,MAAM,CAACf,aAAa,CAAC;QAEzD6B,QAAQ,EAAE;MACd;MAEA,IAAGpB,QAAQ,CAACmB,YAAY,EAAE;QACtB;QACA,KAAI,IAAIf,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGkB,YAAY,EAAElB,CAAC,EAAE,EAAE;UAClCS,QAAQ,CAACR,IAAI,CAACqB,MAAM,CAACC,YAAY,CAACjC,mBAAmB,CAACkC,kBAAkB,CAAC,CAAC,EAAElC,mBAAmB,CAACmC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClH;QAEAR,gBAAgB,GAAGA,gBAAgB,CAACf,MAAM,CAACZ,mBAAmB,CAAC;QAE/D0B,QAAQ,EAAE;MACd;MAEA,IAAIU,QAAQ,GAAG9B,QAAQ,CAACyB,cAAc,GAAIL,QAAQ,GAAGE,YAAa;MAElE,IAAGtB,QAAQ,CAACiB,SAAS,EAAE;QAEnB,KAAI,IAAIb,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG0B,QAAQ,EAAE1B,CAAC,EAAE,EAAE;UAC9BS,QAAQ,CAACR,IAAI,CAACqB,MAAM,CAACC,YAAY,CAAClC,mBAAmB,CAACmC,kBAAkB,CAAC,CAAC,EAAEnC,mBAAmB,CAACoC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAClH;MAEJ,CAAC,MAAM;QAEH,KAAI,IAAIzB,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG0B,QAAQ,EAAE1B,CAAC,EAAE,EAAE;UAC9BS,QAAQ,CAACR,IAAI,CAACqB,MAAM,CAACC,YAAY,CAACN,gBAAgB,CAACO,kBAAkB,CAAC,CAAC,EAAEP,gBAAgB,CAACQ,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5G;MACJ;MAEAhB,QAAQ,GAAGkB,OAAO,CAAClB,QAAQ,CAAC,CAACmB,IAAI,CAAC,EAAE,CAAC;MAErC,IAAGhC,QAAQ,CAACiC,eAAe,KAAK,IAAI,EAAE;QAClC3C,CAAC,CAACU,QAAQ,CAACiC,eAAe,CAAC,CAACC,GAAG,CAACrB,QAAQ,CAAC;MAC7C;MAEA,IAAGb,QAAQ,CAACmC,cAAc,KAAK,IAAI,EAAE;QACjC,IAAG7C,CAAC,CAACU,QAAQ,CAACmC,cAAc,CAAC,CAACC,EAAE,CAAC,OAAO,CAAC,EAAE;UACvC9C,CAAC,CAACU,QAAQ,CAACmC,cAAc,CAAC,CAACD,GAAG,CAACrB,QAAQ,CAAC;QAC5C,CAAC,MAAM;UACHvB,CAAC,CAACU,QAAQ,CAACmC,cAAc,CAAC,CAACE,IAAI,CAACxB,QAAQ,CAAC;QAC7C;MACJ;MAEAb,QAAQ,CAACE,mBAAmB,CAACW,QAAQ,CAAC;IAC1C;EACJ,CAAC;;EAED;AACJ;AACA;AACA;AACA;AACA;AACA;EACI,SAASkB,OAAOA,CAACO,CAAC,EAClB;IACI,KAAI,IAAIC,CAAC,EAAEC,CAAC,EAAEpC,CAAC,GAAGkC,CAAC,CAACT,MAAM,EAAEzB,CAAC,EAAEmC,CAAC,GAAGE,QAAQ,CAAClB,IAAI,CAACmB,MAAM,CAAC,CAAC,GAAGtC,CAAC,CAAC,EAAEoC,CAAC,GAAGF,CAAC,CAAC,EAAElC,CAAC,CAAC,EAAEkC,CAAC,CAAClC,CAAC,CAAC,GAAGkC,CAAC,CAACC,CAAC,CAAC,EAAED,CAAC,CAACC,CAAC,CAAC,GAAGC,CAAC,CAAC;IAElG,OAAOF,CAAC;EACZ;;EAEA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACI,SAASV,kBAAkBA,CAACe,IAAI,EAAEC,EAAE,EACpC;IACI,OAAOrB,IAAI,CAACC,KAAK,CAACD,IAAI,CAACmB,MAAM,CAAC,CAAC,IAAEE,EAAE,GAACD,IAAI,GAAC,CAAC,CAAC,GAACA,IAAI,CAAC;EACrD;;EAEA;AACJ;AACA;AACA;AACA;AACA;EACIrD,CAAC,CAACuD,EAAE,CAACC,UAAU,GAAG,UAASC,MAAM,EACjC;IACI,IAAInD,OAAO,CAACmD,MAAM,CAAC,EAAE;MACjB,OAAOnD,OAAO,CAACmD,MAAM,CAAC,CAACC,KAAK,CAAC,IAAI,EAAElC,KAAK,CAACmC,SAAS,CAACC,KAAK,CAACC,IAAI,CAACC,SAAS,EAAE,CAAC,CAAC,CAAC;IAChF,CAAC,MACI,IAAIC,OAAA,CAAON,MAAM,MAAK,QAAQ,IAAI,CAACA,MAAM,EAAE;MAC5C,OAAOnD,OAAO,CAACC,IAAI,CAACmD,KAAK,CAAC,IAAI,EAAEI,SAAS,CAAC;IAC9C,CAAC,MACI;MACD9D,CAAC,CAACgE,KAAK,CAAE,SAAS,GAAIP,MAAM,GAAG,sCAAuC,CAAC;IAC3E;EACJ,CAAC;AAEL,CAAC,EAAEQ,MAAM,CAAC;;;;;;;;;;;ACtMT,WAAUC,IAAI,EAAEC,OAAO,EAAE;EACxB,IAAI,IAA0C,EAAE;IAC9C;IACAC,iCAAO,EAAE,mCAAE,YAAY;MACrB,OAAQF,IAAI,CAAC,cAAc,CAAC,GAAGC,OAAO,CAAC,CAAC;IAC1C,CAAC;AAAA,kGAAC;EACJ,CAAC,MAAM,EAON;AACH,CAAC,EAAC,IAAI,EAAE,YAAY;EAEpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;EACA,IAAIK,YAAY,GAAI,UAAUC,QAAQ,EAAE;IACpC,YAAY;;IAEZ,IAAID,YAAY,GAAG,SAAfA,YAAYA,CAAaE,MAAM,EAAElE,OAAO,EAAE;MAC1C,IAAImE,IAAI,GAAG,IAAI;QACXC,IAAI,GAAGpE,OAAO,IAAI,CAAC,CAAC;MAExB,IAAI,CAACqE,oBAAoB,GAAGD,IAAI,CAACC,oBAAoB,IAAI,GAAG;MAC5D,IAAI,CAACC,QAAQ,GAAGF,IAAI,CAACE,QAAQ,IAAI,GAAG;MACpC,IAAI,CAACC,QAAQ,GAAGH,IAAI,CAACG,QAAQ,IAAI,GAAG;MACpC,IAAI,CAACC,OAAO,GAAGJ,IAAI,CAACI,OAAO,IAAI,YAAY;QACvC,OAAO,CAAC,IAAI,CAACF,QAAQ,GAAG,IAAI,CAACC,QAAQ,IAAI,CAAC;MAC9C,CAAC;MACD,IAAI,CAACE,QAAQ,GAAGL,IAAI,CAACK,QAAQ,IAAI,OAAO;MACxC,IAAI,CAACC,eAAe,GAAGN,IAAI,CAACM,eAAe,IAAI,eAAe;MAC9D,IAAI,CAACC,KAAK,GAAGP,IAAI,CAACO,KAAK;MACvB,IAAI,CAACC,OAAO,GAAGR,IAAI,CAACQ,OAAO;MAE3B,IAAI,CAACC,OAAO,GAAGX,MAAM;MACrB,IAAI,CAACY,IAAI,GAAGZ,MAAM,CAACa,UAAU,CAAC,IAAI,CAAC;MACnC,IAAI,CAACC,KAAK,CAAC,CAAC;;MAEZ;MACA;MACA,IAAI,CAACC,gBAAgB,GAAG,UAAUC,KAAK,EAAE;QACrC,IAAIA,KAAK,CAACC,KAAK,KAAK,CAAC,EAAE;UACnBhB,IAAI,CAACiB,gBAAgB,GAAG,IAAI;UAC5BjB,IAAI,CAACkB,YAAY,CAACH,KAAK,CAAC;QAC5B;MACJ,CAAC;MAED,IAAI,CAACI,gBAAgB,GAAG,UAAUJ,KAAK,EAAE;QACrC,IAAIf,IAAI,CAACiB,gBAAgB,EAAE;UACvBjB,IAAI,CAACoB,aAAa,CAACL,KAAK,CAAC;QAC7B;MACJ,CAAC;MAED,IAAI,CAACM,cAAc,GAAG,UAAUN,KAAK,EAAE;QACnC,IAAIA,KAAK,CAACC,KAAK,KAAK,CAAC,IAAIhB,IAAI,CAACiB,gBAAgB,EAAE;UAC5CjB,IAAI,CAACiB,gBAAgB,GAAG,KAAK;UAC7BjB,IAAI,CAACsB,UAAU,CAACP,KAAK,CAAC;QAC1B;MACJ,CAAC;MAED,IAAI,CAACQ,iBAAiB,GAAG,UAAUR,KAAK,EAAE;QACtC,IAAIA,KAAK,CAACS,aAAa,CAAC5D,MAAM,IAAI,CAAC,EAAE;UACjC,IAAI6D,KAAK,GAAGV,KAAK,CAACW,cAAc,CAAC,CAAC,CAAC;UACnC1B,IAAI,CAACkB,YAAY,CAACO,KAAK,CAAC;QAC3B;MACL,CAAC;MAED,IAAI,CAACE,gBAAgB,GAAG,UAAUZ,KAAK,EAAE;QACrC;QACAA,KAAK,CAACrE,cAAc,CAAC,CAAC;QAEtB,IAAI+E,KAAK,GAAGV,KAAK,CAACS,aAAa,CAAC,CAAC,CAAC;QAClCxB,IAAI,CAACoB,aAAa,CAACK,KAAK,CAAC;MAC7B,CAAC;MAED,IAAI,CAACG,eAAe,GAAG,UAAUb,KAAK,EAAE;QACpC,IAAIc,gBAAgB,GAAGd,KAAK,CAACe,MAAM,KAAK9B,IAAI,CAACU,OAAO;QACpD,IAAImB,gBAAgB,EAAE;UAClBd,KAAK,CAACrE,cAAc,CAAC,CAAC;UACtBsD,IAAI,CAACsB,UAAU,CAACP,KAAK,CAAC;QAC1B;MACJ,CAAC;MAED,IAAI,CAACgB,kBAAkB,CAAC,CAAC;MACzB,IAAI,CAACC,kBAAkB,CAAC,CAAC;IAC7B,CAAC;IAEDnC,YAAY,CAACb,SAAS,CAAC6B,KAAK,GAAG,YAAY;MACvC,IAAIoB,GAAG,GAAG,IAAI,CAACtB,IAAI;QACfZ,MAAM,GAAG,IAAI,CAACW,OAAO;MAEzBuB,GAAG,CAACC,SAAS,GAAG,IAAI,CAAC3B,eAAe;MACpC0B,GAAG,CAACE,SAAS,CAAC,CAAC,EAAE,CAAC,EAAEpC,MAAM,CAACqC,KAAK,EAAErC,MAAM,CAACsC,MAAM,CAAC;MAChDJ,GAAG,CAACK,QAAQ,CAAC,CAAC,EAAE,CAAC,EAAEvC,MAAM,CAACqC,KAAK,EAAErC,MAAM,CAACsC,MAAM,CAAC;MAC/C,IAAI,CAACE,MAAM,CAAC,CAAC;IACjB,CAAC;IAED1C,YAAY,CAACb,SAAS,CAACwD,SAAS,GAAG,UAAUC,SAAS,EAAEC,OAAO,EAAE;MAC7D,IAAI3C,MAAM,GAAG,IAAI,CAACW,OAAO;MACzB,OAAOX,MAAM,CAACyC,SAAS,CAACzD,KAAK,CAACgB,MAAM,EAAEZ,SAAS,CAAC;IACpD,CAAC;IAEDU,YAAY,CAACb,SAAS,CAAC2D,WAAW,GAAG,UAAUC,OAAO,EAAE;MACpD,IAAI5C,IAAI,GAAG,IAAI;QACX6C,KAAK,GAAG,IAAIC,KAAK,CAAC,CAAC;QACnBC,KAAK,GAAGC,MAAM,CAACC,gBAAgB,IAAI,CAAC;QACpCb,KAAK,GAAG,IAAI,CAAC1B,OAAO,CAAC0B,KAAK,GAAGW,KAAK;QAClCV,MAAM,GAAG,IAAI,CAAC3B,OAAO,CAAC2B,MAAM,GAAGU,KAAK;MAExC,IAAI,CAACR,MAAM,CAAC,CAAC;MACbM,KAAK,CAACK,GAAG,GAAGN,OAAO;MACnBC,KAAK,CAACM,MAAM,GAAG,YAAY;QACvBnD,IAAI,CAACW,IAAI,CAACyC,SAAS,CAACP,KAAK,EAAE,CAAC,EAAE,CAAC,EAAET,KAAK,EAAEC,MAAM,CAAC;MACnD,CAAC;MACD,IAAI,CAACgB,QAAQ,GAAG,KAAK;IACzB,CAAC;IAEDxD,YAAY,CAACb,SAAS,CAACoC,aAAa,GAAG,UAAUL,KAAK,EAAE;MACpD,IAAIuC,KAAK,GAAG,IAAI,CAACC,YAAY,CAACxC,KAAK,CAAC;MACpC,IAAI,CAACyC,SAAS,CAACF,KAAK,CAAC;IACzB,CAAC;IAEDzD,YAAY,CAACb,SAAS,CAACkC,YAAY,GAAG,UAAUH,KAAK,EAAE;MACnD,IAAI,CAACwB,MAAM,CAAC,CAAC;MACb,IAAI,CAACnB,aAAa,CAACL,KAAK,CAAC;MACzB,IAAI,OAAO,IAAI,CAACN,OAAO,KAAK,UAAU,EAAE;QACpC,IAAI,CAACA,OAAO,CAACM,KAAK,CAAC;MACvB;IACJ,CAAC;IAEDlB,YAAY,CAACb,SAAS,CAACyE,WAAW,GAAG,UAAUH,KAAK,EAAE;MAClD,IAAIrB,GAAG,GAAG,IAAI,CAACtB,IAAI;QACfN,OAAO,GAAG,OAAO,IAAI,CAACA,OAAQ,KAAK,UAAU,GAAG,IAAI,CAACA,OAAO,CAAC,CAAC,GAAG,IAAI,CAACA,OAAO;MAEjF4B,GAAG,CAACyB,SAAS,CAAC,CAAC;MACf,IAAI,CAACC,UAAU,CAACL,KAAK,CAAC/E,CAAC,EAAE+E,KAAK,CAACM,CAAC,EAAEvD,OAAO,CAAC;MAC1C4B,GAAG,CAAC4B,SAAS,CAAC,CAAC;MACf5B,GAAG,CAAC6B,IAAI,CAAC,CAAC;IACd,CAAC;IAEDjE,YAAY,CAACb,SAAS,CAACsC,UAAU,GAAG,UAAUP,KAAK,EAAE;MACjD,IAAIgD,YAAY,GAAG,IAAI,CAACC,MAAM,CAACpG,MAAM,GAAG,CAAC;QACrC0F,KAAK,GAAG,IAAI,CAACU,MAAM,CAAC,CAAC,CAAC;MAE1B,IAAI,CAACD,YAAY,IAAIT,KAAK,EAAE;QACxB,IAAI,CAACG,WAAW,CAACH,KAAK,CAAC;MAC3B;MACA,IAAI,OAAO,IAAI,CAAC9C,KAAK,KAAK,UAAU,EAAE;QAClC,IAAI,CAACA,KAAK,CAACO,KAAK,CAAC;MACrB;IACJ,CAAC;IAEDlB,YAAY,CAACb,SAAS,CAAC+C,kBAAkB,GAAG,YAAY;MACpD,IAAI,CAACd,gBAAgB,GAAG,KAAK;MAE7B,IAAI,CAACP,OAAO,CAACuD,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAACnD,gBAAgB,CAAC;MACjE,IAAI,CAACJ,OAAO,CAACuD,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAAC9C,gBAAgB,CAAC;MACjErB,QAAQ,CAACmE,gBAAgB,CAAC,SAAS,EAAE,IAAI,CAAC5C,cAAc,CAAC;IAC7D,CAAC;IAEDxB,YAAY,CAACb,SAAS,CAACgD,kBAAkB,GAAG,YAAY;MACpD;MACA,IAAI,CAACtB,OAAO,CAACwD,KAAK,CAACC,aAAa,GAAG,MAAM;MACzC,IAAI,CAACzD,OAAO,CAACwD,KAAK,CAACE,WAAW,GAAG,MAAM;MAEvC,IAAI,CAAC1D,OAAO,CAACuD,gBAAgB,CAAC,YAAY,EAAE,IAAI,CAAC1C,iBAAiB,CAAC;MACnE,IAAI,CAACb,OAAO,CAACuD,gBAAgB,CAAC,WAAW,EAAE,IAAI,CAACtC,gBAAgB,CAAC;MACjE,IAAI,CAACjB,OAAO,CAACuD,gBAAgB,CAAC,UAAU,EAAE,IAAI,CAACrC,eAAe,CAAC;IACnE,CAAC;IAED/B,YAAY,CAACb,SAAS,CAACqF,EAAE,GAAG,YAAY;MACpC,IAAI,CAACtC,kBAAkB,CAAC,CAAC;MACzB,IAAI,CAACC,kBAAkB,CAAC,CAAC;IAC7B,CAAC;IAEDnC,YAAY,CAACb,SAAS,CAACsF,GAAG,GAAG,YAAY;MACrC,IAAI,CAAC5D,OAAO,CAAC6D,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAACzD,gBAAgB,CAAC;MACpE,IAAI,CAACJ,OAAO,CAAC6D,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAACpD,gBAAgB,CAAC;MACpErB,QAAQ,CAACyE,mBAAmB,CAAC,SAAS,EAAE,IAAI,CAAClD,cAAc,CAAC;MAE5D,IAAI,CAACX,OAAO,CAAC6D,mBAAmB,CAAC,YAAY,EAAE,IAAI,CAAChD,iBAAiB,CAAC;MACtE,IAAI,CAACb,OAAO,CAAC6D,mBAAmB,CAAC,WAAW,EAAE,IAAI,CAAC5C,gBAAgB,CAAC;MACpE,IAAI,CAACjB,OAAO,CAAC6D,mBAAmB,CAAC,UAAU,EAAE,IAAI,CAAC3C,eAAe,CAAC;IACtE,CAAC;IAED/B,YAAY,CAACb,SAAS,CAACwF,OAAO,GAAG,YAAY;MACzC,OAAO,IAAI,CAACnB,QAAQ;IACxB,CAAC;IAEDxD,YAAY,CAACb,SAAS,CAACuD,MAAM,GAAG,YAAY;MACxC,IAAI,CAACyB,MAAM,GAAG,EAAE;MAChB,IAAI,CAACS,aAAa,GAAG,CAAC;MACtB,IAAI,CAACC,UAAU,GAAG,CAAC,IAAI,CAACvE,QAAQ,GAAG,IAAI,CAACC,QAAQ,IAAI,CAAC;MACrD,IAAI,CAACiD,QAAQ,GAAG,IAAI;MACpB,IAAI,CAAC1C,IAAI,CAACuB,SAAS,GAAG,IAAI,CAAC5B,QAAQ;IACvC,CAAC;IAEDT,YAAY,CAACb,SAAS,CAACuE,YAAY,GAAG,UAAUxC,KAAK,EAAE;MACnD,IAAI4D,IAAI,GAAG,IAAI,CAACjE,OAAO,CAACkE,qBAAqB,CAAC,CAAC;MAC/C,OAAO,IAAIC,KAAK,CACZ9D,KAAK,CAAC+D,OAAO,GAAGH,IAAI,CAACI,IAAI,EACzBhE,KAAK,CAACiE,OAAO,GAAGL,IAAI,CAACM,GACzB,CAAC;IACL,CAAC;IAEDpF,YAAY,CAACb,SAAS,CAACwE,SAAS,GAAG,UAAUF,KAAK,EAAE;MAChD,IAAIU,MAAM,GAAG,IAAI,CAACA,MAAM;QACpBkB,EAAE;QAAEC,EAAE;QACNC,KAAK;QAAEC,GAAG;MAEdrB,MAAM,CAAC5H,IAAI,CAACkH,KAAK,CAAC;MAElB,IAAIU,MAAM,CAACpG,MAAM,GAAG,CAAC,EAAE;QACnB;QACA;QACA,IAAIoG,MAAM,CAACpG,MAAM,KAAK,CAAC,EAAEoG,MAAM,CAACsB,OAAO,CAACtB,MAAM,CAAC,CAAC,CAAC,CAAC;QAElDqB,GAAG,GAAG,IAAI,CAACE,4BAA4B,CAACvB,MAAM,CAAC,CAAC,CAAC,EAAEA,MAAM,CAAC,CAAC,CAAC,EAAEA,MAAM,CAAC,CAAC,CAAC,CAAC;QACxEkB,EAAE,GAAGG,GAAG,CAACH,EAAE;QACXG,GAAG,GAAG,IAAI,CAACE,4BAA4B,CAACvB,MAAM,CAAC,CAAC,CAAC,EAAEA,MAAM,CAAC,CAAC,CAAC,EAAEA,MAAM,CAAC,CAAC,CAAC,CAAC;QACxEmB,EAAE,GAAGE,GAAG,CAACG,EAAE;QACXJ,KAAK,GAAG,IAAIK,MAAM,CAACzB,MAAM,CAAC,CAAC,CAAC,EAAEkB,EAAE,EAAEC,EAAE,EAAEnB,MAAM,CAAC,CAAC,CAAC,CAAC;QAChD,IAAI,CAAC0B,SAAS,CAACN,KAAK,CAAC;;QAErB;QACA;QACApB,MAAM,CAAC2B,KAAK,CAAC,CAAC;MAClB;IACJ,CAAC;IAED9F,YAAY,CAACb,SAAS,CAACuG,4BAA4B,GAAG,UAAUK,EAAE,EAAEC,EAAE,EAAEC,EAAE,EAAE;MACxE,IAAIC,GAAG,GAAGH,EAAE,CAACrH,CAAC,GAAGsH,EAAE,CAACtH,CAAC;QAAEyH,GAAG,GAAGJ,EAAE,CAAChC,CAAC,GAAGiC,EAAE,CAACjC,CAAC;QACpCqC,GAAG,GAAGJ,EAAE,CAACtH,CAAC,GAAGuH,EAAE,CAACvH,CAAC;QAAE2H,GAAG,GAAGL,EAAE,CAACjC,CAAC,GAAGkC,EAAE,CAAClC,CAAC;QAEpCuC,EAAE,GAAG;UAAC5H,CAAC,EAAE,CAACqH,EAAE,CAACrH,CAAC,GAAGsH,EAAE,CAACtH,CAAC,IAAI,GAAG;UAAEqF,CAAC,EAAE,CAACgC,EAAE,CAAChC,CAAC,GAAGiC,EAAE,CAACjC,CAAC,IAAI;QAAG,CAAC;QACrDwC,EAAE,GAAG;UAAC7H,CAAC,EAAE,CAACsH,EAAE,CAACtH,CAAC,GAAGuH,EAAE,CAACvH,CAAC,IAAI,GAAG;UAAEqF,CAAC,EAAE,CAACiC,EAAE,CAACjC,CAAC,GAAGkC,EAAE,CAAClC,CAAC,IAAI;QAAG,CAAC;QAErDyC,EAAE,GAAG/I,IAAI,CAACgJ,IAAI,CAACP,GAAG,GAACA,GAAG,GAAGC,GAAG,GAACA,GAAG,CAAC;QACjCO,EAAE,GAAGjJ,IAAI,CAACgJ,IAAI,CAACL,GAAG,GAACA,GAAG,GAAGC,GAAG,GAACA,GAAG,CAAC;QAEjCM,GAAG,GAAIL,EAAE,CAAC5H,CAAC,GAAG6H,EAAE,CAAC7H,CAAE;QACnBkI,GAAG,GAAIN,EAAE,CAACvC,CAAC,GAAGwC,EAAE,CAACxC,CAAE;QAEnB8C,CAAC,GAAGH,EAAE,IAAIF,EAAE,GAAGE,EAAE,CAAC;QAClBI,EAAE,GAAG;UAACpI,CAAC,EAAE6H,EAAE,CAAC7H,CAAC,GAAGiI,GAAG,GAACE,CAAC;UAAE9C,CAAC,EAAEwC,EAAE,CAACxC,CAAC,GAAG6C,GAAG,GAACC;QAAC,CAAC;QAEvCE,EAAE,GAAGf,EAAE,CAACtH,CAAC,GAAGoI,EAAE,CAACpI,CAAC;QAChBsI,EAAE,GAAGhB,EAAE,CAACjC,CAAC,GAAG+C,EAAE,CAAC/C,CAAC;MAEpB,OAAO;QACH4B,EAAE,EAAE,IAAIX,KAAK,CAACsB,EAAE,CAAC5H,CAAC,GAAGqI,EAAE,EAAET,EAAE,CAACvC,CAAC,GAAGiD,EAAE,CAAC;QACnC3B,EAAE,EAAE,IAAIL,KAAK,CAACuB,EAAE,CAAC7H,CAAC,GAAGqI,EAAE,EAAER,EAAE,CAACxC,CAAC,GAAGiD,EAAE;MACtC,CAAC;IACL,CAAC;IAEDhH,YAAY,CAACb,SAAS,CAAC0G,SAAS,GAAG,UAAUN,KAAK,EAAE;MAChD,IAAI0B,UAAU,GAAG1B,KAAK,CAAC0B,UAAU;QAC7BC,QAAQ,GAAG3B,KAAK,CAAC2B,QAAQ;QACzBC,QAAQ;QAAEC,QAAQ;MAEtBD,QAAQ,GAAGD,QAAQ,CAACG,YAAY,CAACJ,UAAU,CAAC;MAC5CE,QAAQ,GAAG,IAAI,CAAC9G,oBAAoB,GAAG8G,QAAQ,GACzC,CAAC,CAAC,GAAG,IAAI,CAAC9G,oBAAoB,IAAI,IAAI,CAACuE,aAAa;MAE1DwC,QAAQ,GAAG,IAAI,CAACE,YAAY,CAACH,QAAQ,CAAC;MACtC,IAAI,CAACI,UAAU,CAAChC,KAAK,EAAE,IAAI,CAACV,UAAU,EAAEuC,QAAQ,CAAC;MAEjD,IAAI,CAACxC,aAAa,GAAGuC,QAAQ;MAC7B,IAAI,CAACtC,UAAU,GAAGuC,QAAQ;IAC9B,CAAC;IAEDpH,YAAY,CAACb,SAAS,CAAC2E,UAAU,GAAG,UAAUpF,CAAC,EAAEqF,CAAC,EAAEyD,IAAI,EAAE;MACtD,IAAIpF,GAAG,GAAG,IAAI,CAACtB,IAAI;MAEnBsB,GAAG,CAACqF,MAAM,CAAC/I,CAAC,EAAEqF,CAAC,CAAC;MAChB3B,GAAG,CAACsF,GAAG,CAAChJ,CAAC,EAAEqF,CAAC,EAAEyD,IAAI,EAAE,CAAC,EAAE,CAAC,GAAG/J,IAAI,CAACkK,EAAE,EAAE,KAAK,CAAC;MAC1C,IAAI,CAACnE,QAAQ,GAAG,KAAK;IACzB,CAAC;IAEDxD,YAAY,CAACb,SAAS,CAACoI,UAAU,GAAG,UAAUhC,KAAK,EAAEqC,UAAU,EAAEC,QAAQ,EAAE;MACvE,IAAIzF,GAAG,GAAG,IAAI,CAACtB,IAAI;QACfgH,UAAU,GAAGD,QAAQ,GAAGD,UAAU;QAClCG,SAAS;QAAExF,KAAK;QAAEjG,CAAC;QAAE0L,CAAC;QAAEC,EAAE;QAAEC,GAAG;QAAEC,CAAC;QAAEC,EAAE;QAAEC,GAAG;QAAE3J,CAAC;QAAEqF,CAAC;MAErDgE,SAAS,GAAGtK,IAAI,CAACC,KAAK,CAAC6H,KAAK,CAACxH,MAAM,CAAC,CAAC,CAAC;MACtCqE,GAAG,CAACyB,SAAS,CAAC,CAAC;MACf,KAAKvH,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAGyL,SAAS,EAAEzL,CAAC,EAAE,EAAE;QAC5B;QACA0L,CAAC,GAAG1L,CAAC,GAAGyL,SAAS;QACjBE,EAAE,GAAGD,CAAC,GAAGA,CAAC;QACVE,GAAG,GAAGD,EAAE,GAAGD,CAAC;QACZG,CAAC,GAAG,CAAC,GAAGH,CAAC;QACTI,EAAE,GAAGD,CAAC,GAAGA,CAAC;QACVE,GAAG,GAAGD,EAAE,GAAGD,CAAC;QAEZzJ,CAAC,GAAG2J,GAAG,GAAG9C,KAAK,CAAC0B,UAAU,CAACvI,CAAC;QAC5BA,CAAC,IAAI,CAAC,GAAG0J,EAAE,GAAGJ,CAAC,GAAGzC,KAAK,CAAC+C,QAAQ,CAAC5J,CAAC;QAClCA,CAAC,IAAI,CAAC,GAAGyJ,CAAC,GAAGF,EAAE,GAAG1C,KAAK,CAACgD,QAAQ,CAAC7J,CAAC;QAClCA,CAAC,IAAIwJ,GAAG,GAAG3C,KAAK,CAAC2B,QAAQ,CAACxI,CAAC;QAE3BqF,CAAC,GAAGsE,GAAG,GAAG9C,KAAK,CAAC0B,UAAU,CAAClD,CAAC;QAC5BA,CAAC,IAAI,CAAC,GAAGqE,EAAE,GAAGJ,CAAC,GAAGzC,KAAK,CAAC+C,QAAQ,CAACvE,CAAC;QAClCA,CAAC,IAAI,CAAC,GAAGoE,CAAC,GAAGF,EAAE,GAAG1C,KAAK,CAACgD,QAAQ,CAACxE,CAAC;QAClCA,CAAC,IAAImE,GAAG,GAAG3C,KAAK,CAAC2B,QAAQ,CAACnD,CAAC;QAE3BxB,KAAK,GAAGqF,UAAU,GAAGM,GAAG,GAAGJ,UAAU;QACrC,IAAI,CAAChE,UAAU,CAACpF,CAAC,EAAEqF,CAAC,EAAExB,KAAK,CAAC;MAChC;MACAH,GAAG,CAAC4B,SAAS,CAAC,CAAC;MACf5B,GAAG,CAAC6B,IAAI,CAAC,CAAC;IACd,CAAC;IAEDjE,YAAY,CAACb,SAAS,CAACmI,YAAY,GAAG,UAAUH,QAAQ,EAAE;MACtD,OAAO1J,IAAI,CAAC+K,GAAG,CAAC,IAAI,CAACjI,QAAQ,IAAI4G,QAAQ,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC7G,QAAQ,CAAC;IAClE,CAAC;IAGD,IAAI0E,KAAK,GAAG,SAARA,KAAKA,CAAatG,CAAC,EAAEqF,CAAC,EAAE0E,IAAI,EAAE;MAC9B,IAAI,CAAC/J,CAAC,GAAGA,CAAC;MACV,IAAI,CAACqF,CAAC,GAAGA,CAAC;MACV,IAAI,CAAC0E,IAAI,GAAGA,IAAI,IAAI,IAAIC,IAAI,CAAC,CAAC,CAACC,OAAO,CAAC,CAAC;IAC5C,CAAC;IAED3D,KAAK,CAAC7F,SAAS,CAACkI,YAAY,GAAG,UAAUuB,KAAK,EAAE;MAC5C,OAAQ,IAAI,CAACH,IAAI,KAAKG,KAAK,CAACH,IAAI,GAAI,IAAI,CAACI,UAAU,CAACD,KAAK,CAAC,IAAI,IAAI,CAACH,IAAI,GAAGG,KAAK,CAACH,IAAI,CAAC,GAAG,CAAC;IAC7F,CAAC;IAEDzD,KAAK,CAAC7F,SAAS,CAAC0J,UAAU,GAAG,UAAUD,KAAK,EAAE;MAC1C,OAAOnL,IAAI,CAACgJ,IAAI,CAAChJ,IAAI,CAACqL,GAAG,CAAC,IAAI,CAACpK,CAAC,GAAGkK,KAAK,CAAClK,CAAC,EAAE,CAAC,CAAC,GAAGjB,IAAI,CAACqL,GAAG,CAAC,IAAI,CAAC/E,CAAC,GAAG6E,KAAK,CAAC7E,CAAC,EAAE,CAAC,CAAC,CAAC;IACnF,CAAC;IAED,IAAI6B,MAAM,GAAG,SAATA,MAAMA,CAAaqB,UAAU,EAAEqB,QAAQ,EAAEC,QAAQ,EAAErB,QAAQ,EAAE;MAC7D,IAAI,CAACD,UAAU,GAAGA,UAAU;MAC5B,IAAI,CAACqB,QAAQ,GAAGA,QAAQ;MACxB,IAAI,CAACC,QAAQ,GAAGA,QAAQ;MACxB,IAAI,CAACrB,QAAQ,GAAGA,QAAQ;IAC5B,CAAC;;IAED;IACAtB,MAAM,CAACzG,SAAS,CAACpB,MAAM,GAAG,YAAY;MAClC,IAAIgL,KAAK,GAAG,EAAE;QACVhL,MAAM,GAAG,CAAC;QACVzB,CAAC;QAAE0L,CAAC;QAAEgB,EAAE;QAAEC,EAAE;QAAEC,EAAE;QAAEC,EAAE;QAAEC,KAAK;QAAEC,KAAK;MAEtC,KAAK/M,CAAC,GAAG,CAAC,EAAEA,CAAC,IAAIyM,KAAK,EAAEzM,CAAC,EAAE,EAAE;QACzB0L,CAAC,GAAG1L,CAAC,GAAGyM,KAAK;QACbC,EAAE,GAAG,IAAI,CAACM,MAAM,CAACtB,CAAC,EAAE,IAAI,CAACf,UAAU,CAACvI,CAAC,EAAE,IAAI,CAAC4J,QAAQ,CAAC5J,CAAC,EAAE,IAAI,CAAC6J,QAAQ,CAAC7J,CAAC,EAAE,IAAI,CAACwI,QAAQ,CAACxI,CAAC,CAAC;QACzFuK,EAAE,GAAG,IAAI,CAACK,MAAM,CAACtB,CAAC,EAAE,IAAI,CAACf,UAAU,CAAClD,CAAC,EAAE,IAAI,CAACuE,QAAQ,CAACvE,CAAC,EAAE,IAAI,CAACwE,QAAQ,CAACxE,CAAC,EAAE,IAAI,CAACmD,QAAQ,CAACnD,CAAC,CAAC;QACzF,IAAIzH,CAAC,GAAG,CAAC,EAAE;UACP8M,KAAK,GAAGJ,EAAE,GAAGE,EAAE;UACfG,KAAK,GAAGJ,EAAE,GAAGE,EAAE;UACfpL,MAAM,IAAIN,IAAI,CAACgJ,IAAI,CAAC2C,KAAK,GAAGA,KAAK,GAAGC,KAAK,GAAGA,KAAK,CAAC;QACtD;QACAH,EAAE,GAAGF,EAAE;QACPG,EAAE,GAAGF,EAAE;MACX;MACA,OAAOlL,MAAM;IACjB,CAAC;IAED6H,MAAM,CAACzG,SAAS,CAACmK,MAAM,GAAG,UAAUtB,CAAC,EAAEY,KAAK,EAAEjD,EAAE,EAAEN,EAAE,EAAEkE,GAAG,EAAE;MACvD,OAAgBX,KAAK,IAAI,GAAG,GAAGZ,CAAC,CAAC,IAAI,GAAG,GAAGA,CAAC,CAAC,IAAK,GAAG,GAAGA,CAAC,CAAC,GACjD,GAAG,GAAIrC,EAAE,IAAO,GAAG,GAAGqC,CAAC,CAAC,IAAI,GAAG,GAAGA,CAAC,CAAC,GAAIA,CAAC,GACzC,GAAG,GAAI3C,EAAE,IAAO,GAAG,GAAG2C,CAAC,CAAC,GAAGA,CAAC,GAAYA,CAAC,GAClCuB,GAAG,GAAKvB,CAAC,GAAWA,CAAC,GAAYA,CAAC;IACtD,CAAC;IAED,OAAOhI,YAAY;EACvB,CAAC,CAAEC,QAAQ,CAAC;EAEZ,OAAOD,YAAY;AAEnB,CAAC,CAAC;;;;;;;;;;ACpYF,IAAIP,MAAM,GAAG+J,mBAAO,CAAC,oDAAQ,CAAC;AAC9BrG,MAAM,CAAC1D,MAAM,GAAGA,MAAM;AACtB0D,MAAM,CAAC3H,CAAC,GAAGiE,MAAM;;AAEjB;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA+J,mBAAO,CAAC,wDAAW,CAAC,CAAC,CAAC;AACtB/J,MAAM,CAACV,EAAE,CAAC0K,SAAS,GAAGhK,MAAM,CAACV,EAAE,CAAC2K,OAAO;AACvCF,mBAAO,CAAC,qEAAgB,CAAC;AACzBA,mBAAO,CAAC,0DAAS,CAAC;AAClBA,mBAAO,CAAC,mEAAW,CAAC;AACpBA,mBAAO,CAAC,uDAAQ,CAAC;AACjBA,mBAAO,CAAC,gFAAmB,CAAC;AAC5BA,mBAAO,CAAC,kGAAyB,CAAC,CAAC,CAAC;AACpCA,mBAAO,CAAC,uFAAqB,CAAC;AAC9BA,mBAAO,CAAC,oGAAuB,CAAC;AAChCA,mBAAO,CAAC,iGAAsB,CAAC;AAC/BA,mBAAO,CAAC,6EAAe,CAAC,EAAC;AACA;AACA;AACzBA,mBAAO,CAAC,6FAAgC,CAAC,CAAC,CAAC;AAC3C;AACA;AACArG,MAAM,CAACnD,YAAY,GAAGwJ,mBAAO,CAAC,+DAAiB,CAAC,CAAC,CAAC;AAClDA,mBAAO,CAAC,mFAAmB,CAAC;AAC5BrG,MAAM,CAACwG,IAAI,GAAGH,mBAAO,CAAC,oDAAS,CAAC;AAChCrG,MAAM,CAACyG,WAAW,GAAGJ,mBAAO,CAAC,6DAAW,CAAC;AACzC;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEAK,WAAW,GAAG;EAENC,MAAM,EAAE;IACJC,QAAQ,EAAE;EACd,CAAC;EACDC,MAAM,EAAE;IACJC,KAAK,EAAE,CAAC;MACJC,KAAK,EAAE;QACHC,SAAS,EAAE,iBAAiB;QAC5BC,SAAS,EAAE,MAAM;QACjBC,WAAW,EAAE,IAAI;QACjBC,aAAa,EAAE,CAAC;QAChBC,OAAO,EAAE;MACb,CAAC;MACDC,SAAS,EAAE;QACPC,SAAS,EAAE,KAAK;QAChBC,OAAO,EAAE;MACb;IACJ,CAAC,CAAC;IACFC,KAAK,EAAE,CAAC;MACJH,SAAS,EAAE;QACPI,aAAa,EAAE;MACnB,CAAC;MACDV,KAAK,EAAE;QACHK,OAAO,EAAE,EAAE;QACXJ,SAAS,EAAE,iBAAiB;QAC5BC,SAAS,EAAE;MACf;IACJ,CAAC;EACL;AAER,CAAC;AAEDS,UAAU,GAAG;EACT;EACAC,iBAAiB,EAAE,IAAI;EACvB;EACAC,kBAAkB,EAAE,MAAM;EAC1B;EACAC,kBAAkB,EAAE,CAAC;EACrB;EACAC,qBAAqB,EAAE,EAAE;EAAE;EAC3B;EACAC,cAAc,EAAE,GAAG;EACnB;EACAC,eAAe,EAAE,eAAe;EAChC;EACAC,aAAa,EAAE,IAAI;EACnB;EACAC,YAAY,EAAE,KAAK;EACnB;EACAC,UAAU,EAAE,IAAI;EAChB;EACAC,mBAAmB,EAAE,KAAK;EAE1B;EACAC,cAAc,EAAE,8FAA8F,GAC9G,2EAA2E,GAC3E,0EAA0E;EAC1E;EACAC,eAAe,EAAE;AACrB,CAAC;;AAED;AACA;AACA;;AAEA,IAAIC,OAAO,GAAGlQ,CAAC,CAAC,sBAAsB,CAAC,CAACmQ,IAAI,CAAC,SAAS,CAAC;AAIvDnQ,CAAC,CAAC,YAAY;EAEV,IAAIoQ,GAAG,GAAGpQ,CAAC,CAAC,MAAM,CAAC;;EAEnB;;EAEAoQ,GAAG,CAACpH,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,UAAUqH,IAAI,EAAE;IAC9C,IAAIC,QAAQ,GAAGtQ,CAAC,CAAC,IAAI,CAAC;IACtB,IAAIuQ,oBAAoB,GAAGvQ,CAAC,CAAC,sBAAsB,CAAC;IACpD,IAAIwQ,IAAI,GAAGF,QAAQ,CAACH,IAAI,CAAC,MAAM,CAAC;IAChC,IAAIM,OAAO,GAAGH,QAAQ,CAACH,IAAI,CAAC,cAAc,CAAC;IAC3C,IAAIO,KAAK,GAAGJ,QAAQ,CAACH,IAAI,CAAC,YAAY,CAAC;IAEvCnQ,CAAC,CAAC,oBAAoB,CAAC,CAAC+C,IAAI,CAAC2N,KAAK,CAAC;IACnCH,oBAAoB,CAACI,IAAI,CAAC,aAAa,CAAC,CAAC5N,IAAI,CAAC0N,OAAO,CAAC;IACtDzQ,CAAC,CAAC,cAAc,CAAC,CAACmQ,IAAI,CAAC,QAAQ,EAAEK,IAAI,CAAC;IACtCD,oBAAoB,CAACK,KAAK,CAAC;MACvBC,IAAI,EAAE;IACV,CAAC,CAAC;IACF,OAAO,KAAK;EAChB,CAAC,CAAC;;EAEF;EACAT,GAAG,CAACpH,EAAE,CAAC,OAAO,EAAE,eAAe,EAAE,UAAUqH,IAAI,EAAE;IAC7C,IAAIC,QAAQ,GAAGtQ,CAAC,CAAC,IAAI,CAAC;IACtB,IAAI8Q,iBAAiB,GAAG9Q,CAAC,CAAC,mBAAmB,CAAC;IAC9C,IAAIwQ,IAAI,GAAGF,QAAQ,CAACH,IAAI,CAAC,MAAM,CAAC;IAChC,IAAIM,OAAO,GAAGH,QAAQ,CAACH,IAAI,CAAC,cAAc,CAAC;IAC3C,IAAIY,UAAU,GAAGT,QAAQ,CAACH,IAAI,CAAC,WAAW,CAAC;IAC3C,IAAIO,KAAK,GAAGJ,QAAQ,CAACH,IAAI,CAAC,YAAY,CAAC;;IAEvC;IACAnQ,CAAC,CAAC,aAAa,CAAC,CAACmQ,IAAI,CAAC,QAAQ,EAAEK,IAAI,CAAC;IACrCM,iBAAiB,CAACH,IAAI,CAAC,oBAAoB,CAAC,CAACK,QAAQ,CAACD,UAAU,CAAC;IACjED,iBAAiB,CAACH,IAAI,CAAC,cAAc,CAAC,CAAC5N,IAAI,CAAC2N,KAAK,CAAC,CAACO,OAAO,CAAC,eAAe,GAAGF,UAAU,GAAG,SAAS,CAAC;IACpGD,iBAAiB,CAACH,IAAI,CAAC,aAAa,CAAC,CAAC5N,IAAI,CAAC0N,OAAO,CAAC;IACnDK,iBAAiB,CAACX,IAAI,CAAC,QAAQ,EAAEK,IAAI,CAAC;;IAEtC;IACAM,iBAAiB,CAACF,KAAK,CAAC;MACpBC,IAAI,EAAE;IACV,CAAC,CAAC;IACF,OAAO,KAAK;EAChB,CAAC,CAAC;;EAID;AACL;AACA;;EAEQ7Q,CAAC,CAAC,kDAAkD,CAAC,CAACkB,IAAI,CAAC,UAAUJ,CAAC,EAACoQ,GAAG,EAAE;IACxE;MACIlR,CAAC,CAACkR,GAAG,CAAC,CAACC,OAAO,CAAC,CAAC;IACpB;EACJ,CAAC,CAAC;;EAGN;EACA;EACA;EACA;;EAEA;EACAnR,CAAC,CAAC,eAAe,CAAC,CAACkB,IAAI,CAAE,UAAUJ,CAAC,EAACsQ,IAAI,EAAE;IACvC,IAAIC,IAAI,GAAGrR,CAAC,CAACoR,IAAI,CAAC;IAClB,IAAIE,QAAQ,GAAGD,IAAI,CAACE,IAAI,CAAC,UAAU,CAAC;IACpC,IAAIC,MAAM,GAAGH,IAAI,CAACE,IAAI,CAAC,QAAQ,CAAC;IAEhCF,IAAI,CAACF,OAAO,CAAC;MAET;AACZ;AACA;AACA;MACYM,WAAW,EAAE,EAAE;MACfC,UAAU,EAAE,IAAI;MAChBC,QAAQ,EAAE3R,CAAC,CAAC,uBAAuB,CAAC,CAACmQ,IAAI,CAAC,SAAS,CAAC;MACpDyB,GAAG,EAAE5R,CAAC,CAAC,iCAAiC,CAAC,CAACmQ,IAAI,CAAC,SAAS,CAAC;MAEzD0B,IAAI,EAAE;QAEF;QACAC,GAAG,EAAE5B,OAAO,GAAG,SAAS,GAAGoB,QAAQ,GAAG,aAAa;QACnDS,QAAQ,EAAE,MAAM;QAChBC,KAAK,EAAE,GAAG;QACVC,OAAO,EAAE;UACL,kBAAkB,EAAE,gBAAgB;UACpC,cAAc,EAAEjS,CAAC,CAAC,yBAAyB,CAAC,CAACmQ,IAAI,CAAC,SAAS;QAC/D,CAAC;QACDoB,IAAI,EAAE,SAAAA,KAAUW,MAAM,EAAE;UACpB,IAAIX,IAAI,GAAG;YACPY,MAAM,EAAED,MAAM,CAACE,IAAI;YACnBC,IAAI,EAAEH,MAAM,CAACG,IAAI,IAAI,CAAC;YACtBC,eAAe,EAAEjB,IAAI,CAACE,IAAI,CAAC,mBAAmB,CAAC;YAC/CgB,SAAS,EAAElB,IAAI,CAACE,IAAI,CAAC,YAAY;UACrC,CAAC;UACD,OAAOA,IAAI;QACf,CAAC;QACD;AAChB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;QAIgBiB,KAAK,EAAE;MACX,CAAC;MACD;MACAC,cAAc,EAAEC;MAChB;IACJ,CAAC,CAAC;EAEN,CAAC,CAAC;EAEL,SAASC,eAAeA,CAACC,OAAO,EAAE;IAEjC;IACA,IAAI,EAAEA,OAAO,YAAY3O,MAAM,CAAC,EAAE2O,OAAO,GAAG5S,CAAC,CAAC4S,OAAO,CAAC;IAEtD,IAAIpB,MAAM,GAAGoB,OAAO,CAACrB,IAAI,CAAC,SAAS,CAAC;;IAEpC;IACAsB,aAAa,GAAGrB,MAAM,CAACsB,QAAQ,CAACC,OAAO,IAAIvB,MAAM,CAACwB,UAAU,CAACrC,IAAI,CAAC,wBAAwB,CAAC;IAE3F,IAAIsC,KAAK,GAAGJ,aAAa,CAACjQ,GAAG,CAAC,CAAC;IAC/B,OAAOqQ,KAAK;EACb;EAEAjT,CAAC,CAAC,4BAA4B,CAAC,CAACgJ,EAAE,CAAC,mBAAmB,EAAE,UAAU5H,CAAC,EAAE;IACpE,IAAImQ,IAAI,GAAGnQ,CAAC,CAAC8Q,MAAM,CAACgB,IAAI,CAAC3B,IAAI;IAC7B,IAAI4B,SAAS,GAAG,KAAK;IACrB,IAAIP,OAAO,GAAG5S,CAAC,CAAC,IAAI,CAAC;IACrB,IAAIiT,KAAK,GAAGN,eAAe,CAACC,OAAO,CAAC;IAEpC,IAAGxR,CAAC,CAAC8Q,MAAM,CAACgB,IAAI,CAACE,aAAa,EAAED,SAAS,GAAG/R,CAAC,CAAC8Q,MAAM,CAACgB,IAAI,CAACE,aAAa,CAACC,IAAI,IAAI,SAAS;;IAEzF;IACA,IAAG,CAACF,SAAS,EAAE;MACd,IAAGF,KAAK,CAACK,WAAW,CAAC,CAAC,IAAI/B,IAAI,CAACxO,IAAI,CAACuQ,WAAW,CAAC,CAAC,CAACC,OAAO,CAACN,KAAK,CAAC,GAAG,CAAC,EAAE;QACrE7R,CAAC,CAACC,cAAc,CAAC,CAAC;QAElBuR,OAAO,CAACzB,OAAO,CAAC,OAAO,CAAC;;QAEzB;MACA,CAAC,MAAM,IAAG8B,KAAK,CAACK,WAAW,CAAC,CAAC,IAAI/B,IAAI,CAACxO,IAAI,CAACuQ,WAAW,CAAC,CAAC,CAACC,OAAO,CAACN,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE;QAC7E7R,CAAC,CAAC8Q,MAAM,CAACgB,IAAI,CAACM,WAAW,GAAG,IAAI;MACjC;IACD;EACD,CAAC,CAAC;EAEFxT,CAAC,CAAC,4BAA4B,CAAC,CAACgJ,EAAE,CAAC,iBAAiB,EAAE,UAAU5H,CAAC,EAAE;IAClE,IAAIwR,OAAO,GAAG5S,CAAC,CAAC,IAAI,CAAC;IACrB,IAAIiT,KAAK,GAAGN,eAAe,CAACC,OAAO,CAAC;IACpC,IAAIY,WAAW,GAAG,KAAK;IACvB,IAAIL,SAAS,GAAG,KAAK;IACrB,IAAG/R,CAAC,CAAC8Q,MAAM,CAACgB,IAAI,CAACO,oBAAoB,EAAED,WAAW,GAAGpS,CAAC,CAAC8Q,MAAM,CAACgB,IAAI,CAACO,oBAAoB,CAACD,WAAW;IACnG,IAAGpS,CAAC,CAAC8Q,MAAM,CAACgB,IAAI,CAACE,aAAa,EAAED,SAAS,GAAG/R,CAAC,CAAC8Q,MAAM,CAACgB,IAAI,CAACE,aAAa,CAACC,IAAI,IAAI,SAAS;IAEzF,IAAGJ,KAAK,IAAI,CAACO,WAAW,IAAI,CAACL,SAAS,EAAE;MACvC,IAAI7B,QAAQ,GAAGsB,OAAO,CAACrB,IAAI,CAAC,UAAU,CAAC;MACvC,IAAIe,eAAe,GAAGM,OAAO,CAACrB,IAAI,CAAC,mBAAmB,CAAC;MACvDvR,CAAC,CAAC6R,IAAI,CAAC;QACNC,GAAG,EAAE5B,OAAO,GAAG,SAAS,GAAGoB,QAAQ,GAAG,qBAAqB,GAAC2B,KAAK,GAAC,SAAS,IAAIX,eAAe,GAAG,mBAAmB,GAACA,eAAe,GAAG,EAAE,CAAC;QAC1IP,QAAQ,EAAE,MAAM;QAChBE,OAAO,EAAE;UACR,kBAAkB,EAAE,gBAAgB;UACpC,cAAc,EAAEjS,CAAC,CAAC,yBAAyB,CAAC,CAACmQ,IAAI,CAAC,SAAS;QAC5D;MACD,CAAC,CAAC,CAACuD,IAAI,CAAC,UAASC,QAAQ,EAAE;QAC1B,IAAIC,iBAAiB,GAAGhB,OAAO,CAACzB,OAAO,CAAC,MAAM,CAAC,CAAC0C,GAAG,CAAC,UAAU3Q,CAAC,EAAC;UAChD,OAAO,CAACA,CAAC,CAAC4Q,EAAE;QAChB,CAAC,CAAC,CAACC,MAAM,CAAC,UAAU7Q,CAAC,EAAE;UACnB,OAAOA,CAAC,KAAK,CAAC;QAClB,CAAC,CAAC;;QAEd;QACA,IAAI8Q,gBAAgB,GAAGL,QAAQ,CAACM,OAAO,CAACF,MAAM,CAAC,UAAS3C,IAAI,EAAE;UAC7D,OAAOwC,iBAAiB,CAACL,OAAO,CAAC,CAACnC,IAAI,CAAC0C,EAAE,CAAC,GAAG,CAAC;QAC/C,CAAC,CAAC;QAEF,IAAII,KAAK,GAAIN,iBAAiB,CAACrR,MAAM,GAAG,CAAC,GAAIyR,gBAAgB,CAAC,CAAC,CAAC,GAAGL,QAAQ,CAACM,OAAO,CAAC,CAAC,CAAC;QAEtF,IAAGC,KAAK,IAAIA,KAAK,CAACJ,EAAE,EAAE;UACrBI,KAAK,CAACpS,QAAQ,GAAG,IAAI;UAErB,IAAG9B,CAAC,CAAC,gBAAgB,GAAGkU,KAAK,CAACJ,EAAE,GAAG,IAAI,EAAElB,OAAO,CAAC,CAACrQ,MAAM,GAAG,CAAC,EAAE;YAC7D,IAAI4R,MAAM,GAAG,IAAIC,MAAM,CAACF,KAAK,CAACnR,IAAI,EAAEmR,KAAK,CAACJ,EAAE,EAAE,IAAI,EAAE,IAAI,CAAC;YACzDlB,OAAO,CAACyB,MAAM,CAACF,MAAM,CAAC;UACvB,CAAC,MAAM;YACN,IAAIG,UAAU,GAAG1B,OAAO,CAACzC,IAAI,CAAC,UAAU,CAAC,IAAI,UAAU;YACvDyC,OAAO,CAAChQ,GAAG,CAAC0R,UAAU,GAAE1B,OAAO,CAAChQ,GAAG,CAAC,CAAC,CAAC5B,MAAM,CAACkT,KAAK,CAACJ,EAAE,CAAC,GAAGlB,OAAO,CAAChQ,GAAG,CAACsR,KAAK,CAACJ,EAAE,CAAC,CAAC;UAChF;UACAlB,OAAO,CAAC2B,OAAO,CAAC,QAAQ,CAAC;UAEzB3B,OAAO,CAAC2B,OAAO,CAAC;YACflB,IAAI,EAAE,gBAAgB;YACtBnB,MAAM,EAAE;cACPX,IAAI,EAAE2C;YACP;UACD,CAAC,CAAC;QACH;MACD,CAAC,CAAC;IACH;EACD,CAAC,CAAC;EAEC,SAASM,cAAcA,CAAEC,QAAQ,EAAE;IAC/B,IAAIC,cAAc,GAAG,sEAAsE;IAC3F,IAAID,QAAQ,CAACE,OAAO,EAAE;MAClB,OAAOD,cAAc;IACzB;IAEA,IAAIE,MAAM,GAAG,wBAAwB;IACrCA,MAAM,IAAI,sDAAsD;IAChE,IAAIH,QAAQ,CAACjN,KAAK,EAAE;MAChBoN,MAAM,IAAI,sCAAsC,GAAGH,QAAQ,CAACjN,KAAK,GAAG,oDAAoD,GAAIiN,QAAQ,CAAC1R,IAAI,GAAG,UAAU;IAC1J,CAAC,MAAM;MACH6R,MAAM,IAAI,gDAAgD;IAC9D;IAEAA,MAAM,IAAI,aAAa,GAAGH,QAAQ,CAAC1R,IAAI,GAAG,QAAQ;IAClD6R,MAAM,IAAI,QAAQ;IAClB,OAAOA,MAAM;EACjB;EAEA,SAASlC,kBAAkBA,CAAC+B,QAAQ,EAAE;IAClC;IACA;IACA,IAAIA,QAAQ,CAACE,OAAO,EAAE;MAClB,OAAO3U,CAAC,CAAC,sEAAsE,CAAC;IACpF;IAEA,IAAI6U,QAAQ,GAAG7U,CAAC,CAAC,wBAAwB,CAAC;IAC1C,IAAI8U,SAAS,GAAG9U,CAAC,CAAC,sDAAsD,CAAC;IACzE,IAAIyU,QAAQ,CAACjN,KAAK,EAAE;MAChB,IAAIuN,SAAS,GAAG/U,CAAC,CAAC,4BAA4B,CAAC;MAC/C;AACZ;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;MACY,IAAIgV,GAAG,GAAGhV,CAAC,CAAC,gEAAgE,CAAC;MAC7E;MACA;MACA;MACA;MACAgV,GAAG,CAAC7E,IAAI,CAAC,KAAK,EAAEsE,QAAQ,CAACjN,KAAM,CAAC;MAChCuN,SAAS,CAACV,MAAM,CAACW,GAAG,CAAC;IACzB,CAAC,MAAM;MACH,IAAID,SAAS,GAAC/U,CAAC,CAAC,gDAAgD,CAAC;IACrE;IACA8U,SAAS,CAACT,MAAM,CAACU,SAAS,CAAC;IAC3BF,QAAQ,CAACR,MAAM,CAACS,SAAS,CAAC;IAC1B,IAAIG,QAAQ,GAAGjV,CAAC,CAAC,OAAO,CAAC;IACzBiV,QAAQ,CAAClS,IAAI,CAAC0R,QAAQ,CAAC1R,IAAI,CAAC;IAC5B8R,QAAQ,CAACR,MAAM,CAACY,QAAQ,CAAC;IACzB,IAAIC,SAAS,GAAGL,QAAQ,CAACM,GAAG,CAAC,CAAC,CAAC,CAACC,SAAS;IACzC,IAAIC,QAAQ,GAAGb,cAAc,CAACC,QAAQ,CAAC;IACvC,IAAGS,SAAS,IAAIG,QAAQ,EAAE;MACtB;MACA;MACA;MACA;MACA;MACA;IAAA;IAEJ,OAAOR,QAAQ;EAEnB;EAEA,SAASS,mBAAmBA,CAAEb,QAAQ,EAAE;IACpC;IACA;IACA;IACA;IACA;IACA;IACA;;IAEA,OAAOA,QAAQ,CAAC1R,IAAI,CAACwS,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CACrCA,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CACrBA,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CACvBA,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;EAChC;;EAEA;EACA;EACAvV,CAAC,CAAC,YAAW;IACTA,CAAC,CAAC,8BAA8B,CAAC,CAACgJ,EAAE,CAAC,QAAQ,EAAC,YAAY;MACtD,IAAIwM,aAAa,GAAGxV,CAAC,CAAC,sCAAsC,CAAC,CAAC4C,GAAG,CAAC,CAAC;MACnE,IAAI6S,MAAM,GAAGzV,CAAC,CAAC,gCAAgC,CAAC,CAAC4C,GAAG,CAAC,CAAC;MAEtD,IAAI4S,aAAa,IAAI,OAAO,EAAE;QAC1BxV,CAAC,CAAC,qBAAqB,CAAC,CAAC0V,OAAO,CAAC,CAAC;QAClC1V,CAAC,CAAC,iBAAiB,CAAC,CAAC6Q,IAAI,CAAC,CAAC;QAC3B7Q,CAAC,CAAC,gBAAgB,CAAC,CAAC2V,IAAI,CAAC,CAAC;QAC1B3V,CAAC,CAAC,oBAAoB,CAAC,CAAC2V,IAAI,CAAC,CAAC;QAC9B3V,CAAC,CAAC,uBAAuB,CAAC,CAAC0V,OAAO,CAAC,CAAC;QAEpC1V,CAAC,CAAC,4BAA4B,CAAC,CAAC4C,GAAG,CAAC,EAAE,CAAC,CAAC2R,OAAO,CAAC,gBAAgB,CAAC;QACjEvU,CAAC,CAAC,wBAAwB,CAAC,CAAC4C,GAAG,CAAC,EAAE,CAAC,CAAC2R,OAAO,CAAC,gBAAgB,CAAC;MAEjE,CAAC,MAAM,IAAIiB,aAAa,IAAI,UAAU,EAAE;QACpCxV,CAAC,CAAC,qBAAqB,CAAC,CAAC0V,OAAO,CAAC,CAAC;QAClC1V,CAAC,CAAC,iBAAiB,CAAC,CAAC2V,IAAI,CAAC,CAAC;QAC3B3V,CAAC,CAAC,gBAAgB,CAAC,CAAC2V,IAAI,CAAC,CAAC;QAC1B3V,CAAC,CAAC,oBAAoB,CAAC,CAAC6Q,IAAI,CAAC,CAAC;QAC9B7Q,CAAC,CAAC,uBAAuB,CAAC,CAAC0V,OAAO,CAAC,CAAC;QAEpC1V,CAAC,CAAC,yBAAyB,CAAC,CAAC4C,GAAG,CAAC,EAAE,CAAC,CAAC2R,OAAO,CAAC,gBAAgB,CAAC;QAC9DvU,CAAC,CAAC,wBAAwB,CAAC,CAAC4C,GAAG,CAAC,EAAE,CAAC,CAAC2R,OAAO,CAAC,gBAAgB,CAAC;MACjE,CAAC,MAAO;QAEJvU,CAAC,CAAC,iBAAiB,CAAC,CAAC2V,IAAI,CAAC,CAAC;QAC3B3V,CAAC,CAAC,gBAAgB,CAAC,CAAC6Q,IAAI,CAAC,CAAC;QAC1B7Q,CAAC,CAAC,oBAAoB,CAAC,CAAC2V,IAAI,CAAC,CAAC;QAC9B,IAAIF,MAAM,EAAE;UACRzV,CAAC,CAAC,qBAAqB,CAAC,CAAC4V,MAAM,CAAC,CAAC;QACrC;QACA5V,CAAC,CAAC,uBAAuB,CAAC,CAAC4V,MAAM,CAAC,CAAC;QAEnC5V,CAAC,CAAC,yBAAyB,CAAC,CAAC4C,GAAG,CAAC,EAAE,CAAC,CAAC2R,OAAO,CAAC,gBAAgB,CAAC;QAC9DvU,CAAC,CAAC,4BAA4B,CAAC,CAAC4C,GAAG,CAAC,EAAE,CAAC,CAAC2R,OAAO,CAAC,gBAAgB,CAAC;MACrE;IACJ,CAAC,CAAC;EACN,CAAC,CAAC;;EAGF;EACA;EACA;EACA,IAAIsB,MAAM,GAAGpR,QAAQ,CAACqR,QAAQ,CAACC,QAAQ,CAAC,CAAC;;EAEzC;EACA;EACA;EACA;EACA;EACA,IAAIF,MAAM,CAACG,KAAK,CAAC,GAAG,CAAC,EAAG;IACpBhW,CAAC,CAAC,qBAAqB,GAAC6V,MAAM,CAACI,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAC,IAAI,CAAC,CAACC,GAAG,CAAC,MAAM,CAAC;EAClE;;EAEA;EACA;EACA;EACA;EACA;EACA;EACAlW,CAAC,CAAC,sBAAsB,CAAC,CAACmW,KAAK,CAAC,UAAU/U,CAAC,EAAE;IACzC,IAAIoP,IAAI,GAAGxQ,CAAC,CAAC,IAAI,CAAC,CAACmQ,IAAI,CAAC,MAAM,CAAC;IAC/BiG,OAAO,CAACC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE7F,IAAI,CAAC;IACnCpP,CAAC,CAACC,cAAc,CAAC,CAAC;IAClBrB,CAAC,CAAC,UAAU,GAAGA,CAAC,CAAC,IAAI,CAAC,CAACmQ,IAAI,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC+F,GAAG,CAAC,MAAM,CAAC;EAC3D,CAAC,CAAC;;EAEF;EACA;EACA;;EAIA;EACA,SAASI,OAAOA,CAACC,KAAK,EAAEC,QAAQ,EAAE;IAC9B,IAAID,KAAK,CAACE,KAAK,IAAIF,KAAK,CAACE,KAAK,CAAC,CAAC,CAAC,EAAE;MAC/B,IAAIC,MAAM,GAAG,IAAIC,UAAU,CAAC,CAAC;MAC7BD,MAAM,CAAC5O,MAAM,GAAG,UAAS1G,CAAC,EAAE;QACxBoV,QAAQ,CAACrG,IAAI,CAAC,KAAK,EAAE/O,CAAC,CAACqF,MAAM,CAACmQ,MAAM,CAAC;MACzC,CAAC;MACDF,MAAM,CAACG,aAAa,CAACN,KAAK,CAACE,KAAK,CAAC,CAAC,CAAC,CAAC;IACxC;EACJ;EAEA,SAASK,WAAWA,CAACC,KAAK,EAAE;IACxB,IAAGA,KAAK,GAAG,IAAI,EAAE,OAAOA,KAAK,GAAG,QAAQ,CAAC,KACpC,IAAGA,KAAK,GAAG,OAAO,EAAE,OAAM,CAACA,KAAK,GAAG,IAAI,EAAEC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAC5D,IAAGD,KAAK,GAAG,UAAU,EAAE,OAAM,CAACA,KAAK,GAAG,OAAO,EAAEC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAClE,OAAM,CAACD,KAAK,GAAG,UAAU,EAAEC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK;EACtD;;EAEC;EACDhX,CAAC,CAAC,gBAAgB,CAAC,CAACmB,IAAI,CAAC,QAAQ,EAAE,YAAW;IAC1C,IAAI8V,KAAK,GAAGjX,CAAC,CAAC,IAAI,CAAC;IACnB,IAAI8T,EAAE,GAAG,GAAG,GAAGmD,KAAK,CAAC9G,IAAI,CAAC,IAAI,CAAC;IAC/B,IAAI+G,MAAM,GAAGpD,EAAE,GAAG,SAAS;IAC3B,IAAIqD,OAAO,GAAGnX,CAAC,CAACkX,MAAM,CAAC;IACvB,IAAIE,SAAS,GAAGpX,CAAC,CAAC8T,EAAE,GAAG,iBAAiB,CAAC;IACzC,IAAIuD,iBAAiB,GAAGrX,CAAC,CAAC8T,EAAE,GAAG,mBAAmB,CAAC;IAInDqD,OAAO,CAACG,WAAW,CAAC,cAAc,CAAC,CAACA,WAAW,CAAC,aAAa,CAAC;IAC9DtX,CAAC,CAACkX,MAAM,GAAG,YAAY,CAAC,CAACK,MAAM,CAAC,CAAC;IACjCvX,CAAC,CAACkX,MAAM,GAAG,WAAW,CAAC,CAACK,MAAM,CAAC,CAAC;IAChCvX,CAAC,CAACkX,MAAM,GAAG,eAAe,CAAC,CAACvB,IAAI,CAAC,CAAC;IAClC0B,iBAAiB,CAAC1B,IAAI,CAAC,CAAC;IACxB3V,CAAC,CAAC8T,EAAE,GAAG,OAAO,CAAC,CAAC0D,IAAI,CAAC,EAAE,CAAC;IAExB,IAAIC,QAAQ,GAAGR,KAAK,CAAC1F,IAAI,CAAC,SAAS,CAAC;IACpC,IAAImG,UAAU,GAAG,CAAC;IAElB,KAAK,IAAI5W,CAAC,GAAG,CAAC,EAAEA,CAAC,GAAG,IAAI,CAAC2V,KAAK,CAAClU,MAAM,EAAEzB,CAAC,EAAE,EAAE;MACxC4W,UAAU,IAAI,IAAI,CAACjB,KAAK,CAAC3V,CAAC,CAAC,CAACkL,IAAI;MAChChM,CAAC,CAAC8T,EAAE,GAAG,OAAO,CAAC,CAACO,MAAM,CAAC,oCAAoC,GAAGsD,YAAY,CAAC,IAAI,CAAClB,KAAK,CAAC3V,CAAC,CAAC,CAAC8W,IAAI,CAAC,GAAG,IAAI,GAAGd,WAAW,CAAC,IAAI,CAACL,KAAK,CAAC3V,CAAC,CAAC,CAACkL,IAAI,CAAC,GAAG,WAAW,CAAC;IAC1J;IAEA,IAAI0L,UAAU,GAAGD,QAAQ,EAAE;MACvBN,OAAO,CAACnG,QAAQ,CAAC,aAAa,CAAC,CAACsG,WAAW,CAAC,YAAY,CAAC,CAACrG,OAAO,CAAC,uCAAuC,CAAC,CAACoD,MAAM,CAAC,uCAAuC,GAAGyC,WAAW,CAACY,UAAU,CAAC,GAAG,UAAU,CAAC;IACrM,CAAC,MAAM;MACHP,OAAO,CAACnG,QAAQ,CAAC,cAAc,CAAC,CAACsG,WAAW,CAAC,YAAY,CAAC,CAACrG,OAAO,CAAC,wCAAwC,CAAC;MAC5G,IAAIuF,QAAQ,GAAIxW,CAAC,CAAC8T,EAAE,GAAG,eAAe,CAAC;MACvCwC,OAAO,CAAC,IAAI,EAAEE,QAAQ,CAAC;MACvBA,QAAQ,CAACZ,MAAM,CAAC,CAAC;MACjByB,iBAAiB,CAACzB,MAAM,CAAC,CAAC;MAC1BwB,SAAS,CAACzB,IAAI,CAAC,CAAC;IACpB;EAGJ,CAAC,CAAC;AAEN,CAAC,CAAC;AAEF,SAASgC,YAAYA,CAACE,GAAG,EAAE;EACvB,OAAOzV,MAAM,CAACyV,GAAG,CAAC,CAACtC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAACA,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAACA,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAACA,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;AACjH;;AAIA;AACA;AACA;AACA,CAAC,UAASvV,CAAC,EAAC;EAERA,CAAC,CAACuD,EAAE,CAACuU,cAAc,GAAG,UAASC,QAAQ,EAAC;IACpC,OAAO,IAAI,CAAC7W,IAAI,CAAC,YAAU;MACvB,IAAI8W,QAAQ;QAAEf,KAAK,GAAGjX,CAAC,CAAC,IAAI,CAAC;MAC7B,IAAGiX,KAAK,CAAC9G,IAAI,CAAC,UAAU,CAAC,EAAC;QACtB8G,KAAK,CAACgB,UAAU,CAAC,UAAU,CAAC;QAC5BD,QAAQ,GAAG,KAAK;MACpB,CAAC,MAAM;QACHf,KAAK,CAAC9G,IAAI,CAAC,UAAU,EAAE,UAAU,CAAC;QAClC6H,QAAQ,GAAG,IAAI;MACnB;MAEA,IAAGD,QAAQ,IAAI,OAAOA,QAAQ,KAAK,UAAU,EAAC;QAC1CA,QAAQ,CAAC,IAAI,EAAEC,QAAQ,CAAC;MAC5B;IACJ,CAAC,CAAC;EACN,CAAC;AAEL,CAAC,EAAE/T,MAAM,CAAC;;AAEV;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACAQ,QAAQ,CAACmE,gBAAgB,CAAC,eAAe,EAAE,YAAM;EAC7C5I,CAAC,CAAC,mBAAmB,CAAC,CAACmR,OAAO,CAAC,CAAC;EAEhCnR,CAAC,CAACyE,QAAQ,CAAC,CAACuE,EAAE,CAAC,gBAAgB,EAAE,mBAAmB,EAAE,UAAUtD,KAAK,EAAE;IACnE,IAAIe,MAAM,GAAGzG,CAAC,CAAC0F,KAAK,CAACe,MAAM,CAAC;IAC5B,IAAG,CAACf,KAAK,CAACe,MAAM,CAACmR,IAAI,IAAI,CAACnR,MAAM,CAAC8K,IAAI,CAAC,oBAAoB,CAAC,EAAE;MACzD2G,OAAO,CAAClU,KAAK,CAAC,sIAAsI,CAAC;MACrJkU,OAAO,CAAClU,KAAK,CAAC,8GAA8G,CAAC;MAC7H,OAAO,KAAK;IAChB;IACAmU,QAAQ,CAACxH,IAAI,CAAClK,MAAM,CAAC8K,IAAI,CAAC,oBAAoB,CAAC,CAAC,CAAC6G,GAAG,CAAC1S,KAAK,CAACe,MAAM,CAACmR,IAAI,EAAE,IAAI,CAACpX,OAAO,CAAC,IAAI,CAAC6X,aAAa,CAAC,CAACpF,KAAK,CAAC;EACnH,CAAC,CAAC;EAEFkF,QAAQ,CAACG,IAAI,CAAC,SAAS,EAAE,UAAAC,IAAA,EAAe;IAAA,IAAbC,OAAO,GAAAD,IAAA,CAAPC,OAAO;IAC9BA,OAAO,CAAC,YAAM;MACVC,cAAc,CAAC,YAAM;QACjBzY,CAAC,CAAC,mBAAmB,CAAC,CAACmR,OAAO,CAAC,CAAC;MACpC,CAAC,CAAC;IACN,CAAC,CAAC;EACN,CAAC,CAAC;AACN,CAAC,CAAC;;;;;;;;;;ACnmBF;AACA;AACA;AACA;AACA;AACA;AACA;;AAEC;AACD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAMAnR,CAAC,CAAC,YAAY;EAEZ,IAAIkQ,OAAO,GAAGlQ,CAAC,CAAC,sBAAsB,CAAC,CAACmQ,IAAI,CAAC,SAAS,CAAC;EACvD;EACA,IAAIuI,KAAK,EAAElH,MAAM,EAAEmH,eAAe;EAElC,IAAG3Y,CAAC,CAAC,cAAc,CAAC,CAACuC,MAAM,IAAI,CAAC,EAAE;IAChCvC,CAAC,CAAC,MAAM,CAAC,CAACqU,MAAM,CAAC,iEAAiE,CAAC;EACrF;EAEArU,CAAC,CAAC,cAAc,CAAC,CAACgJ,EAAE,CAAC,eAAe,EAAE,UAAUtD,KAAK,EAAE;IACnD,IAAI2L,IAAI,GAAGrR,CAAC,CAAC0F,KAAK,CAACkT,aAAa,CAAC;IACjCF,KAAK,GAAGrH,IAAI,CAACE,IAAI,CAAC,YAAY,CAAC;IAC/BC,MAAM,GAAGH,IAAI,CAACE,IAAI,CAAC,QAAQ,CAAC;IAC5BoH,eAAe,GAAGtH,IAAI,CAACE,IAAI,CAAC,SAAS,CAAC;IAEtCvR,CAAC,CAAC,cAAc,CAAC,CAAC6Y,IAAI,CAACxH,IAAI,CAAClB,IAAI,CAAC,MAAM,CAAC,EAAC,YAAY;MAEjD;MACAnQ,CAAC,CAAC,aAAa,CAAC,CAAC8Y,KAAK,CAAC,CAAC;;MAE1B;MACA9Y,CAAC,CAAC,cAAc,CAAC,CAAC2Q,IAAI,CAAC,gBAAgB,CAAC,CAACQ,OAAO,CAAC,CAAC;MAClD;MACA;;MAEAnR,CAAC,CAAC,eAAe,CAAC,CAACkB,IAAI,CAAE,UAAUJ,CAAC,EAACsQ,IAAI,EAAE;QACvC,IAAIC,IAAI,GAAGrR,CAAC,CAACoR,IAAI,CAAC;QAClB,IAAIE,QAAQ,GAAGD,IAAI,CAACE,IAAI,CAAC,UAAU,CAAC;QACpC,IAAIC,MAAM,GAAGH,IAAI,CAACE,IAAI,CAAC,QAAQ,CAAC;QAEhCF,IAAI,CAACF,OAAO,CAAC;UACTU,IAAI,EAAE;YAEF;YACAC,GAAG,EAAE5B,OAAO,GAAG,SAAS,GAAGoB,QAAQ,GAAG,aAAa;YAAE;YACrDS,QAAQ,EAAE,MAAM;YAChBC,KAAK,EAAE,GAAG;YACVC,OAAO,EAAE;cACL,kBAAkB,EAAE,gBAAgB;cACpC,cAAc,EAAEjS,CAAC,CAAC,yBAAyB,CAAC,CAACmQ,IAAI,CAAC,SAAS;YAC/D,CAAC;YACDoB,IAAI,EAAE,SAAAA,KAAUW,MAAM,EAAE;cACpB,IAAIX,IAAI,GAAG;gBACPY,MAAM,EAAED,MAAM,CAACE,IAAI;gBACnBC,IAAI,EAAEH,MAAM,CAACG,IAAI,IAAI,CAAC;gBACtBC,eAAe,EAAEjB,IAAI,CAACE,IAAI,CAAC,mBAAmB;cAClD,CAAC;cACD,OAAOA,IAAI;YACf,CAAC;YACD;AACpB;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;YAIoBiB,KAAK,EAAE;UACX,CAAC;UACD;UACAC,cAAc,EAAEC;UAChB;QACJ,CAAC,CAAC;MACN,CAAC,CAAC;IACJ,CAAC,CAAC;EAEN,CAAC,CAAC;EAIF1S,CAAC,CAAC,cAAc,CAAC,CAACgJ,EAAE,CAAC,OAAO,EAAC,aAAa,EAAE,YAAY;IACtDhJ,CAAC,CAAC6R,IAAI,CAAC;MACHwB,IAAI,EAAE,MAAM;MACZvB,GAAG,EAAE9R,CAAC,CAAC,kBAAkB,CAAC,CAACmQ,IAAI,CAAC,QAAQ,CAAC;MACzC8B,OAAO,EAAE;QACL,kBAAkB,EAAE,gBAAgB;QACpC,cAAc,EAAEjS,CAAC,CAAC,yBAAyB,CAAC,CAACmQ,IAAI,CAAC,SAAS;MAC/D,CAAC;MAEDoB,IAAI,EAAEvR,CAAC,CAAC,kBAAkB,CAAC,CAAC+Y,SAAS,CAAC,CAAC;MACvCC,OAAO,EAAE,SAAAA,QAAUpC,MAAM,EAAE;QAEvB,IAAGA,MAAM,CAACM,MAAM,IAAI,OAAO,EAAE;UACzB,IAAI+B,aAAa,GAAC,EAAE;UACpB,KAAI,IAAIC,KAAK,IAAItC,MAAM,CAACuC,QAAQ,EAAE;YAC9BF,aAAa,IAAI,uCAAuC,GAAGC,KAAK,GAAG,iBAAiB,GAAGtC,MAAM,CAACuC,QAAQ,CAACD,KAAK,CAAC;UAEjH;UACAlZ,CAAC,CAAC,kBAAkB,CAAC,CAACwX,IAAI,CAACyB,aAAa,CAAC,CAACpI,IAAI,CAAC,CAAC;UAChD,OAAO,KAAK;QAChB;QAEA,IAAIiD,EAAE,GAAG8C,MAAM,CAACwC,OAAO,CAACtF,EAAE;QAC1B,IAAI8D,IAAI,GAAGhB,MAAM,CAACwC,OAAO,CAACxB,IAAI,IAAKhB,MAAM,CAACwC,OAAO,CAACC,UAAU,GAAG,GAAG,GAAGzC,MAAM,CAACwC,OAAO,CAACE,SAAU;QAC9F,IAAI,CAACxF,EAAE,IAAI,CAAC8D,IAAI,EAAE;UACdM,OAAO,CAAClU,KAAK,CAAC,+DAA+D,GAAG4T,IAAI,GAAG,QAAQ,GAAG9D,EAAE,CAAC;UACrG,OAAO,KAAK;QAChB;QACA9T,CAAC,CAAC,cAAc,CAAC,CAAC4Q,KAAK,CAAC,MAAM,CAAC;QAC/B5Q,CAAC,CAAC,cAAc,CAAC,CAACwX,IAAI,CAAC,EAAE,CAAC;QAE1B,IAAI+B,YAAY,GAAGvZ,CAAC,CAAC,GAAG,GAAG2Y,eAAe,CAAC;QAE3C,IAAGY,YAAY,CAAChX,MAAM,GAAG,CAAC,EAAE;UACxBgX,YAAY,CAACC,cAAc,CAAC,SAAS,CAAC;QAC1C;;QAEA;QACA;QACA;QACA,IAAIC,QAAQ,GAAGhV,QAAQ,CAACiV,cAAc,CAAClI,MAAM,CAAC;QAE9C,IAAG,CAACiI,QAAQ,EAAE;UACV,OAAO,KAAK;QAChB;QAEAA,QAAQ,CAACjZ,OAAO,CAACiZ,QAAQ,CAAClX,MAAM,CAAC,GAAG,IAAI6R,MAAM,CAACwD,IAAI,EAAE9D,EAAE,CAAC;QACxD2F,QAAQ,CAACpB,aAAa,GAAGoB,QAAQ,CAAClX,MAAM,GAAG,CAAC;QAC5CvC,CAAC,CAACyZ,QAAQ,CAAC,CAAClF,OAAO,CAAC,QAAQ,CAAC;QAC7B,IAAG5M,MAAM,CAACgS,iBAAiB,EAAE;UACzBA,iBAAiB,CAAC,CAAC;QACvB;MAEJ,CAAC;MACD3V,KAAK,EAAE,SAAAA,MAAU4S,MAAM,EAAE;QACrBgD,GAAG,GAAGhD,MAAM,CAACiD,YAAY,CAACV,QAAQ,IAAIvC,MAAM,CAACiD,YAAY,CAAC7V,KAAK;QAC/DhE,CAAC,CAAC,kBAAkB,CAAC,CAACwX,IAAI,CAAC,gBAAgB,GAACoC,GAAG,CAAC,CAAC/I,IAAI,CAAC,CAAC;MAC3D;IAIJ,CAAC,CAAC;EACJ,CAAC,CAAC;AACJ,CAAC,CAAC;AAEF,SAAS6B,kBAAkBA,CAAC+B,QAAQ,EAAE;EAClC;EACA;EACA,IAAIA,QAAQ,CAACE,OAAO,EAAE;IAClB,OAAO3U,CAAC,CAAC,sEAAsE,CAAC;EACpF;EAEA,IAAI6U,QAAQ,GAAG7U,CAAC,CAAC,wBAAwB,CAAC;EAC1C,IAAI8U,SAAS,GAAG9U,CAAC,CAAC,sDAAsD,CAAC;EACzE,IAAIyU,QAAQ,CAACjN,KAAK,EAAE;IAChB,IAAIuN,SAAS,GAAG/U,CAAC,CAAC,4BAA4B,CAAC;IAC/C;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;IACQ,IAAIgV,GAAG,GAAGhV,CAAC,CAAC,gEAAgE,CAAC;IAC7E;IACA;IACA;IACA;IACAgV,GAAG,CAAC7E,IAAI,CAAC,KAAK,EAAEsE,QAAQ,CAACjN,KAAM,CAAC;IAChCuN,SAAS,CAACV,MAAM,CAACW,GAAG,CAAC;EACzB,CAAC,MAAM;IACH,IAAID,SAAS,GAAC/U,CAAC,CAAC,gDAAgD,CAAC;EACrE;EACA8U,SAAS,CAACT,MAAM,CAACU,SAAS,CAAC;EAC3BF,QAAQ,CAACR,MAAM,CAACS,SAAS,CAAC;EAC1B,IAAIG,QAAQ,GAAGjV,CAAC,CAAC,OAAO,CAAC;EACzBiV,QAAQ,CAAClS,IAAI,CAAC0R,QAAQ,CAAC1R,IAAI,CAAC;EAC5B8R,QAAQ,CAACR,MAAM,CAACY,QAAQ,CAAC;EACzB,IAAIC,SAAS,GAAGL,QAAQ,CAACM,GAAG,CAAC,CAAC,CAAC,CAACC,SAAS;EACzC,IAAIC,QAAQ,GAAGb,cAAc,CAACC,QAAQ,CAAC;EACvC,IAAIS,SAAS,IAAIG,QAAQ,EAAE;IACvB;IACA;IACA;IACA;IACA;IACA;EAAA;EAEJ,OAAOR,QAAQ;AAEnB;AAEA,SAASL,cAAcA,CAAEC,QAAQ,EAAE;EAC/B,IAAIC,cAAc,GAAG,sEAAsE;EAC3F,IAAID,QAAQ,CAACE,OAAO,EAAE;IAClB,OAAOD,cAAc;EACzB;EAEA,IAAIE,MAAM,GAAG,wBAAwB;EACrCA,MAAM,IAAG,sDAAsD;EAC/D,IAAIH,QAAQ,CAACjN,KAAK,EAAE;IAChBoN,MAAM,IAAI,sCAAsC,GAAGH,QAAQ,CAACjN,KAAK,GAAG,SAAS,GAAEiN,QAAQ,CAACqF,GAAG,GAAG,qDAAqD;EACvJ,CAAC,MAAM;IACHlF,MAAM,IAAI,gDAAgD;EAC9D;EAEAA,MAAM,IAAI,aAAa,GAAGH,QAAQ,CAAC1R,IAAI,GAAG,QAAQ;EAClD6R,MAAM,IAAI,QAAQ;EAClB,OAAOA,MAAM;AACjB;AAEA,SAASU,mBAAmBA,CAAEb,QAAQ,EAAE;EACpC,OAAOA,QAAQ,CAAC1R,IAAI,CAACwS,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CACrCA,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CACrBA,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CACvBA,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC;AAChC;;;;;;;;;;;;ACnPA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;;;;;;;ACAA;;;;;;;UCAA;UACA;;UAEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;;UAEA;UACA;;UAEA;UACA;UACA;;UAEA;UACA;;;;;WCzBA;WACA;WACA;WACA;WACA,+BAA+B,wCAAwC;WACvE;WACA;WACA;WACA;WACA,iBAAiB,qBAAqB;WACtC;WACA;WACA,kBAAkB,qBAAqB;WACvC;WACA;WACA,KAAK;WACL;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;;;WC3BA;;;;;WCAA;WACA;WACA;WACA,uDAAuD,iBAAiB;WACxE;WACA,gDAAgD,aAAa;WAC7D;;;;;WCNA;;WAEA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;;WAEA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA;WACA,MAAM,qBAAqB;WAC3B;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;WAEA;WACA;WACA;;;;;UEnEA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA;UACA","sources":["webpack:///./node_modules/admin-lte/build/less/AdminLTE.less?4749","webpack:///./node_modules/admin-lte/dist/js/adminlte.min.js","webpack:///./node_modules/blueimp-file-upload/js/jquery.fileupload.js","webpack:///./node_modules/bootstrap-colorpicker/dist/js/bootstrap-colorpicker.js","webpack:///./node_modules/bootstrap-datepicker/dist/js/bootstrap-datepicker.js","webpack:///./node_modules/bootstrap-less/js/bootstrap.js","webpack:///./node_modules/canvas-confetti/dist/confetti.browser.js","webpack:///./node_modules/clipboard/dist/clipboard.js","webpack:///./node_modules/ekko-lightbox/dist/ekko-lightbox.min.js","webpack:///./node_modules/jquery-slimscroll/jquery.slimscroll.js","webpack:///./node_modules/jquery-ui/ui/version.js","webpack:///./node_modules/jquery-ui/ui/widget.js","webpack:///./node_modules/jquery-validation/dist/jquery.validate.js","webpack:///./node_modules/jquery.iframe-transport/jquery.iframe-transport.js","webpack:///./node_modules/jquery/dist/jquery.js","webpack:///./node_modules/list.js/src/add-async.js","webpack:///./node_modules/list.js/src/filter.js","webpack:///./node_modules/list.js/src/fuzzy-search.js","webpack:///./node_modules/list.js/src/index.js","webpack:///./node_modules/list.js/src/item.js","webpack:///./node_modules/list.js/src/pagination.js","webpack:///./node_modules/list.js/src/parse.js","webpack:///./node_modules/list.js/src/search.js","webpack:///./node_modules/list.js/src/sort.js","webpack:///./node_modules/list.js/src/templater.js","webpack:///./node_modules/list.js/src/utils/classes.js","webpack:///./node_modules/list.js/src/utils/events.js","webpack:///./node_modules/list.js/src/utils/extend.js","webpack:///./node_modules/list.js/src/utils/fuzzy.js","webpack:///./node_modules/list.js/src/utils/get-attribute.js","webpack:///./node_modules/list.js/src/utils/get-by-class.js","webpack:///./node_modules/list.js/src/utils/index-of.js","webpack:///./node_modules/list.js/src/utils/to-array.js","webpack:///./node_modules/list.js/src/utils/to-string.js","webpack:///./node_modules/select2/dist/js/select2.js","webpack:///./node_modules/string-natural-compare/natural-compare.js","webpack:///./node_modules/tether/dist/js/tether.js","webpack:///./resources/assets/js/extensions/pGenerator.jquery.js","webpack:///./resources/assets/js/signature_pad.js","webpack:///./resources/assets/js/snipeit.js","webpack:///./resources/assets/js/snipeit_modals.js","webpack:///./resources/assets/less/app.less?62ee","webpack:///./resources/assets/less/overrides.less?ddb8","webpack:///./resources/assets/less/skins/_all-skins.less?56bc","webpack:///./resources/assets/less/skins/skin-black-dark.less?32b5","webpack:///./resources/assets/less/skins/skin-black.less?1132","webpack:///./resources/assets/less/skins/skin-blue-dark.less?6784","webpack:///./resources/assets/less/skins/skin-blue.less?092d","webpack:///./resources/assets/less/skins/skin-contrast.less?bf9b","webpack:///./resources/assets/less/skins/skin-green-dark.less?90ba","webpack:///./resources/assets/less/skins/skin-green.less?f018","webpack:///./resources/assets/less/skins/skin-orange-dark.less?f7d1","webpack:///./resources/assets/less/skins/skin-orange.less?8b4b","webpack:///./resources/assets/less/skins/skin-purple-dark.less?c895","webpack:///./resources/assets/less/skins/skin-purple.less?fd9a","webpack:///./resources/assets/less/skins/skin-red-dark.less?575d","webpack:///./resources/assets/less/skins/skin-red.less?6b05","webpack:///./resources/assets/less/skins/skin-yellow-dark.less?57fe","webpack:///./resources/assets/less/skins/skin-yellow.less?4418","webpack:///webpack/bootstrap","webpack:///webpack/runtime/chunk loaded","webpack:///webpack/runtime/hasOwnProperty shorthand","webpack:///webpack/runtime/make namespace object","webpack:///webpack/runtime/jsonp chunk loading","webpack:///webpack/before-startup","webpack:///webpack/startup","webpack:///webpack/after-startup"],"sourcesContent":["// extracted by mini-css-extract-plugin\nexport {};","/*! AdminLTE app.js\n* ================\n* Main JS application file for AdminLTE v2. This file\n* should be included in all pages. It controls some layout\n* options and implements exclusive AdminLTE plugins.\n*\n* @author Colorlib\n* @support \n* @version v2.4.18\n* @repository git://github.com/ColorlibHQ/AdminLTE.git\n* @license MIT \n*/\nif(\"undefined\"==typeof jQuery)throw new Error(\"AdminLTE requires jQuery\");!function(i){\"use strict\";function s(t,e){if(this.element=t,this.options=e,this.$overlay=i(e.overlayTemplate),\"\"===e.source)throw new Error(\"Source url was not defined. Please specify a url in your BoxRefresh source option.\");this._setUpListeners(),this.load()}var r=\"lte.boxrefresh\",a={source:\"\",params:{},trigger:\".refresh-btn\",content:\".box-body\",loadInContent:!0,responseType:\"\",overlayTemplate:'
      ',onLoadStart:function(){},onLoadDone:function(t){return t}},t='[data-widget=\"box-refresh\"]';function e(n){return this.each(function(){var t=i(this),e=t.data(r);if(!e){var o=i.extend({},a,t.data(),\"object\"==typeof n&&n);t.data(r,e=new s(t,o))}if(\"string\"==typeof e){if(void 0===e[n])throw new Error(\"No method named \"+n);e[n]()}})}s.prototype.load=function(){this._addOverlay(),this.options.onLoadStart.call(i(this)),i.get(this.options.source,this.options.params,function(t){this.options.loadInContent&&i(this.element).find(this.options.content).html(t),this.options.onLoadDone.call(i(this),t),this._removeOverlay()}.bind(this),\"\"!==this.options.responseType&&this.options.responseType)},s.prototype._setUpListeners=function(){i(this.element).on(\"click\",this.options.trigger,function(t){t&&t.preventDefault(),this.load()}.bind(this))},s.prototype._addOverlay=function(){i(this.element).append(this.$overlay)},s.prototype._removeOverlay=function(){i(this.$overlay).remove()};var o=i.fn.boxRefresh;i.fn.boxRefresh=e,i.fn.boxRefresh.Constructor=s,i.fn.boxRefresh.noConflict=function(){return i.fn.boxRefresh=o,this},i(window).on(\"load\",function(){i(t).each(function(){e.call(i(this))})})}(jQuery),function(i){\"use strict\";function s(t,e){this.element=t,this.options=e,this._setUpListeners()}var r=\"lte.boxwidget\",a={animationSpeed:500,collapseTrigger:'[data-widget=\"collapse\"]',removeTrigger:'[data-widget=\"remove\"]',collapseIcon:\"fa-minus\",expandIcon:\"fa-plus\",removeIcon:\"fa-times\"},t=\".box\",e=\".collapsed-box\",d=\".box-header\",l=\".box-body\",c=\".box-footer\",h=\".box-tools\",f=\"collapsed-box\",p=\"collapsing.boxwidget\",u=\"collapsed.boxwidget\",g=\"expanding.boxwidget\",v=\"expanded.boxwidget\",o=\"removing.boxwidget\",n=\"removed.boxwidget\";function b(n){return this.each(function(){var t=i(this),e=t.data(r);if(!e){var o=i.extend({},a,t.data(),\"object\"==typeof n&&n);t.data(r,e=new s(t,o))}if(\"string\"==typeof n){if(void 0===e[n])throw new Error(\"No method named \"+n);e[n]()}})}s.prototype.toggle=function(){!i(this.element).is(e)?this.collapse():this.expand()},s.prototype.expand=function(){var t=i.Event(v),e=i.Event(g),o=this.options.collapseIcon,n=this.options.expandIcon;i(this.element).removeClass(f),i(this.element).children(d+\", \"+l+\", \"+c).children(h).find(\".\"+n).removeClass(n).addClass(o),i(this.element).children(l+\", \"+c).slideDown(this.options.animationSpeed,function(){i(this.element).trigger(t)}.bind(this)).trigger(e)},s.prototype.collapse=function(){var t=i.Event(u),e=i.Event(p),o=this.options.collapseIcon,n=this.options.expandIcon;i(this.element).children(d+\", \"+l+\", \"+c).children(h).find(\".\"+o).removeClass(o).addClass(n),i(this.element).children(l+\", \"+c).slideUp(this.options.animationSpeed,function(){i(this.element).addClass(f),i(this.element).trigger(t)}.bind(this)).trigger(e)},s.prototype.remove=function(){var t=i.Event(n),e=i.Event(o);i(this.element).slideUp(this.options.animationSpeed,function(){i(this.element).trigger(t),i(this.element).remove()}.bind(this)).trigger(e)},s.prototype._setUpListeners=function(){var e=this;i(this.element).on(\"click\",this.options.collapseTrigger,function(t){return t&&t.preventDefault(),e.toggle(i(this)),!1}),i(this.element).on(\"click\",this.options.removeTrigger,function(t){return t&&t.preventDefault(),e.remove(i(this)),!1})};var m=i.fn.boxWidget;i.fn.boxWidget=b,i.fn.boxWidget.Constructor=s,i.fn.boxWidget.noConflict=function(){return i.fn.boxWidget=m,this},i(window).on(\"load\",function(){i(t).each(function(){b.call(i(this))})})}(jQuery),function(i){\"use strict\";function s(t,e){this.element=t,this.options=e,this.hasBindedResize=!1,this.init()}var r=\"lte.controlsidebar\",a={controlsidebarSlide:!0},e=\".control-sidebar\",t='[data-toggle=\"control-sidebar\"]',o=\".control-sidebar-open\",n=\".control-sidebar-bg\",d=\".wrapper\",l=\".layout-boxed\",c=\"control-sidebar-open\",h=\"control-sidebar-hold-transition\",f=\"collapsed.controlsidebar\",p=\"expanded.controlsidebar\";function u(n){return this.each(function(){var t=i(this),e=t.data(r);if(!e){var o=i.extend({},a,t.data(),\"object\"==typeof n&&n);t.data(r,e=new s(t,o))}\"string\"==typeof n&&e.toggle()})}s.prototype.init=function(){i(this.element).is(t)||i(this).on(\"click\",this.toggle),this.fix(),i(window).resize(function(){this.fix()}.bind(this))},s.prototype.toggle=function(t){t&&t.preventDefault(),this.fix(),i(e).is(o)||i(\"body\").is(o)?this.collapse():this.expand()},s.prototype.expand=function(){i(e).show(),this.options.controlsidebarSlide?i(e).addClass(c):i(\"body\").addClass(h).addClass(c).delay(50).queue(function(){i(\"body\").removeClass(h),i(this).dequeue()}),i(this.element).trigger(i.Event(p))},s.prototype.collapse=function(){this.options.controlsidebarSlide?i(e).removeClass(c):i(\"body\").addClass(h).removeClass(c).delay(50).queue(function(){i(\"body\").removeClass(h),i(this).dequeue()}),i(e).fadeOut(),i(this.element).trigger(i.Event(f))},s.prototype.fix=function(){i(\"body\").is(l)&&this._fixForBoxed(i(n))},s.prototype._fixForBoxed=function(t){t.css({position:\"absolute\",height:i(d).height()})};var g=i.fn.controlSidebar;i.fn.controlSidebar=u,i.fn.controlSidebar.Constructor=s,i.fn.controlSidebar.noConflict=function(){return i.fn.controlSidebar=g,this},i(document).on(\"click\",t,function(t){t&&t.preventDefault(),u.call(i(this),\"toggle\")})}(jQuery),function(n){\"use strict\";function i(t){this.element=t}var s=\"lte.directchat\",t='[data-widget=\"chat-pane-toggle\"]',e=\".direct-chat\",o=\"direct-chat-contacts-open\";function r(o){return this.each(function(){var t=n(this),e=t.data(s);e||t.data(s,e=new i(t)),\"string\"==typeof o&&e.toggle(t)})}i.prototype.toggle=function(t){t.parents(e).first().toggleClass(o)};var a=n.fn.directChat;n.fn.directChat=r,n.fn.directChat.Constructor=i,n.fn.directChat.noConflict=function(){return n.fn.directChat=a,this},n(document).on(\"click\",t,function(t){t&&t.preventDefault(),r.call(n(this),\"toggle\")})}(jQuery),function(i){\"use strict\";function s(t){this.options=t,this.init()}var r=\"lte.pushmenu\",a={collapseScreenSize:767,expandOnHover:!1,expandTransitionDelay:200},t=\".sidebar-collapse\",e=\".main-sidebar\",o=\".content-wrapper\",n=\".sidebar-form .form-control\",d='[data-toggle=\"push-menu\"]',l=\".sidebar-mini\",c=\".sidebar-expanded-on-hover\",h=\".fixed\",f=\"sidebar-collapse\",p=\"sidebar-open\",u=\"sidebar-expanded-on-hover\",g=\"sidebar-mini-expand-feature\",v=\"expanded.pushMenu\",b=\"collapsed.pushMenu\";function m(n){return this.each(function(){var t=i(this),e=t.data(r);if(!e){var o=i.extend({},a,t.data(),\"object\"==typeof n&&n);t.data(r,e=new s(o))}\"toggle\"===n&&e.toggle()})}s.prototype.init=function(){(this.options.expandOnHover||i(\"body\").is(l+h))&&(this.expandOnHover(),i(\"body\").addClass(g)),i(o).click(function(){i(window).width()<=this.options.collapseScreenSize&&i(\"body\").hasClass(p)&&this.close()}.bind(this)),i(n).click(function(t){t.stopPropagation()})},s.prototype.toggle=function(){var t=i(window).width(),e=!i(\"body\").hasClass(f);t<=this.options.collapseScreenSize&&(e=i(\"body\").hasClass(p)),e?this.close():this.open()},s.prototype.open=function(){i(window).width()>this.options.collapseScreenSize?i(\"body\").removeClass(f).trigger(i.Event(v)):i(\"body\").addClass(p).trigger(i.Event(v))},s.prototype.close=function(){i(window).width()>this.options.collapseScreenSize?i(\"body\").addClass(f).trigger(i.Event(b)):i(\"body\").removeClass(p+\" \"+f).trigger(i.Event(b))},s.prototype.expandOnHover=function(){i(e).hover(function(){i(\"body\").is(l+t)&&i(window).width()>this.options.collapseScreenSize&&this.expand()}.bind(this),function(){i(\"body\").is(c)&&this.collapse()}.bind(this))},s.prototype.expand=function(){setTimeout(function(){i(\"body\").removeClass(f).addClass(u)},this.options.expandTransitionDelay)},s.prototype.collapse=function(){setTimeout(function(){i(\"body\").removeClass(u).addClass(f)},this.options.expandTransitionDelay)};var y=i.fn.pushMenu;i.fn.pushMenu=m,i.fn.pushMenu.Constructor=s,i.fn.pushMenu.noConflict=function(){return i.fn.pushMenu=y,this},i(document).on(\"click\",d,function(t){t.preventDefault(),m.call(i(this),\"toggle\")}),i(window).on(\"load\",function(){m.call(i(d))})}(jQuery),function(i){\"use strict\";function s(t,e){this.element=t,this.options=e,this._setUpListeners()}var r=\"lte.todolist\",a={onCheck:function(t){return t},onUnCheck:function(t){return t}},e={data:'[data-widget=\"todo-list\"]'},o=\"done\";function t(n){return this.each(function(){var t=i(this),e=t.data(r);if(!e){var o=i.extend({},a,t.data(),\"object\"==typeof n&&n);t.data(r,e=new s(t,o))}if(\"string\"==typeof e){if(void 0===e[n])throw new Error(\"No method named \"+n);e[n]()}})}s.prototype.toggle=function(t){t.parents(e.li).first().toggleClass(o),t.prop(\"checked\")?this.check(t):this.unCheck(t)},s.prototype.check=function(t){this.options.onCheck.call(t)},s.prototype.unCheck=function(t){this.options.onUnCheck.call(t)},s.prototype._setUpListeners=function(){var t=this;i(this.element).on(\"change ifChanged\",\"input:checkbox\",function(){t.toggle(i(this))})};var n=i.fn.todoList;i.fn.todoList=t,i.fn.todoList.Constructor=s,i.fn.todoList.noConflict=function(){return i.fn.todoList=n,this},i(window).on(\"load\",function(){i(e.data).each(function(){t.call(i(this))})})}(jQuery),function(s){\"use strict\";function n(t,e){this.element=t,this.options=e,s(this.element).addClass(h),s(a+o,this.element).addClass(c),this._setUpListeners()}var i=\"lte.tree\",r={animationSpeed:500,accordion:!0,followLink:!1,trigger:\".treeview a\"},a=\".treeview\",d=\".treeview-menu\",l=\".menu-open, .active\",t='[data-widget=\"tree\"]',o=\".active\",c=\"menu-open\",h=\"tree\",f=\"collapsed.tree\",p=\"expanded.tree\";function e(o){return this.each(function(){var t=s(this);if(!t.data(i)){var e=s.extend({},r,t.data(),\"object\"==typeof o&&o);t.data(i,new n(t,e))}})}n.prototype.toggle=function(t,e){var o=t.next(d),n=t.parent(),i=n.hasClass(c);n.is(a)&&(this.options.followLink&&\"#\"!==t.attr(\"href\")||e.preventDefault(),i?this.collapse(o,n):this.expand(o,n))},n.prototype.expand=function(t,e){var o=s.Event(p);if(this.options.accordion){var n=e.siblings(l),i=n.children(d);this.collapse(i,n)}e.addClass(c),t.stop().slideDown(this.options.animationSpeed,function(){s(this.element).trigger(o),e.height(\"auto\")}.bind(this))},n.prototype.collapse=function(t,e){var o=s.Event(f);e.removeClass(c),t.stop().slideUp(this.options.animationSpeed,function(){s(this.element).trigger(o),e.find(a).removeClass(c).find(d).hide()}.bind(this))},n.prototype._setUpListeners=function(){var e=this;s(this.element).on(\"click\",this.options.trigger,function(t){e.toggle(s(this),t)})};var u=s.fn.tree;s.fn.tree=e,s.fn.tree.Constructor=n,s.fn.tree.noConflict=function(){return s.fn.tree=u,this},s(window).on(\"load\",function(){s(t).each(function(){e.call(s(this))})})}(jQuery),function(a){\"use strict\";function i(t){this.options=t,this.bindedResize=!1,this.activate()}var s=\"lte.layout\",r={slimscroll:!0,resetHeight:!0},d=\".wrapper\",l=\".content-wrapper\",c=\".layout-boxed\",h=\".main-footer\",f=\".main-header\",t=\".main-sidebar\",e=\"slimScrollDiv\",p=\".sidebar\",u=\".control-sidebar\",o=\".sidebar-menu\",n=\".main-header .logo\",g=\"fixed\",v=\"hold-transition\";function b(n){return this.each(function(){var t=a(this),e=t.data(s);if(!e){var o=a.extend({},r,t.data(),\"object\"==typeof n&&n);t.data(s,e=new i(o))}if(\"string\"==typeof n){if(void 0===e[n])throw new Error(\"No method named \"+n);e[n]()}})}i.prototype.activate=function(){this.fix(),this.fixSidebar(),a(\"body\").removeClass(v),this.options.resetHeight&&a(\"body, html, \"+d).css({height:\"auto\",\"min-height\":\"100%\"}),this.bindedResize||(a(window).resize(function(){this.fix(),this.fixSidebar(),a(n+\", \"+p).one(\"webkitTransitionEnd otransitionend oTransitionEnd msTransitionEnd transitionend\",function(){this.fix(),this.fixSidebar()}.bind(this))}.bind(this)),this.bindedResize=!0),a(o).on(\"expanded.tree\",function(){this.fix(),this.fixSidebar()}.bind(this)),a(o).on(\"collapsed.tree\",function(){this.fix(),this.fixSidebar()}.bind(this))},i.prototype.fix=function(){a(c+\" > \"+d).css(\"overflow\",\"hidden\");var t=a(h).outerHeight()||0,e=a(f).outerHeight()||0,o=e+t,n=a(window).height(),i=a(p).outerHeight()||0;if(a(\"body\").hasClass(g))a(l).css(\"min-height\",n-t);else{var s;s=i+e<=n?(a(l).css(\"min-height\",n-o),n-o):(a(l).css(\"min-height\",i),i);var r=a(u);void 0!==r&&r.height()>s&&a(l).css(\"min-height\",r.height())}},i.prototype.fixSidebar=function(){a(\"body\").hasClass(g)?this.options.slimscroll&&void 0!==a.fn.slimScroll&&0===a(t).find(e).length&&a(p).slimScroll({height:a(window).height()-a(f).height()+\"px\"}):void 0!==a.fn.slimScroll&&a(p).slimScroll({destroy:!0}).height(\"auto\")};var m=a.fn.layout;a.fn.layout=b,a.fn.layout.Constuctor=i,a.fn.layout.noConflict=function(){return a.fn.layout=m,this},a(window).on(\"load\",function(){b.call(a(\"body\"))})}(jQuery);","/*\n * jQuery File Upload Plugin\n * https://github.com/blueimp/jQuery-File-Upload\n *\n * Copyright 2010, Sebastian Tschan\n * https://blueimp.net\n *\n * Licensed under the MIT license:\n * https://opensource.org/licenses/MIT\n */\n\n/* jshint nomen:false */\n/* global define, require, window, document, location, Blob, FormData */\n\n;(function (factory) {\n 'use strict';\n if (typeof define === 'function' && define.amd) {\n // Register as an anonymous AMD module:\n define([\n 'jquery',\n 'jquery-ui/ui/widget'\n ], factory);\n } else if (typeof exports === 'object') {\n // Node/CommonJS:\n factory(\n require('jquery'),\n require('./vendor/jquery.ui.widget')\n );\n } else {\n // Browser globals:\n factory(window.jQuery);\n }\n}(function ($) {\n 'use strict';\n\n // Detect file input support, based on\n // http://viljamis.com/blog/2012/file-upload-support-on-mobile/\n $.support.fileInput = !(new RegExp(\n // Handle devices which give false positives for the feature detection:\n '(Android (1\\\\.[0156]|2\\\\.[01]))' +\n '|(Windows Phone (OS 7|8\\\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +\n '|(w(eb)?OSBrowser)|(webOS)' +\n '|(Kindle/(1\\\\.0|2\\\\.[05]|3\\\\.0))'\n ).test(window.navigator.userAgent) ||\n // Feature detection for all other devices:\n $('').prop('disabled'));\n\n // The FileReader API is not actually used, but works as feature detection,\n // as some Safari versions (5?) support XHR file uploads via the FormData API,\n // but not non-multipart XHR file uploads.\n // window.XMLHttpRequestUpload is not available on IE10, so we check for\n // window.ProgressEvent instead to detect XHR2 file upload capability:\n $.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader);\n $.support.xhrFormDataFileUpload = !!window.FormData;\n\n // Detect support for Blob slicing (required for chunked uploads):\n $.support.blobSlice = window.Blob && (Blob.prototype.slice ||\n Blob.prototype.webkitSlice || Blob.prototype.mozSlice);\n\n // Helper function to create drag handlers for dragover/dragenter/dragleave:\n function getDragHandler(type) {\n var isDragOver = type === 'dragover';\n return function (e) {\n e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;\n var dataTransfer = e.dataTransfer;\n if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 &&\n this._trigger(\n type,\n $.Event(type, {delegatedEvent: e})\n ) !== false) {\n e.preventDefault();\n if (isDragOver) {\n dataTransfer.dropEffect = 'copy';\n }\n }\n };\n }\n\n // The fileupload widget listens for change events on file input fields defined\n // via fileInput setting and paste or drop events of the given dropZone.\n // In addition to the default jQuery Widget methods, the fileupload widget\n // exposes the \"add\" and \"send\" methods, to add or directly send files using\n // the fileupload API.\n // By default, files added via file input selection, paste, drag & drop or\n // \"add\" method are uploaded immediately, but it is possible to override\n // the \"add\" callback option to queue file uploads.\n $.widget('blueimp.fileupload', {\n\n options: {\n // The drop target element(s), by the default the complete document.\n // Set to null to disable drag & drop support:\n dropZone: $(document),\n // The paste target element(s), by the default undefined.\n // Set to a DOM node or jQuery object to enable file pasting:\n pasteZone: undefined,\n // The file input field(s), that are listened to for change events.\n // If undefined, it is set to the file input fields inside\n // of the widget element on plugin initialization.\n // Set to null to disable the change listener.\n fileInput: undefined,\n // By default, the file input field is replaced with a clone after\n // each input field change event. This is required for iframe transport\n // queues and allows change events to be fired for the same file\n // selection, but can be disabled by setting the following option to false:\n replaceFileInput: true,\n // The parameter name for the file form data (the request argument name).\n // If undefined or empty, the name property of the file input field is\n // used, or \"files[]\" if the file input name property is also empty,\n // can be a string or an array of strings:\n paramName: undefined,\n // By default, each file of a selection is uploaded using an individual\n // request for XHR type uploads. Set to false to upload file\n // selections in one request each:\n singleFileUploads: true,\n // To limit the number of files uploaded with one XHR request,\n // set the following option to an integer greater than 0:\n limitMultiFileUploads: undefined,\n // The following option limits the number of files uploaded with one\n // XHR request to keep the request size under or equal to the defined\n // limit in bytes:\n limitMultiFileUploadSize: undefined,\n // Multipart file uploads add a number of bytes to each uploaded file,\n // therefore the following option adds an overhead for each file used\n // in the limitMultiFileUploadSize configuration:\n limitMultiFileUploadSizeOverhead: 512,\n // Set the following option to true to issue all file upload requests\n // in a sequential order:\n sequentialUploads: false,\n // To limit the number of concurrent uploads,\n // set the following option to an integer greater than 0:\n limitConcurrentUploads: undefined,\n // Set the following option to true to force iframe transport uploads:\n forceIframeTransport: false,\n // Set the following option to the location of a redirect url on the\n // origin server, for cross-domain iframe transport uploads:\n redirect: undefined,\n // The parameter name for the redirect url, sent as part of the form\n // data and set to 'redirect' if this option is empty:\n redirectParamName: undefined,\n // Set the following option to the location of a postMessage window,\n // to enable postMessage transport uploads:\n postMessage: undefined,\n // By default, XHR file uploads are sent as multipart/form-data.\n // The iframe transport is always using multipart/form-data.\n // Set to false to enable non-multipart XHR uploads:\n multipart: true,\n // To upload large files in smaller chunks, set the following option\n // to a preferred maximum chunk size. If set to 0, null or undefined,\n // or the browser does not support the required Blob API, files will\n // be uploaded as a whole.\n maxChunkSize: undefined,\n // When a non-multipart upload or a chunked multipart upload has been\n // aborted, this option can be used to resume the upload by setting\n // it to the size of the already uploaded bytes. This option is most\n // useful when modifying the options object inside of the \"add\" or\n // \"send\" callbacks, as the options are cloned for each file upload.\n uploadedBytes: undefined,\n // By default, failed (abort or error) file uploads are removed from the\n // global progress calculation. Set the following option to false to\n // prevent recalculating the global progress data:\n recalculateProgress: true,\n // Interval in milliseconds to calculate and trigger progress events:\n progressInterval: 100,\n // Interval in milliseconds to calculate progress bitrate:\n bitrateInterval: 500,\n // By default, uploads are started automatically when adding files:\n autoUpload: true,\n // By default, duplicate file names are expected to be handled on\n // the server-side. If this is not possible (e.g. when uploading\n // files directly to Amazon S3), the following option can be set to\n // an empty object or an object mapping existing filenames, e.g.:\n // { \"image.jpg\": true, \"image (1).jpg\": true }\n // If it is set, all files will be uploaded with unique filenames,\n // adding increasing number suffixes if necessary, e.g.:\n // \"image (2).jpg\"\n uniqueFilenames: undefined,\n\n // Error and info messages:\n messages: {\n uploadedBytes: 'Uploaded bytes exceed file size'\n },\n\n // Translation function, gets the message key to be translated\n // and an object with context specific data as arguments:\n i18n: function (message, context) {\n message = this.messages[message] || message.toString();\n if (context) {\n $.each(context, function (key, value) {\n message = message.replace('{' + key + '}', value);\n });\n }\n return message;\n },\n\n // Additional form data to be sent along with the file uploads can be set\n // using this option, which accepts an array of objects with name and\n // value properties, a function returning such an array, a FormData\n // object (for XHR file uploads), or a simple object.\n // The form of the first fileInput is given as parameter to the function:\n formData: function (form) {\n return form.serializeArray();\n },\n\n // The add callback is invoked as soon as files are added to the fileupload\n // widget (via file input selection, drag & drop, paste or add API call).\n // If the singleFileUploads option is enabled, this callback will be\n // called once for each file in the selection for XHR file uploads, else\n // once for each file selection.\n //\n // The upload starts when the submit method is invoked on the data parameter.\n // The data object contains a files property holding the added files\n // and allows you to override plugin options as well as define ajax settings.\n //\n // Listeners for this callback can also be bound the following way:\n // .bind('fileuploadadd', func);\n //\n // data.submit() returns a Promise object and allows to attach additional\n // handlers using jQuery's Deferred callbacks:\n // data.submit().done(func).fail(func).always(func);\n add: function (e, data) {\n if (e.isDefaultPrevented()) {\n return false;\n }\n if (data.autoUpload || (data.autoUpload !== false &&\n $(this).fileupload('option', 'autoUpload'))) {\n data.process().done(function () {\n data.submit();\n });\n }\n },\n\n // Other callbacks:\n\n // Callback for the submit event of each file upload:\n // submit: function (e, data) {}, // .bind('fileuploadsubmit', func);\n\n // Callback for the start of each file upload request:\n // send: function (e, data) {}, // .bind('fileuploadsend', func);\n\n // Callback for successful uploads:\n // done: function (e, data) {}, // .bind('fileuploaddone', func);\n\n // Callback for failed (abort or error) uploads:\n // fail: function (e, data) {}, // .bind('fileuploadfail', func);\n\n // Callback for completed (success, abort or error) requests:\n // always: function (e, data) {}, // .bind('fileuploadalways', func);\n\n // Callback for upload progress events:\n // progress: function (e, data) {}, // .bind('fileuploadprogress', func);\n\n // Callback for global upload progress events:\n // progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);\n\n // Callback for uploads start, equivalent to the global ajaxStart event:\n // start: function (e) {}, // .bind('fileuploadstart', func);\n\n // Callback for uploads stop, equivalent to the global ajaxStop event:\n // stop: function (e) {}, // .bind('fileuploadstop', func);\n\n // Callback for change events of the fileInput(s):\n // change: function (e, data) {}, // .bind('fileuploadchange', func);\n\n // Callback for paste events to the pasteZone(s):\n // paste: function (e, data) {}, // .bind('fileuploadpaste', func);\n\n // Callback for drop events of the dropZone(s):\n // drop: function (e, data) {}, // .bind('fileuploaddrop', func);\n\n // Callback for dragover events of the dropZone(s):\n // dragover: function (e) {}, // .bind('fileuploaddragover', func);\n\n // Callback before the start of each chunk upload request (before form data initialization):\n // chunkbeforesend: function (e, data) {}, // .bind('fileuploadchunkbeforesend', func);\n\n // Callback for the start of each chunk upload request:\n // chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);\n\n // Callback for successful chunk uploads:\n // chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func);\n\n // Callback for failed (abort or error) chunk uploads:\n // chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func);\n\n // Callback for completed (success, abort or error) chunk upload requests:\n // chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func);\n\n // The plugin options are used as settings object for the ajax calls.\n // The following are jQuery ajax settings required for the file uploads:\n processData: false,\n contentType: false,\n cache: false,\n timeout: 0\n },\n\n // A list of options that require reinitializing event listeners and/or\n // special initialization code:\n _specialOptions: [\n 'fileInput',\n 'dropZone',\n 'pasteZone',\n 'multipart',\n 'forceIframeTransport'\n ],\n\n _blobSlice: $.support.blobSlice && function () {\n var slice = this.slice || this.webkitSlice || this.mozSlice;\n return slice.apply(this, arguments);\n },\n\n _BitrateTimer: function () {\n this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());\n this.loaded = 0;\n this.bitrate = 0;\n this.getBitrate = function (now, loaded, interval) {\n var timeDiff = now - this.timestamp;\n if (!this.bitrate || !interval || timeDiff > interval) {\n this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;\n this.loaded = loaded;\n this.timestamp = now;\n }\n return this.bitrate;\n };\n },\n\n _isXHRUpload: function (options) {\n return !options.forceIframeTransport &&\n ((!options.multipart && $.support.xhrFileUpload) ||\n $.support.xhrFormDataFileUpload);\n },\n\n _getFormData: function (options) {\n var formData;\n if ($.type(options.formData) === 'function') {\n return options.formData(options.form);\n }\n if ($.isArray(options.formData)) {\n return options.formData;\n }\n if ($.type(options.formData) === 'object') {\n formData = [];\n $.each(options.formData, function (name, value) {\n formData.push({name: name, value: value});\n });\n return formData;\n }\n return [];\n },\n\n _getTotal: function (files) {\n var total = 0;\n $.each(files, function (index, file) {\n total += file.size || 1;\n });\n return total;\n },\n\n _initProgressObject: function (obj) {\n var progress = {\n loaded: 0,\n total: 0,\n bitrate: 0\n };\n if (obj._progress) {\n $.extend(obj._progress, progress);\n } else {\n obj._progress = progress;\n }\n },\n\n _initResponseObject: function (obj) {\n var prop;\n if (obj._response) {\n for (prop in obj._response) {\n if (obj._response.hasOwnProperty(prop)) {\n delete obj._response[prop];\n }\n }\n } else {\n obj._response = {};\n }\n },\n\n _onProgress: function (e, data) {\n if (e.lengthComputable) {\n var now = ((Date.now) ? Date.now() : (new Date()).getTime()),\n loaded;\n if (data._time && data.progressInterval &&\n (now - data._time < data.progressInterval) &&\n e.loaded !== e.total) {\n return;\n }\n data._time = now;\n loaded = Math.floor(\n e.loaded / e.total * (data.chunkSize || data._progress.total)\n ) + (data.uploadedBytes || 0);\n // Add the difference from the previously loaded state\n // to the global loaded counter:\n this._progress.loaded += (loaded - data._progress.loaded);\n this._progress.bitrate = this._bitrateTimer.getBitrate(\n now,\n this._progress.loaded,\n data.bitrateInterval\n );\n data._progress.loaded = data.loaded = loaded;\n data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(\n now,\n loaded,\n data.bitrateInterval\n );\n // Trigger a custom progress event with a total data property set\n // to the file size(s) of the current upload and a loaded data\n // property calculated accordingly:\n this._trigger(\n 'progress',\n $.Event('progress', {delegatedEvent: e}),\n data\n );\n // Trigger a global progress event for all current file uploads,\n // including ajax calls queued for sequential file uploads:\n this._trigger(\n 'progressall',\n $.Event('progressall', {delegatedEvent: e}),\n this._progress\n );\n }\n },\n\n _initProgressListener: function (options) {\n var that = this,\n xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();\n // Accesss to the native XHR object is required to add event listeners\n // for the upload progress event:\n if (xhr.upload) {\n $(xhr.upload).bind('progress', function (e) {\n var oe = e.originalEvent;\n // Make sure the progress event properties get copied over:\n e.lengthComputable = oe.lengthComputable;\n e.loaded = oe.loaded;\n e.total = oe.total;\n that._onProgress(e, options);\n });\n options.xhr = function () {\n return xhr;\n };\n }\n },\n\n _deinitProgressListener: function (options) {\n var xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();\n if (xhr.upload) {\n $(xhr.upload).unbind('progress');\n }\n },\n\n _isInstanceOf: function (type, obj) {\n // Cross-frame instanceof check\n return Object.prototype.toString.call(obj) === '[object ' + type + ']';\n },\n\n _getUniqueFilename: function (name, map) {\n name = String(name);\n if (map[name]) {\n name = name.replace(\n /(?: \\(([\\d]+)\\))?(\\.[^.]+)?$/,\n function (_, p1, p2) {\n var index = p1 ? Number(p1) + 1 : 1;\n var ext = p2 || '';\n return ' (' + index + ')' + ext;\n }\n );\n return this._getUniqueFilename(name, map);\n }\n map[name] = true;\n return name;\n },\n\n _initXHRData: function (options) {\n var that = this,\n formData,\n file = options.files[0],\n // Ignore non-multipart setting if not supported:\n multipart = options.multipart || !$.support.xhrFileUpload,\n paramName = $.type(options.paramName) === 'array' ?\n options.paramName[0] : options.paramName;\n options.headers = $.extend({}, options.headers);\n if (options.contentRange) {\n options.headers['Content-Range'] = options.contentRange;\n }\n if (!multipart || options.blob || !this._isInstanceOf('File', file)) {\n options.headers['Content-Disposition'] = 'attachment; filename=\"' +\n encodeURI(file.uploadName || file.name) + '\"';\n }\n if (!multipart) {\n options.contentType = file.type || 'application/octet-stream';\n options.data = options.blob || file;\n } else if ($.support.xhrFormDataFileUpload) {\n if (options.postMessage) {\n // window.postMessage does not allow sending FormData\n // objects, so we just add the File/Blob objects to\n // the formData array and let the postMessage window\n // create the FormData object out of this array:\n formData = this._getFormData(options);\n if (options.blob) {\n formData.push({\n name: paramName,\n value: options.blob\n });\n } else {\n $.each(options.files, function (index, file) {\n formData.push({\n name: ($.type(options.paramName) === 'array' &&\n options.paramName[index]) || paramName,\n value: file\n });\n });\n }\n } else {\n if (that._isInstanceOf('FormData', options.formData)) {\n formData = options.formData;\n } else {\n formData = new FormData();\n $.each(this._getFormData(options), function (index, field) {\n formData.append(field.name, field.value);\n });\n }\n if (options.blob) {\n formData.append(\n paramName,\n options.blob,\n file.uploadName || file.name\n );\n } else {\n $.each(options.files, function (index, file) {\n // This check allows the tests to run with\n // dummy objects:\n if (that._isInstanceOf('File', file) ||\n that._isInstanceOf('Blob', file)) {\n var fileName = file.uploadName || file.name;\n if (options.uniqueFilenames) {\n fileName = that._getUniqueFilename(\n fileName,\n options.uniqueFilenames\n );\n }\n formData.append(\n ($.type(options.paramName) === 'array' &&\n options.paramName[index]) || paramName,\n file,\n fileName\n );\n }\n });\n }\n }\n options.data = formData;\n }\n // Blob reference is not needed anymore, free memory:\n options.blob = null;\n },\n\n _initIframeSettings: function (options) {\n var targetHost = $('
      ').prop('href', options.url).prop('host');\n // Setting the dataType to iframe enables the iframe transport:\n options.dataType = 'iframe ' + (options.dataType || '');\n // The iframe transport accepts a serialized array as form data:\n options.formData = this._getFormData(options);\n // Add redirect url to form data on cross-domain uploads:\n if (options.redirect && targetHost && targetHost !== location.host) {\n options.formData.push({\n name: options.redirectParamName || 'redirect',\n value: options.redirect\n });\n }\n },\n\n _initDataSettings: function (options) {\n if (this._isXHRUpload(options)) {\n if (!this._chunkedUpload(options, true)) {\n if (!options.data) {\n this._initXHRData(options);\n }\n this._initProgressListener(options);\n }\n if (options.postMessage) {\n // Setting the dataType to postmessage enables the\n // postMessage transport:\n options.dataType = 'postmessage ' + (options.dataType || '');\n }\n } else {\n this._initIframeSettings(options);\n }\n },\n\n _getParamName: function (options) {\n var fileInput = $(options.fileInput),\n paramName = options.paramName;\n if (!paramName) {\n paramName = [];\n fileInput.each(function () {\n var input = $(this),\n name = input.prop('name') || 'files[]',\n i = (input.prop('files') || [1]).length;\n while (i) {\n paramName.push(name);\n i -= 1;\n }\n });\n if (!paramName.length) {\n paramName = [fileInput.prop('name') || 'files[]'];\n }\n } else if (!$.isArray(paramName)) {\n paramName = [paramName];\n }\n return paramName;\n },\n\n _initFormSettings: function (options) {\n // Retrieve missing options from the input field and the\n // associated form, if available:\n if (!options.form || !options.form.length) {\n options.form = $(options.fileInput.prop('form'));\n // If the given file input doesn't have an associated form,\n // use the default widget file input's form:\n if (!options.form.length) {\n options.form = $(this.options.fileInput.prop('form'));\n }\n }\n options.paramName = this._getParamName(options);\n if (!options.url) {\n options.url = options.form.prop('action') || location.href;\n }\n // The HTTP request method must be \"POST\" or \"PUT\":\n options.type = (options.type ||\n ($.type(options.form.prop('method')) === 'string' &&\n options.form.prop('method')) || ''\n ).toUpperCase();\n if (options.type !== 'POST' && options.type !== 'PUT' &&\n options.type !== 'PATCH') {\n options.type = 'POST';\n }\n if (!options.formAcceptCharset) {\n options.formAcceptCharset = options.form.attr('accept-charset');\n }\n },\n\n _getAJAXSettings: function (data) {\n var options = $.extend({}, this.options, data);\n this._initFormSettings(options);\n this._initDataSettings(options);\n return options;\n },\n\n // jQuery 1.6 doesn't provide .state(),\n // while jQuery 1.8+ removed .isRejected() and .isResolved():\n _getDeferredState: function (deferred) {\n if (deferred.state) {\n return deferred.state();\n }\n if (deferred.isResolved()) {\n return 'resolved';\n }\n if (deferred.isRejected()) {\n return 'rejected';\n }\n return 'pending';\n },\n\n // Maps jqXHR callbacks to the equivalent\n // methods of the given Promise object:\n _enhancePromise: function (promise) {\n promise.success = promise.done;\n promise.error = promise.fail;\n promise.complete = promise.always;\n return promise;\n },\n\n // Creates and returns a Promise object enhanced with\n // the jqXHR methods abort, success, error and complete:\n _getXHRPromise: function (resolveOrReject, context, args) {\n var dfd = $.Deferred(),\n promise = dfd.promise();\n context = context || this.options.context || promise;\n if (resolveOrReject === true) {\n dfd.resolveWith(context, args);\n } else if (resolveOrReject === false) {\n dfd.rejectWith(context, args);\n }\n promise.abort = dfd.promise;\n return this._enhancePromise(promise);\n },\n\n // Adds convenience methods to the data callback argument:\n _addConvenienceMethods: function (e, data) {\n var that = this,\n getPromise = function (args) {\n return $.Deferred().resolveWith(that, args).promise();\n };\n data.process = function (resolveFunc, rejectFunc) {\n if (resolveFunc || rejectFunc) {\n data._processQueue = this._processQueue =\n (this._processQueue || getPromise([this])).then(\n function () {\n if (data.errorThrown) {\n return $.Deferred()\n .rejectWith(that, [data]).promise();\n }\n return getPromise(arguments);\n }\n ).then(resolveFunc, rejectFunc);\n }\n return this._processQueue || getPromise([this]);\n };\n data.submit = function () {\n if (this.state() !== 'pending') {\n data.jqXHR = this.jqXHR =\n (that._trigger(\n 'submit',\n $.Event('submit', {delegatedEvent: e}),\n this\n ) !== false) && that._onSend(e, this);\n }\n return this.jqXHR || that._getXHRPromise();\n };\n data.abort = function () {\n if (this.jqXHR) {\n return this.jqXHR.abort();\n }\n this.errorThrown = 'abort';\n that._trigger('fail', null, this);\n return that._getXHRPromise(false);\n };\n data.state = function () {\n if (this.jqXHR) {\n return that._getDeferredState(this.jqXHR);\n }\n if (this._processQueue) {\n return that._getDeferredState(this._processQueue);\n }\n };\n data.processing = function () {\n return !this.jqXHR && this._processQueue && that\n ._getDeferredState(this._processQueue) === 'pending';\n };\n data.progress = function () {\n return this._progress;\n };\n data.response = function () {\n return this._response;\n };\n },\n\n // Parses the Range header from the server response\n // and returns the uploaded bytes:\n _getUploadedBytes: function (jqXHR) {\n var range = jqXHR.getResponseHeader('Range'),\n parts = range && range.split('-'),\n upperBytesPos = parts && parts.length > 1 &&\n parseInt(parts[1], 10);\n return upperBytesPos && upperBytesPos + 1;\n },\n\n // Uploads a file in multiple, sequential requests\n // by splitting the file up in multiple blob chunks.\n // If the second parameter is true, only tests if the file\n // should be uploaded in chunks, but does not invoke any\n // upload requests:\n _chunkedUpload: function (options, testOnly) {\n options.uploadedBytes = options.uploadedBytes || 0;\n var that = this,\n file = options.files[0],\n fs = file.size,\n ub = options.uploadedBytes,\n mcs = options.maxChunkSize || fs,\n slice = this._blobSlice,\n dfd = $.Deferred(),\n promise = dfd.promise(),\n jqXHR,\n upload;\n if (!(this._isXHRUpload(options) && slice && (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs)) ||\n options.data) {\n return false;\n }\n if (testOnly) {\n return true;\n }\n if (ub >= fs) {\n file.error = options.i18n('uploadedBytes');\n return this._getXHRPromise(\n false,\n options.context,\n [null, 'error', file.error]\n );\n }\n // The chunk upload method:\n upload = function () {\n // Clone the options object for each chunk upload:\n var o = $.extend({}, options),\n currentLoaded = o._progress.loaded;\n o.blob = slice.call(\n file,\n ub,\n ub + ($.type(mcs) === 'function' ? mcs(o) : mcs),\n file.type\n );\n // Store the current chunk size, as the blob itself\n // will be dereferenced after data processing:\n o.chunkSize = o.blob.size;\n // Expose the chunk bytes position range:\n o.contentRange = 'bytes ' + ub + '-' +\n (ub + o.chunkSize - 1) + '/' + fs;\n // Trigger chunkbeforesend to allow form data to be updated for this chunk\n that._trigger('chunkbeforesend', null, o);\n // Process the upload data (the blob and potential form data):\n that._initXHRData(o);\n // Add progress listeners for this chunk upload:\n that._initProgressListener(o);\n jqXHR = ((that._trigger('chunksend', null, o) !== false && $.ajax(o)) ||\n that._getXHRPromise(false, o.context))\n .done(function (result, textStatus, jqXHR) {\n ub = that._getUploadedBytes(jqXHR) ||\n (ub + o.chunkSize);\n // Create a progress event if no final progress event\n // with loaded equaling total has been triggered\n // for this chunk:\n if (currentLoaded + o.chunkSize - o._progress.loaded) {\n that._onProgress($.Event('progress', {\n lengthComputable: true,\n loaded: ub - o.uploadedBytes,\n total: ub - o.uploadedBytes\n }), o);\n }\n options.uploadedBytes = o.uploadedBytes = ub;\n o.result = result;\n o.textStatus = textStatus;\n o.jqXHR = jqXHR;\n that._trigger('chunkdone', null, o);\n that._trigger('chunkalways', null, o);\n if (ub < fs) {\n // File upload not yet complete,\n // continue with the next chunk:\n upload();\n } else {\n dfd.resolveWith(\n o.context,\n [result, textStatus, jqXHR]\n );\n }\n })\n .fail(function (jqXHR, textStatus, errorThrown) {\n o.jqXHR = jqXHR;\n o.textStatus = textStatus;\n o.errorThrown = errorThrown;\n that._trigger('chunkfail', null, o);\n that._trigger('chunkalways', null, o);\n dfd.rejectWith(\n o.context,\n [jqXHR, textStatus, errorThrown]\n );\n })\n .always(function () {\n that._deinitProgressListener(o);\n });\n };\n this._enhancePromise(promise);\n promise.abort = function () {\n return jqXHR.abort();\n };\n upload();\n return promise;\n },\n\n _beforeSend: function (e, data) {\n if (this._active === 0) {\n // the start callback is triggered when an upload starts\n // and no other uploads are currently running,\n // equivalent to the global ajaxStart event:\n this._trigger('start');\n // Set timer for global bitrate progress calculation:\n this._bitrateTimer = new this._BitrateTimer();\n // Reset the global progress values:\n this._progress.loaded = this._progress.total = 0;\n this._progress.bitrate = 0;\n }\n // Make sure the container objects for the .response() and\n // .progress() methods on the data object are available\n // and reset to their initial state:\n this._initResponseObject(data);\n this._initProgressObject(data);\n data._progress.loaded = data.loaded = data.uploadedBytes || 0;\n data._progress.total = data.total = this._getTotal(data.files) || 1;\n data._progress.bitrate = data.bitrate = 0;\n this._active += 1;\n // Initialize the global progress values:\n this._progress.loaded += data.loaded;\n this._progress.total += data.total;\n },\n\n _onDone: function (result, textStatus, jqXHR, options) {\n var total = options._progress.total,\n response = options._response;\n if (options._progress.loaded < total) {\n // Create a progress event if no final progress event\n // with loaded equaling total has been triggered:\n this._onProgress($.Event('progress', {\n lengthComputable: true,\n loaded: total,\n total: total\n }), options);\n }\n response.result = options.result = result;\n response.textStatus = options.textStatus = textStatus;\n response.jqXHR = options.jqXHR = jqXHR;\n this._trigger('done', null, options);\n },\n\n _onFail: function (jqXHR, textStatus, errorThrown, options) {\n var response = options._response;\n if (options.recalculateProgress) {\n // Remove the failed (error or abort) file upload from\n // the global progress calculation:\n this._progress.loaded -= options._progress.loaded;\n this._progress.total -= options._progress.total;\n }\n response.jqXHR = options.jqXHR = jqXHR;\n response.textStatus = options.textStatus = textStatus;\n response.errorThrown = options.errorThrown = errorThrown;\n this._trigger('fail', null, options);\n },\n\n _onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {\n // jqXHRorResult, textStatus and jqXHRorError are added to the\n // options object via done and fail callbacks\n this._trigger('always', null, options);\n },\n\n _onSend: function (e, data) {\n if (!data.submit) {\n this._addConvenienceMethods(e, data);\n }\n var that = this,\n jqXHR,\n aborted,\n slot,\n pipe,\n options = that._getAJAXSettings(data),\n send = function () {\n that._sending += 1;\n // Set timer for bitrate progress calculation:\n options._bitrateTimer = new that._BitrateTimer();\n jqXHR = jqXHR || (\n ((aborted || that._trigger(\n 'send',\n $.Event('send', {delegatedEvent: e}),\n options\n ) === false) &&\n that._getXHRPromise(false, options.context, aborted)) ||\n that._chunkedUpload(options) || $.ajax(options)\n ).done(function (result, textStatus, jqXHR) {\n that._onDone(result, textStatus, jqXHR, options);\n }).fail(function (jqXHR, textStatus, errorThrown) {\n that._onFail(jqXHR, textStatus, errorThrown, options);\n }).always(function (jqXHRorResult, textStatus, jqXHRorError) {\n that._deinitProgressListener(options);\n that._onAlways(\n jqXHRorResult,\n textStatus,\n jqXHRorError,\n options\n );\n that._sending -= 1;\n that._active -= 1;\n if (options.limitConcurrentUploads &&\n options.limitConcurrentUploads > that._sending) {\n // Start the next queued upload,\n // that has not been aborted:\n var nextSlot = that._slots.shift();\n while (nextSlot) {\n if (that._getDeferredState(nextSlot) === 'pending') {\n nextSlot.resolve();\n break;\n }\n nextSlot = that._slots.shift();\n }\n }\n if (that._active === 0) {\n // The stop callback is triggered when all uploads have\n // been completed, equivalent to the global ajaxStop event:\n that._trigger('stop');\n }\n });\n return jqXHR;\n };\n this._beforeSend(e, options);\n if (this.options.sequentialUploads ||\n (this.options.limitConcurrentUploads &&\n this.options.limitConcurrentUploads <= this._sending)) {\n if (this.options.limitConcurrentUploads > 1) {\n slot = $.Deferred();\n this._slots.push(slot);\n pipe = slot.then(send);\n } else {\n this._sequence = this._sequence.then(send, send);\n pipe = this._sequence;\n }\n // Return the piped Promise object, enhanced with an abort method,\n // which is delegated to the jqXHR object of the current upload,\n // and jqXHR callbacks mapped to the equivalent Promise methods:\n pipe.abort = function () {\n aborted = [undefined, 'abort', 'abort'];\n if (!jqXHR) {\n if (slot) {\n slot.rejectWith(options.context, aborted);\n }\n return send();\n }\n return jqXHR.abort();\n };\n return this._enhancePromise(pipe);\n }\n return send();\n },\n\n _onAdd: function (e, data) {\n var that = this,\n result = true,\n options = $.extend({}, this.options, data),\n files = data.files,\n filesLength = files.length,\n limit = options.limitMultiFileUploads,\n limitSize = options.limitMultiFileUploadSize,\n overhead = options.limitMultiFileUploadSizeOverhead,\n batchSize = 0,\n paramName = this._getParamName(options),\n paramNameSet,\n paramNameSlice,\n fileSet,\n i,\n j = 0;\n if (!filesLength) {\n return false;\n }\n if (limitSize && files[0].size === undefined) {\n limitSize = undefined;\n }\n if (!(options.singleFileUploads || limit || limitSize) ||\n !this._isXHRUpload(options)) {\n fileSet = [files];\n paramNameSet = [paramName];\n } else if (!(options.singleFileUploads || limitSize) && limit) {\n fileSet = [];\n paramNameSet = [];\n for (i = 0; i < filesLength; i += limit) {\n fileSet.push(files.slice(i, i + limit));\n paramNameSlice = paramName.slice(i, i + limit);\n if (!paramNameSlice.length) {\n paramNameSlice = paramName;\n }\n paramNameSet.push(paramNameSlice);\n }\n } else if (!options.singleFileUploads && limitSize) {\n fileSet = [];\n paramNameSet = [];\n for (i = 0; i < filesLength; i = i + 1) {\n batchSize += files[i].size + overhead;\n if (i + 1 === filesLength ||\n ((batchSize + files[i + 1].size + overhead) > limitSize) ||\n (limit && i + 1 - j >= limit)) {\n fileSet.push(files.slice(j, i + 1));\n paramNameSlice = paramName.slice(j, i + 1);\n if (!paramNameSlice.length) {\n paramNameSlice = paramName;\n }\n paramNameSet.push(paramNameSlice);\n j = i + 1;\n batchSize = 0;\n }\n }\n } else {\n paramNameSet = paramName;\n }\n data.originalFiles = files;\n $.each(fileSet || files, function (index, element) {\n var newData = $.extend({}, data);\n newData.files = fileSet ? element : [element];\n newData.paramName = paramNameSet[index];\n that._initResponseObject(newData);\n that._initProgressObject(newData);\n that._addConvenienceMethods(e, newData);\n result = that._trigger(\n 'add',\n $.Event('add', {delegatedEvent: e}),\n newData\n );\n return result;\n });\n return result;\n },\n\n _replaceFileInput: function (data) {\n var input = data.fileInput,\n inputClone = input.clone(true),\n restoreFocus = input.is(document.activeElement);\n // Add a reference for the new cloned file input to the data argument:\n data.fileInputClone = inputClone;\n $('
      ').append(inputClone)[0].reset();\n // Detaching allows to insert the fileInput on another form\n // without loosing the file input value:\n input.after(inputClone).detach();\n // If the fileInput had focus before it was detached,\n // restore focus to the inputClone.\n if (restoreFocus) {\n inputClone.focus();\n }\n // Avoid memory leaks with the detached file input:\n $.cleanData(input.unbind('remove'));\n // Replace the original file input element in the fileInput\n // elements set with the clone, which has been copied including\n // event handlers:\n this.options.fileInput = this.options.fileInput.map(function (i, el) {\n if (el === input[0]) {\n return inputClone[0];\n }\n return el;\n });\n // If the widget has been initialized on the file input itself,\n // override this.element with the file input clone:\n if (input[0] === this.element[0]) {\n this.element = inputClone;\n }\n },\n\n _handleFileTreeEntry: function (entry, path) {\n var that = this,\n dfd = $.Deferred(),\n entries = [],\n dirReader,\n errorHandler = function (e) {\n if (e && !e.entry) {\n e.entry = entry;\n }\n // Since $.when returns immediately if one\n // Deferred is rejected, we use resolve instead.\n // This allows valid files and invalid items\n // to be returned together in one set:\n dfd.resolve([e]);\n },\n successHandler = function (entries) {\n that._handleFileTreeEntries(\n entries,\n path + entry.name + '/'\n ).done(function (files) {\n dfd.resolve(files);\n }).fail(errorHandler);\n },\n readEntries = function () {\n dirReader.readEntries(function (results) {\n if (!results.length) {\n successHandler(entries);\n } else {\n entries = entries.concat(results);\n readEntries();\n }\n }, errorHandler);\n };\n path = path || '';\n if (entry.isFile) {\n if (entry._file) {\n // Workaround for Chrome bug #149735\n entry._file.relativePath = path;\n dfd.resolve(entry._file);\n } else {\n entry.file(function (file) {\n file.relativePath = path;\n dfd.resolve(file);\n }, errorHandler);\n }\n } else if (entry.isDirectory) {\n dirReader = entry.createReader();\n readEntries();\n } else {\n // Return an empty list for file system items\n // other than files or directories:\n dfd.resolve([]);\n }\n return dfd.promise();\n },\n\n _handleFileTreeEntries: function (entries, path) {\n var that = this;\n return $.when.apply(\n $,\n $.map(entries, function (entry) {\n return that._handleFileTreeEntry(entry, path);\n })\n ).then(function () {\n return Array.prototype.concat.apply(\n [],\n arguments\n );\n });\n },\n\n _getDroppedFiles: function (dataTransfer) {\n dataTransfer = dataTransfer || {};\n var items = dataTransfer.items;\n if (items && items.length && (items[0].webkitGetAsEntry ||\n items[0].getAsEntry)) {\n return this._handleFileTreeEntries(\n $.map(items, function (item) {\n var entry;\n if (item.webkitGetAsEntry) {\n entry = item.webkitGetAsEntry();\n if (entry) {\n // Workaround for Chrome bug #149735:\n entry._file = item.getAsFile();\n }\n return entry;\n }\n return item.getAsEntry();\n })\n );\n }\n return $.Deferred().resolve(\n $.makeArray(dataTransfer.files)\n ).promise();\n },\n\n _getSingleFileInputFiles: function (fileInput) {\n fileInput = $(fileInput);\n var entries = fileInput.prop('webkitEntries') ||\n fileInput.prop('entries'),\n files,\n value;\n if (entries && entries.length) {\n return this._handleFileTreeEntries(entries);\n }\n files = $.makeArray(fileInput.prop('files'));\n if (!files.length) {\n value = fileInput.prop('value');\n if (!value) {\n return $.Deferred().resolve([]).promise();\n }\n // If the files property is not available, the browser does not\n // support the File API and we add a pseudo File object with\n // the input value as name with path information removed:\n files = [{name: value.replace(/^.*\\\\/, '')}];\n } else if (files[0].name === undefined && files[0].fileName) {\n // File normalization for Safari 4 and Firefox 3:\n $.each(files, function (index, file) {\n file.name = file.fileName;\n file.size = file.fileSize;\n });\n }\n return $.Deferred().resolve(files).promise();\n },\n\n _getFileInputFiles: function (fileInput) {\n if (!(fileInput instanceof $) || fileInput.length === 1) {\n return this._getSingleFileInputFiles(fileInput);\n }\n return $.when.apply(\n $,\n $.map(fileInput, this._getSingleFileInputFiles)\n ).then(function () {\n return Array.prototype.concat.apply(\n [],\n arguments\n );\n });\n },\n\n _onChange: function (e) {\n var that = this,\n data = {\n fileInput: $(e.target),\n form: $(e.target.form)\n };\n this._getFileInputFiles(data.fileInput).always(function (files) {\n data.files = files;\n if (that.options.replaceFileInput) {\n that._replaceFileInput(data);\n }\n if (that._trigger(\n 'change',\n $.Event('change', {delegatedEvent: e}),\n data\n ) !== false) {\n that._onAdd(e, data);\n }\n });\n },\n\n _onPaste: function (e) {\n var items = e.originalEvent && e.originalEvent.clipboardData &&\n e.originalEvent.clipboardData.items,\n data = {files: []};\n if (items && items.length) {\n $.each(items, function (index, item) {\n var file = item.getAsFile && item.getAsFile();\n if (file) {\n data.files.push(file);\n }\n });\n if (this._trigger(\n 'paste',\n $.Event('paste', {delegatedEvent: e}),\n data\n ) !== false) {\n this._onAdd(e, data);\n }\n }\n },\n\n _onDrop: function (e) {\n e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;\n var that = this,\n dataTransfer = e.dataTransfer,\n data = {};\n if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {\n e.preventDefault();\n this._getDroppedFiles(dataTransfer).always(function (files) {\n data.files = files;\n if (that._trigger(\n 'drop',\n $.Event('drop', {delegatedEvent: e}),\n data\n ) !== false) {\n that._onAdd(e, data);\n }\n });\n }\n },\n\n _onDragOver: getDragHandler('dragover'),\n\n _onDragEnter: getDragHandler('dragenter'),\n\n _onDragLeave: getDragHandler('dragleave'),\n\n _initEventHandlers: function () {\n if (this._isXHRUpload(this.options)) {\n this._on(this.options.dropZone, {\n dragover: this._onDragOver,\n drop: this._onDrop,\n // event.preventDefault() on dragenter is required for IE10+:\n dragenter: this._onDragEnter,\n // dragleave is not required, but added for completeness:\n dragleave: this._onDragLeave\n });\n this._on(this.options.pasteZone, {\n paste: this._onPaste\n });\n }\n if ($.support.fileInput) {\n this._on(this.options.fileInput, {\n change: this._onChange\n });\n }\n },\n\n _destroyEventHandlers: function () {\n this._off(this.options.dropZone, 'dragenter dragleave dragover drop');\n this._off(this.options.pasteZone, 'paste');\n this._off(this.options.fileInput, 'change');\n },\n\n _destroy: function () {\n this._destroyEventHandlers();\n },\n\n _setOption: function (key, value) {\n var reinit = $.inArray(key, this._specialOptions) !== -1;\n if (reinit) {\n this._destroyEventHandlers();\n }\n this._super(key, value);\n if (reinit) {\n this._initSpecialOptions();\n this._initEventHandlers();\n }\n },\n\n _initSpecialOptions: function () {\n var options = this.options;\n if (options.fileInput === undefined) {\n options.fileInput = this.element.is('input[type=\"file\"]') ?\n this.element : this.element.find('input[type=\"file\"]');\n } else if (!(options.fileInput instanceof $)) {\n options.fileInput = $(options.fileInput);\n }\n if (!(options.dropZone instanceof $)) {\n options.dropZone = $(options.dropZone);\n }\n if (!(options.pasteZone instanceof $)) {\n options.pasteZone = $(options.pasteZone);\n }\n },\n\n _getRegExp: function (str) {\n var parts = str.split('/'),\n modifiers = parts.pop();\n parts.shift();\n return new RegExp(parts.join('/'), modifiers);\n },\n\n _isRegExpOption: function (key, value) {\n return key !== 'url' && $.type(value) === 'string' &&\n /^\\/.*\\/[igm]{0,3}$/.test(value);\n },\n\n _initDataAttributes: function () {\n var that = this,\n options = this.options,\n data = this.element.data();\n // Initialize options set via HTML5 data-attributes:\n $.each(\n this.element[0].attributes,\n function (index, attr) {\n var key = attr.name.toLowerCase(),\n value;\n if (/^data-/.test(key)) {\n // Convert hyphen-ated key to camelCase:\n key = key.slice(5).replace(/-[a-z]/g, function (str) {\n return str.charAt(1).toUpperCase();\n });\n value = data[key];\n if (that._isRegExpOption(key, value)) {\n value = that._getRegExp(value);\n }\n options[key] = value;\n }\n }\n );\n },\n\n _create: function () {\n this._initDataAttributes();\n this._initSpecialOptions();\n this._slots = [];\n this._sequence = this._getXHRPromise(true);\n this._sending = this._active = 0;\n this._initProgressObject(this);\n this._initEventHandlers();\n },\n\n // This method is exposed to the widget API and allows to query\n // the number of active uploads:\n active: function () {\n return this._active;\n },\n\n // This method is exposed to the widget API and allows to query\n // the widget upload progress.\n // It returns an object with loaded, total and bitrate properties\n // for the running uploads:\n progress: function () {\n return this._progress;\n },\n\n // This method is exposed to the widget API and allows adding files\n // using the fileupload API. The data parameter accepts an object which\n // must have a files property and can contain additional options:\n // .fileupload('add', {files: filesList});\n add: function (data) {\n var that = this;\n if (!data || this.options.disabled) {\n return;\n }\n if (data.fileInput && !data.files) {\n this._getFileInputFiles(data.fileInput).always(function (files) {\n data.files = files;\n that._onAdd(null, data);\n });\n } else {\n data.files = $.makeArray(data.files);\n this._onAdd(null, data);\n }\n },\n\n // This method is exposed to the widget API and allows sending files\n // using the fileupload API. The data parameter accepts an object which\n // must have a files or fileInput property and can contain additional options:\n // .fileupload('send', {files: filesList});\n // The method returns a Promise object for the file upload call.\n send: function (data) {\n if (data && !this.options.disabled) {\n if (data.fileInput && !data.files) {\n var that = this,\n dfd = $.Deferred(),\n promise = dfd.promise(),\n jqXHR,\n aborted;\n promise.abort = function () {\n aborted = true;\n if (jqXHR) {\n return jqXHR.abort();\n }\n dfd.reject(null, 'abort', 'abort');\n return promise;\n };\n this._getFileInputFiles(data.fileInput).always(\n function (files) {\n if (aborted) {\n return;\n }\n if (!files.length) {\n dfd.reject();\n return;\n }\n data.files = files;\n jqXHR = that._onSend(null, data);\n jqXHR.then(\n function (result, textStatus, jqXHR) {\n dfd.resolve(result, textStatus, jqXHR);\n },\n function (jqXHR, textStatus, errorThrown) {\n dfd.reject(jqXHR, textStatus, errorThrown);\n }\n );\n }\n );\n return this._enhancePromise(promise);\n }\n data.files = $.makeArray(data.files);\n if (data.files.length) {\n return this._onSend(null, data);\n }\n }\n return this._getXHRPromise(false, data && data.context);\n }\n\n });\n\n}));\n","/*!\n * Bootstrap Colorpicker v2.5.2\n * https://itsjavi.com/bootstrap-colorpicker/\n *\n * Originally written by (c) 2012 Stefan Petre\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0.txt\n *\n */\n\n(function(root, factory) {\n if (typeof define === 'function' && define.amd) {\n // AMD. Register as an anonymous module unless amdModuleId is set\n define([\"jquery\"], function(jq) {\n return (factory(jq));\n });\n } else if (typeof exports === 'object') {\n // Node. Does not work with strict CommonJS, but\n // only CommonJS-like environments that support module.exports,\n // like Node.\n module.exports = factory(require(\"jquery\"));\n } else if (jQuery && !jQuery.fn.colorpicker) {\n factory(jQuery);\n }\n}(this, function($) {\n 'use strict';\n /**\n * Color manipulation helper class\n *\n * @param {Object|String} [val]\n * @param {Object} [predefinedColors]\n * @param {String|null} [fallbackColor]\n * @param {String|null} [fallbackFormat]\n * @param {Boolean} [hexNumberSignPrefix]\n * @constructor\n */\n var Color = function(\n val, predefinedColors, fallbackColor, fallbackFormat, hexNumberSignPrefix) {\n this.fallbackValue = fallbackColor ?\n (\n (typeof fallbackColor === 'string') ?\n this.parse(fallbackColor) :\n fallbackColor\n ) :\n null;\n\n this.fallbackFormat = fallbackFormat ? fallbackFormat : 'rgba';\n\n this.hexNumberSignPrefix = hexNumberSignPrefix === true;\n\n this.value = this.fallbackValue;\n\n this.origFormat = null; // original string format\n\n this.predefinedColors = predefinedColors ? predefinedColors : {};\n\n // We don't want to share aliases across instances so we extend new object\n this.colors = $.extend({}, Color.webColors, this.predefinedColors);\n\n if (val) {\n if (typeof val.h !== 'undefined') {\n this.value = val;\n } else {\n this.setColor(String(val));\n }\n }\n\n if (!this.value) {\n // Initial value is always black if no arguments are passed or val is empty\n this.value = {\n h: 0,\n s: 0,\n b: 0,\n a: 1\n };\n }\n };\n\n Color.webColors = { // 140 predefined colors from the HTML Colors spec\n \"aliceblue\": \"f0f8ff\",\n \"antiquewhite\": \"faebd7\",\n \"aqua\": \"00ffff\",\n \"aquamarine\": \"7fffd4\",\n \"azure\": \"f0ffff\",\n \"beige\": \"f5f5dc\",\n \"bisque\": \"ffe4c4\",\n \"black\": \"000000\",\n \"blanchedalmond\": \"ffebcd\",\n \"blue\": \"0000ff\",\n \"blueviolet\": \"8a2be2\",\n \"brown\": \"a52a2a\",\n \"burlywood\": \"deb887\",\n \"cadetblue\": \"5f9ea0\",\n \"chartreuse\": \"7fff00\",\n \"chocolate\": \"d2691e\",\n \"coral\": \"ff7f50\",\n \"cornflowerblue\": \"6495ed\",\n \"cornsilk\": \"fff8dc\",\n \"crimson\": \"dc143c\",\n \"cyan\": \"00ffff\",\n \"darkblue\": \"00008b\",\n \"darkcyan\": \"008b8b\",\n \"darkgoldenrod\": \"b8860b\",\n \"darkgray\": \"a9a9a9\",\n \"darkgreen\": \"006400\",\n \"darkkhaki\": \"bdb76b\",\n \"darkmagenta\": \"8b008b\",\n \"darkolivegreen\": \"556b2f\",\n \"darkorange\": \"ff8c00\",\n \"darkorchid\": \"9932cc\",\n \"darkred\": \"8b0000\",\n \"darksalmon\": \"e9967a\",\n \"darkseagreen\": \"8fbc8f\",\n \"darkslateblue\": \"483d8b\",\n \"darkslategray\": \"2f4f4f\",\n \"darkturquoise\": \"00ced1\",\n \"darkviolet\": \"9400d3\",\n \"deeppink\": \"ff1493\",\n \"deepskyblue\": \"00bfff\",\n \"dimgray\": \"696969\",\n \"dodgerblue\": \"1e90ff\",\n \"firebrick\": \"b22222\",\n \"floralwhite\": \"fffaf0\",\n \"forestgreen\": \"228b22\",\n \"fuchsia\": \"ff00ff\",\n \"gainsboro\": \"dcdcdc\",\n \"ghostwhite\": \"f8f8ff\",\n \"gold\": \"ffd700\",\n \"goldenrod\": \"daa520\",\n \"gray\": \"808080\",\n \"green\": \"008000\",\n \"greenyellow\": \"adff2f\",\n \"honeydew\": \"f0fff0\",\n \"hotpink\": \"ff69b4\",\n \"indianred\": \"cd5c5c\",\n \"indigo\": \"4b0082\",\n \"ivory\": \"fffff0\",\n \"khaki\": \"f0e68c\",\n \"lavender\": \"e6e6fa\",\n \"lavenderblush\": \"fff0f5\",\n \"lawngreen\": \"7cfc00\",\n \"lemonchiffon\": \"fffacd\",\n \"lightblue\": \"add8e6\",\n \"lightcoral\": \"f08080\",\n \"lightcyan\": \"e0ffff\",\n \"lightgoldenrodyellow\": \"fafad2\",\n \"lightgrey\": \"d3d3d3\",\n \"lightgreen\": \"90ee90\",\n \"lightpink\": \"ffb6c1\",\n \"lightsalmon\": \"ffa07a\",\n \"lightseagreen\": \"20b2aa\",\n \"lightskyblue\": \"87cefa\",\n \"lightslategray\": \"778899\",\n \"lightsteelblue\": \"b0c4de\",\n \"lightyellow\": \"ffffe0\",\n \"lime\": \"00ff00\",\n \"limegreen\": \"32cd32\",\n \"linen\": \"faf0e6\",\n \"magenta\": \"ff00ff\",\n \"maroon\": \"800000\",\n \"mediumaquamarine\": \"66cdaa\",\n \"mediumblue\": \"0000cd\",\n \"mediumorchid\": \"ba55d3\",\n \"mediumpurple\": \"9370d8\",\n \"mediumseagreen\": \"3cb371\",\n \"mediumslateblue\": \"7b68ee\",\n \"mediumspringgreen\": \"00fa9a\",\n \"mediumturquoise\": \"48d1cc\",\n \"mediumvioletred\": \"c71585\",\n \"midnightblue\": \"191970\",\n \"mintcream\": \"f5fffa\",\n \"mistyrose\": \"ffe4e1\",\n \"moccasin\": \"ffe4b5\",\n \"navajowhite\": \"ffdead\",\n \"navy\": \"000080\",\n \"oldlace\": \"fdf5e6\",\n \"olive\": \"808000\",\n \"olivedrab\": \"6b8e23\",\n \"orange\": \"ffa500\",\n \"orangered\": \"ff4500\",\n \"orchid\": \"da70d6\",\n \"palegoldenrod\": \"eee8aa\",\n \"palegreen\": \"98fb98\",\n \"paleturquoise\": \"afeeee\",\n \"palevioletred\": \"d87093\",\n \"papayawhip\": \"ffefd5\",\n \"peachpuff\": \"ffdab9\",\n \"peru\": \"cd853f\",\n \"pink\": \"ffc0cb\",\n \"plum\": \"dda0dd\",\n \"powderblue\": \"b0e0e6\",\n \"purple\": \"800080\",\n \"red\": \"ff0000\",\n \"rosybrown\": \"bc8f8f\",\n \"royalblue\": \"4169e1\",\n \"saddlebrown\": \"8b4513\",\n \"salmon\": \"fa8072\",\n \"sandybrown\": \"f4a460\",\n \"seagreen\": \"2e8b57\",\n \"seashell\": \"fff5ee\",\n \"sienna\": \"a0522d\",\n \"silver\": \"c0c0c0\",\n \"skyblue\": \"87ceeb\",\n \"slateblue\": \"6a5acd\",\n \"slategray\": \"708090\",\n \"snow\": \"fffafa\",\n \"springgreen\": \"00ff7f\",\n \"steelblue\": \"4682b4\",\n \"tan\": \"d2b48c\",\n \"teal\": \"008080\",\n \"thistle\": \"d8bfd8\",\n \"tomato\": \"ff6347\",\n \"turquoise\": \"40e0d0\",\n \"violet\": \"ee82ee\",\n \"wheat\": \"f5deb3\",\n \"white\": \"ffffff\",\n \"whitesmoke\": \"f5f5f5\",\n \"yellow\": \"ffff00\",\n \"yellowgreen\": \"9acd32\",\n \"transparent\": \"transparent\"\n };\n\n Color.prototype = {\n constructor: Color,\n colors: {}, // merged web and predefined colors\n predefinedColors: {},\n /**\n * @return {Object}\n */\n getValue: function() {\n return this.value;\n },\n /**\n * @param {Object} val\n */\n setValue: function(val) {\n this.value = val;\n },\n _sanitizeNumber: function(val) {\n if (typeof val === 'number') {\n return val;\n }\n if (isNaN(val) || (val === null) || (val === '') || (val === undefined)) {\n return 1;\n }\n if (val === '') {\n return 0;\n }\n if (typeof val.toLowerCase !== 'undefined') {\n if (val.match(/^\\./)) {\n val = \"0\" + val;\n }\n return Math.ceil(parseFloat(val) * 100) / 100;\n }\n return 1;\n },\n isTransparent: function(strVal) {\n if (!strVal || !(typeof strVal === 'string' || strVal instanceof String)) {\n return false;\n }\n strVal = strVal.toLowerCase().trim();\n return (strVal === 'transparent') || (strVal.match(/#?00000000/)) || (strVal.match(/(rgba|hsla)\\(0,0,0,0?\\.?0\\)/));\n },\n rgbaIsTransparent: function(rgba) {\n return ((rgba.r === 0) && (rgba.g === 0) && (rgba.b === 0) && (rgba.a === 0));\n },\n // parse a string to HSB\n /**\n * @protected\n * @param {String} strVal\n * @returns {boolean} Returns true if it could be parsed, false otherwise\n */\n setColor: function(strVal) {\n strVal = strVal.toLowerCase().trim();\n if (strVal) {\n if (this.isTransparent(strVal)) {\n this.value = {\n h: 0,\n s: 0,\n b: 0,\n a: 0\n };\n return true;\n } else {\n var parsedColor = this.parse(strVal);\n if (parsedColor) {\n this.value = this.value = {\n h: parsedColor.h,\n s: parsedColor.s,\n b: parsedColor.b,\n a: parsedColor.a\n };\n if (!this.origFormat) {\n this.origFormat = parsedColor.format;\n }\n } else if (this.fallbackValue) {\n // if parser fails, defaults to fallbackValue if defined, otherwise the value won't be changed\n this.value = this.fallbackValue;\n }\n }\n }\n return false;\n },\n setHue: function(h) {\n this.value.h = 1 - h;\n },\n setSaturation: function(s) {\n this.value.s = s;\n },\n setBrightness: function(b) {\n this.value.b = 1 - b;\n },\n setAlpha: function(a) {\n this.value.a = Math.round((parseInt((1 - a) * 100, 10) / 100) * 100) / 100;\n },\n toRGB: function(h, s, b, a) {\n if (arguments.length === 0) {\n h = this.value.h;\n s = this.value.s;\n b = this.value.b;\n a = this.value.a;\n }\n\n h *= 360;\n var R, G, B, X, C;\n h = (h % 360) / 60;\n C = b * s;\n X = C * (1 - Math.abs(h % 2 - 1));\n R = G = B = b - C;\n\n h = ~~h;\n R += [C, X, 0, 0, X, C][h];\n G += [X, C, C, X, 0, 0][h];\n B += [0, 0, X, C, C, X][h];\n\n return {\n r: Math.round(R * 255),\n g: Math.round(G * 255),\n b: Math.round(B * 255),\n a: a\n };\n },\n toHex: function(ignoreFormat, h, s, b, a) {\n if (arguments.length <= 1) {\n h = this.value.h;\n s = this.value.s;\n b = this.value.b;\n a = this.value.a;\n }\n\n var prefix = '#';\n var rgb = this.toRGB(h, s, b, a);\n\n if (this.rgbaIsTransparent(rgb)) {\n return 'transparent';\n }\n\n if (!ignoreFormat) {\n prefix = (this.hexNumberSignPrefix ? '#' : '');\n }\n\n var hexStr = prefix + (\n (1 << 24) +\n (parseInt(rgb.r) << 16) +\n (parseInt(rgb.g) << 8) +\n parseInt(rgb.b))\n .toString(16)\n .slice(1);\n\n return hexStr;\n },\n toHSL: function(h, s, b, a) {\n if (arguments.length === 0) {\n h = this.value.h;\n s = this.value.s;\n b = this.value.b;\n a = this.value.a;\n }\n\n var H = h,\n L = (2 - s) * b,\n S = s * b;\n if (L > 0 && L <= 1) {\n S /= L;\n } else {\n S /= 2 - L;\n }\n L /= 2;\n if (S > 1) {\n S = 1;\n }\n return {\n h: isNaN(H) ? 0 : H,\n s: isNaN(S) ? 0 : S,\n l: isNaN(L) ? 0 : L,\n a: isNaN(a) ? 0 : a\n };\n },\n toAlias: function(r, g, b, a) {\n var c, rgb = (arguments.length === 0) ? this.toHex(true) : this.toHex(true, r, g, b, a);\n\n // support predef. colors in non-hex format too, as defined in the alias itself\n var original = this.origFormat === 'alias' ? rgb : this.toString(false, this.origFormat);\n\n for (var alias in this.colors) {\n c = this.colors[alias].toLowerCase().trim();\n if ((c === rgb) || (c === original)) {\n return alias;\n }\n }\n return false;\n },\n RGBtoHSB: function(r, g, b, a) {\n r /= 255;\n g /= 255;\n b /= 255;\n\n var H, S, V, C;\n V = Math.max(r, g, b);\n C = V - Math.min(r, g, b);\n H = (C === 0 ? null :\n V === r ? (g - b) / C :\n V === g ? (b - r) / C + 2 :\n (r - g) / C + 4\n );\n H = ((H + 360) % 6) * 60 / 360;\n S = C === 0 ? 0 : C / V;\n return {\n h: this._sanitizeNumber(H),\n s: S,\n b: V,\n a: this._sanitizeNumber(a)\n };\n },\n HueToRGB: function(p, q, h) {\n if (h < 0) {\n h += 1;\n } else if (h > 1) {\n h -= 1;\n }\n if ((h * 6) < 1) {\n return p + (q - p) * h * 6;\n } else if ((h * 2) < 1) {\n return q;\n } else if ((h * 3) < 2) {\n return p + (q - p) * ((2 / 3) - h) * 6;\n } else {\n return p;\n }\n },\n HSLtoRGB: function(h, s, l, a) {\n if (s < 0) {\n s = 0;\n }\n var q;\n if (l <= 0.5) {\n q = l * (1 + s);\n } else {\n q = l + s - (l * s);\n }\n\n var p = 2 * l - q;\n\n var tr = h + (1 / 3);\n var tg = h;\n var tb = h - (1 / 3);\n\n var r = Math.round(this.HueToRGB(p, q, tr) * 255);\n var g = Math.round(this.HueToRGB(p, q, tg) * 255);\n var b = Math.round(this.HueToRGB(p, q, tb) * 255);\n return [r, g, b, this._sanitizeNumber(a)];\n },\n /**\n * @param {String} strVal\n * @returns {Object} Object containing h,s,b,a,format properties or FALSE if failed to parse\n */\n parse: function(strVal) {\n if (typeof strVal !== 'string') {\n return this.fallbackValue;\n }\n if (arguments.length === 0) {\n return false;\n }\n\n var that = this,\n result = false,\n isAlias = (typeof this.colors[strVal] !== 'undefined'),\n values, format;\n\n if (isAlias) {\n strVal = this.colors[strVal].toLowerCase().trim();\n }\n\n $.each(this.stringParsers, function(i, parser) {\n var match = parser.re.exec(strVal);\n values = match && parser.parse.apply(that, [match]);\n if (values) {\n result = {};\n format = (isAlias ? 'alias' : (parser.format ? parser.format : that.getValidFallbackFormat()));\n if (format.match(/hsla?/)) {\n result = that.RGBtoHSB.apply(that, that.HSLtoRGB.apply(that, values));\n } else {\n result = that.RGBtoHSB.apply(that, values);\n }\n if (result instanceof Object) {\n result.format = format;\n }\n return false; // stop iterating\n }\n return true;\n });\n return result;\n },\n getValidFallbackFormat: function() {\n var formats = [\n 'rgba', 'rgb', 'hex', 'hsla', 'hsl'\n ];\n if (this.origFormat && (formats.indexOf(this.origFormat) !== -1)) {\n return this.origFormat;\n }\n if (this.fallbackFormat && (formats.indexOf(this.fallbackFormat) !== -1)) {\n return this.fallbackFormat;\n }\n\n return 'rgba'; // By default, return a format that will not lose the alpha info\n },\n /**\n *\n * @param {string} [format] (default: rgba)\n * @param {boolean} [translateAlias] Return real color for pre-defined (non-standard) aliases (default: false)\n * @param {boolean} [forceRawValue] Forces hashtag prefix when getting hex color (default: false)\n * @returns {String}\n */\n toString: function(forceRawValue, format, translateAlias) {\n format = format || this.origFormat || this.fallbackFormat;\n translateAlias = translateAlias || false;\n\n var c = false;\n\n switch (format) {\n case 'rgb':\n {\n c = this.toRGB();\n if (this.rgbaIsTransparent(c)) {\n return 'transparent';\n }\n return 'rgb(' + c.r + ',' + c.g + ',' + c.b + ')';\n }\n break;\n case 'rgba':\n {\n c = this.toRGB();\n return 'rgba(' + c.r + ',' + c.g + ',' + c.b + ',' + c.a + ')';\n }\n break;\n case 'hsl':\n {\n c = this.toHSL();\n return 'hsl(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%)';\n }\n break;\n case 'hsla':\n {\n c = this.toHSL();\n return 'hsla(' + Math.round(c.h * 360) + ',' + Math.round(c.s * 100) + '%,' + Math.round(c.l * 100) + '%,' + c.a + ')';\n }\n break;\n case 'hex':\n {\n return this.toHex(forceRawValue);\n }\n break;\n case 'alias':\n {\n c = this.toAlias();\n\n if (c === false) {\n return this.toString(forceRawValue, this.getValidFallbackFormat());\n }\n\n if (translateAlias && !(c in Color.webColors) && (c in this.predefinedColors)) {\n return this.predefinedColors[c];\n }\n\n return c;\n }\n default:\n {\n return c;\n }\n break;\n }\n },\n // a set of RE's that can match strings and generate color tuples.\n // from John Resig color plugin\n // https://github.com/jquery/jquery-color/\n stringParsers: [{\n re: /rgb\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*?\\)/,\n format: 'rgb',\n parse: function(execResult) {\n return [\n execResult[1],\n execResult[2],\n execResult[3],\n 1\n ];\n }\n }, {\n re: /rgb\\(\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*?\\)/,\n format: 'rgb',\n parse: function(execResult) {\n return [\n 2.55 * execResult[1],\n 2.55 * execResult[2],\n 2.55 * execResult[3],\n 1\n ];\n }\n }, {\n re: /rgba\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*(?:,\\s*(\\d*(?:\\.\\d+)?)\\s*)?\\)/,\n format: 'rgba',\n parse: function(execResult) {\n return [\n execResult[1],\n execResult[2],\n execResult[3],\n execResult[4]\n ];\n }\n }, {\n re: /rgba\\(\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*(?:,\\s*(\\d*(?:\\.\\d+)?)\\s*)?\\)/,\n format: 'rgba',\n parse: function(execResult) {\n return [\n 2.55 * execResult[1],\n 2.55 * execResult[2],\n 2.55 * execResult[3],\n execResult[4]\n ];\n }\n }, {\n re: /hsl\\(\\s*(\\d*(?:\\.\\d+)?)\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*?\\)/,\n format: 'hsl',\n parse: function(execResult) {\n return [\n execResult[1] / 360,\n execResult[2] / 100,\n execResult[3] / 100,\n execResult[4]\n ];\n }\n }, {\n re: /hsla\\(\\s*(\\d*(?:\\.\\d+)?)\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*,\\s*(\\d*(?:\\.\\d+)?)\\%\\s*(?:,\\s*(\\d*(?:\\.\\d+)?)\\s*)?\\)/,\n format: 'hsla',\n parse: function(execResult) {\n return [\n execResult[1] / 360,\n execResult[2] / 100,\n execResult[3] / 100,\n execResult[4]\n ];\n }\n }, {\n re: /#?([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/,\n format: 'hex',\n parse: function(execResult) {\n return [\n parseInt(execResult[1], 16),\n parseInt(execResult[2], 16),\n parseInt(execResult[3], 16),\n 1\n ];\n }\n }, {\n re: /#?([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/,\n format: 'hex',\n parse: function(execResult) {\n return [\n parseInt(execResult[1] + execResult[1], 16),\n parseInt(execResult[2] + execResult[2], 16),\n parseInt(execResult[3] + execResult[3], 16),\n 1\n ];\n }\n }],\n colorNameToHex: function(name) {\n if (typeof this.colors[name.toLowerCase()] !== 'undefined') {\n return this.colors[name.toLowerCase()];\n }\n return false;\n }\n };\n\n /*\n * Default plugin options\n */\n var defaults = {\n horizontal: false, // horizontal mode layout ?\n inline: false, //forces to show the colorpicker as an inline element\n color: false, //forces a color\n format: false, //forces a format\n input: 'input', // children input selector\n container: false, // container selector\n component: '.add-on, .input-group-addon', // children component selector\n fallbackColor: false, // fallback color value. null = keeps current color.\n fallbackFormat: 'hex', // fallback color format\n hexNumberSignPrefix: true, // put a '#' (number sign) before hex strings\n sliders: {\n saturation: {\n maxLeft: 100,\n maxTop: 100,\n callLeft: 'setSaturation',\n callTop: 'setBrightness'\n },\n hue: {\n maxLeft: 0,\n maxTop: 100,\n callLeft: false,\n callTop: 'setHue'\n },\n alpha: {\n maxLeft: 0,\n maxTop: 100,\n callLeft: false,\n callTop: 'setAlpha'\n }\n },\n slidersHorz: {\n saturation: {\n maxLeft: 100,\n maxTop: 100,\n callLeft: 'setSaturation',\n callTop: 'setBrightness'\n },\n hue: {\n maxLeft: 100,\n maxTop: 0,\n callLeft: 'setHue',\n callTop: false\n },\n alpha: {\n maxLeft: 100,\n maxTop: 0,\n callLeft: 'setAlpha',\n callTop: false\n }\n },\n template: '
      ' +\n '
      ' +\n '
      ' +\n '
      ' +\n '
      ' +\n '
      ' +\n '
      ',\n align: 'right',\n customClass: null, // custom class added to the colorpicker element\n colorSelectors: null // custom color aliases\n };\n\n /**\n * Colorpicker component class\n *\n * @param {Object|String} element\n * @param {Object} options\n * @constructor\n */\n var Colorpicker = function(element, options) {\n this.element = $(element).addClass('colorpicker-element');\n this.options = $.extend(true, {}, defaults, this.element.data(), options);\n this.component = this.options.component;\n this.component = (this.component !== false) ? this.element.find(this.component) : false;\n if (this.component && (this.component.length === 0)) {\n this.component = false;\n }\n this.container = (this.options.container === true) ? this.element : this.options.container;\n this.container = (this.container !== false) ? $(this.container) : false;\n\n // Is the element an input? Should we search inside for any input?\n this.input = this.element.is('input') ? this.element : (this.options.input ?\n this.element.find(this.options.input) : false);\n if (this.input && (this.input.length === 0)) {\n this.input = false;\n }\n // Set HSB color\n this.color = this.createColor(this.options.color !== false ? this.options.color : this.getValue());\n\n this.format = this.options.format !== false ? this.options.format : this.color.origFormat;\n\n if (this.options.color !== false) {\n this.updateInput(this.color);\n this.updateData(this.color);\n }\n\n this.disabled = false;\n\n // Setup picker\n var $picker = this.picker = $(this.options.template);\n if (this.options.customClass) {\n $picker.addClass(this.options.customClass);\n }\n if (this.options.inline) {\n $picker.addClass('colorpicker-inline colorpicker-visible');\n } else {\n $picker.addClass('colorpicker-hidden');\n }\n if (this.options.horizontal) {\n $picker.addClass('colorpicker-horizontal');\n }\n if (\n (['rgba', 'hsla', 'alias'].indexOf(this.format) !== -1) ||\n this.options.format === false ||\n this.getValue() === 'transparent'\n ) {\n $picker.addClass('colorpicker-with-alpha');\n }\n if (this.options.align === 'right') {\n $picker.addClass('colorpicker-right');\n }\n if (this.options.inline === true) {\n $picker.addClass('colorpicker-no-arrow');\n }\n if (this.options.colorSelectors) {\n var colorpicker = this,\n selectorsContainer = colorpicker.picker.find('.colorpicker-selectors');\n\n if (selectorsContainer.length > 0) {\n $.each(this.options.colorSelectors, function(name, color) {\n var $btn = $('')\n .addClass('colorpicker-selectors-color')\n .css('background-color', color)\n .data('class', name).data('alias', name);\n\n $btn.on('mousedown.colorpicker touchstart.colorpicker', function(event) {\n event.preventDefault();\n colorpicker.setValue(\n colorpicker.format === 'alias' ? $(this).data('alias') : $(this).css('background-color')\n );\n });\n selectorsContainer.append($btn);\n });\n selectorsContainer.show().addClass('colorpicker-visible');\n }\n }\n\n // Prevent closing the colorpicker when clicking on itself\n $picker.on('mousedown.colorpicker touchstart.colorpicker', $.proxy(function(e) {\n if (e.target === e.currentTarget) {\n e.preventDefault();\n }\n }, this));\n\n // Bind click/tap events on the sliders\n $picker.find('.colorpicker-saturation, .colorpicker-hue, .colorpicker-alpha')\n .on('mousedown.colorpicker touchstart.colorpicker', $.proxy(this.mousedown, this));\n\n $picker.appendTo(this.container ? this.container : $('body'));\n\n // Bind other events\n if (this.input !== false) {\n this.input.on({\n 'keyup.colorpicker': $.proxy(this.keyup, this)\n });\n this.input.on({\n 'input.colorpicker': $.proxy(this.change, this)\n });\n if (this.component === false) {\n this.element.on({\n 'focus.colorpicker': $.proxy(this.show, this)\n });\n }\n if (this.options.inline === false) {\n this.element.on({\n 'focusout.colorpicker': $.proxy(this.hide, this)\n });\n }\n }\n\n if (this.component !== false) {\n this.component.on({\n 'click.colorpicker': $.proxy(this.show, this)\n });\n }\n\n if ((this.input === false) && (this.component === false)) {\n this.element.on({\n 'click.colorpicker': $.proxy(this.show, this)\n });\n }\n\n // for HTML5 input[type='color']\n if ((this.input !== false) && (this.component !== false) && (this.input.attr('type') === 'color')) {\n\n this.input.on({\n 'click.colorpicker': $.proxy(this.show, this),\n 'focus.colorpicker': $.proxy(this.show, this)\n });\n }\n this.update();\n\n $($.proxy(function() {\n this.element.trigger('create');\n }, this));\n };\n\n Colorpicker.Color = Color;\n\n Colorpicker.prototype = {\n constructor: Colorpicker,\n destroy: function() {\n this.picker.remove();\n this.element.removeData('colorpicker', 'color').off('.colorpicker');\n if (this.input !== false) {\n this.input.off('.colorpicker');\n }\n if (this.component !== false) {\n this.component.off('.colorpicker');\n }\n this.element.removeClass('colorpicker-element');\n this.element.trigger({\n type: 'destroy'\n });\n },\n reposition: function() {\n if (this.options.inline !== false || this.options.container) {\n return false;\n }\n var type = this.container && this.container[0] !== window.document.body ? 'position' : 'offset';\n var element = this.component || this.element;\n var offset = element[type]();\n if (this.options.align === 'right') {\n offset.left -= this.picker.outerWidth() - element.outerWidth();\n }\n this.picker.css({\n top: offset.top + element.outerHeight(),\n left: offset.left\n });\n },\n show: function(e) {\n if (this.isDisabled()) {\n // Don't show the widget if it's disabled (the input)\n return;\n }\n this.picker.addClass('colorpicker-visible').removeClass('colorpicker-hidden');\n this.reposition();\n $(window).on('resize.colorpicker', $.proxy(this.reposition, this));\n if (e && (!this.hasInput() || this.input.attr('type') === 'color')) {\n if (e.stopPropagation && e.preventDefault) {\n e.stopPropagation();\n e.preventDefault();\n }\n }\n if ((this.component || !this.input) && (this.options.inline === false)) {\n $(window.document).on({\n 'mousedown.colorpicker': $.proxy(this.hide, this)\n });\n }\n this.element.trigger({\n type: 'showPicker',\n color: this.color\n });\n },\n hide: function(e) {\n if ((typeof e !== 'undefined') && e.target) {\n // Prevent hide if triggered by an event and an element inside the colorpicker has been clicked/touched\n if (\n $(e.currentTarget).parents('.colorpicker').length > 0 ||\n $(e.target).parents('.colorpicker').length > 0\n ) {\n return false;\n }\n }\n this.picker.addClass('colorpicker-hidden').removeClass('colorpicker-visible');\n $(window).off('resize.colorpicker', this.reposition);\n $(window.document).off({\n 'mousedown.colorpicker': this.hide\n });\n this.update();\n this.element.trigger({\n type: 'hidePicker',\n color: this.color\n });\n },\n updateData: function(val) {\n val = val || this.color.toString(false, this.format);\n this.element.data('color', val);\n return val;\n },\n updateInput: function(val) {\n val = val || this.color.toString(false, this.format);\n if (this.input !== false) {\n this.input.prop('value', val);\n this.input.trigger('change');\n }\n return val;\n },\n updatePicker: function(val) {\n if (typeof val !== 'undefined') {\n this.color = this.createColor(val);\n }\n var sl = (this.options.horizontal === false) ? this.options.sliders : this.options.slidersHorz;\n var icns = this.picker.find('i');\n if (icns.length === 0) {\n return;\n }\n if (this.options.horizontal === false) {\n sl = this.options.sliders;\n icns.eq(1).css('top', sl.hue.maxTop * (1 - this.color.value.h)).end()\n .eq(2).css('top', sl.alpha.maxTop * (1 - this.color.value.a));\n } else {\n sl = this.options.slidersHorz;\n icns.eq(1).css('left', sl.hue.maxLeft * (1 - this.color.value.h)).end()\n .eq(2).css('left', sl.alpha.maxLeft * (1 - this.color.value.a));\n }\n icns.eq(0).css({\n 'top': sl.saturation.maxTop - this.color.value.b * sl.saturation.maxTop,\n 'left': this.color.value.s * sl.saturation.maxLeft\n });\n\n this.picker.find('.colorpicker-saturation')\n .css('backgroundColor', this.color.toHex(true, this.color.value.h, 1, 1, 1));\n\n this.picker.find('.colorpicker-alpha')\n .css('backgroundColor', this.color.toHex(true));\n\n this.picker.find('.colorpicker-color, .colorpicker-color div')\n .css('backgroundColor', this.color.toString(true, this.format));\n\n return val;\n },\n updateComponent: function(val) {\n var color;\n\n if (typeof val !== 'undefined') {\n color = this.createColor(val);\n } else {\n color = this.color;\n }\n\n if (this.component !== false) {\n var icn = this.component.find('i').eq(0);\n if (icn.length > 0) {\n icn.css({\n 'backgroundColor': color.toString(true, this.format)\n });\n } else {\n this.component.css({\n 'backgroundColor': color.toString(true, this.format)\n });\n }\n }\n\n return color.toString(false, this.format);\n },\n update: function(force) {\n var val;\n if ((this.getValue(false) !== false) || (force === true)) {\n // Update input/data only if the current value is not empty\n val = this.updateComponent();\n this.updateInput(val);\n this.updateData(val);\n this.updatePicker(); // only update picker if value is not empty\n }\n return val;\n\n },\n setValue: function(val) { // set color manually\n this.color = this.createColor(val);\n this.update(true);\n this.element.trigger({\n type: 'changeColor',\n color: this.color,\n value: val\n });\n },\n /**\n * Creates a new color using the instance options\n * @protected\n * @param {String} val\n * @returns {Color}\n */\n createColor: function(val) {\n return new Color(\n val ? val : null,\n this.options.colorSelectors,\n this.options.fallbackColor ? this.options.fallbackColor : this.color,\n this.options.fallbackFormat,\n this.options.hexNumberSignPrefix\n );\n },\n getValue: function(defaultValue) {\n defaultValue = (typeof defaultValue === 'undefined') ? this.options.fallbackColor : defaultValue;\n var val;\n if (this.hasInput()) {\n val = this.input.val();\n } else {\n val = this.element.data('color');\n }\n if ((val === undefined) || (val === '') || (val === null)) {\n // if not defined or empty, return default\n val = defaultValue;\n }\n return val;\n },\n hasInput: function() {\n return (this.input !== false);\n },\n isDisabled: function() {\n return this.disabled;\n },\n disable: function() {\n if (this.hasInput()) {\n this.input.prop('disabled', true);\n }\n this.disabled = true;\n this.element.trigger({\n type: 'disable',\n color: this.color,\n value: this.getValue()\n });\n return true;\n },\n enable: function() {\n if (this.hasInput()) {\n this.input.prop('disabled', false);\n }\n this.disabled = false;\n this.element.trigger({\n type: 'enable',\n color: this.color,\n value: this.getValue()\n });\n return true;\n },\n currentSlider: null,\n mousePointer: {\n left: 0,\n top: 0\n },\n mousedown: function(e) {\n if (!e.pageX && !e.pageY && e.originalEvent && e.originalEvent.touches) {\n e.pageX = e.originalEvent.touches[0].pageX;\n e.pageY = e.originalEvent.touches[0].pageY;\n }\n e.stopPropagation();\n e.preventDefault();\n\n var target = $(e.target);\n\n //detect the slider and set the limits and callbacks\n var zone = target.closest('div');\n var sl = this.options.horizontal ? this.options.slidersHorz : this.options.sliders;\n if (!zone.is('.colorpicker')) {\n if (zone.is('.colorpicker-saturation')) {\n this.currentSlider = $.extend({}, sl.saturation);\n } else if (zone.is('.colorpicker-hue')) {\n this.currentSlider = $.extend({}, sl.hue);\n } else if (zone.is('.colorpicker-alpha')) {\n this.currentSlider = $.extend({}, sl.alpha);\n } else {\n return false;\n }\n var offset = zone.offset();\n //reference to guide's style\n this.currentSlider.guide = zone.find('i')[0].style;\n this.currentSlider.left = e.pageX - offset.left;\n this.currentSlider.top = e.pageY - offset.top;\n this.mousePointer = {\n left: e.pageX,\n top: e.pageY\n };\n //trigger mousemove to move the guide to the current position\n $(window.document).on({\n 'mousemove.colorpicker': $.proxy(this.mousemove, this),\n 'touchmove.colorpicker': $.proxy(this.mousemove, this),\n 'mouseup.colorpicker': $.proxy(this.mouseup, this),\n 'touchend.colorpicker': $.proxy(this.mouseup, this)\n }).trigger('mousemove');\n }\n return false;\n },\n mousemove: function(e) {\n if (!e.pageX && !e.pageY && e.originalEvent && e.originalEvent.touches) {\n e.pageX = e.originalEvent.touches[0].pageX;\n e.pageY = e.originalEvent.touches[0].pageY;\n }\n e.stopPropagation();\n e.preventDefault();\n var left = Math.max(\n 0,\n Math.min(\n this.currentSlider.maxLeft,\n this.currentSlider.left + ((e.pageX || this.mousePointer.left) - this.mousePointer.left)\n )\n );\n var top = Math.max(\n 0,\n Math.min(\n this.currentSlider.maxTop,\n this.currentSlider.top + ((e.pageY || this.mousePointer.top) - this.mousePointer.top)\n )\n );\n this.currentSlider.guide.left = left + 'px';\n this.currentSlider.guide.top = top + 'px';\n if (this.currentSlider.callLeft) {\n this.color[this.currentSlider.callLeft].call(this.color, left / this.currentSlider.maxLeft);\n }\n if (this.currentSlider.callTop) {\n this.color[this.currentSlider.callTop].call(this.color, top / this.currentSlider.maxTop);\n }\n // Change format dynamically\n // Only occurs if user choose the dynamic format by\n // setting option format to false\n if (\n this.options.format === false &&\n (this.currentSlider.callTop === 'setAlpha' ||\n this.currentSlider.callLeft === 'setAlpha')\n ) {\n\n // Converting from hex / rgb to rgba\n if (this.color.value.a !== 1) {\n this.format = 'rgba';\n this.color.origFormat = 'rgba';\n }\n\n // Converting from rgba to hex\n else {\n this.format = 'hex';\n this.color.origFormat = 'hex';\n }\n }\n this.update(true);\n\n this.element.trigger({\n type: 'changeColor',\n color: this.color\n });\n return false;\n },\n mouseup: function(e) {\n e.stopPropagation();\n e.preventDefault();\n $(window.document).off({\n 'mousemove.colorpicker': this.mousemove,\n 'touchmove.colorpicker': this.mousemove,\n 'mouseup.colorpicker': this.mouseup,\n 'touchend.colorpicker': this.mouseup\n });\n return false;\n },\n change: function(e) {\n this.color = this.createColor(this.input.val());\n // Change format dynamically\n // Only occurs if user choose the dynamic format by\n // setting option format to false\n if (this.color.origFormat && this.options.format === false) {\n this.format = this.color.origFormat;\n }\n if (this.getValue(false) !== false) {\n this.updateData();\n this.updateComponent();\n this.updatePicker();\n }\n\n this.element.trigger({\n type: 'changeColor',\n color: this.color,\n value: this.input.val()\n });\n },\n keyup: function(e) {\n if ((e.keyCode === 38)) {\n if (this.color.value.a < 1) {\n this.color.value.a = Math.round((this.color.value.a + 0.01) * 100) / 100;\n }\n this.update(true);\n } else if ((e.keyCode === 40)) {\n if (this.color.value.a > 0) {\n this.color.value.a = Math.round((this.color.value.a - 0.01) * 100) / 100;\n }\n this.update(true);\n }\n\n this.element.trigger({\n type: 'changeColor',\n color: this.color,\n value: this.input.val()\n });\n }\n };\n\n $.colorpicker = Colorpicker;\n\n $.fn.colorpicker = function(option) {\n var apiArgs = Array.prototype.slice.call(arguments, 1),\n isSingleElement = (this.length === 1),\n returnValue = null;\n\n var $jq = this.each(function() {\n var $this = $(this),\n inst = $this.data('colorpicker'),\n options = ((typeof option === 'object') ? option : {});\n\n if (!inst) {\n inst = new Colorpicker(this, options);\n $this.data('colorpicker', inst);\n }\n\n if (typeof option === 'string') {\n if ($.isFunction(inst[option])) {\n returnValue = inst[option].apply(inst, apiArgs);\n } else { // its a property ?\n if (apiArgs.length) {\n // set property\n inst[option] = apiArgs[0];\n }\n returnValue = inst[option];\n }\n } else {\n returnValue = $this;\n }\n });\n return isSingleElement ? returnValue : $jq;\n };\n\n $.fn.colorpicker.constructor = Colorpicker;\n\n}));\n","/*!\n * Datepicker for Bootstrap v1.10.0 (https://github.com/uxsolutions/bootstrap-datepicker)\n *\n * Licensed under the Apache License v2.0 (https://www.apache.org/licenses/LICENSE-2.0)\n */\n\n(function(factory){\n if (typeof define === 'function' && define.amd) {\n define(['jquery'], factory);\n } else if (typeof exports === 'object') {\n factory(require('jquery'));\n } else {\n factory(jQuery);\n }\n}(function($, undefined){\n\tfunction UTCDate(){\n\t\treturn new Date(Date.UTC.apply(Date, arguments));\n\t}\n\tfunction UTCToday(){\n\t\tvar today = new Date();\n\t\treturn UTCDate(today.getFullYear(), today.getMonth(), today.getDate());\n\t}\n\tfunction isUTCEquals(date1, date2) {\n\t\treturn (\n\t\t\tdate1.getUTCFullYear() === date2.getUTCFullYear() &&\n\t\t\tdate1.getUTCMonth() === date2.getUTCMonth() &&\n\t\t\tdate1.getUTCDate() === date2.getUTCDate()\n\t\t);\n\t}\n\tfunction alias(method, deprecationMsg){\n\t\treturn function(){\n\t\t\tif (deprecationMsg !== undefined) {\n\t\t\t\t$.fn.datepicker.deprecated(deprecationMsg);\n\t\t\t}\n\n\t\t\treturn this[method].apply(this, arguments);\n\t\t};\n\t}\n\tfunction isValidDate(d) {\n\t\treturn d && !isNaN(d.getTime());\n\t}\n\n\tvar DateArray = (function(){\n\t\tvar extras = {\n\t\t\tget: function(i){\n\t\t\t\treturn this.slice(i)[0];\n\t\t\t},\n\t\t\tcontains: function(d){\n\t\t\t\t// Array.indexOf is not cross-browser;\n\t\t\t\t// $.inArray doesn't work with Dates\n\t\t\t\tvar val = d && d.valueOf();\n\t\t\t\tfor (var i=0, l=this.length; i < l; i++)\n // Use date arithmetic to allow dates with different times to match\n if (0 <= this[i].valueOf() - val && this[i].valueOf() - val < 1000*60*60*24)\n\t\t\t\t\t\treturn i;\n\t\t\t\treturn -1;\n\t\t\t},\n\t\t\tremove: function(i){\n\t\t\t\tthis.splice(i,1);\n\t\t\t},\n\t\t\treplace: function(new_array){\n\t\t\t\tif (!new_array)\n\t\t\t\t\treturn;\n\t\t\t\tif (!Array.isArray(new_array))\n\t\t\t\t\tnew_array = [new_array];\n\t\t\t\tthis.clear();\n\t\t\t\tthis.push.apply(this, new_array);\n\t\t\t},\n\t\t\tclear: function(){\n\t\t\t\tthis.length = 0;\n\t\t\t},\n\t\t\tcopy: function(){\n\t\t\t\tvar a = new DateArray();\n\t\t\t\ta.replace(this);\n\t\t\t\treturn a;\n\t\t\t}\n\t\t};\n\n\t\treturn function(){\n\t\t\tvar a = [];\n\t\t\ta.push.apply(a, arguments);\n\t\t\t$.extend(a, extras);\n\t\t\treturn a;\n\t\t};\n\t})();\n\n\n\t// Picker object\n\n\tvar Datepicker = function(element, options){\n\t\t$.data(element, 'datepicker', this);\n\n\t\tthis._events = [];\n\t\tthis._secondaryEvents = [];\n\n\t\tthis._process_options(options);\n\n\t\tthis.dates = new DateArray();\n\t\tthis.viewDate = this.o.defaultViewDate;\n\t\tthis.focusDate = null;\n\n\t\tthis.element = $(element);\n\t\tthis.isInput = this.element.is('input');\n\t\tthis.inputField = this.isInput ? this.element : this.element.find('input');\n\t\tthis.component = this.element.hasClass('date') ? this.element.find('.add-on, .input-group-addon, .input-group-append, .input-group-prepend, .btn') : false;\n\t\tif (this.component && this.component.length === 0){\n\t\t\tthis.component = false;\n }\n\n\t\tif (this.o.isInline === null){\n\t\t\tthis.isInline = !this.component && !this.isInput;\n\t\t} else {\n\t\t\tthis.isInline = this.o.isInline;\n\t\t}\n\n\t\tthis.picker = $(DPGlobal.template);\n\n\t\t// Checking templates and inserting\n\t\tif (this._check_template(this.o.templates.leftArrow)) {\n\t\t\tthis.picker.find('.prev').html(this.o.templates.leftArrow);\n\t\t}\n\n\t\tif (this._check_template(this.o.templates.rightArrow)) {\n\t\t\tthis.picker.find('.next').html(this.o.templates.rightArrow);\n\t\t}\n\n\t\tthis._buildEvents();\n\t\tthis._attachEvents();\n\n\t\tif (this.isInline){\n\t\t\tthis.picker.addClass('datepicker-inline').appendTo(this.element);\n\t\t}\n\t\telse {\n\t\t\tthis.picker.addClass('datepicker-dropdown dropdown-menu');\n\t\t}\n\n\t\tif (this.o.rtl){\n\t\t\tthis.picker.addClass('datepicker-rtl');\n\t\t}\n\n\t\tif (this.o.calendarWeeks) {\n\t\t\tthis.picker.find('.datepicker-days .datepicker-switch, thead .datepicker-title, tfoot .today, tfoot .clear')\n\t\t\t\t.attr('colspan', function(i, val){\n\t\t\t\t\treturn Number(val) + 1;\n\t\t\t\t});\n\t\t}\n\n\t\tthis._process_options({\n\t\t\tstartDate: this._o.startDate,\n\t\t\tendDate: this._o.endDate,\n\t\t\tdaysOfWeekDisabled: this.o.daysOfWeekDisabled,\n\t\t\tdaysOfWeekHighlighted: this.o.daysOfWeekHighlighted,\n\t\t\tdatesDisabled: this.o.datesDisabled\n\t\t});\n\n\t\tthis._allow_update = false;\n\t\tthis.setViewMode(this.o.startView);\n\t\tthis._allow_update = true;\n\n\t\tthis.fillDow();\n\t\tthis.fillMonths();\n\n\t\tthis.update();\n\n\t\tif (this.isInline){\n\t\t\tthis.show();\n\t\t}\n\t};\n\n\tDatepicker.prototype = {\n\t\tconstructor: Datepicker,\n\n\t\t_resolveViewName: function(view){\n\t\t\t$.each(DPGlobal.viewModes, function(i, viewMode){\n\t\t\t\tif (view === i || $.inArray(view, viewMode.names) !== -1){\n\t\t\t\t\tview = i;\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t});\n\n\t\t\treturn view;\n\t\t},\n\n\t\t_resolveDaysOfWeek: function(daysOfWeek){\n\t\t\tif (!Array.isArray(daysOfWeek))\n\t\t\t\tdaysOfWeek = daysOfWeek.split(/[,\\s]*/);\n\t\t\treturn $.map(daysOfWeek, Number);\n\t\t},\n\n\t\t_check_template: function(tmp){\n\t\t\ttry {\n\t\t\t\t// If empty\n\t\t\t\tif (tmp === undefined || tmp === \"\") {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\t// If no html, everything ok\n\t\t\t\tif ((tmp.match(/[<>]/g) || []).length <= 0) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\t// Checking if html is fine\n\t\t\t\tvar jDom = $(tmp);\n\t\t\t\treturn jDom.length > 0;\n\t\t\t}\n\t\t\tcatch (ex) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t},\n\n\t\t_process_options: function(opts){\n\t\t\t// Store raw options for reference\n\t\t\tthis._o = $.extend({}, this._o, opts);\n\t\t\t// Processed options\n\t\t\tvar o = this.o = $.extend({}, this._o);\n\n\t\t\t// Check if \"de-DE\" style date is available, if not language should\n\t\t\t// fallback to 2 letter code eg \"de\"\n\t\t\tvar lang = o.language;\n\t\t\tif (!dates[lang]){\n\t\t\t\tlang = lang.split('-')[0];\n\t\t\t\tif (!dates[lang])\n\t\t\t\t\tlang = defaults.language;\n\t\t\t}\n\t\t\to.language = lang;\n\n\t\t\t// Retrieve view index from any aliases\n\t\t\to.startView = this._resolveViewName(o.startView);\n\t\t\to.minViewMode = this._resolveViewName(o.minViewMode);\n\t\t\to.maxViewMode = this._resolveViewName(o.maxViewMode);\n\n\t\t\t// Check view is between min and max\n\t\t\to.startView = Math.max(this.o.minViewMode, Math.min(this.o.maxViewMode, o.startView));\n\n\t\t\t// true, false, or Number > 0\n\t\t\tif (o.multidate !== true){\n\t\t\t\to.multidate = Number(o.multidate) || false;\n\t\t\t\tif (o.multidate !== false)\n\t\t\t\t\to.multidate = Math.max(0, o.multidate);\n\t\t\t}\n\t\t\to.multidateSeparator = String(o.multidateSeparator);\n\n\t\t\to.weekStart %= 7;\n\t\t\to.weekEnd = (o.weekStart + 6) % 7;\n\n\t\t\tvar format = DPGlobal.parseFormat(o.format);\n\t\t\tif (o.startDate !== -Infinity){\n\t\t\t\tif (!!o.startDate){\n\t\t\t\t\tif (o.startDate instanceof Date)\n\t\t\t\t\t\to.startDate = this._local_to_utc(this._zero_time(o.startDate));\n\t\t\t\t\telse\n\t\t\t\t\t\to.startDate = DPGlobal.parseDate(o.startDate, format, o.language, o.assumeNearbyYear);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\to.startDate = -Infinity;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (o.endDate !== Infinity){\n\t\t\t\tif (!!o.endDate){\n\t\t\t\t\tif (o.endDate instanceof Date)\n\t\t\t\t\t\to.endDate = this._local_to_utc(this._zero_time(o.endDate));\n\t\t\t\t\telse\n\t\t\t\t\t\to.endDate = DPGlobal.parseDate(o.endDate, format, o.language, o.assumeNearbyYear);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\to.endDate = Infinity;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\to.daysOfWeekDisabled = this._resolveDaysOfWeek(o.daysOfWeekDisabled||[]);\n\t\t\to.daysOfWeekHighlighted = this._resolveDaysOfWeek(o.daysOfWeekHighlighted||[]);\n\n\t\t\to.datesDisabled = o.datesDisabled||[];\n\t\t\tif (!Array.isArray(o.datesDisabled)) {\n\t\t\t\to.datesDisabled = o.datesDisabled.split(',');\n\t\t\t}\n\t\t\to.datesDisabled = $.map(o.datesDisabled, function(d){\n\t\t\t\treturn DPGlobal.parseDate(d, format, o.language, o.assumeNearbyYear);\n\t\t\t});\n\n\t\t\tvar plc = String(o.orientation).toLowerCase().split(/\\s+/g),\n\t\t\t\t_plc = o.orientation.toLowerCase();\n\t\t\tplc = $.grep(plc, function(word){\n\t\t\t\treturn /^auto|left|right|top|bottom$/.test(word);\n\t\t\t});\n\t\t\to.orientation = {x: 'auto', y: 'auto'};\n\t\t\tif (!_plc || _plc === 'auto')\n\t\t\t\t; // no action\n\t\t\telse if (plc.length === 1){\n\t\t\t\tswitch (plc[0]){\n\t\t\t\t\tcase 'top':\n\t\t\t\t\tcase 'bottom':\n\t\t\t\t\t\to.orientation.y = plc[0];\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 'left':\n\t\t\t\t\tcase 'right':\n\t\t\t\t\t\to.orientation.x = plc[0];\n\t\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\telse {\n\t\t\t\t_plc = $.grep(plc, function(word){\n\t\t\t\t\treturn /^left|right$/.test(word);\n\t\t\t\t});\n\t\t\t\to.orientation.x = _plc[0] || 'auto';\n\n\t\t\t\t_plc = $.grep(plc, function(word){\n\t\t\t\t\treturn /^top|bottom$/.test(word);\n\t\t\t\t});\n\t\t\t\to.orientation.y = _plc[0] || 'auto';\n\t\t\t}\n\t\t\tif (o.defaultViewDate instanceof Date || typeof o.defaultViewDate === 'string') {\n\t\t\t\to.defaultViewDate = DPGlobal.parseDate(o.defaultViewDate, format, o.language, o.assumeNearbyYear);\n\t\t\t} else if (o.defaultViewDate) {\n\t\t\t\tvar year = o.defaultViewDate.year || new Date().getFullYear();\n\t\t\t\tvar month = o.defaultViewDate.month || 0;\n\t\t\t\tvar day = o.defaultViewDate.day || 1;\n\t\t\t\to.defaultViewDate = UTCDate(year, month, day);\n\t\t\t} else {\n\t\t\t\to.defaultViewDate = UTCToday();\n\t\t\t}\n\t\t},\n\t\t_applyEvents: function(evs){\n\t\t\tfor (var i=0, el, ch, ev; i < evs.length; i++){\n\t\t\t\tel = evs[i][0];\n\t\t\t\tif (evs[i].length === 2){\n\t\t\t\t\tch = undefined;\n\t\t\t\t\tev = evs[i][1];\n\t\t\t\t} else if (evs[i].length === 3){\n\t\t\t\t\tch = evs[i][1];\n\t\t\t\t\tev = evs[i][2];\n\t\t\t\t}\n\t\t\t\tel.on(ev, ch);\n\t\t\t}\n\t\t},\n\t\t_unapplyEvents: function(evs){\n\t\t\tfor (var i=0, el, ev, ch; i < evs.length; i++){\n\t\t\t\tel = evs[i][0];\n\t\t\t\tif (evs[i].length === 2){\n\t\t\t\t\tch = undefined;\n\t\t\t\t\tev = evs[i][1];\n\t\t\t\t} else if (evs[i].length === 3){\n\t\t\t\t\tch = evs[i][1];\n\t\t\t\t\tev = evs[i][2];\n\t\t\t\t}\n\t\t\t\tel.off(ev, ch);\n\t\t\t}\n\t\t},\n\t\t_buildEvents: function(){\n var events = {\n keyup: $.proxy(function(e){\n if ($.inArray(e.keyCode, [27, 37, 39, 38, 40, 32, 13, 9]) === -1)\n this.update();\n }, this),\n keydown: $.proxy(this.keydown, this),\n paste: $.proxy(this.paste, this)\n };\n\n if (this.o.showOnFocus === true) {\n events.focus = $.proxy(this.show, this);\n }\n\n if (this.isInput) { // single input\n this._events = [\n [this.element, events]\n ];\n }\n // component: input + button\n else if (this.component && this.inputField.length) {\n this._events = [\n // For components that are not readonly, allow keyboard nav\n [this.inputField, events],\n [this.component, {\n click: $.proxy(this.show, this)\n }]\n ];\n }\n\t\t\telse {\n\t\t\t\tthis._events = [\n\t\t\t\t\t[this.element, {\n\t\t\t\t\t\tclick: $.proxy(this.show, this),\n\t\t\t\t\t\tkeydown: $.proxy(this.keydown, this)\n\t\t\t\t\t}]\n\t\t\t\t];\n\t\t\t}\n\t\t\tthis._events.push(\n\t\t\t\t// Component: listen for blur on element descendants\n\t\t\t\t[this.element, '*', {\n\t\t\t\t\tblur: $.proxy(function(e){\n\t\t\t\t\t\tthis._focused_from = e.target;\n\t\t\t\t\t}, this)\n\t\t\t\t}],\n\t\t\t\t// Input: listen for blur on element\n\t\t\t\t[this.element, {\n\t\t\t\t\tblur: $.proxy(function(e){\n\t\t\t\t\t\tthis._focused_from = e.target;\n\t\t\t\t\t}, this)\n\t\t\t\t}]\n\t\t\t);\n\n\t\t\tif (this.o.immediateUpdates) {\n\t\t\t\t// Trigger input updates immediately on changed year/month\n\t\t\t\tthis._events.push([this.element, {\n\t\t\t\t\t'changeYear changeMonth': $.proxy(function(e){\n\t\t\t\t\t\tthis.update(e.date);\n\t\t\t\t\t}, this)\n\t\t\t\t}]);\n\t\t\t}\n\n\t\t\tthis._secondaryEvents = [\n\t\t\t\t[this.picker, {\n\t\t\t\t\tclick: $.proxy(this.click, this)\n\t\t\t\t}],\n\t\t\t\t[this.picker, '.prev, .next', {\n\t\t\t\t\tclick: $.proxy(this.navArrowsClick, this)\n\t\t\t\t}],\n\t\t\t\t[this.picker, '.day:not(.disabled)', {\n\t\t\t\t\tclick: $.proxy(this.dayCellClick, this)\n\t\t\t\t}],\n\t\t\t\t[$(window), {\n\t\t\t\t\tresize: $.proxy(this.place, this)\n\t\t\t\t}],\n\t\t\t\t[$(document), {\n\t\t\t\t\t'mousedown touchstart': $.proxy(function(e){\n\t\t\t\t\t\t// Clicked outside the datepicker, hide it\n\t\t\t\t\t\tif (!(\n\t\t\t\t\t\t\tthis.element.is(e.target) ||\n\t\t\t\t\t\t\tthis.element.find(e.target).length ||\n\t\t\t\t\t\t\tthis.picker.is(e.target) ||\n\t\t\t\t\t\t\tthis.picker.find(e.target).length ||\n\t\t\t\t\t\t\tthis.isInline\n\t\t\t\t\t\t)){\n\t\t\t\t\t\t\tthis.hide();\n\t\t\t\t\t\t}\n\t\t\t\t\t}, this)\n\t\t\t\t}]\n\t\t\t];\n\t\t},\n\t\t_attachEvents: function(){\n\t\t\tthis._detachEvents();\n\t\t\tthis._applyEvents(this._events);\n\t\t},\n\t\t_detachEvents: function(){\n\t\t\tthis._unapplyEvents(this._events);\n\t\t},\n\t\t_attachSecondaryEvents: function(){\n\t\t\tthis._detachSecondaryEvents();\n\t\t\tthis._applyEvents(this._secondaryEvents);\n\t\t},\n\t\t_detachSecondaryEvents: function(){\n\t\t\tthis._unapplyEvents(this._secondaryEvents);\n\t\t},\n\t\t_trigger: function(event, altdate){\n\t\t\tvar date = altdate || this.dates.get(-1),\n\t\t\t\tlocal_date = this._utc_to_local(date);\n\n\t\t\tthis.element.trigger({\n\t\t\t\ttype: event,\n\t\t\t\tdate: local_date,\n\t\t\t\tviewMode: this.viewMode,\n\t\t\t\tdates: $.map(this.dates, this._utc_to_local),\n\t\t\t\tformat: $.proxy(function(ix, format){\n\t\t\t\t\tif (arguments.length === 0){\n\t\t\t\t\t\tix = this.dates.length - 1;\n\t\t\t\t\t\tformat = this.o.format;\n\t\t\t\t\t} else if (typeof ix === 'string'){\n\t\t\t\t\t\tformat = ix;\n\t\t\t\t\t\tix = this.dates.length - 1;\n\t\t\t\t\t}\n\t\t\t\t\tformat = format || this.o.format;\n\t\t\t\t\tvar date = this.dates.get(ix);\n\t\t\t\t\treturn DPGlobal.formatDate(date, format, this.o.language);\n\t\t\t\t}, this)\n\t\t\t});\n\t\t},\n\n\t\tshow: function(){\n\t\t\tif (this.inputField.is(':disabled') || (this.inputField.prop('readonly') && this.o.enableOnReadonly === false))\n\t\t\t\treturn;\n\t\t\tif (!this.isInline)\n\t\t\t\tthis.picker.appendTo(this.o.container);\n\t\t\tthis.place();\n\t\t\tthis.picker.show();\n\t\t\tthis._attachSecondaryEvents();\n\t\t\tthis._trigger('show');\n\t\t\tif ((window.navigator.msMaxTouchPoints || 'ontouchstart' in document) && this.o.disableTouchKeyboard) {\n\t\t\t\t$(this.element).blur();\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\n\t\thide: function(){\n\t\t\tif (this.isInline || !this.picker.is(':visible'))\n\t\t\t\treturn this;\n\t\t\tthis.focusDate = null;\n\t\t\tthis.picker.hide().detach();\n\t\t\tthis._detachSecondaryEvents();\n\t\t\tthis.setViewMode(this.o.startView);\n\n\t\t\tif (this.o.forceParse && this.inputField.val())\n\t\t\t\tthis.setValue();\n\t\t\tthis._trigger('hide');\n\t\t\treturn this;\n\t\t},\n\n\t\tdestroy: function(){\n\t\t\tthis.hide();\n\t\t\tthis._detachEvents();\n\t\t\tthis._detachSecondaryEvents();\n\t\t\tthis.picker.remove();\n\t\t\tdelete this.element.data().datepicker;\n\t\t\tif (!this.isInput){\n\t\t\t\tdelete this.element.data().date;\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\n\t\tpaste: function(e){\n\t\t\tvar dateString;\n\t\t\tif (e.originalEvent.clipboardData && e.originalEvent.clipboardData.types\n\t\t\t\t&& $.inArray('text/plain', e.originalEvent.clipboardData.types) !== -1) {\n\t\t\t\tdateString = e.originalEvent.clipboardData.getData('text/plain');\n\t\t\t} else if (window.clipboardData) {\n\t\t\t\tdateString = window.clipboardData.getData('Text');\n\t\t\t} else {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tthis.setDate(dateString);\n\t\t\tthis.update();\n\t\t\te.preventDefault();\n\t\t},\n\n\t\t_utc_to_local: function(utc){\n\t\t\tif (!utc) {\n\t\t\t\treturn utc;\n\t\t\t}\n\n\t\t\tvar local = new Date(utc.getTime() + (utc.getTimezoneOffset() * 60000));\n\n\t\t\tif (local.getTimezoneOffset() !== utc.getTimezoneOffset()) {\n\t\t\t\tlocal = new Date(utc.getTime() + (local.getTimezoneOffset() * 60000));\n\t\t\t}\n\n\t\t\treturn local;\n\t\t},\n\t\t_local_to_utc: function(local){\n\t\t\treturn local && new Date(local.getTime() - (local.getTimezoneOffset()*60000));\n\t\t},\n\t\t_zero_time: function(local){\n\t\t\treturn local && new Date(local.getFullYear(), local.getMonth(), local.getDate());\n\t\t},\n\t\t_zero_utc_time: function(utc){\n\t\t\treturn utc && UTCDate(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate());\n\t\t},\n\n\t\tgetDates: function(){\n\t\t\treturn $.map(this.dates, this._utc_to_local);\n\t\t},\n\n\t\tgetUTCDates: function(){\n\t\t\treturn $.map(this.dates, function(d){\n\t\t\t\treturn new Date(d);\n\t\t\t});\n\t\t},\n\n\t\tgetDate: function(){\n\t\t\treturn this._utc_to_local(this.getUTCDate());\n\t\t},\n\n\t\tgetUTCDate: function(){\n\t\t\tvar selected_date = this.dates.get(-1);\n\t\t\tif (selected_date !== undefined) {\n\t\t\t\treturn new Date(selected_date);\n\t\t\t} else {\n\t\t\t\treturn null;\n\t\t\t}\n\t\t},\n\n\t\tclearDates: function(){\n\t\t\tthis.inputField.val('');\n\t\t\tthis._trigger('changeDate');\n\t\t\tthis.update();\n\t\t\tif (this.o.autoclose) {\n\t\t\t\tthis.hide();\n\t\t\t}\n\t\t},\n\n\t\tsetDates: function(){\n\t\t\tvar args = Array.isArray(arguments[0]) ? arguments[0] : arguments;\n\t\t\tthis.update.apply(this, args);\n\t\t\tthis._trigger('changeDate');\n\t\t\tthis.setValue();\n\t\t\treturn this;\n\t\t},\n\n\t\tsetUTCDates: function(){\n\t\t\tvar args = Array.isArray(arguments[0]) ? arguments[0] : arguments;\n\t\t\tthis.setDates.apply(this, $.map(args, this._utc_to_local));\n\t\t\treturn this;\n\t\t},\n\n\t\tsetDate: alias('setDates'),\n\t\tsetUTCDate: alias('setUTCDates'),\n\t\tremove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead'),\n\n\t\tsetValue: function(){\n\t\t\tvar formatted = this.getFormattedDate();\n\t\t\tthis.inputField.val(formatted);\n\t\t\treturn this;\n\t\t},\n\n\t\tgetFormattedDate: function(format){\n\t\t\tif (format === undefined)\n\t\t\t\tformat = this.o.format;\n\n\t\t\tvar lang = this.o.language;\n\t\t\treturn $.map(this.dates, function(d){\n\t\t\t\treturn DPGlobal.formatDate(d, format, lang);\n\t\t\t}).join(this.o.multidateSeparator);\n\t\t},\n\n\t\tgetStartDate: function(){\n\t\t\treturn this.o.startDate;\n\t\t},\n\n\t\tsetStartDate: function(startDate){\n\t\t\tthis._process_options({startDate: startDate});\n\t\t\tthis.update();\n\t\t\tthis.updateNavArrows();\n\t\t\treturn this;\n\t\t},\n\n\t\tgetEndDate: function(){\n\t\t\treturn this.o.endDate;\n\t\t},\n\n\t\tsetEndDate: function(endDate){\n\t\t\tthis._process_options({endDate: endDate});\n\t\t\tthis.update();\n\t\t\tthis.updateNavArrows();\n\t\t\treturn this;\n\t\t},\n\n\t\tsetDaysOfWeekDisabled: function(daysOfWeekDisabled){\n\t\t\tthis._process_options({daysOfWeekDisabled: daysOfWeekDisabled});\n\t\t\tthis.update();\n\t\t\treturn this;\n\t\t},\n\n\t\tsetDaysOfWeekHighlighted: function(daysOfWeekHighlighted){\n\t\t\tthis._process_options({daysOfWeekHighlighted: daysOfWeekHighlighted});\n\t\t\tthis.update();\n\t\t\treturn this;\n\t\t},\n\n\t\tsetDatesDisabled: function(datesDisabled){\n\t\t\tthis._process_options({datesDisabled: datesDisabled});\n\t\t\tthis.update();\n\t\t\treturn this;\n\t\t},\n\n\t\tplace: function(){\n\t\t\tif (this.isInline)\n\t\t\t\treturn this;\n\t\t\tvar calendarWidth = this.picker.outerWidth(),\n\t\t\t\tcalendarHeight = this.picker.outerHeight(),\n\t\t\t\tvisualPadding = 10,\n\t\t\t\tcontainer = $(this.o.container),\n\t\t\t\twindowWidth = container.width(),\n\t\t\t\tscrollTop = this.o.container === 'body' ? $(document).scrollTop() : container.scrollTop(),\n\t\t\t\tappendOffset = container.offset();\n\n\t\t\tvar parentsZindex = [0];\n\t\t\tthis.element.parents().each(function(){\n\t\t\t\tvar itemZIndex = $(this).css('z-index');\n\t\t\t\tif (itemZIndex !== 'auto' && Number(itemZIndex) !== 0) parentsZindex.push(Number(itemZIndex));\n\t\t\t});\n\t\t\tvar zIndex = Math.max.apply(Math, parentsZindex) + this.o.zIndexOffset;\n\t\t\tvar offset = this.component ? this.component.parent().offset() : this.element.offset();\n\t\t\tvar height = this.component ? this.component.outerHeight(true) : this.element.outerHeight(false);\n\t\t\tvar width = this.component ? this.component.outerWidth(true) : this.element.outerWidth(false);\n\t\t\tvar left = offset.left - appendOffset.left;\n\t\t\tvar top = offset.top - appendOffset.top;\n\n\t\t\tif (this.o.container !== 'body') {\n\t\t\t\ttop += scrollTop;\n\t\t\t}\n\n\t\t\tthis.picker.removeClass(\n\t\t\t\t'datepicker-orient-top datepicker-orient-bottom '+\n\t\t\t\t'datepicker-orient-right datepicker-orient-left'\n\t\t\t);\n\n\t\t\tif (this.o.orientation.x !== 'auto'){\n\t\t\t\tthis.picker.addClass('datepicker-orient-' + this.o.orientation.x);\n\t\t\t\tif (this.o.orientation.x === 'right')\n\t\t\t\t\tleft -= calendarWidth - width;\n\t\t\t}\n\t\t\t// auto x orientation is best-placement: if it crosses a window\n\t\t\t// edge, fudge it sideways\n\t\t\telse {\n\t\t\t\tif (offset.left < 0) {\n\t\t\t\t\t// component is outside the window on the left side. Move it into visible range\n\t\t\t\t\tthis.picker.addClass('datepicker-orient-left');\n\t\t\t\t\tleft -= offset.left - visualPadding;\n\t\t\t\t} else if (left + calendarWidth > windowWidth) {\n\t\t\t\t\t// the calendar passes the widow right edge. Align it to component right side\n\t\t\t\t\tthis.picker.addClass('datepicker-orient-right');\n\t\t\t\t\tleft += width - calendarWidth;\n\t\t\t\t} else {\n\t\t\t\t\tif (this.o.rtl) {\n\t\t\t\t\t\t// Default to right\n\t\t\t\t\t\tthis.picker.addClass('datepicker-orient-right');\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// Default to left\n\t\t\t\t\t\tthis.picker.addClass('datepicker-orient-left');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// auto y orientation is best-situation: top or bottom, no fudging,\n\t\t\t// decision based on which shows more of the calendar\n\t\t\tvar yorient = this.o.orientation.y,\n\t\t\t\ttop_overflow;\n\t\t\tif (yorient === 'auto'){\n\t\t\t\ttop_overflow = -scrollTop + top - calendarHeight;\n\t\t\t\tyorient = top_overflow < 0 ? 'bottom' : 'top';\n\t\t\t}\n\n\t\t\tthis.picker.addClass('datepicker-orient-' + yorient);\n\t\t\tif (yorient === 'top')\n\t\t\t\ttop -= calendarHeight + parseInt(this.picker.css('padding-top'));\n\t\t\telse\n\t\t\t\ttop += height;\n\n\t\t\tif (this.o.rtl) {\n\t\t\t\tvar right = windowWidth - (left + width);\n\t\t\t\tthis.picker.css({\n\t\t\t\t\ttop: top,\n\t\t\t\t\tright: right,\n\t\t\t\t\tzIndex: zIndex\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tthis.picker.css({\n\t\t\t\t\ttop: top,\n\t\t\t\t\tleft: left,\n\t\t\t\t\tzIndex: zIndex\n\t\t\t\t});\n\t\t\t}\n\t\t\treturn this;\n\t\t},\n\n\t\t_allow_update: true,\n\t\tupdate: function(){\n\t\t\tif (!this._allow_update)\n\t\t\t\treturn this;\n\n\t\t\tvar oldDates = this.dates.copy(),\n\t\t\t\tdates = [],\n\t\t\t\tfromArgs = false;\n\t\t\tif (arguments.length){\n\t\t\t\t$.each(arguments, $.proxy(function(i, date){\n\t\t\t\t\tif (date instanceof Date)\n\t\t\t\t\t\tdate = this._local_to_utc(date);\n\t\t\t\t\tdates.push(date);\n\t\t\t\t}, this));\n\t\t\t\tfromArgs = true;\n\t\t\t} else {\n\t\t\t\tdates = this.isInput\n\t\t\t\t\t\t? this.element.val()\n\t\t\t\t\t\t: this.element.data('date') || this.inputField.val();\n\t\t\t\tif (dates && this.o.multidate)\n\t\t\t\t\tdates = dates.split(this.o.multidateSeparator);\n\t\t\t\telse\n\t\t\t\t\tdates = [dates];\n\t\t\t\tdelete this.element.data().date;\n\t\t\t}\n\n\t\t\tdates = $.map(dates, $.proxy(function(date){\n\t\t\t\treturn DPGlobal.parseDate(date, this.o.format, this.o.language, this.o.assumeNearbyYear);\n\t\t\t}, this));\n\t\t\tdates = $.grep(dates, $.proxy(function(date){\n\t\t\t\treturn (\n\t\t\t\t\t!this.dateWithinRange(date) ||\n\t\t\t\t\t!date\n\t\t\t\t);\n\t\t\t}, this), true);\n\t\t\tthis.dates.replace(dates);\n\n\t\t\tif (this.o.updateViewDate) {\n\t\t\t\tif (this.dates.length)\n\t\t\t\t\tthis.viewDate = new Date(this.dates.get(-1));\n\t\t\t\telse if (this.viewDate < this.o.startDate)\n\t\t\t\t\tthis.viewDate = new Date(this.o.startDate);\n\t\t\t\telse if (this.viewDate > this.o.endDate)\n\t\t\t\t\tthis.viewDate = new Date(this.o.endDate);\n\t\t\t\telse\n\t\t\t\t\tthis.viewDate = this.o.defaultViewDate;\n\t\t\t}\n\n\t\t\tif (fromArgs){\n\t\t\t\t// setting date by clicking\n\t\t\t\tthis.setValue();\n\t\t\t\tthis.element.change();\n\t\t\t}\n\t\t\telse if (this.dates.length){\n\t\t\t\t// setting date by typing\n\t\t\t\tif (String(oldDates) !== String(this.dates) && fromArgs) {\n\t\t\t\t\tthis._trigger('changeDate');\n\t\t\t\t\tthis.element.change();\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!this.dates.length && oldDates.length) {\n\t\t\t\tthis._trigger('clearDate');\n\t\t\t\tthis.element.change();\n\t\t\t}\n\n\t\t\tthis.fill();\n\t\t\treturn this;\n\t\t},\n\n\t\tfillDow: function(){\n if (this.o.showWeekDays) {\n\t\t\tvar dowCnt = this.o.weekStart,\n\t\t\t\thtml = '';\n\t\t\tif (this.o.calendarWeeks){\n\t\t\t\thtml += ' ';\n\t\t\t}\n\t\t\twhile (dowCnt < this.o.weekStart + 7){\n\t\t\t\thtml += '';\n\t\t\t}\n\t\t\thtml += '';\n\t\t\tthis.picker.find('.datepicker-days thead').append(html);\n }\n\t\t},\n\n\t\tfillMonths: function(){\n var localDate = this._utc_to_local(this.viewDate);\n\t\t\tvar html = '';\n\t\t\tvar focused;\n\t\t\tfor (var i = 0; i < 12; i++){\n\t\t\t\tfocused = localDate && localDate.getMonth() === i ? ' focused' : '';\n\t\t\t\thtml += '' + dates[this.o.language].monthsShort[i] + '';\n\t\t\t}\n\t\t\tthis.picker.find('.datepicker-months td').html(html);\n\t\t},\n\n\t\tsetRange: function(range){\n\t\t\tif (!range || !range.length)\n\t\t\t\tdelete this.range;\n\t\t\telse\n\t\t\t\tthis.range = $.map(range, function(d){\n\t\t\t\t\treturn d.valueOf();\n\t\t\t\t});\n\t\t\tthis.fill();\n\t\t},\n\n\t\tgetClassNames: function(date){\n\t\t\tvar cls = [],\n\t\t\t\tyear = this.viewDate.getUTCFullYear(),\n\t\t\t\tmonth = this.viewDate.getUTCMonth(),\n\t\t\t\ttoday = UTCToday();\n\t\t\tif (date.getUTCFullYear() < year || (date.getUTCFullYear() === year && date.getUTCMonth() < month)){\n\t\t\t\tcls.push('old');\n\t\t\t} else if (date.getUTCFullYear() > year || (date.getUTCFullYear() === year && date.getUTCMonth() > month)){\n\t\t\t\tcls.push('new');\n\t\t\t}\n\t\t\tif (this.focusDate && date.valueOf() === this.focusDate.valueOf())\n\t\t\t\tcls.push('focused');\n\t\t\t// Compare internal UTC date with UTC today, not local today\n\t\t\tif (this.o.todayHighlight && isUTCEquals(date, today)) {\n\t\t\t\tcls.push('today');\n\t\t\t}\n\t\t\tif (this.dates.contains(date) !== -1)\n\t\t\t\tcls.push('active');\n\t\t\tif (!this.dateWithinRange(date)){\n\t\t\t\tcls.push('disabled');\n\t\t\t}\n\t\t\tif (this.dateIsDisabled(date)){\n\t\t\t\tcls.push('disabled', 'disabled-date');\n\t\t\t}\n\t\t\tif ($.inArray(date.getUTCDay(), this.o.daysOfWeekHighlighted) !== -1){\n\t\t\t\tcls.push('highlighted');\n\t\t\t}\n\n\t\t\tif (this.range){\n\t\t\t\tif (date > this.range[0] && date < this.range[this.range.length-1]){\n\t\t\t\t\tcls.push('range');\n\t\t\t\t}\n\t\t\t\tif ($.inArray(date.valueOf(), this.range) !== -1){\n\t\t\t\t\tcls.push('selected');\n\t\t\t\t}\n\t\t\t\tif (date.valueOf() === this.range[0]){\n cls.push('range-start');\n }\n if (date.valueOf() === this.range[this.range.length-1]){\n cls.push('range-end');\n }\n\t\t\t}\n\t\t\treturn cls;\n\t\t},\n\n\t\t_fill_yearsView: function(selector, cssClass, factor, year, startYear, endYear, beforeFn){\n\t\t\tvar html = '';\n\t\t\tvar step = factor / 10;\n\t\t\tvar view = this.picker.find(selector);\n\t\t\tvar startVal = Math.floor(year / factor) * factor;\n\t\t\tvar endVal = startVal + step * 9;\n\t\t\tvar focusedVal = Math.floor(this.viewDate.getFullYear() / step) * step;\n\t\t\tvar selected = $.map(this.dates, function(d){\n\t\t\t\treturn Math.floor(d.getUTCFullYear() / step) * step;\n\t\t\t});\n\n\t\t\tvar classes, tooltip, before;\n\t\t\tfor (var currVal = startVal - step; currVal <= endVal + step; currVal += step) {\n\t\t\t\tclasses = [cssClass];\n\t\t\t\ttooltip = null;\n\n\t\t\t\tif (currVal === startVal - step) {\n\t\t\t\t\tclasses.push('old');\n\t\t\t\t} else if (currVal === endVal + step) {\n\t\t\t\t\tclasses.push('new');\n\t\t\t\t}\n\t\t\t\tif ($.inArray(currVal, selected) !== -1) {\n\t\t\t\t\tclasses.push('active');\n\t\t\t\t}\n\t\t\t\tif (currVal < startYear || currVal > endYear) {\n\t\t\t\t\tclasses.push('disabled');\n\t\t\t\t}\n\t\t\t\tif (currVal === focusedVal) {\n\t\t\t\t classes.push('focused');\n }\n\n\t\t\t\tif (beforeFn !== $.noop) {\n\t\t\t\t\tbefore = beforeFn(new Date(currVal, 0, 1));\n\t\t\t\t\tif (before === undefined) {\n\t\t\t\t\t\tbefore = {};\n\t\t\t\t\t} else if (typeof before === 'boolean') {\n\t\t\t\t\t\tbefore = {enabled: before};\n\t\t\t\t\t} else if (typeof before === 'string') {\n\t\t\t\t\t\tbefore = {classes: before};\n\t\t\t\t\t}\n\t\t\t\t\tif (before.enabled === false) {\n\t\t\t\t\t\tclasses.push('disabled');\n\t\t\t\t\t}\n\t\t\t\t\tif (before.classes) {\n\t\t\t\t\t\tclasses = classes.concat(before.classes.split(/\\s+/));\n\t\t\t\t\t}\n\t\t\t\t\tif (before.tooltip) {\n\t\t\t\t\t\ttooltip = before.tooltip;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\thtml += '' + currVal + '';\n\t\t\t}\n\n\t\t\tview.find('.datepicker-switch').text(startVal + '-' + endVal);\n\t\t\tview.find('td').html(html);\n\t\t},\n\n\t\tfill: function(){\n\t\t\tvar d = new Date(this.viewDate),\n\t\t\t\tyear = d.getUTCFullYear(),\n\t\t\t\tmonth = d.getUTCMonth(),\n\t\t\t\tstartYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,\n\t\t\t\tstartMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,\n\t\t\t\tendYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,\n\t\t\t\tendMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,\n\t\t\t\ttodaytxt = dates[this.o.language].today || dates['en'].today || '',\n\t\t\t\tcleartxt = dates[this.o.language].clear || dates['en'].clear || '',\n titleFormat = dates[this.o.language].titleFormat || dates['en'].titleFormat,\n todayDate = UTCToday(),\n titleBtnVisible = (this.o.todayBtn === true || this.o.todayBtn === 'linked') && todayDate >= this.o.startDate && todayDate <= this.o.endDate && !this.weekOfDateIsDisabled(todayDate),\n\t\t\t\ttooltip,\n\t\t\t\tbefore;\n\t\t\tif (isNaN(year) || isNaN(month))\n\t\t\t\treturn;\n\t\t\tthis.picker.find('.datepicker-days .datepicker-switch')\n\t\t\t\t\t\t.text(DPGlobal.formatDate(d, titleFormat, this.o.language));\n\t\t\tthis.picker.find('tfoot .today')\n\t\t\t\t\t\t.text(todaytxt)\n .css('display', titleBtnVisible ? 'table-cell' : 'none');\n\t\t\tthis.picker.find('tfoot .clear')\n\t\t\t\t\t\t.text(cleartxt)\n\t\t\t\t\t\t.css('display', this.o.clearBtn === true ? 'table-cell' : 'none');\n\t\t\tthis.picker.find('thead .datepicker-title')\n\t\t\t\t\t\t.text(this.o.title)\n\t\t\t\t\t\t.css('display', typeof this.o.title === 'string' && this.o.title !== '' ? 'table-cell' : 'none');\n\t\t\tthis.updateNavArrows();\n\t\t\tthis.fillMonths();\n\t\t\tvar prevMonth = UTCDate(year, month, 0),\n\t\t\t\tday = prevMonth.getUTCDate();\n\t\t\tprevMonth.setUTCDate(day - (prevMonth.getUTCDay() - this.o.weekStart + 7)%7);\n\t\t\tvar nextMonth = new Date(prevMonth);\n\t\t\tif (prevMonth.getUTCFullYear() < 100){\n nextMonth.setUTCFullYear(prevMonth.getUTCFullYear());\n }\n\t\t\tnextMonth.setUTCDate(nextMonth.getUTCDate() + 42);\n\t\t\tnextMonth = nextMonth.valueOf();\n\t\t\tvar html = [];\n\t\t\tvar weekDay, clsName;\n\t\t\twhile (prevMonth.valueOf() < nextMonth){\n\t\t\t\tweekDay = prevMonth.getUTCDay();\n\t\t\t\tif (weekDay === this.o.weekStart){\n\t\t\t\t\thtml.push('');\n\t\t\t\t\tif (this.o.calendarWeeks){\n\t\t\t\t\t\t// ISO 8601: First week contains first thursday.\n\t\t\t\t\t\t// ISO also states week starts on Monday, but we can be more abstract here.\n\t\t\t\t\t\tvar\n\t\t\t\t\t\t\t// Start of current week: based on weekstart/current date\n\t\t\t\t\t\t\tws = new Date(+prevMonth + (this.o.weekStart - weekDay - 7) % 7 * 864e5),\n\t\t\t\t\t\t\t// Thursday of this week\n\t\t\t\t\t\t\tth = new Date(Number(ws) + (7 + 4 - ws.getUTCDay()) % 7 * 864e5),\n\t\t\t\t\t\t\t// First Thursday of year, year from thursday\n\t\t\t\t\t\t\tyth = new Date(Number(yth = UTCDate(th.getUTCFullYear(), 0, 1)) + (7 + 4 - yth.getUTCDay()) % 7 * 864e5),\n\t\t\t\t\t\t\t// Calendar week: ms between thursdays, div ms per day, div 7 days\n\t\t\t\t\t\t\tcalWeek = (th - yth) / 864e5 / 7 + 1;\n\t\t\t\t\t\thtml.push(''+ calWeek +'');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tclsName = this.getClassNames(prevMonth);\n\t\t\t\tclsName.push('day');\n\n\t\t\t\tvar content = prevMonth.getUTCDate();\n\n\t\t\t\tif (this.o.beforeShowDay !== $.noop){\n\t\t\t\t\tbefore = this.o.beforeShowDay(this._utc_to_local(prevMonth));\n\t\t\t\t\tif (before === undefined)\n\t\t\t\t\t\tbefore = {};\n\t\t\t\t\telse if (typeof before === 'boolean')\n\t\t\t\t\t\tbefore = {enabled: before};\n\t\t\t\t\telse if (typeof before === 'string')\n\t\t\t\t\t\tbefore = {classes: before};\n\t\t\t\t\tif (before.enabled === false)\n\t\t\t\t\t\tclsName.push('disabled');\n\t\t\t\t\tif (before.classes)\n\t\t\t\t\t\tclsName = clsName.concat(before.classes.split(/\\s+/));\n\t\t\t\t\tif (before.tooltip)\n\t\t\t\t\t\ttooltip = before.tooltip;\n\t\t\t\t\tif (before.content)\n\t\t\t\t\t\tcontent = before.content;\n\t\t\t\t}\n\n\t\t\t\t//Check if uniqueSort exists (supported by jquery >=1.12 and >=2.2)\n\t\t\t\t//Fallback to unique function for older jquery versions\n\t\t\t\tif (typeof $.uniqueSort === \"function\") {\n\t\t\t\t\tclsName = $.uniqueSort(clsName);\n\t\t\t\t} else {\n\t\t\t\t\tclsName = $.unique(clsName);\n\t\t\t\t}\n\n\t\t\t\thtml.push('' + content + '');\n\t\t\t\ttooltip = null;\n\t\t\t\tif (weekDay === this.o.weekEnd){\n\t\t\t\t\thtml.push('');\n\t\t\t\t}\n\t\t\t\tprevMonth.setUTCDate(prevMonth.getUTCDate() + 1);\n\t\t\t}\n\t\t\tthis.picker.find('.datepicker-days tbody').html(html.join(''));\n\n\t\t\tvar monthsTitle = dates[this.o.language].monthsTitle || dates['en'].monthsTitle || 'Months';\n\t\t\tvar months = this.picker.find('.datepicker-months')\n\t\t\t\t\t\t.find('.datepicker-switch')\n\t\t\t\t\t\t\t.text(this.o.maxViewMode < 2 ? monthsTitle : year)\n\t\t\t\t\t\t\t.end()\n\t\t\t\t\t\t.find('tbody span').removeClass('active');\n\n\t\t\t$.each(this.dates, function(i, d){\n\t\t\t\tif (d.getUTCFullYear() === year)\n\t\t\t\t\tmonths.eq(d.getUTCMonth()).addClass('active');\n\t\t\t});\n\n\t\t\tif (year < startYear || year > endYear){\n\t\t\t\tmonths.addClass('disabled');\n\t\t\t}\n\t\t\tif (year === startYear){\n\t\t\t\tmonths.slice(0, startMonth).addClass('disabled');\n\t\t\t}\n\t\t\tif (year === endYear){\n\t\t\t\tmonths.slice(endMonth+1).addClass('disabled');\n\t\t\t}\n\n\t\t\tif (this.o.beforeShowMonth !== $.noop){\n\t\t\t\tvar that = this;\n\t\t\t\t$.each(months, function(i, month){\n var moDate = new Date(year, i, 1);\n var before = that.o.beforeShowMonth(moDate);\n\t\t\t\t\tif (before === undefined)\n\t\t\t\t\t\tbefore = {};\n\t\t\t\t\telse if (typeof before === 'boolean')\n\t\t\t\t\t\tbefore = {enabled: before};\n\t\t\t\t\telse if (typeof before === 'string')\n\t\t\t\t\t\tbefore = {classes: before};\n\t\t\t\t\tif (before.enabled === false && !$(month).hasClass('disabled'))\n\t\t\t\t\t $(month).addClass('disabled');\n\t\t\t\t\tif (before.classes)\n\t\t\t\t\t $(month).addClass(before.classes);\n\t\t\t\t\tif (before.tooltip)\n\t\t\t\t\t $(month).prop('title', before.tooltip);\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Generating decade/years picker\n\t\t\tthis._fill_yearsView(\n\t\t\t\t'.datepicker-years',\n\t\t\t\t'year',\n\t\t\t\t10,\n\t\t\t\tyear,\n\t\t\t\tstartYear,\n\t\t\t\tendYear,\n\t\t\t\tthis.o.beforeShowYear\n\t\t\t);\n\n\t\t\t// Generating century/decades picker\n\t\t\tthis._fill_yearsView(\n\t\t\t\t'.datepicker-decades',\n\t\t\t\t'decade',\n\t\t\t\t100,\n\t\t\t\tyear,\n\t\t\t\tstartYear,\n\t\t\t\tendYear,\n\t\t\t\tthis.o.beforeShowDecade\n\t\t\t);\n\n\t\t\t// Generating millennium/centuries picker\n\t\t\tthis._fill_yearsView(\n\t\t\t\t'.datepicker-centuries',\n\t\t\t\t'century',\n\t\t\t\t1000,\n\t\t\t\tyear,\n\t\t\t\tstartYear,\n\t\t\t\tendYear,\n\t\t\t\tthis.o.beforeShowCentury\n\t\t\t);\n\t\t},\n\n\t\tupdateNavArrows: function(){\n\t\t\tif (!this._allow_update)\n\t\t\t\treturn;\n\n\t\t\tvar d = new Date(this.viewDate),\n\t\t\t\tyear = d.getUTCFullYear(),\n\t\t\t\tmonth = d.getUTCMonth(),\n\t\t\t\tstartYear = this.o.startDate !== -Infinity ? this.o.startDate.getUTCFullYear() : -Infinity,\n\t\t\t\tstartMonth = this.o.startDate !== -Infinity ? this.o.startDate.getUTCMonth() : -Infinity,\n\t\t\t\tendYear = this.o.endDate !== Infinity ? this.o.endDate.getUTCFullYear() : Infinity,\n\t\t\t\tendMonth = this.o.endDate !== Infinity ? this.o.endDate.getUTCMonth() : Infinity,\n\t\t\t\tprevIsDisabled,\n\t\t\t\tnextIsDisabled,\n\t\t\t\tfactor = 1;\n\t\t\tswitch (this.viewMode){\n\t\t\t\tcase 4:\n\t\t\t\t\tfactor *= 10;\n\t\t\t\t\t/* falls through */\n\t\t\t\tcase 3:\n\t\t\t\t\tfactor *= 10;\n\t\t\t\t\t/* falls through */\n\t\t\t\tcase 2:\n\t\t\t\t\tfactor *= 10;\n\t\t\t\t\t/* falls through */\n\t\t\t\tcase 1:\n\t\t\t\t\tprevIsDisabled = Math.floor(year / factor) * factor <= startYear;\n\t\t\t\t\tnextIsDisabled = Math.floor(year / factor) * factor + factor > endYear;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 0:\n\t\t\t\t\tprevIsDisabled = year <= startYear && month <= startMonth;\n\t\t\t\t\tnextIsDisabled = year >= endYear && month >= endMonth;\n\t\t\t\t\tbreak;\n\t\t\t}\n\n\t\t\tthis.picker.find('.prev').toggleClass('disabled', prevIsDisabled);\n\t\t\tthis.picker.find('.next').toggleClass('disabled', nextIsDisabled);\n\t\t},\n\n\t\tclick: function(e){\n\t\t\te.preventDefault();\n\t\t\te.stopPropagation();\n\n\t\t\tvar target, dir, day, year, month;\n\t\t\ttarget = $(e.target);\n\n\t\t\t// Clicked on the switch\n\t\t\tif (target.hasClass('datepicker-switch') && this.viewMode !== this.o.maxViewMode){\n\t\t\t\tthis.setViewMode(this.viewMode + 1);\n\t\t\t}\n\n\t\t\t// Clicked on today button\n\t\t\tif (target.hasClass('today') && !target.hasClass('day')){\n\t\t\t\tthis.setViewMode(0);\n\t\t\t\tthis._setDate(UTCToday(), this.o.todayBtn === 'linked' ? null : 'view');\n\t\t\t}\n\n\t\t\t// Clicked on clear button\n\t\t\tif (target.hasClass('clear')){\n\t\t\t\tthis.clearDates();\n\t\t\t}\n\n\t\t\tif (!target.hasClass('disabled')){\n\t\t\t\t// Clicked on a month, year, decade, century\n\t\t\t\tif (target.hasClass('month')\n\t\t\t\t\t\t|| target.hasClass('year')\n\t\t\t\t\t\t|| target.hasClass('decade')\n\t\t\t\t\t\t|| target.hasClass('century')) {\n\t\t\t\t\tthis.viewDate.setUTCDate(1);\n\n\t\t\t\t\tday = 1;\n\t\t\t\t\tif (this.viewMode === 1){\n\t\t\t\t\t\tmonth = target.parent().find('span').index(target);\n\t\t\t\t\t\tyear = this.viewDate.getUTCFullYear();\n\t\t\t\t\t\tthis.viewDate.setUTCMonth(month);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tmonth = 0;\n\t\t\t\t\t\tyear = Number(target.text());\n\t\t\t\t\t\tthis.viewDate.setUTCFullYear(year);\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._trigger(DPGlobal.viewModes[this.viewMode - 1].e, this.viewDate);\n\n\t\t\t\t\tif (this.viewMode === this.o.minViewMode){\n\t\t\t\t\t\tthis._setDate(UTCDate(year, month, day));\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.setViewMode(this.viewMode - 1);\n\t\t\t\t\t\tthis.fill();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (this.picker.is(':visible') && this._focused_from){\n\t\t\t\tthis._focused_from.focus();\n\t\t\t}\n\t\t\tdelete this._focused_from;\n\t\t},\n\n\t\tdayCellClick: function(e){\n\t\t\tvar $target = $(e.currentTarget);\n\t\t\tvar timestamp = $target.data('date');\n\t\t\tvar date = new Date(timestamp);\n\n\t\t\tif (this.o.updateViewDate) {\n\t\t\t\tif (date.getUTCFullYear() !== this.viewDate.getUTCFullYear()) {\n\t\t\t\t\tthis._trigger('changeYear', this.viewDate);\n\t\t\t\t}\n\n\t\t\t\tif (date.getUTCMonth() !== this.viewDate.getUTCMonth()) {\n\t\t\t\t\tthis._trigger('changeMonth', this.viewDate);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis._setDate(date);\n\t\t},\n\n\t\t// Clicked on prev or next\n\t\tnavArrowsClick: function(e){\n\t\t\tvar $target = $(e.currentTarget);\n\t\t\tvar dir = $target.hasClass('prev') ? -1 : 1;\n\t\t\tif (this.viewMode !== 0){\n\t\t\t\tdir *= DPGlobal.viewModes[this.viewMode].navStep * 12;\n\t\t\t}\n\t\t\tthis.viewDate = this.moveMonth(this.viewDate, dir);\n\t\t\tthis._trigger(DPGlobal.viewModes[this.viewMode].e, this.viewDate);\n\t\t\tthis.fill();\n\t\t},\n\n\t\t_toggle_multidate: function(date){\n\t\t\tvar ix = this.dates.contains(date);\n\t\t\tif (!date){\n\t\t\t\tthis.dates.clear();\n\t\t\t}\n\n\t\t\tif (ix !== -1){\n\t\t\t\tif (this.o.multidate === true || this.o.multidate > 1 || this.o.toggleActive){\n\t\t\t\t\tthis.dates.remove(ix);\n\t\t\t\t}\n\t\t\t} else if (this.o.multidate === false) {\n\t\t\t\tthis.dates.clear();\n\t\t\t\tthis.dates.push(date);\n\t\t\t}\n\t\t\telse {\n\t\t\t\tthis.dates.push(date);\n\t\t\t}\n\n\t\t\tif (typeof this.o.multidate === 'number')\n\t\t\t\twhile (this.dates.length > this.o.multidate)\n\t\t\t\t\tthis.dates.remove(0);\n\t\t},\n\n\t\t_setDate: function(date, which){\n\t\t\tif (!which || which === 'date')\n\t\t\t\tthis._toggle_multidate(date && new Date(date));\n\t\t\tif ((!which && this.o.updateViewDate) || which === 'view')\n\t\t\t\tthis.viewDate = date && new Date(date);\n\n\t\t\tthis.fill();\n\t\t\tthis.setValue();\n\t\t\tif (!which || which !== 'view') {\n\t\t\t\tthis._trigger('changeDate');\n\t\t\t}\n\t\t\tthis.inputField.trigger('change');\n\t\t\tif (this.o.autoclose && (!which || which === 'date')){\n\t\t\t\tthis.hide();\n\t\t\t}\n\t\t},\n\n\t\tmoveDay: function(date, dir){\n\t\t\tvar newDate = new Date(date);\n\t\t\tnewDate.setUTCDate(date.getUTCDate() + dir);\n\n\t\t\treturn newDate;\n\t\t},\n\n\t\tmoveWeek: function(date, dir){\n\t\t\treturn this.moveDay(date, dir * 7);\n\t\t},\n\n\t\tmoveMonth: function(date, dir){\n\t\t\tif (!isValidDate(date))\n\t\t\t\treturn this.o.defaultViewDate;\n\t\t\tif (!dir)\n\t\t\t\treturn date;\n\t\t\tvar new_date = new Date(date.valueOf()),\n\t\t\t\tday = new_date.getUTCDate(),\n\t\t\t\tmonth = new_date.getUTCMonth(),\n\t\t\t\tmag = Math.abs(dir),\n\t\t\t\tnew_month, test;\n\t\t\tdir = dir > 0 ? 1 : -1;\n\t\t\tif (mag === 1){\n\t\t\t\ttest = dir === -1\n\t\t\t\t\t// If going back one month, make sure month is not current month\n\t\t\t\t\t// (eg, Mar 31 -> Feb 31 == Feb 28, not Mar 02)\n\t\t\t\t\t? function(){\n\t\t\t\t\t\treturn new_date.getUTCMonth() === month;\n\t\t\t\t\t}\n\t\t\t\t\t// If going forward one month, make sure month is as expected\n\t\t\t\t\t// (eg, Jan 31 -> Feb 31 == Feb 28, not Mar 02)\n\t\t\t\t\t: function(){\n\t\t\t\t\t\treturn new_date.getUTCMonth() !== new_month;\n\t\t\t\t\t};\n\t\t\t\tnew_month = month + dir;\n\t\t\t\tnew_date.setUTCMonth(new_month);\n\t\t\t\t// Dec -> Jan (12) or Jan -> Dec (-1) -- limit expected date to 0-11\n\t\t\t\tnew_month = (new_month + 12) % 12;\n\t\t\t}\n\t\t\telse {\n\t\t\t\t// For magnitudes >1, move one month at a time...\n\t\t\t\tfor (var i=0; i < mag; i++)\n\t\t\t\t\t// ...which might decrease the day (eg, Jan 31 to Feb 28, etc)...\n\t\t\t\t\tnew_date = this.moveMonth(new_date, dir);\n\t\t\t\t// ...then reset the day, keeping it in the new month\n\t\t\t\tnew_month = new_date.getUTCMonth();\n\t\t\t\tnew_date.setUTCDate(day);\n\t\t\t\ttest = function(){\n\t\t\t\t\treturn new_month !== new_date.getUTCMonth();\n\t\t\t\t};\n\t\t\t}\n\t\t\t// Common date-resetting loop -- if date is beyond end of month, make it\n\t\t\t// end of month\n\t\t\twhile (test()){\n\t\t\t\tnew_date.setUTCDate(--day);\n\t\t\t\tnew_date.setUTCMonth(new_month);\n\t\t\t}\n\t\t\treturn new_date;\n\t\t},\n\n\t\tmoveYear: function(date, dir){\n\t\t\treturn this.moveMonth(date, dir*12);\n\t\t},\n\n\t\tmoveAvailableDate: function(date, dir, fn){\n\t\t\tdo {\n\t\t\t\tdate = this[fn](date, dir);\n\n\t\t\t\tif (!this.dateWithinRange(date))\n\t\t\t\t\treturn false;\n\n\t\t\t\tfn = 'moveDay';\n\t\t\t}\n\t\t\twhile (this.dateIsDisabled(date));\n\n\t\t\treturn date;\n\t\t},\n\n\t\tweekOfDateIsDisabled: function(date){\n\t\t\treturn $.inArray(date.getUTCDay(), this.o.daysOfWeekDisabled) !== -1;\n\t\t},\n\n\t\tdateIsDisabled: function(date){\n\t\t\treturn (\n\t\t\t\tthis.weekOfDateIsDisabled(date) ||\n\t\t\t\t$.grep(this.o.datesDisabled, function(d){\n\t\t\t\t\treturn isUTCEquals(date, d);\n\t\t\t\t}).length > 0\n\t\t\t);\n\t\t},\n\n\t\tdateWithinRange: function(date){\n\t\t\treturn date >= this.o.startDate && date <= this.o.endDate;\n\t\t},\n\n\t\tkeydown: function(e){\n\t\t\tif (!this.picker.is(':visible')){\n\t\t\t\tif (e.keyCode === 40 || e.keyCode === 27) { // allow down to re-show picker\n\t\t\t\t\tthis.show();\n\t\t\t\t\te.stopPropagation();\n }\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tvar dateChanged = false,\n\t\t\t\tdir, newViewDate,\n\t\t\t\tfocusDate = this.focusDate || this.viewDate;\n\t\t\tswitch (e.keyCode){\n\t\t\t\tcase 27: // escape\n\t\t\t\t\tif (this.focusDate){\n\t\t\t\t\t\tthis.focusDate = null;\n\t\t\t\t\t\tthis.viewDate = this.dates.get(-1) || this.viewDate;\n\t\t\t\t\t\tthis.fill();\n\t\t\t\t\t}\n\t\t\t\t\telse\n\t\t\t\t\t\tthis.hide();\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\te.stopPropagation();\n\t\t\t\t\tbreak;\n\t\t\t\tcase 37: // left\n\t\t\t\tcase 38: // up\n\t\t\t\tcase 39: // right\n\t\t\t\tcase 40: // down\n\t\t\t\t\tif (!this.o.keyboardNavigation || this.o.daysOfWeekDisabled.length === 7)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tdir = e.keyCode === 37 || e.keyCode === 38 ? -1 : 1;\n if (this.viewMode === 0) {\n \t\t\t\t\tif (e.ctrlKey){\n \t\t\t\t\t\tnewViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');\n\n \t\t\t\t\t\tif (newViewDate)\n \t\t\t\t\t\t\tthis._trigger('changeYear', this.viewDate);\n \t\t\t\t\t} else if (e.shiftKey){\n \t\t\t\t\t\tnewViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');\n\n \t\t\t\t\t\tif (newViewDate)\n \t\t\t\t\t\t\tthis._trigger('changeMonth', this.viewDate);\n \t\t\t\t\t} else if (e.keyCode === 37 || e.keyCode === 39){\n \t\t\t\t\t\tnewViewDate = this.moveAvailableDate(focusDate, dir, 'moveDay');\n \t\t\t\t\t} else if (!this.weekOfDateIsDisabled(focusDate)){\n \t\t\t\t\t\tnewViewDate = this.moveAvailableDate(focusDate, dir, 'moveWeek');\n \t\t\t\t\t}\n } else if (this.viewMode === 1) {\n if (e.keyCode === 38 || e.keyCode === 40) {\n dir = dir * 4;\n }\n newViewDate = this.moveAvailableDate(focusDate, dir, 'moveMonth');\n } else if (this.viewMode === 2) {\n if (e.keyCode === 38 || e.keyCode === 40) {\n dir = dir * 4;\n }\n newViewDate = this.moveAvailableDate(focusDate, dir, 'moveYear');\n }\n\t\t\t\t\tif (newViewDate){\n\t\t\t\t\t\tthis.focusDate = this.viewDate = newViewDate;\n\t\t\t\t\t\tthis.setValue();\n\t\t\t\t\t\tthis.fill();\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 13: // enter\n\t\t\t\t\tif (!this.o.forceParse)\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tfocusDate = this.focusDate || this.dates.get(-1) || this.viewDate;\n\t\t\t\t\tif (this.o.keyboardNavigation) {\n\t\t\t\t\t\tthis._toggle_multidate(focusDate);\n\t\t\t\t\t\tdateChanged = true;\n\t\t\t\t\t}\n\t\t\t\t\tthis.focusDate = null;\n\t\t\t\t\tthis.viewDate = this.dates.get(-1) || this.viewDate;\n\t\t\t\t\tthis.setValue();\n\t\t\t\t\tthis.fill();\n\t\t\t\t\tif (this.picker.is(':visible')){\n\t\t\t\t\t\te.preventDefault();\n\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\tif (this.o.autoclose)\n\t\t\t\t\t\t\tthis.hide();\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 9: // tab\n\t\t\t\t\tthis.focusDate = null;\n\t\t\t\t\tthis.viewDate = this.dates.get(-1) || this.viewDate;\n\t\t\t\t\tthis.fill();\n\t\t\t\t\tthis.hide();\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (dateChanged){\n\t\t\t\tif (this.dates.length)\n\t\t\t\t\tthis._trigger('changeDate');\n\t\t\t\telse\n\t\t\t\t\tthis._trigger('clearDate');\n\t\t\t\tthis.inputField.trigger('change');\n\t\t\t}\n\t\t},\n\n\t\tsetViewMode: function(viewMode){\n\t\t\tthis.viewMode = viewMode;\n\t\t\tthis.picker\n\t\t\t\t.children('div')\n\t\t\t\t.hide()\n\t\t\t\t.filter('.datepicker-' + DPGlobal.viewModes[this.viewMode].clsName)\n\t\t\t\t\t.show();\n\t\t\tthis.updateNavArrows();\n this._trigger('changeViewMode', new Date(this.viewDate));\n\t\t}\n\t};\n\n\tvar DateRangePicker = function(element, options){\n\t\t$.data(element, 'datepicker', this);\n\t\tthis.element = $(element);\n\t\tthis.inputs = $.map(options.inputs, function(i){\n\t\t\treturn i.jquery ? i[0] : i;\n\t\t});\n\t\tdelete options.inputs;\n\n\t\tthis.keepEmptyValues = options.keepEmptyValues;\n\t\tdelete options.keepEmptyValues;\n\n\t\tdatepickerPlugin.call($(this.inputs), options)\n\t\t\t.on('changeDate', $.proxy(this.dateUpdated, this));\n\n\t\tthis.pickers = $.map(this.inputs, function(i){\n\t\t\treturn $.data(i, 'datepicker');\n\t\t});\n\t\tthis.updateDates();\n\t};\n\tDateRangePicker.prototype = {\n\t\tupdateDates: function(){\n\t\t\tthis.dates = $.map(this.pickers, function(i){\n\t\t\t\treturn i.getUTCDate();\n\t\t\t});\n\t\t\tthis.updateRanges();\n\t\t},\n\t\tupdateRanges: function(){\n\t\t\tvar range = $.map(this.dates, function(d){\n\t\t\t\treturn d.valueOf();\n\t\t\t});\n\t\t\t$.each(this.pickers, function(i, p){\n\t\t\t\tp.setRange(range);\n\t\t\t});\n\t\t},\n\t\tclearDates: function(){\n\t\t\t$.each(this.pickers, function(i, p){\n\t\t\t\tp.clearDates();\n\t\t\t});\n\t\t},\n\t\tdateUpdated: function(e){\n\t\t\t// `this.updating` is a workaround for preventing infinite recursion\n\t\t\t// between `changeDate` triggering and `setUTCDate` calling. Until\n\t\t\t// there is a better mechanism.\n\t\t\tif (this.updating)\n\t\t\t\treturn;\n\t\t\tthis.updating = true;\n\n\t\t\tvar dp = $.data(e.target, 'datepicker');\n\n\t\t\tif (dp === undefined) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tvar new_date = dp.getUTCDate(),\n\t\t\t\tkeep_empty_values = this.keepEmptyValues,\n\t\t\t\ti = $.inArray(e.target, this.inputs),\n\t\t\t\tj = i - 1,\n\t\t\t\tk = i + 1,\n\t\t\t\tl = this.inputs.length;\n\t\t\tif (i === -1)\n\t\t\t\treturn;\n\n\t\t\t$.each(this.pickers, function(i, p){\n\t\t\t\tif (!p.getUTCDate() && (p === dp || !keep_empty_values))\n\t\t\t\t\tp.setUTCDate(new_date);\n\t\t\t});\n\n\t\t\tif (new_date < this.dates[j]){\n\t\t\t\t// Date being moved earlier/left\n\t\t\t\twhile (j >= 0 && new_date < this.dates[j] && (this.pickers[j].element.val() || \"\").length > 0) {\n\t\t\t\t\tthis.pickers[j--].setUTCDate(new_date);\n\t\t\t\t}\n\t\t\t} else if (new_date > this.dates[k]){\n\t\t\t\t// Date being moved later/right\n\t\t\t\twhile (k < l && new_date > this.dates[k] && (this.pickers[k].element.val() || \"\").length > 0) {\n\t\t\t\t\tthis.pickers[k++].setUTCDate(new_date);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.updateDates();\n\n\t\t\tdelete this.updating;\n\t\t},\n\t\tdestroy: function(){\n\t\t\t$.map(this.pickers, function(p){ p.destroy(); });\n\t\t\t$(this.inputs).off('changeDate', this.dateUpdated);\n\t\t\tdelete this.element.data().datepicker;\n\t\t},\n\t\tremove: alias('destroy', 'Method `remove` is deprecated and will be removed in version 2.0. Use `destroy` instead')\n\t};\n\n\tfunction opts_from_el(el, prefix){\n\t\t// Derive options from element data-attrs\n\t\tvar data = $(el).data(),\n\t\t\tout = {}, inkey,\n\t\t\treplace = new RegExp('^' + prefix.toLowerCase() + '([A-Z])');\n\t\tprefix = new RegExp('^' + prefix.toLowerCase());\n\t\tfunction re_lower(_,a){\n\t\t\treturn a.toLowerCase();\n\t\t}\n\t\tfor (var key in data)\n\t\t\tif (prefix.test(key)){\n\t\t\t\tinkey = key.replace(replace, re_lower);\n\t\t\t\tout[inkey] = data[key];\n\t\t\t}\n\t\treturn out;\n\t}\n\n\tfunction opts_from_locale(lang){\n\t\t// Derive options from locale plugins\n\t\tvar out = {};\n\t\t// Check if \"de-DE\" style date is available, if not language should\n\t\t// fallback to 2 letter code eg \"de\"\n\t\tif (!dates[lang]){\n\t\t\tlang = lang.split('-')[0];\n\t\t\tif (!dates[lang])\n\t\t\t\treturn;\n\t\t}\n\t\tvar d = dates[lang];\n\t\t$.each(locale_opts, function(i,k){\n\t\t\tif (k in d)\n\t\t\t\tout[k] = d[k];\n\t\t});\n\t\treturn out;\n\t}\n\n\tvar old = $.fn.datepicker;\n\tvar datepickerPlugin = function(option){\n\t\tvar args = Array.apply(null, arguments);\n\t\targs.shift();\n\t\tvar internal_return;\n\t\tthis.each(function(){\n\t\t\tvar $this = $(this),\n\t\t\t\tdata = $this.data('datepicker'),\n\t\t\t\toptions = typeof option === 'object' && option;\n\t\t\tif (!data){\n\t\t\t\tvar elopts = opts_from_el(this, 'date'),\n\t\t\t\t\t// Preliminary otions\n\t\t\t\t\txopts = $.extend({}, defaults, elopts, options),\n\t\t\t\t\tlocopts = opts_from_locale(xopts.language),\n\t\t\t\t\t// Options priority: js args, data-attrs, locales, defaults\n\t\t\t\t\topts = $.extend({}, defaults, locopts, elopts, options);\n\t\t\t\tif ($this.hasClass('input-daterange') || opts.inputs){\n\t\t\t\t\t$.extend(opts, {\n\t\t\t\t\t\tinputs: opts.inputs || $this.find('input').toArray()\n\t\t\t\t\t});\n\t\t\t\t\tdata = new DateRangePicker(this, opts);\n\t\t\t\t}\n\t\t\t\telse {\n\t\t\t\t\tdata = new Datepicker(this, opts);\n\t\t\t\t}\n\t\t\t\t$this.data('datepicker', data);\n\t\t\t}\n\t\t\tif (typeof option === 'string' && typeof data[option] === 'function'){\n\t\t\t\tinternal_return = data[option].apply(data, args);\n\t\t\t}\n\t\t});\n\n\t\tif (\n\t\t\tinternal_return === undefined ||\n\t\t\tinternal_return instanceof Datepicker ||\n\t\t\tinternal_return instanceof DateRangePicker\n\t\t)\n\t\t\treturn this;\n\n\t\tif (this.length > 1)\n\t\t\tthrow new Error('Using only allowed for the collection of a single element (' + option + ' function)');\n\t\telse\n\t\t\treturn internal_return;\n\t};\n\t$.fn.datepicker = datepickerPlugin;\n\n\tvar defaults = $.fn.datepicker.defaults = {\n\t\tassumeNearbyYear: false,\n\t\tautoclose: false,\n\t\tbeforeShowDay: $.noop,\n\t\tbeforeShowMonth: $.noop,\n\t\tbeforeShowYear: $.noop,\n\t\tbeforeShowDecade: $.noop,\n\t\tbeforeShowCentury: $.noop,\n\t\tcalendarWeeks: false,\n\t\tclearBtn: false,\n\t\ttoggleActive: false,\n\t\tdaysOfWeekDisabled: [],\n\t\tdaysOfWeekHighlighted: [],\n\t\tdatesDisabled: [],\n\t\tendDate: Infinity,\n\t\tforceParse: true,\n\t\tformat: 'mm/dd/yyyy',\n\t\tisInline: null,\n\t\tkeepEmptyValues: false,\n\t\tkeyboardNavigation: true,\n\t\tlanguage: 'en',\n\t\tminViewMode: 0,\n\t\tmaxViewMode: 4,\n\t\tmultidate: false,\n\t\tmultidateSeparator: ',',\n\t\torientation: \"auto\",\n\t\trtl: false,\n\t\tstartDate: -Infinity,\n\t\tstartView: 0,\n\t\ttodayBtn: false,\n\t\ttodayHighlight: false,\n\t\tupdateViewDate: true,\n\t\tweekStart: 0,\n\t\tdisableTouchKeyboard: false,\n\t\tenableOnReadonly: true,\n\t\tshowOnFocus: true,\n\t\tzIndexOffset: 10,\n\t\tcontainer: 'body',\n\t\timmediateUpdates: false,\n\t\ttitle: '',\n\t\ttemplates: {\n\t\t\tleftArrow: '«',\n\t\t\trightArrow: '»'\n\t\t},\n showWeekDays: true\n\t};\n\tvar locale_opts = $.fn.datepicker.locale_opts = [\n\t\t'format',\n\t\t'rtl',\n\t\t'weekStart'\n\t];\n\t$.fn.datepicker.Constructor = Datepicker;\n\tvar dates = $.fn.datepicker.dates = {\n\t\ten: {\n\t\t\tdays: [\"Sunday\", \"Monday\", \"Tuesday\", \"Wednesday\", \"Thursday\", \"Friday\", \"Saturday\"],\n\t\t\tdaysShort: [\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"],\n\t\t\tdaysMin: [\"Su\", \"Mo\", \"Tu\", \"We\", \"Th\", \"Fr\", \"Sa\"],\n\t\t\tmonths: [\"January\", \"February\", \"March\", \"April\", \"May\", \"June\", \"July\", \"August\", \"September\", \"October\", \"November\", \"December\"],\n\t\t\tmonthsShort: [\"Jan\", \"Feb\", \"Mar\", \"Apr\", \"May\", \"Jun\", \"Jul\", \"Aug\", \"Sep\", \"Oct\", \"Nov\", \"Dec\"],\n\t\t\ttoday: \"Today\",\n\t\t\tclear: \"Clear\",\n\t\t\ttitleFormat: \"MM yyyy\"\n\t\t}\n\t};\n\n\tvar DPGlobal = {\n\t\tviewModes: [\n\t\t\t{\n\t\t\t\tnames: ['days', 'month'],\n\t\t\t\tclsName: 'days',\n\t\t\t\te: 'changeMonth'\n\t\t\t},\n\t\t\t{\n\t\t\t\tnames: ['months', 'year'],\n\t\t\t\tclsName: 'months',\n\t\t\t\te: 'changeYear',\n\t\t\t\tnavStep: 1\n\t\t\t},\n\t\t\t{\n\t\t\t\tnames: ['years', 'decade'],\n\t\t\t\tclsName: 'years',\n\t\t\t\te: 'changeDecade',\n\t\t\t\tnavStep: 10\n\t\t\t},\n\t\t\t{\n\t\t\t\tnames: ['decades', 'century'],\n\t\t\t\tclsName: 'decades',\n\t\t\t\te: 'changeCentury',\n\t\t\t\tnavStep: 100\n\t\t\t},\n\t\t\t{\n\t\t\t\tnames: ['centuries', 'millennium'],\n\t\t\t\tclsName: 'centuries',\n\t\t\t\te: 'changeMillennium',\n\t\t\t\tnavStep: 1000\n\t\t\t}\n\t\t],\n\t\tvalidParts: /dd?|DD?|mm?|MM?|yy(?:yy)?/g,\n\t\tnonpunctuation: /[^ -\\/:-@\\u5e74\\u6708\\u65e5\\[-`{-~\\t\\n\\r]+/g,\n\t\tparseFormat: function(format){\n\t\t\tif (typeof format.toValue === 'function' && typeof format.toDisplay === 'function')\n return format;\n // IE treats \\0 as a string end in inputs (truncating the value),\n\t\t\t// so it's a bad format delimiter, anyway\n\t\t\tvar separators = format.replace(this.validParts, '\\0').split('\\0'),\n\t\t\t\tparts = format.match(this.validParts);\n\t\t\tif (!separators || !separators.length || !parts || parts.length === 0){\n\t\t\t\tthrow new Error(\"Invalid date format.\");\n\t\t\t}\n\t\t\treturn {separators: separators, parts: parts};\n\t\t},\n\t\tparseDate: function(date, format, language, assumeNearby){\n\t\t\tif (!date)\n\t\t\t\treturn undefined;\n\t\t\tif (date instanceof Date)\n\t\t\t\treturn date;\n\t\t\tif (typeof format === 'string')\n\t\t\t\tformat = DPGlobal.parseFormat(format);\n\t\t\tif (format.toValue)\n\t\t\t\treturn format.toValue(date, format, language);\n\t\t\tvar fn_map = {\n\t\t\t\t\td: 'moveDay',\n\t\t\t\t\tm: 'moveMonth',\n\t\t\t\t\tw: 'moveWeek',\n\t\t\t\t\ty: 'moveYear'\n\t\t\t\t},\n\t\t\t\tdateAliases = {\n\t\t\t\t\tyesterday: '-1d',\n\t\t\t\t\ttoday: '+0d',\n\t\t\t\t\ttomorrow: '+1d'\n\t\t\t\t},\n\t\t\t\tparts, part, dir, i, fn;\n\t\t\tif (date in dateAliases){\n\t\t\t\tdate = dateAliases[date];\n\t\t\t}\n\t\t\tif (/^[\\-+]\\d+[dmwy]([\\s,]+[\\-+]\\d+[dmwy])*$/i.test(date)){\n\t\t\t\tparts = date.match(/([\\-+]\\d+)([dmwy])/gi);\n\t\t\t\tdate = new Date();\n\t\t\t\tfor (i=0; i < parts.length; i++){\n\t\t\t\t\tpart = parts[i].match(/([\\-+]\\d+)([dmwy])/i);\n\t\t\t\t\tdir = Number(part[1]);\n\t\t\t\t\tfn = fn_map[part[2].toLowerCase()];\n\t\t\t\t\tdate = Datepicker.prototype[fn](date, dir);\n\t\t\t\t}\n\t\t\t\treturn Datepicker.prototype._zero_utc_time(date);\n\t\t\t}\n\n\t\t\tparts = date && date.match(this.nonpunctuation) || [];\n\n\t\t\tfunction applyNearbyYear(year, threshold){\n\t\t\t\tif (threshold === true)\n\t\t\t\t\tthreshold = 10;\n\n\t\t\t\t// if year is 2 digits or less, than the user most likely is trying to get a recent century\n\t\t\t\tif (year < 100){\n\t\t\t\t\tyear += 2000;\n\t\t\t\t\t// if the new year is more than threshold years in advance, use last century\n\t\t\t\t\tif (year > ((new Date()).getFullYear()+threshold)){\n\t\t\t\t\t\tyear -= 100;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn year;\n\t\t\t}\n\n\t\t\tvar parsed = {},\n\t\t\t\tsetters_order = ['yyyy', 'yy', 'M', 'MM', 'm', 'mm', 'd', 'dd'],\n\t\t\t\tsetters_map = {\n\t\t\t\t\tyyyy: function(d,v){\n\t\t\t\t\t\treturn d.setUTCFullYear(assumeNearby ? applyNearbyYear(v, assumeNearby) : v);\n\t\t\t\t\t},\n\t\t\t\t\tm: function(d,v){\n\t\t\t\t\t\tif (isNaN(d))\n\t\t\t\t\t\t\treturn d;\n\t\t\t\t\t\tv -= 1;\n\t\t\t\t\t\twhile (v < 0) v += 12;\n\t\t\t\t\t\tv %= 12;\n\t\t\t\t\t\td.setUTCMonth(v);\n\t\t\t\t\t\twhile (d.getUTCMonth() !== v)\n\t\t\t\t\t\t\td.setUTCDate(d.getUTCDate()-1);\n\t\t\t\t\t\treturn d;\n\t\t\t\t\t},\n\t\t\t\t\td: function(d,v){\n\t\t\t\t\t\treturn d.setUTCDate(v);\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t\tval, filtered;\n\t\t\tsetters_map['yy'] = setters_map['yyyy'];\n\t\t\tsetters_map['M'] = setters_map['MM'] = setters_map['mm'] = setters_map['m'];\n\t\t\tsetters_map['dd'] = setters_map['d'];\n\t\t\tdate = UTCToday();\n\t\t\tvar fparts = format.parts.slice();\n\t\t\t// Remove noop parts\n\t\t\tif (parts.length !== fparts.length){\n\t\t\t\tfparts = $(fparts).filter(function(i,p){\n\t\t\t\t\treturn $.inArray(p, setters_order) !== -1;\n\t\t\t\t}).toArray();\n\t\t\t}\n\t\t\t// Process remainder\n\t\t\tfunction match_part(){\n\t\t\t\tvar m = this.slice(0, parts[i].length),\n\t\t\t\t\tp = parts[i].slice(0, m.length);\n\t\t\t\treturn m.toLowerCase() === p.toLowerCase();\n\t\t\t}\n\t\t\tif (parts.length === fparts.length){\n\t\t\t\tvar cnt;\n\t\t\t\tfor (i=0, cnt = fparts.length; i < cnt; i++){\n\t\t\t\t\tval = parseInt(parts[i], 10);\n\t\t\t\t\tpart = fparts[i];\n\t\t\t\t\tif (isNaN(val)){\n\t\t\t\t\t\tswitch (part){\n\t\t\t\t\t\t\tcase 'MM':\n\t\t\t\t\t\t\t\tfiltered = $(dates[language].months).filter(match_part);\n\t\t\t\t\t\t\t\tval = $.inArray(filtered[0], dates[language].months) + 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\tcase 'M':\n\t\t\t\t\t\t\t\tfiltered = $(dates[language].monthsShort).filter(match_part);\n\t\t\t\t\t\t\t\tval = $.inArray(filtered[0], dates[language].monthsShort) + 1;\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tparsed[part] = val;\n\t\t\t\t}\n\t\t\t\tvar _date, s;\n\t\t\t\tfor (i=0; i < setters_order.length; i++){\n\t\t\t\t\ts = setters_order[i];\n\t\t\t\t\tif (s in parsed && !isNaN(parsed[s])){\n\t\t\t\t\t\t_date = new Date(date);\n\t\t\t\t\t\tsetters_map[s](_date, parsed[s]);\n\t\t\t\t\t\tif (!isNaN(_date))\n\t\t\t\t\t\t\tdate = _date;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn date;\n\t\t},\n\t\tformatDate: function(date, format, language){\n\t\t\tif (!date)\n\t\t\t\treturn '';\n\t\t\tif (typeof format === 'string')\n\t\t\t\tformat = DPGlobal.parseFormat(format);\n\t\t\tif (format.toDisplay)\n return format.toDisplay(date, format, language);\n var val = {\n\t\t\t\td: date.getUTCDate(),\n\t\t\t\tD: dates[language].daysShort[date.getUTCDay()],\n\t\t\t\tDD: dates[language].days[date.getUTCDay()],\n\t\t\t\tm: date.getUTCMonth() + 1,\n\t\t\t\tM: dates[language].monthsShort[date.getUTCMonth()],\n\t\t\t\tMM: dates[language].months[date.getUTCMonth()],\n\t\t\t\tyy: date.getUTCFullYear().toString().substring(2),\n\t\t\t\tyyyy: date.getUTCFullYear()\n\t\t\t};\n\t\t\tval.dd = (val.d < 10 ? '0' : '') + val.d;\n\t\t\tval.mm = (val.m < 10 ? '0' : '') + val.m;\n\t\t\tdate = [];\n\t\t\tvar seps = $.extend([], format.separators);\n\t\t\tfor (var i=0, cnt = format.parts.length; i <= cnt; i++){\n\t\t\t\tif (seps.length)\n\t\t\t\t\tdate.push(seps.shift());\n\t\t\t\tdate.push(val[format.parts[i]]);\n\t\t\t}\n\t\t\treturn date.join('');\n\t\t},\n\t\theadTemplate: ''+\n\t\t\t ''+\n\t\t\t ''+\n\t\t\t ''+\n\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t''+defaults.templates.leftArrow+''+\n\t\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t''+defaults.templates.rightArrow+''+\n\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t'',\n\t\tcontTemplate: '',\n\t\tfootTemplate: ''+\n\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t''\n\t};\n\tDPGlobal.template = '
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t\tDPGlobal.headTemplate+\n\t\t\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t\tDPGlobal.footTemplate+\n\t\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t\tDPGlobal.headTemplate+\n\t\t\t\t\t\t\t\t\tDPGlobal.contTemplate+\n\t\t\t\t\t\t\t\t\tDPGlobal.footTemplate+\n\t\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t\tDPGlobal.headTemplate+\n\t\t\t\t\t\t\t\t\tDPGlobal.contTemplate+\n\t\t\t\t\t\t\t\t\tDPGlobal.footTemplate+\n\t\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t\tDPGlobal.headTemplate+\n\t\t\t\t\t\t\t\t\tDPGlobal.contTemplate+\n\t\t\t\t\t\t\t\t\tDPGlobal.footTemplate+\n\t\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t\t''+\n\t\t\t\t\t\t\t\t\tDPGlobal.headTemplate+\n\t\t\t\t\t\t\t\t\tDPGlobal.contTemplate+\n\t\t\t\t\t\t\t\t\tDPGlobal.footTemplate+\n\t\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t\t'
      '+\n\t\t\t\t\t\t'
      ';\n\n\t$.fn.datepicker.DPGlobal = DPGlobal;\n\n\n\t/* DATEPICKER NO CONFLICT\n\t* =================== */\n\n\t$.fn.datepicker.noConflict = function(){\n\t\t$.fn.datepicker = old;\n\t\treturn this;\n\t};\n\n\t/* DATEPICKER VERSION\n\t * =================== */\n\t$.fn.datepicker.version = '1.10.0';\n\n\t$.fn.datepicker.deprecated = function(msg){\n\t\tvar console = window.console;\n\t\tif (console && console.warn) {\n\t\t\tconsole.warn('DEPRECATED: ' + msg);\n\t\t}\n\t};\n\n\n\t/* DATEPICKER DATA-API\n\t* ================== */\n\n\t$(document).on(\n\t\t'focus.datepicker.data-api click.datepicker.data-api',\n\t\t'[data-provide=\"datepicker\"]',\n\t\tfunction(e){\n\t\t\tvar $this = $(this);\n\t\t\tif ($this.data('datepicker'))\n\t\t\t\treturn;\n\t\t\te.preventDefault();\n\t\t\t// component click requires us to explicitly show it\n\t\t\tdatepickerPlugin.call($this, 'show');\n\t\t}\n\t);\n\t$(function(){\n\t\tdatepickerPlugin.call($('[data-provide=\"datepicker-inline\"]'));\n\t});\n\n}));\n","/* */ \n\"format global\";\n\"deps jquery\";\n\"exports $\";\n/*!\n * Bootstrap v3.3.4 (http://getbootstrap.com)\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\nif (typeof jQuery === 'undefined') {\n throw new Error('Bootstrap\\'s JavaScript requires jQuery')\n}\n\n+function ($) {\n 'use strict';\n var version = $.fn.jquery.split(' ')[0].split('.')\n if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1)) {\n throw new Error('Bootstrap\\'s JavaScript requires jQuery version 1.9.1 or higher')\n }\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: transition.js v3.3.4\n * http://getbootstrap.com/javascript/#transitions\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // CSS TRANSITION SUPPORT (Shoutout: http://www.modernizr.com/)\n // ============================================================\n\n function transitionEnd() {\n var el = document.createElement('bootstrap')\n\n var transEndEventNames = {\n WebkitTransition : 'webkitTransitionEnd',\n MozTransition : 'transitionend',\n OTransition : 'oTransitionEnd otransitionend',\n transition : 'transitionend'\n }\n\n for (var name in transEndEventNames) {\n if (el.style[name] !== undefined) {\n return { end: transEndEventNames[name] }\n }\n }\n\n return false // explicit for ie8 ( ._.)\n }\n\n // http://blog.alexmaccaw.com/css-transitions\n $.fn.emulateTransitionEnd = function (duration) {\n var called = false\n var $el = this\n $(this).one('bsTransitionEnd', function () { called = true })\n var callback = function () { if (!called) $($el).trigger($.support.transition.end) }\n setTimeout(callback, duration)\n return this\n }\n\n $(function () {\n $.support.transition = transitionEnd()\n\n if (!$.support.transition) return\n\n $.event.special.bsTransitionEnd = {\n bindType: $.support.transition.end,\n delegateType: $.support.transition.end,\n handle: function (e) {\n if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)\n }\n }\n })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: alert.js v3.3.4\n * http://getbootstrap.com/javascript/#alerts\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // ALERT CLASS DEFINITION\n // ======================\n\n var dismiss = '[data-dismiss=\"alert\"]'\n var Alert = function (el) {\n $(el).on('click', dismiss, this.close)\n }\n\n Alert.VERSION = '3.3.4'\n\n Alert.TRANSITION_DURATION = 150\n\n Alert.prototype.close = function (e) {\n var $this = $(this)\n var selector = $this.attr('data-target')\n\n if (!selector) {\n selector = $this.attr('href')\n selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n }\n\n var $parent = $(selector)\n\n if (e) e.preventDefault()\n\n if (!$parent.length) {\n $parent = $this.closest('.alert')\n }\n\n $parent.trigger(e = $.Event('close.bs.alert'))\n\n if (e.isDefaultPrevented()) return\n\n $parent.removeClass('in')\n\n function removeElement() {\n // detach from parent, fire event then clean up data\n $parent.detach().trigger('closed.bs.alert').remove()\n }\n\n $.support.transition && $parent.hasClass('fade') ?\n $parent\n .one('bsTransitionEnd', removeElement)\n .emulateTransitionEnd(Alert.TRANSITION_DURATION) :\n removeElement()\n }\n\n\n // ALERT PLUGIN DEFINITION\n // =======================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.alert')\n\n if (!data) $this.data('bs.alert', (data = new Alert(this)))\n if (typeof option == 'string') data[option].call($this)\n })\n }\n\n var old = $.fn.alert\n\n $.fn.alert = Plugin\n $.fn.alert.Constructor = Alert\n\n\n // ALERT NO CONFLICT\n // =================\n\n $.fn.alert.noConflict = function () {\n $.fn.alert = old\n return this\n }\n\n\n // ALERT DATA-API\n // ==============\n\n $(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: button.js v3.3.4\n * http://getbootstrap.com/javascript/#buttons\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // BUTTON PUBLIC CLASS DEFINITION\n // ==============================\n\n var Button = function (element, options) {\n this.$element = $(element)\n this.options = $.extend({}, Button.DEFAULTS, options)\n this.isLoading = false\n }\n\n Button.VERSION = '3.3.4'\n\n Button.DEFAULTS = {\n loadingText: 'loading...'\n }\n\n Button.prototype.setState = function (state) {\n var d = 'disabled'\n var $el = this.$element\n var val = $el.is('input') ? 'val' : 'html'\n var data = $el.data()\n\n state = state + 'Text'\n\n if (data.resetText == null) $el.data('resetText', $el[val]())\n\n // push to event loop to allow forms to submit\n setTimeout($.proxy(function () {\n $el[val](data[state] == null ? this.options[state] : data[state])\n\n if (state == 'loadingText') {\n this.isLoading = true\n $el.addClass(d).attr(d, d)\n } else if (this.isLoading) {\n this.isLoading = false\n $el.removeClass(d).removeAttr(d)\n }\n }, this), 0)\n }\n\n Button.prototype.toggle = function () {\n var changed = true\n var $parent = this.$element.closest('[data-toggle=\"buttons\"]')\n\n if ($parent.length) {\n var $input = this.$element.find('input')\n if ($input.prop('type') == 'radio') {\n if ($input.prop('checked') && this.$element.hasClass('active')) changed = false\n else $parent.find('.active').removeClass('active')\n }\n if (changed) $input.prop('checked', !this.$element.hasClass('active')).trigger('change')\n } else {\n this.$element.attr('aria-pressed', !this.$element.hasClass('active'))\n }\n\n if (changed) this.$element.toggleClass('active')\n }\n\n\n // BUTTON PLUGIN DEFINITION\n // ========================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.button')\n var options = typeof option == 'object' && option\n\n if (!data) $this.data('bs.button', (data = new Button(this, options)))\n\n if (option == 'toggle') data.toggle()\n else if (option) data.setState(option)\n })\n }\n\n var old = $.fn.button\n\n $.fn.button = Plugin\n $.fn.button.Constructor = Button\n\n\n // BUTTON NO CONFLICT\n // ==================\n\n $.fn.button.noConflict = function () {\n $.fn.button = old\n return this\n }\n\n\n // BUTTON DATA-API\n // ===============\n\n $(document)\n .on('click.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n var $btn = $(e.target)\n if (!$btn.hasClass('btn')) $btn = $btn.closest('.btn')\n Plugin.call($btn, 'toggle')\n e.preventDefault()\n })\n .on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^=\"button\"]', function (e) {\n $(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))\n })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: carousel.js v3.3.4\n * http://getbootstrap.com/javascript/#carousel\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // CAROUSEL CLASS DEFINITION\n // =========================\n\n var Carousel = function (element, options) {\n this.$element = $(element)\n this.$indicators = this.$element.find('.carousel-indicators')\n this.options = options\n this.paused = null\n this.sliding = null\n this.interval = null\n this.$active = null\n this.$items = null\n\n this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))\n\n this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element\n .on('mouseenter.bs.carousel', $.proxy(this.pause, this))\n .on('mouseleave.bs.carousel', $.proxy(this.cycle, this))\n }\n\n Carousel.VERSION = '3.3.4'\n\n Carousel.TRANSITION_DURATION = 600\n\n Carousel.DEFAULTS = {\n interval: 5000,\n pause: 'hover',\n wrap: true,\n keyboard: true\n }\n\n Carousel.prototype.keydown = function (e) {\n if (/input|textarea/i.test(e.target.tagName)) return\n switch (e.which) {\n case 37: this.prev(); break\n case 39: this.next(); break\n default: return\n }\n\n e.preventDefault()\n }\n\n Carousel.prototype.cycle = function (e) {\n e || (this.paused = false)\n\n this.interval && clearInterval(this.interval)\n\n this.options.interval\n && !this.paused\n && (this.interval = setInterval($.proxy(this.next, this), this.options.interval))\n\n return this\n }\n\n Carousel.prototype.getItemIndex = function (item) {\n this.$items = item.parent().children('.item')\n return this.$items.index(item || this.$active)\n }\n\n Carousel.prototype.getItemForDirection = function (direction, active) {\n var activeIndex = this.getItemIndex(active)\n var willWrap = (direction == 'prev' && activeIndex === 0)\n || (direction == 'next' && activeIndex == (this.$items.length - 1))\n if (willWrap && !this.options.wrap) return active\n var delta = direction == 'prev' ? -1 : 1\n var itemIndex = (activeIndex + delta) % this.$items.length\n return this.$items.eq(itemIndex)\n }\n\n Carousel.prototype.to = function (pos) {\n var that = this\n var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))\n\n if (pos > (this.$items.length - 1) || pos < 0) return\n\n if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, \"slid\"\n if (activeIndex == pos) return this.pause().cycle()\n\n return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))\n }\n\n Carousel.prototype.pause = function (e) {\n e || (this.paused = true)\n\n if (this.$element.find('.next, .prev').length && $.support.transition) {\n this.$element.trigger($.support.transition.end)\n this.cycle(true)\n }\n\n this.interval = clearInterval(this.interval)\n\n return this\n }\n\n Carousel.prototype.next = function () {\n if (this.sliding) return\n return this.slide('next')\n }\n\n Carousel.prototype.prev = function () {\n if (this.sliding) return\n return this.slide('prev')\n }\n\n Carousel.prototype.slide = function (type, next) {\n var $active = this.$element.find('.item.active')\n var $next = next || this.getItemForDirection(type, $active)\n var isCycling = this.interval\n var direction = type == 'next' ? 'left' : 'right'\n var that = this\n\n if ($next.hasClass('active')) return (this.sliding = false)\n\n var relatedTarget = $next[0]\n var slideEvent = $.Event('slide.bs.carousel', {\n relatedTarget: relatedTarget,\n direction: direction\n })\n this.$element.trigger(slideEvent)\n if (slideEvent.isDefaultPrevented()) return\n\n this.sliding = true\n\n isCycling && this.pause()\n\n if (this.$indicators.length) {\n this.$indicators.find('.active').removeClass('active')\n var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])\n $nextIndicator && $nextIndicator.addClass('active')\n }\n\n var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, \"slid\"\n if ($.support.transition && this.$element.hasClass('slide')) {\n $next.addClass(type)\n $next[0].offsetWidth // force reflow\n $active.addClass(direction)\n $next.addClass(direction)\n $active\n .one('bsTransitionEnd', function () {\n $next.removeClass([type, direction].join(' ')).addClass('active')\n $active.removeClass(['active', direction].join(' '))\n that.sliding = false\n setTimeout(function () {\n that.$element.trigger(slidEvent)\n }, 0)\n })\n .emulateTransitionEnd(Carousel.TRANSITION_DURATION)\n } else {\n $active.removeClass('active')\n $next.addClass('active')\n this.sliding = false\n this.$element.trigger(slidEvent)\n }\n\n isCycling && this.cycle()\n\n return this\n }\n\n\n // CAROUSEL PLUGIN DEFINITION\n // ==========================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.carousel')\n var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)\n var action = typeof option == 'string' ? option : options.slide\n\n if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))\n if (typeof option == 'number') data.to(option)\n else if (action) data[action]()\n else if (options.interval) data.pause().cycle()\n })\n }\n\n var old = $.fn.carousel\n\n $.fn.carousel = Plugin\n $.fn.carousel.Constructor = Carousel\n\n\n // CAROUSEL NO CONFLICT\n // ====================\n\n $.fn.carousel.noConflict = function () {\n $.fn.carousel = old\n return this\n }\n\n\n // CAROUSEL DATA-API\n // =================\n\n var clickHandler = function (e) {\n var href\n var $this = $(this)\n var $target = $($this.attr('data-target') || (href = $this.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '')) // strip for ie7\n if (!$target.hasClass('carousel')) return\n var options = $.extend({}, $target.data(), $this.data())\n var slideIndex = $this.attr('data-slide-to')\n if (slideIndex) options.interval = false\n\n Plugin.call($target, options)\n\n if (slideIndex) {\n $target.data('bs.carousel').to(slideIndex)\n }\n\n e.preventDefault()\n }\n\n $(document)\n .on('click.bs.carousel.data-api', '[data-slide]', clickHandler)\n .on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)\n\n $(window).on('load', function () {\n $('[data-ride=\"carousel\"]').each(function () {\n var $carousel = $(this)\n Plugin.call($carousel, $carousel.data())\n })\n })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: collapse.js v3.3.4\n * http://getbootstrap.com/javascript/#collapse\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // COLLAPSE PUBLIC CLASS DEFINITION\n // ================================\n\n var Collapse = function (element, options) {\n this.$element = $(element)\n this.options = $.extend({}, Collapse.DEFAULTS, options)\n this.$trigger = $('[data-toggle=\"collapse\"][href=\"#' + element.id + '\"],' +\n '[data-toggle=\"collapse\"][data-target=\"#' + element.id + '\"]')\n this.transitioning = null\n\n if (this.options.parent) {\n this.$parent = this.getParent()\n } else {\n this.addAriaAndCollapsedClass(this.$element, this.$trigger)\n }\n\n if (this.options.toggle) this.toggle()\n }\n\n Collapse.VERSION = '3.3.4'\n\n Collapse.TRANSITION_DURATION = 350\n\n Collapse.DEFAULTS = {\n toggle: true\n }\n\n Collapse.prototype.dimension = function () {\n var hasWidth = this.$element.hasClass('width')\n return hasWidth ? 'width' : 'height'\n }\n\n Collapse.prototype.show = function () {\n if (this.transitioning || this.$element.hasClass('in')) return\n\n var activesData\n var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')\n\n if (actives && actives.length) {\n activesData = actives.data('bs.collapse')\n if (activesData && activesData.transitioning) return\n }\n\n var startEvent = $.Event('show.bs.collapse')\n this.$element.trigger(startEvent)\n if (startEvent.isDefaultPrevented()) return\n\n if (actives && actives.length) {\n Plugin.call(actives, 'hide')\n activesData || actives.data('bs.collapse', null)\n }\n\n var dimension = this.dimension()\n\n this.$element\n .removeClass('collapse')\n .addClass('collapsing')[dimension](0)\n .attr('aria-expanded', true)\n\n this.$trigger\n .removeClass('collapsed')\n .attr('aria-expanded', true)\n\n this.transitioning = 1\n\n var complete = function () {\n this.$element\n .removeClass('collapsing')\n .addClass('collapse in')[dimension]('')\n this.transitioning = 0\n this.$element\n .trigger('shown.bs.collapse')\n }\n\n if (!$.support.transition) return complete.call(this)\n\n var scrollSize = $.camelCase(['scroll', dimension].join('-'))\n\n this.$element\n .one('bsTransitionEnd', $.proxy(complete, this))\n .emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])\n }\n\n Collapse.prototype.hide = function () {\n if (this.transitioning || !this.$element.hasClass('in')) return\n\n var startEvent = $.Event('hide.bs.collapse')\n this.$element.trigger(startEvent)\n if (startEvent.isDefaultPrevented()) return\n\n var dimension = this.dimension()\n\n this.$element[dimension](this.$element[dimension]())[0].offsetHeight\n\n this.$element\n .addClass('collapsing')\n .removeClass('collapse in')\n .attr('aria-expanded', false)\n\n this.$trigger\n .addClass('collapsed')\n .attr('aria-expanded', false)\n\n this.transitioning = 1\n\n var complete = function () {\n this.transitioning = 0\n this.$element\n .removeClass('collapsing')\n .addClass('collapse')\n .trigger('hidden.bs.collapse')\n }\n\n if (!$.support.transition) return complete.call(this)\n\n this.$element\n [dimension](0)\n .one('bsTransitionEnd', $.proxy(complete, this))\n .emulateTransitionEnd(Collapse.TRANSITION_DURATION)\n }\n\n Collapse.prototype.toggle = function () {\n this[this.$element.hasClass('in') ? 'hide' : 'show']()\n }\n\n Collapse.prototype.getParent = function () {\n return $(this.options.parent)\n .find('[data-toggle=\"collapse\"][data-parent=\"' + this.options.parent + '\"]')\n .each($.proxy(function (i, element) {\n var $element = $(element)\n this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)\n }, this))\n .end()\n }\n\n Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {\n var isOpen = $element.hasClass('in')\n\n $element.attr('aria-expanded', isOpen)\n $trigger\n .toggleClass('collapsed', !isOpen)\n .attr('aria-expanded', isOpen)\n }\n\n function getTargetFromTrigger($trigger) {\n var href\n var target = $trigger.attr('data-target')\n || (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\\s]+$)/, '') // strip for ie7\n\n return $(target)\n }\n\n\n // COLLAPSE PLUGIN DEFINITION\n // ==========================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.collapse')\n var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false\n if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))\n if (typeof option == 'string') data[option]()\n })\n }\n\n var old = $.fn.collapse\n\n $.fn.collapse = Plugin\n $.fn.collapse.Constructor = Collapse\n\n\n // COLLAPSE NO CONFLICT\n // ====================\n\n $.fn.collapse.noConflict = function () {\n $.fn.collapse = old\n return this\n }\n\n\n // COLLAPSE DATA-API\n // =================\n\n $(document).on('click.bs.collapse.data-api', '[data-toggle=\"collapse\"]', function (e) {\n var $this = $(this)\n\n if (!$this.attr('data-target')) e.preventDefault()\n\n var $target = getTargetFromTrigger($this)\n var data = $target.data('bs.collapse')\n var option = data ? 'toggle' : $this.data()\n\n Plugin.call($target, option)\n })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: dropdown.js v3.3.4\n * http://getbootstrap.com/javascript/#dropdowns\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // DROPDOWN CLASS DEFINITION\n // =========================\n\n var backdrop = '.dropdown-backdrop'\n var toggle = '[data-toggle=\"dropdown\"]'\n var Dropdown = function (element) {\n $(element).on('click.bs.dropdown', this.toggle)\n }\n\n Dropdown.VERSION = '3.3.4'\n\n Dropdown.prototype.toggle = function (e) {\n var $this = $(this)\n\n if ($this.is('.disabled, :disabled')) return\n\n var $parent = getParent($this)\n var isActive = $parent.hasClass('open')\n\n clearMenus()\n\n if (!isActive) {\n if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {\n // if mobile we use a backdrop because click events don't delegate\n $('
      ').insertAfter($(this)).on('click', clearMenus)\n }\n\n var relatedTarget = { relatedTarget: this }\n $parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))\n\n if (e.isDefaultPrevented()) return\n\n $this\n .trigger('focus')\n .attr('aria-expanded', 'true')\n\n $parent\n .toggleClass('open')\n .trigger('shown.bs.dropdown', relatedTarget)\n }\n\n return false\n }\n\n Dropdown.prototype.keydown = function (e) {\n if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return\n\n var $this = $(this)\n\n e.preventDefault()\n e.stopPropagation()\n\n if ($this.is('.disabled, :disabled')) return\n\n var $parent = getParent($this)\n var isActive = $parent.hasClass('open')\n\n if ((!isActive && e.which != 27) || (isActive && e.which == 27)) {\n if (e.which == 27) $parent.find(toggle).trigger('focus')\n return $this.trigger('click')\n }\n\n var desc = ' li:not(.disabled):visible a'\n var $items = $parent.find('[role=\"menu\"]' + desc + ', [role=\"listbox\"]' + desc)\n\n if (!$items.length) return\n\n var index = $items.index(e.target)\n\n if (e.which == 38 && index > 0) index-- // up\n if (e.which == 40 && index < $items.length - 1) index++ // down\n if (!~index) index = 0\n\n $items.eq(index).trigger('focus')\n }\n\n function clearMenus(e) {\n if (e && e.which === 3) return\n $(backdrop).remove()\n $(toggle).each(function () {\n var $this = $(this)\n var $parent = getParent($this)\n var relatedTarget = { relatedTarget: this }\n\n if (!$parent.hasClass('open')) return\n\n $parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))\n\n if (e.isDefaultPrevented()) return\n\n $this.attr('aria-expanded', 'false')\n $parent.removeClass('open').trigger('hidden.bs.dropdown', relatedTarget)\n })\n }\n\n function getParent($this) {\n var selector = $this.attr('data-target')\n\n if (!selector) {\n selector = $this.attr('href')\n selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n }\n\n var $parent = selector && $(selector)\n\n return $parent && $parent.length ? $parent : $this.parent()\n }\n\n\n // DROPDOWN PLUGIN DEFINITION\n // ==========================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.dropdown')\n\n if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))\n if (typeof option == 'string') data[option].call($this)\n })\n }\n\n var old = $.fn.dropdown\n\n $.fn.dropdown = Plugin\n $.fn.dropdown.Constructor = Dropdown\n\n\n // DROPDOWN NO CONFLICT\n // ====================\n\n $.fn.dropdown.noConflict = function () {\n $.fn.dropdown = old\n return this\n }\n\n\n // APPLY TO STANDARD DROPDOWN ELEMENTS\n // ===================================\n\n $(document)\n .on('click.bs.dropdown.data-api', clearMenus)\n .on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })\n .on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)\n .on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)\n .on('keydown.bs.dropdown.data-api', '[role=\"menu\"]', Dropdown.prototype.keydown)\n .on('keydown.bs.dropdown.data-api', '[role=\"listbox\"]', Dropdown.prototype.keydown)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: modal.js v3.3.4\n * http://getbootstrap.com/javascript/#modals\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // MODAL CLASS DEFINITION\n // ======================\n\n var Modal = function (element, options) {\n this.options = options\n this.$body = $(document.body)\n this.$element = $(element)\n this.$dialog = this.$element.find('.modal-dialog')\n this.$backdrop = null\n this.isShown = null\n this.originalBodyPad = null\n this.scrollbarWidth = 0\n this.ignoreBackdropClick = false\n\n if (this.options.remote) {\n this.$element\n .find('.modal-content')\n .load(this.options.remote, $.proxy(function () {\n this.$element.trigger('loaded.bs.modal')\n }, this))\n }\n }\n\n Modal.VERSION = '3.3.4'\n\n Modal.TRANSITION_DURATION = 300\n Modal.BACKDROP_TRANSITION_DURATION = 150\n\n Modal.DEFAULTS = {\n backdrop: true,\n keyboard: true,\n show: true\n }\n\n Modal.prototype.toggle = function (_relatedTarget) {\n return this.isShown ? this.hide() : this.show(_relatedTarget)\n }\n\n Modal.prototype.show = function (_relatedTarget) {\n var that = this\n var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })\n\n this.$element.trigger(e)\n\n if (this.isShown || e.isDefaultPrevented()) return\n\n this.isShown = true\n\n this.checkScrollbar()\n this.setScrollbar()\n this.$body.addClass('modal-open')\n\n this.escape()\n this.resize()\n\n this.$element.on('click.dismiss.bs.modal', '[data-dismiss=\"modal\"]', $.proxy(this.hide, this))\n\n this.$dialog.on('mousedown.dismiss.bs.modal', function () {\n that.$element.one('mouseup.dismiss.bs.modal', function (e) {\n if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true\n })\n })\n\n this.backdrop(function () {\n var transition = $.support.transition && that.$element.hasClass('fade')\n\n if (!that.$element.parent().length) {\n that.$element.appendTo(that.$body) // don't move modals dom position\n }\n\n that.$element\n .show()\n .scrollTop(0)\n\n that.adjustDialog()\n\n if (transition) {\n that.$element[0].offsetWidth // force reflow\n }\n\n that.$element\n .addClass('in')\n .attr('aria-hidden', false)\n\n that.enforceFocus()\n\n var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })\n\n transition ?\n that.$dialog // wait for modal to slide in\n .one('bsTransitionEnd', function () {\n that.$element.trigger('focus').trigger(e)\n })\n .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n that.$element.trigger('focus').trigger(e)\n })\n }\n\n Modal.prototype.hide = function (e) {\n if (e) e.preventDefault()\n\n e = $.Event('hide.bs.modal')\n\n this.$element.trigger(e)\n\n if (!this.isShown || e.isDefaultPrevented()) return\n\n this.isShown = false\n\n this.escape()\n this.resize()\n\n $(document).off('focusin.bs.modal')\n\n this.$element\n .removeClass('in')\n .attr('aria-hidden', true)\n .off('click.dismiss.bs.modal')\n .off('mouseup.dismiss.bs.modal')\n\n this.$dialog.off('mousedown.dismiss.bs.modal')\n\n $.support.transition && this.$element.hasClass('fade') ?\n this.$element\n .one('bsTransitionEnd', $.proxy(this.hideModal, this))\n .emulateTransitionEnd(Modal.TRANSITION_DURATION) :\n this.hideModal()\n }\n\n Modal.prototype.enforceFocus = function () {\n $(document)\n .off('focusin.bs.modal') // guard against infinite focus loop\n .on('focusin.bs.modal', $.proxy(function (e) {\n if (this.$element[0] !== e.target && !this.$element.has(e.target).length) {\n this.$element.trigger('focus')\n }\n }, this))\n }\n\n Modal.prototype.escape = function () {\n if (this.isShown && this.options.keyboard) {\n this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {\n e.which == 27 && this.hide()\n }, this))\n } else if (!this.isShown) {\n this.$element.off('keydown.dismiss.bs.modal')\n }\n }\n\n Modal.prototype.resize = function () {\n if (this.isShown) {\n $(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))\n } else {\n $(window).off('resize.bs.modal')\n }\n }\n\n Modal.prototype.hideModal = function () {\n var that = this\n this.$element.hide()\n this.backdrop(function () {\n that.$body.removeClass('modal-open')\n that.resetAdjustments()\n that.resetScrollbar()\n that.$element.trigger('hidden.bs.modal')\n })\n }\n\n Modal.prototype.removeBackdrop = function () {\n this.$backdrop && this.$backdrop.remove()\n this.$backdrop = null\n }\n\n Modal.prototype.backdrop = function (callback) {\n var that = this\n var animate = this.$element.hasClass('fade') ? 'fade' : ''\n\n if (this.isShown && this.options.backdrop) {\n var doAnimate = $.support.transition && animate\n\n this.$backdrop = $('
      ')\n .appendTo(this.$body)\n\n this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {\n if (this.ignoreBackdropClick) {\n this.ignoreBackdropClick = false\n return\n }\n if (e.target !== e.currentTarget) return\n this.options.backdrop == 'static'\n ? this.$element[0].focus()\n : this.hide()\n }, this))\n\n if (doAnimate) this.$backdrop[0].offsetWidth // force reflow\n\n this.$backdrop.addClass('in')\n\n if (!callback) return\n\n doAnimate ?\n this.$backdrop\n .one('bsTransitionEnd', callback)\n .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n callback()\n\n } else if (!this.isShown && this.$backdrop) {\n this.$backdrop.removeClass('in')\n\n var callbackRemove = function () {\n that.removeBackdrop()\n callback && callback()\n }\n $.support.transition && this.$element.hasClass('fade') ?\n this.$backdrop\n .one('bsTransitionEnd', callbackRemove)\n .emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :\n callbackRemove()\n\n } else if (callback) {\n callback()\n }\n }\n\n // these following methods are used to handle overflowing modals\n\n Modal.prototype.handleUpdate = function () {\n this.adjustDialog()\n }\n\n Modal.prototype.adjustDialog = function () {\n var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight\n\n this.$element.css({\n paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',\n paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''\n })\n }\n\n Modal.prototype.resetAdjustments = function () {\n this.$element.css({\n paddingLeft: '',\n paddingRight: ''\n })\n }\n\n Modal.prototype.checkScrollbar = function () {\n var fullWindowWidth = window.innerWidth\n if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8\n var documentElementRect = document.documentElement.getBoundingClientRect()\n fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)\n }\n this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth\n this.scrollbarWidth = this.measureScrollbar()\n }\n\n Modal.prototype.setScrollbar = function () {\n var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)\n this.originalBodyPad = document.body.style.paddingRight || ''\n if (this.bodyIsOverflowing) this.$body.css('padding-right', bodyPad + this.scrollbarWidth)\n }\n\n Modal.prototype.resetScrollbar = function () {\n this.$body.css('padding-right', this.originalBodyPad)\n }\n\n Modal.prototype.measureScrollbar = function () { // thx walsh\n var scrollDiv = document.createElement('div')\n scrollDiv.className = 'modal-scrollbar-measure'\n this.$body.append(scrollDiv)\n var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth\n this.$body[0].removeChild(scrollDiv)\n return scrollbarWidth\n }\n\n\n // MODAL PLUGIN DEFINITION\n // =======================\n\n function Plugin(option, _relatedTarget) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.modal')\n var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)\n\n if (!data) $this.data('bs.modal', (data = new Modal(this, options)))\n if (typeof option == 'string') data[option](_relatedTarget)\n else if (options.show) data.show(_relatedTarget)\n })\n }\n\n var old = $.fn.modal\n\n $.fn.modal = Plugin\n $.fn.modal.Constructor = Modal\n\n\n // MODAL NO CONFLICT\n // =================\n\n $.fn.modal.noConflict = function () {\n $.fn.modal = old\n return this\n }\n\n\n // MODAL DATA-API\n // ==============\n\n $(document).on('click.bs.modal.data-api', '[data-toggle=\"modal\"]', function (e) {\n var $this = $(this)\n var href = $this.attr('href')\n var $target = $($this.attr('data-target') || (href && href.replace(/.*(?=#[^\\s]+$)/, ''))) // strip for ie7\n var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())\n\n if ($this.is('a')) e.preventDefault()\n\n $target.one('show.bs.modal', function (showEvent) {\n if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown\n $target.one('hidden.bs.modal', function () {\n $this.is(':visible') && $this.trigger('focus')\n })\n })\n Plugin.call($target, option, this)\n })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tooltip.js v3.3.4\n * http://getbootstrap.com/javascript/#tooltip\n * Inspired by the original jQuery.tipsy by Jason Frame\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // TOOLTIP PUBLIC CLASS DEFINITION\n // ===============================\n\n var Tooltip = function (element, options) {\n this.type = null\n this.options = null\n this.enabled = null\n this.timeout = null\n this.hoverState = null\n this.$element = null\n\n this.init('tooltip', element, options)\n }\n\n Tooltip.VERSION = '3.3.4'\n\n Tooltip.TRANSITION_DURATION = 150\n\n Tooltip.DEFAULTS = {\n animation: true,\n placement: 'top',\n selector: false,\n template: '
      ',\n trigger: 'hover focus',\n title: '',\n delay: 0,\n html: false,\n container: false,\n viewport: {\n selector: 'body',\n padding: 0\n }\n }\n\n Tooltip.prototype.init = function (type, element, options) {\n this.enabled = true\n this.type = type\n this.$element = $(element)\n this.options = this.getOptions(options)\n this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)\n\n if (this.$element[0] instanceof document.constructor && !this.options.selector) {\n throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')\n }\n\n var triggers = this.options.trigger.split(' ')\n\n for (var i = triggers.length; i--;) {\n var trigger = triggers[i]\n\n if (trigger == 'click') {\n this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))\n } else if (trigger != 'manual') {\n var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'\n var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'\n\n this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))\n this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))\n }\n }\n\n this.options.selector ?\n (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :\n this.fixTitle()\n }\n\n Tooltip.prototype.getDefaults = function () {\n return Tooltip.DEFAULTS\n }\n\n Tooltip.prototype.getOptions = function (options) {\n options = $.extend({}, this.getDefaults(), this.$element.data(), options)\n\n if (options.delay && typeof options.delay == 'number') {\n options.delay = {\n show: options.delay,\n hide: options.delay\n }\n }\n\n return options\n }\n\n Tooltip.prototype.getDelegateOptions = function () {\n var options = {}\n var defaults = this.getDefaults()\n\n this._options && $.each(this._options, function (key, value) {\n if (defaults[key] != value) options[key] = value\n })\n\n return options\n }\n\n Tooltip.prototype.enter = function (obj) {\n var self = obj instanceof this.constructor ?\n obj : $(obj.currentTarget).data('bs.' + this.type)\n\n if (self && self.$tip && self.$tip.is(':visible')) {\n self.hoverState = 'in'\n return\n }\n\n if (!self) {\n self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n $(obj.currentTarget).data('bs.' + this.type, self)\n }\n\n clearTimeout(self.timeout)\n\n self.hoverState = 'in'\n\n if (!self.options.delay || !self.options.delay.show) return self.show()\n\n self.timeout = setTimeout(function () {\n if (self.hoverState == 'in') self.show()\n }, self.options.delay.show)\n }\n\n Tooltip.prototype.leave = function (obj) {\n var self = obj instanceof this.constructor ?\n obj : $(obj.currentTarget).data('bs.' + this.type)\n\n if (!self) {\n self = new this.constructor(obj.currentTarget, this.getDelegateOptions())\n $(obj.currentTarget).data('bs.' + this.type, self)\n }\n\n clearTimeout(self.timeout)\n\n self.hoverState = 'out'\n\n if (!self.options.delay || !self.options.delay.hide) return self.hide()\n\n self.timeout = setTimeout(function () {\n if (self.hoverState == 'out') self.hide()\n }, self.options.delay.hide)\n }\n\n Tooltip.prototype.show = function () {\n var e = $.Event('show.bs.' + this.type)\n\n if (this.hasContent() && this.enabled) {\n this.$element.trigger(e)\n\n var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])\n if (e.isDefaultPrevented() || !inDom) return\n var that = this\n\n var $tip = this.tip()\n\n var tipId = this.getUID(this.type)\n\n this.setContent()\n $tip.attr('id', tipId)\n this.$element.attr('aria-describedby', tipId)\n\n if (this.options.animation) $tip.addClass('fade')\n\n var placement = typeof this.options.placement == 'function' ?\n this.options.placement.call(this, $tip[0], this.$element[0]) :\n this.options.placement\n\n var autoToken = /\\s?auto?\\s?/i\n var autoPlace = autoToken.test(placement)\n if (autoPlace) placement = placement.replace(autoToken, '') || 'top'\n\n $tip\n .detach()\n .css({ top: 0, left: 0, display: 'block' })\n .addClass(placement)\n .data('bs.' + this.type, this)\n\n this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)\n\n var pos = this.getPosition()\n var actualWidth = $tip[0].offsetWidth\n var actualHeight = $tip[0].offsetHeight\n\n if (autoPlace) {\n var orgPlacement = placement\n var $container = this.options.container ? $(this.options.container) : this.$element.parent()\n var containerDim = this.getPosition($container)\n\n placement = placement == 'bottom' && pos.bottom + actualHeight > containerDim.bottom ? 'top' :\n placement == 'top' && pos.top - actualHeight < containerDim.top ? 'bottom' :\n placement == 'right' && pos.right + actualWidth > containerDim.width ? 'left' :\n placement == 'left' && pos.left - actualWidth < containerDim.left ? 'right' :\n placement\n\n $tip\n .removeClass(orgPlacement)\n .addClass(placement)\n }\n\n var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)\n\n this.applyPlacement(calculatedOffset, placement)\n\n var complete = function () {\n var prevHoverState = that.hoverState\n that.$element.trigger('shown.bs.' + that.type)\n that.hoverState = null\n\n if (prevHoverState == 'out') that.leave(that)\n }\n\n $.support.transition && this.$tip.hasClass('fade') ?\n $tip\n .one('bsTransitionEnd', complete)\n .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n complete()\n }\n }\n\n Tooltip.prototype.applyPlacement = function (offset, placement) {\n var $tip = this.tip()\n var width = $tip[0].offsetWidth\n var height = $tip[0].offsetHeight\n\n // manually read margins because getBoundingClientRect includes difference\n var marginTop = parseInt($tip.css('margin-top'), 10)\n var marginLeft = parseInt($tip.css('margin-left'), 10)\n\n // we must check for NaN for ie 8/9\n if (isNaN(marginTop)) marginTop = 0\n if (isNaN(marginLeft)) marginLeft = 0\n\n offset.top = offset.top + marginTop\n offset.left = offset.left + marginLeft\n\n // $.fn.offset doesn't round pixel values\n // so we use setOffset directly with our own function B-0\n $.offset.setOffset($tip[0], $.extend({\n using: function (props) {\n $tip.css({\n top: Math.round(props.top),\n left: Math.round(props.left)\n })\n }\n }, offset), 0)\n\n $tip.addClass('in')\n\n // check to see if placing tip in new offset caused the tip to resize itself\n var actualWidth = $tip[0].offsetWidth\n var actualHeight = $tip[0].offsetHeight\n\n if (placement == 'top' && actualHeight != height) {\n offset.top = offset.top + height - actualHeight\n }\n\n var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)\n\n if (delta.left) offset.left += delta.left\n else offset.top += delta.top\n\n var isVertical = /top|bottom/.test(placement)\n var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight\n var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'\n\n $tip.offset(offset)\n this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)\n }\n\n Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {\n this.arrow()\n .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')\n .css(isVertical ? 'top' : 'left', '')\n }\n\n Tooltip.prototype.setContent = function () {\n var $tip = this.tip()\n var title = this.getTitle()\n\n $tip.find('.tooltip-inner')[this.options.html ? 'html' : 'text'](title)\n $tip.removeClass('fade in top bottom left right')\n }\n\n Tooltip.prototype.hide = function (callback) {\n var that = this\n var $tip = $(this.$tip)\n var e = $.Event('hide.bs.' + this.type)\n\n function complete() {\n if (that.hoverState != 'in') $tip.detach()\n that.$element\n .removeAttr('aria-describedby')\n .trigger('hidden.bs.' + that.type)\n callback && callback()\n }\n\n this.$element.trigger(e)\n\n if (e.isDefaultPrevented()) return\n\n $tip.removeClass('in')\n\n $.support.transition && $tip.hasClass('fade') ?\n $tip\n .one('bsTransitionEnd', complete)\n .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :\n complete()\n\n this.hoverState = null\n\n return this\n }\n\n Tooltip.prototype.fixTitle = function () {\n var $e = this.$element\n if ($e.attr('title') || typeof ($e.attr('data-original-title')) != 'string') {\n $e.attr('data-original-title', $e.attr('title') || '').attr('title', '')\n }\n }\n\n Tooltip.prototype.hasContent = function () {\n return this.getTitle()\n }\n\n Tooltip.prototype.getPosition = function ($element) {\n $element = $element || this.$element\n\n var el = $element[0]\n var isBody = el.tagName == 'BODY'\n\n var elRect = el.getBoundingClientRect()\n if (elRect.width == null) {\n // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093\n elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })\n }\n var elOffset = isBody ? { top: 0, left: 0 } : $element.offset()\n var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }\n var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null\n\n return $.extend({}, elRect, scroll, outerDims, elOffset)\n }\n\n Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {\n return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :\n placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :\n placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :\n /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }\n\n }\n\n Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {\n var delta = { top: 0, left: 0 }\n if (!this.$viewport) return delta\n\n var viewportPadding = this.options.viewport && this.options.viewport.padding || 0\n var viewportDimensions = this.getPosition(this.$viewport)\n\n if (/right|left/.test(placement)) {\n var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll\n var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight\n if (topEdgeOffset < viewportDimensions.top) { // top overflow\n delta.top = viewportDimensions.top - topEdgeOffset\n } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow\n delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset\n }\n } else {\n var leftEdgeOffset = pos.left - viewportPadding\n var rightEdgeOffset = pos.left + viewportPadding + actualWidth\n if (leftEdgeOffset < viewportDimensions.left) { // left overflow\n delta.left = viewportDimensions.left - leftEdgeOffset\n } else if (rightEdgeOffset > viewportDimensions.width) { // right overflow\n delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset\n }\n }\n\n return delta\n }\n\n Tooltip.prototype.getTitle = function () {\n var title\n var $e = this.$element\n var o = this.options\n\n title = $e.attr('data-original-title')\n || (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)\n\n return title\n }\n\n Tooltip.prototype.getUID = function (prefix) {\n do prefix += ~~(Math.random() * 1000000)\n while (document.getElementById(prefix))\n return prefix\n }\n\n Tooltip.prototype.tip = function () {\n return (this.$tip = this.$tip || $(this.options.template))\n }\n\n Tooltip.prototype.arrow = function () {\n return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))\n }\n\n Tooltip.prototype.enable = function () {\n this.enabled = true\n }\n\n Tooltip.prototype.disable = function () {\n this.enabled = false\n }\n\n Tooltip.prototype.toggleEnabled = function () {\n this.enabled = !this.enabled\n }\n\n Tooltip.prototype.toggle = function (e) {\n var self = this\n if (e) {\n self = $(e.currentTarget).data('bs.' + this.type)\n if (!self) {\n self = new this.constructor(e.currentTarget, this.getDelegateOptions())\n $(e.currentTarget).data('bs.' + this.type, self)\n }\n }\n\n self.tip().hasClass('in') ? self.leave(self) : self.enter(self)\n }\n\n Tooltip.prototype.destroy = function () {\n var that = this\n clearTimeout(this.timeout)\n this.hide(function () {\n that.$element.off('.' + that.type).removeData('bs.' + that.type)\n })\n }\n\n\n // TOOLTIP PLUGIN DEFINITION\n // =========================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.tooltip')\n var options = typeof option == 'object' && option\n\n if (!data && /destroy|hide/.test(option)) return\n if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))\n if (typeof option == 'string') data[option]()\n })\n }\n\n var old = $.fn.tooltip\n\n $.fn.tooltip = Plugin\n $.fn.tooltip.Constructor = Tooltip\n\n\n // TOOLTIP NO CONFLICT\n // ===================\n\n $.fn.tooltip.noConflict = function () {\n $.fn.tooltip = old\n return this\n }\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: popover.js v3.3.4\n * http://getbootstrap.com/javascript/#popovers\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // POPOVER PUBLIC CLASS DEFINITION\n // ===============================\n\n var Popover = function (element, options) {\n this.init('popover', element, options)\n }\n\n if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')\n\n Popover.VERSION = '3.3.4'\n\n Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {\n placement: 'right',\n trigger: 'click',\n content: '',\n template: '

      '\n })\n\n\n // NOTE: POPOVER EXTENDS tooltip.js\n // ================================\n\n Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)\n\n Popover.prototype.constructor = Popover\n\n Popover.prototype.getDefaults = function () {\n return Popover.DEFAULTS\n }\n\n Popover.prototype.setContent = function () {\n var $tip = this.tip()\n var title = this.getTitle()\n var content = this.getContent()\n\n $tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title)\n $tip.find('.popover-content').children().detach().end()[ // we use append for html objects to maintain js events\n this.options.html ? (typeof content == 'string' ? 'html' : 'append') : 'text'\n ](content)\n\n $tip.removeClass('fade top bottom left right in')\n\n // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do\n // this manually by checking the contents.\n if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()\n }\n\n Popover.prototype.hasContent = function () {\n return this.getTitle() || this.getContent()\n }\n\n Popover.prototype.getContent = function () {\n var $e = this.$element\n var o = this.options\n\n return $e.attr('data-content')\n || (typeof o.content == 'function' ?\n o.content.call($e[0]) :\n o.content)\n }\n\n Popover.prototype.arrow = function () {\n return (this.$arrow = this.$arrow || this.tip().find('.arrow'))\n }\n\n\n // POPOVER PLUGIN DEFINITION\n // =========================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.popover')\n var options = typeof option == 'object' && option\n\n if (!data && /destroy|hide/.test(option)) return\n if (!data) $this.data('bs.popover', (data = new Popover(this, options)))\n if (typeof option == 'string') data[option]()\n })\n }\n\n var old = $.fn.popover\n\n $.fn.popover = Plugin\n $.fn.popover.Constructor = Popover\n\n\n // POPOVER NO CONFLICT\n // ===================\n\n $.fn.popover.noConflict = function () {\n $.fn.popover = old\n return this\n }\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: scrollspy.js v3.3.4\n * http://getbootstrap.com/javascript/#scrollspy\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // SCROLLSPY CLASS DEFINITION\n // ==========================\n\n function ScrollSpy(element, options) {\n this.$body = $(document.body)\n this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)\n this.options = $.extend({}, ScrollSpy.DEFAULTS, options)\n this.selector = (this.options.target || '') + ' .nav li > a'\n this.offsets = []\n this.targets = []\n this.activeTarget = null\n this.scrollHeight = 0\n\n this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))\n this.refresh()\n this.process()\n }\n\n ScrollSpy.VERSION = '3.3.4'\n\n ScrollSpy.DEFAULTS = {\n offset: 10\n }\n\n ScrollSpy.prototype.getScrollHeight = function () {\n return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)\n }\n\n ScrollSpy.prototype.refresh = function () {\n var that = this\n var offsetMethod = 'offset'\n var offsetBase = 0\n\n this.offsets = []\n this.targets = []\n this.scrollHeight = this.getScrollHeight()\n\n if (!$.isWindow(this.$scrollElement[0])) {\n offsetMethod = 'position'\n offsetBase = this.$scrollElement.scrollTop()\n }\n\n this.$body\n .find(this.selector)\n .map(function () {\n var $el = $(this)\n var href = $el.data('target') || $el.attr('href')\n var $href = /^#./.test(href) && $(href)\n\n return ($href\n && $href.length\n && $href.is(':visible')\n && [[$href[offsetMethod]().top + offsetBase, href]]) || null\n })\n .sort(function (a, b) { return a[0] - b[0] })\n .each(function () {\n that.offsets.push(this[0])\n that.targets.push(this[1])\n })\n }\n\n ScrollSpy.prototype.process = function () {\n var scrollTop = this.$scrollElement.scrollTop() + this.options.offset\n var scrollHeight = this.getScrollHeight()\n var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()\n var offsets = this.offsets\n var targets = this.targets\n var activeTarget = this.activeTarget\n var i\n\n if (this.scrollHeight != scrollHeight) {\n this.refresh()\n }\n\n if (scrollTop >= maxScroll) {\n return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)\n }\n\n if (activeTarget && scrollTop < offsets[0]) {\n this.activeTarget = null\n return this.clear()\n }\n\n for (i = offsets.length; i--;) {\n activeTarget != targets[i]\n && scrollTop >= offsets[i]\n && (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])\n && this.activate(targets[i])\n }\n }\n\n ScrollSpy.prototype.activate = function (target) {\n this.activeTarget = target\n\n this.clear()\n\n var selector = this.selector +\n '[data-target=\"' + target + '\"],' +\n this.selector + '[href=\"' + target + '\"]'\n\n var active = $(selector)\n .parents('li')\n .addClass('active')\n\n if (active.parent('.dropdown-menu').length) {\n active = active\n .closest('li.dropdown')\n .addClass('active')\n }\n\n active.trigger('activate.bs.scrollspy')\n }\n\n ScrollSpy.prototype.clear = function () {\n $(this.selector)\n .parentsUntil(this.options.target, '.active')\n .removeClass('active')\n }\n\n\n // SCROLLSPY PLUGIN DEFINITION\n // ===========================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.scrollspy')\n var options = typeof option == 'object' && option\n\n if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))\n if (typeof option == 'string') data[option]()\n })\n }\n\n var old = $.fn.scrollspy\n\n $.fn.scrollspy = Plugin\n $.fn.scrollspy.Constructor = ScrollSpy\n\n\n // SCROLLSPY NO CONFLICT\n // =====================\n\n $.fn.scrollspy.noConflict = function () {\n $.fn.scrollspy = old\n return this\n }\n\n\n // SCROLLSPY DATA-API\n // ==================\n\n $(window).on('load.bs.scrollspy.data-api', function () {\n $('[data-spy=\"scroll\"]').each(function () {\n var $spy = $(this)\n Plugin.call($spy, $spy.data())\n })\n })\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: tab.js v3.3.4\n * http://getbootstrap.com/javascript/#tabs\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // TAB CLASS DEFINITION\n // ====================\n\n var Tab = function (element) {\n this.element = $(element)\n }\n\n Tab.VERSION = '3.3.4'\n\n Tab.TRANSITION_DURATION = 150\n\n Tab.prototype.show = function () {\n var $this = this.element\n var $ul = $this.closest('ul:not(.dropdown-menu)')\n var selector = $this.data('target')\n\n if (!selector) {\n selector = $this.attr('href')\n selector = selector && selector.replace(/.*(?=#[^\\s]*$)/, '') // strip for ie7\n }\n\n if ($this.parent('li').hasClass('active')) return\n\n var $previous = $ul.find('.active:last a')\n var hideEvent = $.Event('hide.bs.tab', {\n relatedTarget: $this[0]\n })\n var showEvent = $.Event('show.bs.tab', {\n relatedTarget: $previous[0]\n })\n\n $previous.trigger(hideEvent)\n $this.trigger(showEvent)\n\n if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return\n\n var $target = $(selector)\n\n this.activate($this.closest('li'), $ul)\n this.activate($target, $target.parent(), function () {\n $previous.trigger({\n type: 'hidden.bs.tab',\n relatedTarget: $this[0]\n })\n $this.trigger({\n type: 'shown.bs.tab',\n relatedTarget: $previous[0]\n })\n })\n }\n\n Tab.prototype.activate = function (element, container, callback) {\n var $active = container.find('> .active')\n var transition = callback\n && $.support.transition\n && (($active.length && $active.hasClass('fade')) || !!container.find('> .fade').length)\n\n function next() {\n $active\n .removeClass('active')\n .find('> .dropdown-menu > .active')\n .removeClass('active')\n .end()\n .find('[data-toggle=\"tab\"]')\n .attr('aria-expanded', false)\n\n element\n .addClass('active')\n .find('[data-toggle=\"tab\"]')\n .attr('aria-expanded', true)\n\n if (transition) {\n element[0].offsetWidth // reflow for transition\n element.addClass('in')\n } else {\n element.removeClass('fade')\n }\n\n if (element.parent('.dropdown-menu').length) {\n element\n .closest('li.dropdown')\n .addClass('active')\n .end()\n .find('[data-toggle=\"tab\"]')\n .attr('aria-expanded', true)\n }\n\n callback && callback()\n }\n\n $active.length && transition ?\n $active\n .one('bsTransitionEnd', next)\n .emulateTransitionEnd(Tab.TRANSITION_DURATION) :\n next()\n\n $active.removeClass('in')\n }\n\n\n // TAB PLUGIN DEFINITION\n // =====================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.tab')\n\n if (!data) $this.data('bs.tab', (data = new Tab(this)))\n if (typeof option == 'string') data[option]()\n })\n }\n\n var old = $.fn.tab\n\n $.fn.tab = Plugin\n $.fn.tab.Constructor = Tab\n\n\n // TAB NO CONFLICT\n // ===============\n\n $.fn.tab.noConflict = function () {\n $.fn.tab = old\n return this\n }\n\n\n // TAB DATA-API\n // ============\n\n var clickHandler = function (e) {\n e.preventDefault()\n Plugin.call($(this), 'show')\n }\n\n $(document)\n .on('click.bs.tab.data-api', '[data-toggle=\"tab\"]', clickHandler)\n .on('click.bs.tab.data-api', '[data-toggle=\"pill\"]', clickHandler)\n\n}(jQuery);\n\n/* ========================================================================\n * Bootstrap: affix.js v3.3.4\n * http://getbootstrap.com/javascript/#affix\n * ========================================================================\n * Copyright 2011-2015 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n * ======================================================================== */\n\n\n+function ($) {\n 'use strict';\n\n // AFFIX CLASS DEFINITION\n // ======================\n\n var Affix = function (element, options) {\n this.options = $.extend({}, Affix.DEFAULTS, options)\n\n this.$target = $(this.options.target)\n .on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))\n .on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))\n\n this.$element = $(element)\n this.affixed = null\n this.unpin = null\n this.pinnedOffset = null\n\n this.checkPosition()\n }\n\n Affix.VERSION = '3.3.4'\n\n Affix.RESET = 'affix affix-top affix-bottom'\n\n Affix.DEFAULTS = {\n offset: 0,\n target: window\n }\n\n Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {\n var scrollTop = this.$target.scrollTop()\n var position = this.$element.offset()\n var targetHeight = this.$target.height()\n\n if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false\n\n if (this.affixed == 'bottom') {\n if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'\n return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'\n }\n\n var initializing = this.affixed == null\n var colliderTop = initializing ? scrollTop : position.top\n var colliderHeight = initializing ? targetHeight : height\n\n if (offsetTop != null && scrollTop <= offsetTop) return 'top'\n if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'\n\n return false\n }\n\n Affix.prototype.getPinnedOffset = function () {\n if (this.pinnedOffset) return this.pinnedOffset\n this.$element.removeClass(Affix.RESET).addClass('affix')\n var scrollTop = this.$target.scrollTop()\n var position = this.$element.offset()\n return (this.pinnedOffset = position.top - scrollTop)\n }\n\n Affix.prototype.checkPositionWithEventLoop = function () {\n setTimeout($.proxy(this.checkPosition, this), 1)\n }\n\n Affix.prototype.checkPosition = function () {\n if (!this.$element.is(':visible')) return\n\n var height = this.$element.height()\n var offset = this.options.offset\n var offsetTop = offset.top\n var offsetBottom = offset.bottom\n var scrollHeight = $(document.body).height()\n\n if (typeof offset != 'object') offsetBottom = offsetTop = offset\n if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)\n if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)\n\n var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)\n\n if (this.affixed != affix) {\n if (this.unpin != null) this.$element.css('top', '')\n\n var affixType = 'affix' + (affix ? '-' + affix : '')\n var e = $.Event(affixType + '.bs.affix')\n\n this.$element.trigger(e)\n\n if (e.isDefaultPrevented()) return\n\n this.affixed = affix\n this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null\n\n this.$element\n .removeClass(Affix.RESET)\n .addClass(affixType)\n .trigger(affixType.replace('affix', 'affixed') + '.bs.affix')\n }\n\n if (affix == 'bottom') {\n this.$element.offset({\n top: scrollHeight - height - offsetBottom\n })\n }\n }\n\n\n // AFFIX PLUGIN DEFINITION\n // =======================\n\n function Plugin(option) {\n return this.each(function () {\n var $this = $(this)\n var data = $this.data('bs.affix')\n var options = typeof option == 'object' && option\n\n if (!data) $this.data('bs.affix', (data = new Affix(this, options)))\n if (typeof option == 'string') data[option]()\n })\n }\n\n var old = $.fn.affix\n\n $.fn.affix = Plugin\n $.fn.affix.Constructor = Affix\n\n\n // AFFIX NO CONFLICT\n // =================\n\n $.fn.affix.noConflict = function () {\n $.fn.affix = old\n return this\n }\n\n\n // AFFIX DATA-API\n // ==============\n\n $(window).on('load', function () {\n $('[data-spy=\"affix\"]').each(function () {\n var $spy = $(this)\n var data = $spy.data()\n\n data.offset = data.offset || {}\n\n if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom\n if (data.offsetTop != null) data.offset.top = data.offsetTop\n\n Plugin.call($spy, data)\n })\n })\n\n}(jQuery);\n","// canvas-confetti v1.9.3 built on 2024-04-30T22:19:17.794Z\n!(function (window, module) {\n// source content\n/* globals Map */\n\n(function main(global, module, isWorker, workerSize) {\n var canUseWorker = !!(\n global.Worker &&\n global.Blob &&\n global.Promise &&\n global.OffscreenCanvas &&\n global.OffscreenCanvasRenderingContext2D &&\n global.HTMLCanvasElement &&\n global.HTMLCanvasElement.prototype.transferControlToOffscreen &&\n global.URL &&\n global.URL.createObjectURL);\n\n var canUsePaths = typeof Path2D === 'function' && typeof DOMMatrix === 'function';\n var canDrawBitmap = (function () {\n // this mostly supports ssr\n if (!global.OffscreenCanvas) {\n return false;\n }\n\n var canvas = new OffscreenCanvas(1, 1);\n var ctx = canvas.getContext('2d');\n ctx.fillRect(0, 0, 1, 1);\n var bitmap = canvas.transferToImageBitmap();\n\n try {\n ctx.createPattern(bitmap, 'no-repeat');\n } catch (e) {\n return false;\n }\n\n return true;\n })();\n\n function noop() {}\n\n // create a promise if it exists, otherwise, just\n // call the function directly\n function promise(func) {\n var ModulePromise = module.exports.Promise;\n var Prom = ModulePromise !== void 0 ? ModulePromise : global.Promise;\n\n if (typeof Prom === 'function') {\n return new Prom(func);\n }\n\n func(noop, noop);\n\n return null;\n }\n\n var bitmapMapper = (function (skipTransform, map) {\n // see https://github.com/catdad/canvas-confetti/issues/209\n // creating canvases is actually pretty expensive, so we should create a\n // 1:1 map for bitmap:canvas, so that we can animate the confetti in\n // a performant manner, but also not store them forever so that we don't\n // have a memory leak\n return {\n transform: function(bitmap) {\n if (skipTransform) {\n return bitmap;\n }\n\n if (map.has(bitmap)) {\n return map.get(bitmap);\n }\n\n var canvas = new OffscreenCanvas(bitmap.width, bitmap.height);\n var ctx = canvas.getContext('2d');\n ctx.drawImage(bitmap, 0, 0);\n\n map.set(bitmap, canvas);\n\n return canvas;\n },\n clear: function () {\n map.clear();\n }\n };\n })(canDrawBitmap, new Map());\n\n var raf = (function () {\n var TIME = Math.floor(1000 / 60);\n var frame, cancel;\n var frames = {};\n var lastFrameTime = 0;\n\n if (typeof requestAnimationFrame === 'function' && typeof cancelAnimationFrame === 'function') {\n frame = function (cb) {\n var id = Math.random();\n\n frames[id] = requestAnimationFrame(function onFrame(time) {\n if (lastFrameTime === time || lastFrameTime + TIME - 1 < time) {\n lastFrameTime = time;\n delete frames[id];\n\n cb();\n } else {\n frames[id] = requestAnimationFrame(onFrame);\n }\n });\n\n return id;\n };\n cancel = function (id) {\n if (frames[id]) {\n cancelAnimationFrame(frames[id]);\n }\n };\n } else {\n frame = function (cb) {\n return setTimeout(cb, TIME);\n };\n cancel = function (timer) {\n return clearTimeout(timer);\n };\n }\n\n return { frame: frame, cancel: cancel };\n }());\n\n var getWorker = (function () {\n var worker;\n var prom;\n var resolves = {};\n\n function decorate(worker) {\n function execute(options, callback) {\n worker.postMessage({ options: options || {}, callback: callback });\n }\n worker.init = function initWorker(canvas) {\n var offscreen = canvas.transferControlToOffscreen();\n worker.postMessage({ canvas: offscreen }, [offscreen]);\n };\n\n worker.fire = function fireWorker(options, size, done) {\n if (prom) {\n execute(options, null);\n return prom;\n }\n\n var id = Math.random().toString(36).slice(2);\n\n prom = promise(function (resolve) {\n function workerDone(msg) {\n if (msg.data.callback !== id) {\n return;\n }\n\n delete resolves[id];\n worker.removeEventListener('message', workerDone);\n\n prom = null;\n\n bitmapMapper.clear();\n\n done();\n resolve();\n }\n\n worker.addEventListener('message', workerDone);\n execute(options, id);\n\n resolves[id] = workerDone.bind(null, { data: { callback: id }});\n });\n\n return prom;\n };\n\n worker.reset = function resetWorker() {\n worker.postMessage({ reset: true });\n\n for (var id in resolves) {\n resolves[id]();\n delete resolves[id];\n }\n };\n }\n\n return function () {\n if (worker) {\n return worker;\n }\n\n if (!isWorker && canUseWorker) {\n var code = [\n 'var CONFETTI, SIZE = {}, module = {};',\n '(' + main.toString() + ')(this, module, true, SIZE);',\n 'onmessage = function(msg) {',\n ' if (msg.data.options) {',\n ' CONFETTI(msg.data.options).then(function () {',\n ' if (msg.data.callback) {',\n ' postMessage({ callback: msg.data.callback });',\n ' }',\n ' });',\n ' } else if (msg.data.reset) {',\n ' CONFETTI && CONFETTI.reset();',\n ' } else if (msg.data.resize) {',\n ' SIZE.width = msg.data.resize.width;',\n ' SIZE.height = msg.data.resize.height;',\n ' } else if (msg.data.canvas) {',\n ' SIZE.width = msg.data.canvas.width;',\n ' SIZE.height = msg.data.canvas.height;',\n ' CONFETTI = module.exports.create(msg.data.canvas);',\n ' }',\n '}',\n ].join('\\n');\n try {\n worker = new Worker(URL.createObjectURL(new Blob([code])));\n } catch (e) {\n // eslint-disable-next-line no-console\n typeof console !== undefined && typeof console.warn === 'function' ? console.warn('🎊 Could not load worker', e) : null;\n\n return null;\n }\n\n decorate(worker);\n }\n\n return worker;\n };\n })();\n\n var defaults = {\n particleCount: 50,\n angle: 90,\n spread: 45,\n startVelocity: 45,\n decay: 0.9,\n gravity: 1,\n drift: 0,\n ticks: 200,\n x: 0.5,\n y: 0.5,\n shapes: ['square', 'circle'],\n zIndex: 100,\n colors: [\n '#26ccff',\n '#a25afd',\n '#ff5e7e',\n '#88ff5a',\n '#fcff42',\n '#ffa62d',\n '#ff36ff'\n ],\n // probably should be true, but back-compat\n disableForReducedMotion: false,\n scalar: 1\n };\n\n function convert(val, transform) {\n return transform ? transform(val) : val;\n }\n\n function isOk(val) {\n return !(val === null || val === undefined);\n }\n\n function prop(options, name, transform) {\n return convert(\n options && isOk(options[name]) ? options[name] : defaults[name],\n transform\n );\n }\n\n function onlyPositiveInt(number){\n return number < 0 ? 0 : Math.floor(number);\n }\n\n function randomInt(min, max) {\n // [min, max)\n return Math.floor(Math.random() * (max - min)) + min;\n }\n\n function toDecimal(str) {\n return parseInt(str, 16);\n }\n\n function colorsToRgb(colors) {\n return colors.map(hexToRgb);\n }\n\n function hexToRgb(str) {\n var val = String(str).replace(/[^0-9a-f]/gi, '');\n\n if (val.length < 6) {\n val = val[0]+val[0]+val[1]+val[1]+val[2]+val[2];\n }\n\n return {\n r: toDecimal(val.substring(0,2)),\n g: toDecimal(val.substring(2,4)),\n b: toDecimal(val.substring(4,6))\n };\n }\n\n function getOrigin(options) {\n var origin = prop(options, 'origin', Object);\n origin.x = prop(origin, 'x', Number);\n origin.y = prop(origin, 'y', Number);\n\n return origin;\n }\n\n function setCanvasWindowSize(canvas) {\n canvas.width = document.documentElement.clientWidth;\n canvas.height = document.documentElement.clientHeight;\n }\n\n function setCanvasRectSize(canvas) {\n var rect = canvas.getBoundingClientRect();\n canvas.width = rect.width;\n canvas.height = rect.height;\n }\n\n function getCanvas(zIndex) {\n var canvas = document.createElement('canvas');\n\n canvas.style.position = 'fixed';\n canvas.style.top = '0px';\n canvas.style.left = '0px';\n canvas.style.pointerEvents = 'none';\n canvas.style.zIndex = zIndex;\n\n return canvas;\n }\n\n function ellipse(context, x, y, radiusX, radiusY, rotation, startAngle, endAngle, antiClockwise) {\n context.save();\n context.translate(x, y);\n context.rotate(rotation);\n context.scale(radiusX, radiusY);\n context.arc(0, 0, 1, startAngle, endAngle, antiClockwise);\n context.restore();\n }\n\n function randomPhysics(opts) {\n var radAngle = opts.angle * (Math.PI / 180);\n var radSpread = opts.spread * (Math.PI / 180);\n\n return {\n x: opts.x,\n y: opts.y,\n wobble: Math.random() * 10,\n wobbleSpeed: Math.min(0.11, Math.random() * 0.1 + 0.05),\n velocity: (opts.startVelocity * 0.5) + (Math.random() * opts.startVelocity),\n angle2D: -radAngle + ((0.5 * radSpread) - (Math.random() * radSpread)),\n tiltAngle: (Math.random() * (0.75 - 0.25) + 0.25) * Math.PI,\n color: opts.color,\n shape: opts.shape,\n tick: 0,\n totalTicks: opts.ticks,\n decay: opts.decay,\n drift: opts.drift,\n random: Math.random() + 2,\n tiltSin: 0,\n tiltCos: 0,\n wobbleX: 0,\n wobbleY: 0,\n gravity: opts.gravity * 3,\n ovalScalar: 0.6,\n scalar: opts.scalar,\n flat: opts.flat\n };\n }\n\n function updateFetti(context, fetti) {\n fetti.x += Math.cos(fetti.angle2D) * fetti.velocity + fetti.drift;\n fetti.y += Math.sin(fetti.angle2D) * fetti.velocity + fetti.gravity;\n fetti.velocity *= fetti.decay;\n\n if (fetti.flat) {\n fetti.wobble = 0;\n fetti.wobbleX = fetti.x + (10 * fetti.scalar);\n fetti.wobbleY = fetti.y + (10 * fetti.scalar);\n\n fetti.tiltSin = 0;\n fetti.tiltCos = 0;\n fetti.random = 1;\n } else {\n fetti.wobble += fetti.wobbleSpeed;\n fetti.wobbleX = fetti.x + ((10 * fetti.scalar) * Math.cos(fetti.wobble));\n fetti.wobbleY = fetti.y + ((10 * fetti.scalar) * Math.sin(fetti.wobble));\n\n fetti.tiltAngle += 0.1;\n fetti.tiltSin = Math.sin(fetti.tiltAngle);\n fetti.tiltCos = Math.cos(fetti.tiltAngle);\n fetti.random = Math.random() + 2;\n }\n\n var progress = (fetti.tick++) / fetti.totalTicks;\n\n var x1 = fetti.x + (fetti.random * fetti.tiltCos);\n var y1 = fetti.y + (fetti.random * fetti.tiltSin);\n var x2 = fetti.wobbleX + (fetti.random * fetti.tiltCos);\n var y2 = fetti.wobbleY + (fetti.random * fetti.tiltSin);\n\n context.fillStyle = 'rgba(' + fetti.color.r + ', ' + fetti.color.g + ', ' + fetti.color.b + ', ' + (1 - progress) + ')';\n\n context.beginPath();\n\n if (canUsePaths && fetti.shape.type === 'path' && typeof fetti.shape.path === 'string' && Array.isArray(fetti.shape.matrix)) {\n context.fill(transformPath2D(\n fetti.shape.path,\n fetti.shape.matrix,\n fetti.x,\n fetti.y,\n Math.abs(x2 - x1) * 0.1,\n Math.abs(y2 - y1) * 0.1,\n Math.PI / 10 * fetti.wobble\n ));\n } else if (fetti.shape.type === 'bitmap') {\n var rotation = Math.PI / 10 * fetti.wobble;\n var scaleX = Math.abs(x2 - x1) * 0.1;\n var scaleY = Math.abs(y2 - y1) * 0.1;\n var width = fetti.shape.bitmap.width * fetti.scalar;\n var height = fetti.shape.bitmap.height * fetti.scalar;\n\n var matrix = new DOMMatrix([\n Math.cos(rotation) * scaleX,\n Math.sin(rotation) * scaleX,\n -Math.sin(rotation) * scaleY,\n Math.cos(rotation) * scaleY,\n fetti.x,\n fetti.y\n ]);\n\n // apply the transform matrix from the confetti shape\n matrix.multiplySelf(new DOMMatrix(fetti.shape.matrix));\n\n var pattern = context.createPattern(bitmapMapper.transform(fetti.shape.bitmap), 'no-repeat');\n pattern.setTransform(matrix);\n\n context.globalAlpha = (1 - progress);\n context.fillStyle = pattern;\n context.fillRect(\n fetti.x - (width / 2),\n fetti.y - (height / 2),\n width,\n height\n );\n context.globalAlpha = 1;\n } else if (fetti.shape === 'circle') {\n context.ellipse ?\n context.ellipse(fetti.x, fetti.y, Math.abs(x2 - x1) * fetti.ovalScalar, Math.abs(y2 - y1) * fetti.ovalScalar, Math.PI / 10 * fetti.wobble, 0, 2 * Math.PI) :\n ellipse(context, fetti.x, fetti.y, Math.abs(x2 - x1) * fetti.ovalScalar, Math.abs(y2 - y1) * fetti.ovalScalar, Math.PI / 10 * fetti.wobble, 0, 2 * Math.PI);\n } else if (fetti.shape === 'star') {\n var rot = Math.PI / 2 * 3;\n var innerRadius = 4 * fetti.scalar;\n var outerRadius = 8 * fetti.scalar;\n var x = fetti.x;\n var y = fetti.y;\n var spikes = 5;\n var step = Math.PI / spikes;\n\n while (spikes--) {\n x = fetti.x + Math.cos(rot) * outerRadius;\n y = fetti.y + Math.sin(rot) * outerRadius;\n context.lineTo(x, y);\n rot += step;\n\n x = fetti.x + Math.cos(rot) * innerRadius;\n y = fetti.y + Math.sin(rot) * innerRadius;\n context.lineTo(x, y);\n rot += step;\n }\n } else {\n context.moveTo(Math.floor(fetti.x), Math.floor(fetti.y));\n context.lineTo(Math.floor(fetti.wobbleX), Math.floor(y1));\n context.lineTo(Math.floor(x2), Math.floor(y2));\n context.lineTo(Math.floor(x1), Math.floor(fetti.wobbleY));\n }\n\n context.closePath();\n context.fill();\n\n return fetti.tick < fetti.totalTicks;\n }\n\n function animate(canvas, fettis, resizer, size, done) {\n var animatingFettis = fettis.slice();\n var context = canvas.getContext('2d');\n var animationFrame;\n var destroy;\n\n var prom = promise(function (resolve) {\n function onDone() {\n animationFrame = destroy = null;\n\n context.clearRect(0, 0, size.width, size.height);\n bitmapMapper.clear();\n\n done();\n resolve();\n }\n\n function update() {\n if (isWorker && !(size.width === workerSize.width && size.height === workerSize.height)) {\n size.width = canvas.width = workerSize.width;\n size.height = canvas.height = workerSize.height;\n }\n\n if (!size.width && !size.height) {\n resizer(canvas);\n size.width = canvas.width;\n size.height = canvas.height;\n }\n\n context.clearRect(0, 0, size.width, size.height);\n\n animatingFettis = animatingFettis.filter(function (fetti) {\n return updateFetti(context, fetti);\n });\n\n if (animatingFettis.length) {\n animationFrame = raf.frame(update);\n } else {\n onDone();\n }\n }\n\n animationFrame = raf.frame(update);\n destroy = onDone;\n });\n\n return {\n addFettis: function (fettis) {\n animatingFettis = animatingFettis.concat(fettis);\n\n return prom;\n },\n canvas: canvas,\n promise: prom,\n reset: function () {\n if (animationFrame) {\n raf.cancel(animationFrame);\n }\n\n if (destroy) {\n destroy();\n }\n }\n };\n }\n\n function confettiCannon(canvas, globalOpts) {\n var isLibCanvas = !canvas;\n var allowResize = !!prop(globalOpts || {}, 'resize');\n var hasResizeEventRegistered = false;\n var globalDisableForReducedMotion = prop(globalOpts, 'disableForReducedMotion', Boolean);\n var shouldUseWorker = canUseWorker && !!prop(globalOpts || {}, 'useWorker');\n var worker = shouldUseWorker ? getWorker() : null;\n var resizer = isLibCanvas ? setCanvasWindowSize : setCanvasRectSize;\n var initialized = (canvas && worker) ? !!canvas.__confetti_initialized : false;\n var preferLessMotion = typeof matchMedia === 'function' && matchMedia('(prefers-reduced-motion)').matches;\n var animationObj;\n\n function fireLocal(options, size, done) {\n var particleCount = prop(options, 'particleCount', onlyPositiveInt);\n var angle = prop(options, 'angle', Number);\n var spread = prop(options, 'spread', Number);\n var startVelocity = prop(options, 'startVelocity', Number);\n var decay = prop(options, 'decay', Number);\n var gravity = prop(options, 'gravity', Number);\n var drift = prop(options, 'drift', Number);\n var colors = prop(options, 'colors', colorsToRgb);\n var ticks = prop(options, 'ticks', Number);\n var shapes = prop(options, 'shapes');\n var scalar = prop(options, 'scalar');\n var flat = !!prop(options, 'flat');\n var origin = getOrigin(options);\n\n var temp = particleCount;\n var fettis = [];\n\n var startX = canvas.width * origin.x;\n var startY = canvas.height * origin.y;\n\n while (temp--) {\n fettis.push(\n randomPhysics({\n x: startX,\n y: startY,\n angle: angle,\n spread: spread,\n startVelocity: startVelocity,\n color: colors[temp % colors.length],\n shape: shapes[randomInt(0, shapes.length)],\n ticks: ticks,\n decay: decay,\n gravity: gravity,\n drift: drift,\n scalar: scalar,\n flat: flat\n })\n );\n }\n\n // if we have a previous canvas already animating,\n // add to it\n if (animationObj) {\n return animationObj.addFettis(fettis);\n }\n\n animationObj = animate(canvas, fettis, resizer, size , done);\n\n return animationObj.promise;\n }\n\n function fire(options) {\n var disableForReducedMotion = globalDisableForReducedMotion || prop(options, 'disableForReducedMotion', Boolean);\n var zIndex = prop(options, 'zIndex', Number);\n\n if (disableForReducedMotion && preferLessMotion) {\n return promise(function (resolve) {\n resolve();\n });\n }\n\n if (isLibCanvas && animationObj) {\n // use existing canvas from in-progress animation\n canvas = animationObj.canvas;\n } else if (isLibCanvas && !canvas) {\n // create and initialize a new canvas\n canvas = getCanvas(zIndex);\n document.body.appendChild(canvas);\n }\n\n if (allowResize && !initialized) {\n // initialize the size of a user-supplied canvas\n resizer(canvas);\n }\n\n var size = {\n width: canvas.width,\n height: canvas.height\n };\n\n if (worker && !initialized) {\n worker.init(canvas);\n }\n\n initialized = true;\n\n if (worker) {\n canvas.__confetti_initialized = true;\n }\n\n function onResize() {\n if (worker) {\n // TODO this really shouldn't be immediate, because it is expensive\n var obj = {\n getBoundingClientRect: function () {\n if (!isLibCanvas) {\n return canvas.getBoundingClientRect();\n }\n }\n };\n\n resizer(obj);\n\n worker.postMessage({\n resize: {\n width: obj.width,\n height: obj.height\n }\n });\n return;\n }\n\n // don't actually query the size here, since this\n // can execute frequently and rapidly\n size.width = size.height = null;\n }\n\n function done() {\n animationObj = null;\n\n if (allowResize) {\n hasResizeEventRegistered = false;\n global.removeEventListener('resize', onResize);\n }\n\n if (isLibCanvas && canvas) {\n if (document.body.contains(canvas)) {\n document.body.removeChild(canvas); \n }\n canvas = null;\n initialized = false;\n }\n }\n\n if (allowResize && !hasResizeEventRegistered) {\n hasResizeEventRegistered = true;\n global.addEventListener('resize', onResize, false);\n }\n\n if (worker) {\n return worker.fire(options, size, done);\n }\n\n return fireLocal(options, size, done);\n }\n\n fire.reset = function () {\n if (worker) {\n worker.reset();\n }\n\n if (animationObj) {\n animationObj.reset();\n }\n };\n\n return fire;\n }\n\n // Make default export lazy to defer worker creation until called.\n var defaultFire;\n function getDefaultFire() {\n if (!defaultFire) {\n defaultFire = confettiCannon(null, { useWorker: true, resize: true });\n }\n return defaultFire;\n }\n\n function transformPath2D(pathString, pathMatrix, x, y, scaleX, scaleY, rotation) {\n var path2d = new Path2D(pathString);\n\n var t1 = new Path2D();\n t1.addPath(path2d, new DOMMatrix(pathMatrix));\n\n var t2 = new Path2D();\n // see https://developer.mozilla.org/en-US/docs/Web/API/DOMMatrix/DOMMatrix\n t2.addPath(t1, new DOMMatrix([\n Math.cos(rotation) * scaleX,\n Math.sin(rotation) * scaleX,\n -Math.sin(rotation) * scaleY,\n Math.cos(rotation) * scaleY,\n x,\n y\n ]));\n\n return t2;\n }\n\n function shapeFromPath(pathData) {\n if (!canUsePaths) {\n throw new Error('path confetti are not supported in this browser');\n }\n\n var path, matrix;\n\n if (typeof pathData === 'string') {\n path = pathData;\n } else {\n path = pathData.path;\n matrix = pathData.matrix;\n }\n\n var path2d = new Path2D(path);\n var tempCanvas = document.createElement('canvas');\n var tempCtx = tempCanvas.getContext('2d');\n\n if (!matrix) {\n // attempt to figure out the width of the path, up to 1000x1000\n var maxSize = 1000;\n var minX = maxSize;\n var minY = maxSize;\n var maxX = 0;\n var maxY = 0;\n var width, height;\n\n // do some line skipping... this is faster than checking\n // every pixel and will be mostly still correct\n for (var x = 0; x < maxSize; x += 2) {\n for (var y = 0; y < maxSize; y += 2) {\n if (tempCtx.isPointInPath(path2d, x, y, 'nonzero')) {\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n }\n }\n }\n\n width = maxX - minX;\n height = maxY - minY;\n\n var maxDesiredSize = 10;\n var scale = Math.min(maxDesiredSize/width, maxDesiredSize/height);\n\n matrix = [\n scale, 0, 0, scale,\n -Math.round((width/2) + minX) * scale,\n -Math.round((height/2) + minY) * scale\n ];\n }\n\n return {\n type: 'path',\n path: path,\n matrix: matrix\n };\n }\n\n function shapeFromText(textData) {\n var text,\n scalar = 1,\n color = '#000000',\n // see https://nolanlawson.com/2022/04/08/the-struggle-of-using-native-emoji-on-the-web/\n fontFamily = '\"Apple Color Emoji\", \"Segoe UI Emoji\", \"Segoe UI Symbol\", \"Noto Color Emoji\", \"EmojiOne Color\", \"Android Emoji\", \"Twemoji Mozilla\", \"system emoji\", sans-serif';\n\n if (typeof textData === 'string') {\n text = textData;\n } else {\n text = textData.text;\n scalar = 'scalar' in textData ? textData.scalar : scalar;\n fontFamily = 'fontFamily' in textData ? textData.fontFamily : fontFamily;\n color = 'color' in textData ? textData.color : color;\n }\n\n // all other confetti are 10 pixels,\n // so this pixel size is the de-facto 100% scale confetti\n var fontSize = 10 * scalar;\n var font = '' + fontSize + 'px ' + fontFamily;\n\n var canvas = new OffscreenCanvas(fontSize, fontSize);\n var ctx = canvas.getContext('2d');\n\n ctx.font = font;\n var size = ctx.measureText(text);\n var width = Math.ceil(size.actualBoundingBoxRight + size.actualBoundingBoxLeft);\n var height = Math.ceil(size.actualBoundingBoxAscent + size.actualBoundingBoxDescent);\n\n var padding = 2;\n var x = size.actualBoundingBoxLeft + padding;\n var y = size.actualBoundingBoxAscent + padding;\n width += padding + padding;\n height += padding + padding;\n\n canvas = new OffscreenCanvas(width, height);\n ctx = canvas.getContext('2d');\n ctx.font = font;\n ctx.fillStyle = color;\n\n ctx.fillText(text, x, y);\n\n var scale = 1 / scalar;\n\n return {\n type: 'bitmap',\n // TODO these probably need to be transfered for workers\n bitmap: canvas.transferToImageBitmap(),\n matrix: [scale, 0, 0, scale, -width * scale / 2, -height * scale / 2]\n };\n }\n\n module.exports = function() {\n return getDefaultFire().apply(this, arguments);\n };\n module.exports.reset = function() {\n getDefaultFire().reset();\n };\n module.exports.create = confettiCannon;\n module.exports.shapeFromPath = shapeFromPath;\n module.exports.shapeFromText = shapeFromText;\n}((function () {\n if (typeof window !== 'undefined') {\n return window;\n }\n\n if (typeof self !== 'undefined') {\n return self;\n }\n\n return this || {};\n})(), module, false));\n\n// end source content\n\n window.confetti = module.exports;\n}(window, {}));\n","/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT © Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});","+function(a){\"use strict\";function b(a,b){if(!(a instanceof b))throw new TypeError(\"Cannot call a class as a function\")}var c=function(){function a(a,b){for(var c=0;c
      ',leftArrow:\"\",rightArrow:\"\",strings:{close:\"Close\",fail:\"Failed to load image:\",type:\"Could not detect remote target type. Force the type using data-type\"},doc:document,onShow:function(){},onShown:function(){},onHide:function(){},onHidden:function(){},onNavigate:function(){},onContentLoaded:function(){}},g=function(){function d(c,e){var g=this;b(this,d),this._config=a.extend({},f,e),this._$modalArrows=null,this._galleryIndex=0,this._galleryName=null,this._padding=null,this._border=null,this._titleIsShown=!1,this._footerIsShown=!1,this._wantedWidth=0,this._wantedHeight=0,this._touchstartX=0,this._touchendX=0,this._modalId=\"ekkoLightbox-\"+Math.floor(1e3*Math.random()+1),this._$element=c instanceof jQuery?c:a(c),this._isBootstrap3=3==a.fn.modal.Constructor.VERSION[0];var h='

      '+(this._config.title||\" \")+\"

      \",i='',j='
      '+(this._isBootstrap3?i+h:h+i)+\"
      \",k='
      '+(this._config.footer||\" \")+\"
      \",l='
      ',m='
      '+j+l+k+\"
      \";a(this._config.doc.body).append('
      '+m+\"
      \"),this._$modal=a(\"#\"+this._modalId,this._config.doc),this._$modalDialog=this._$modal.find(\".modal-dialog\").first(),this._$modalContent=this._$modal.find(\".modal-content\").first(),this._$modalBody=this._$modal.find(\".modal-body\").first(),this._$modalHeader=this._$modal.find(\".modal-header\").first(),this._$modalFooter=this._$modal.find(\".modal-footer\").first(),this._$lightboxContainer=this._$modalBody.find(\".ekko-lightbox-container\").first(),this._$lightboxBodyOne=this._$lightboxContainer.find(\"> div:first-child\").first(),this._$lightboxBodyTwo=this._$lightboxContainer.find(\"> div:last-child\").first(),this._border=this._calculateBorders(),this._padding=this._calculatePadding(),this._galleryName=this._$element.data(\"gallery\"),this._galleryName&&(this._$galleryItems=a(document.body).find('*[data-gallery=\"'+this._galleryName+'\"]'),this._galleryIndex=this._$galleryItems.index(this._$element),a(document).on(\"keydown.ekkoLightbox\",this._navigationalBinder.bind(this)),this._config.showArrows&&this._$galleryItems.length>1&&(this._$lightboxContainer.append('\"),this._$modalArrows=this._$lightboxContainer.find(\"div.ekko-lightbox-nav-overlay\").first(),this._$lightboxContainer.on(\"click\",\"a:first-child\",function(a){return a.preventDefault(),g.navigateLeft()}),this._$lightboxContainer.on(\"click\",\"a:last-child\",function(a){return a.preventDefault(),g.navigateRight()}),this.updateNavigation())),this._$modal.on(\"show.bs.modal\",this._config.onShow.bind(this)).on(\"shown.bs.modal\",function(){return g._toggleLoading(!0),g._handle(),g._config.onShown.call(g)}).on(\"hide.bs.modal\",this._config.onHide.bind(this)).on(\"hidden.bs.modal\",function(){return g._galleryName&&(a(document).off(\"keydown.ekkoLightbox\"),a(window).off(\"resize.ekkoLightbox\")),g._$modal.remove(),g._config.onHidden.call(g)}).modal(this._config),a(window).on(\"resize.ekkoLightbox\",function(){g._resize(g._wantedWidth,g._wantedHeight)}),this._$lightboxContainer.on(\"touchstart\",function(){g._touchstartX=event.changedTouches[0].screenX}).on(\"touchend\",function(){g._touchendX=event.changedTouches[0].screenX,g._swipeGesure()})}return c(d,null,[{key:\"Default\",get:function(){return f}}]),c(d,[{key:\"element\",value:function(){return this._$element}},{key:\"modal\",value:function(){return this._$modal}},{key:\"navigateTo\",value:function(b){return b<0||b>this._$galleryItems.length-1?this:(this._galleryIndex=b,this.updateNavigation(),this._$element=a(this._$galleryItems.get(this._galleryIndex)),void this._handle())}},{key:\"navigateLeft\",value:function(){if(this._$galleryItems&&1!==this._$galleryItems.length){if(0===this._galleryIndex){if(!this._config.wrapping)return;this._galleryIndex=this._$galleryItems.length-1}else this._galleryIndex--;return this._config.onNavigate.call(this,\"left\",this._galleryIndex),this.navigateTo(this._galleryIndex)}}},{key:\"navigateRight\",value:function(){if(this._$galleryItems&&1!==this._$galleryItems.length){if(this._galleryIndex===this._$galleryItems.length-1){if(!this._config.wrapping)return;this._galleryIndex=0}else this._galleryIndex++;return this._config.onNavigate.call(this,\"right\",this._galleryIndex),this.navigateTo(this._galleryIndex)}}},{key:\"updateNavigation\",value:function(){if(!this._config.wrapping){var a=this._$lightboxContainer.find(\"div.ekko-lightbox-nav-overlay\");0===this._galleryIndex?a.find(\"a:first-child\").addClass(\"disabled\"):a.find(\"a:first-child\").removeClass(\"disabled\"),this._galleryIndex===this._$galleryItems.length-1?a.find(\"a:last-child\").addClass(\"disabled\"):a.find(\"a:last-child\").removeClass(\"disabled\")}}},{key:\"close\",value:function(){return this._$modal.modal(\"hide\")}},{key:\"_navigationalBinder\",value:function(a){return a=a||window.event,39===a.keyCode?this.navigateRight():37===a.keyCode?this.navigateLeft():void 0}},{key:\"_detectRemoteType\",value:function(a,b){return b=b||!1,!b&&this._isImage(a)&&(b=\"image\"),!b&&this._getYoutubeId(a)&&(b=\"youtube\"),!b&&this._getVimeoId(a)&&(b=\"vimeo\"),!b&&this._getInstagramId(a)&&(b=\"instagram\"),(!b||[\"image\",\"youtube\",\"vimeo\",\"instagram\",\"video\",\"url\"].indexOf(b)<0)&&(b=\"url\"),b}},{key:\"_isImage\",value:function(a){return a&&a.match(/(^data:image\\/.*,)|(\\.(jp(e|g|eg)|gif|png|bmp|webp|svg)((\\?|#).*)?$)/i)}},{key:\"_containerToUse\",value:function(){var a=this,b=this._$lightboxBodyTwo,c=this._$lightboxBodyOne;return this._$lightboxBodyTwo.hasClass(\"in\")&&(b=this._$lightboxBodyOne,c=this._$lightboxBodyTwo),c.removeClass(\"in show\"),setTimeout(function(){a._$lightboxBodyTwo.hasClass(\"in\")||a._$lightboxBodyTwo.empty(),a._$lightboxBodyOne.hasClass(\"in\")||a._$lightboxBodyOne.empty()},500),b.addClass(\"in show\"),b}},{key:\"_handle\",value:function(){var a=this._containerToUse();this._updateTitleAndFooter();var b=this._$element.attr(\"data-remote\")||this._$element.attr(\"href\"),c=this._detectRemoteType(b,this._$element.attr(\"data-type\")||!1);if([\"image\",\"youtube\",\"vimeo\",\"instagram\",\"video\",\"url\"].indexOf(c)<0)return this._error(this._config.strings.type);switch(c){case\"image\":this._preloadImage(b,a),this._preloadImageByIndex(this._galleryIndex,3);break;case\"youtube\":this._showYoutubeVideo(b,a);break;case\"vimeo\":this._showVimeoVideo(this._getVimeoId(b),a);break;case\"instagram\":this._showInstagramVideo(this._getInstagramId(b),a);break;case\"video\":this._showHtml5Video(b,a);break;default:this._loadRemoteContent(b,a)}return this}},{key:\"_getYoutubeId\",value:function(a){if(!a)return!1;var b=a.match(/^.*(youtu.be\\/|v\\/|u\\/\\w\\/|embed\\/|watch\\?v=|\\&v=)([^#\\&\\?]*).*/);return!(!b||11!==b[2].length)&&b[2]}},{key:\"_getVimeoId\",value:function(a){return!!(a&&a.indexOf(\"vimeo\")>0)&&a}},{key:\"_getInstagramId\",value:function(a){return!!(a&&a.indexOf(\"instagram\")>0)&&a}},{key:\"_toggleLoading\",value:function(b){return b=b||!1,b?(this._$modalDialog.css(\"display\",\"none\"),this._$modal.removeClass(\"in show\"),a(\".modal-backdrop\").append(this._config.loadingMessage)):(this._$modalDialog.css(\"display\",\"block\"),this._$modal.addClass(\"in show\"),a(\".modal-backdrop\").find(\".ekko-lightbox-loader\").remove()),this}},{key:\"_calculateBorders\",value:function(){return{top:this._totalCssByAttribute(\"border-top-width\"),right:this._totalCssByAttribute(\"border-right-width\"),bottom:this._totalCssByAttribute(\"border-bottom-width\"),left:this._totalCssByAttribute(\"border-left-width\")}}},{key:\"_calculatePadding\",value:function(){return{top:this._totalCssByAttribute(\"padding-top\"),right:this._totalCssByAttribute(\"padding-right\"),bottom:this._totalCssByAttribute(\"padding-bottom\"),left:this._totalCssByAttribute(\"padding-left\")}}},{key:\"_totalCssByAttribute\",value:function(a){return parseInt(this._$modalDialog.css(a),10)+parseInt(this._$modalContent.css(a),10)+parseInt(this._$modalBody.css(a),10)}},{key:\"_updateTitleAndFooter\",value:function(){var a=this._$element.data(\"title\")||\"\",b=this._$element.data(\"footer\")||\"\";return this._titleIsShown=!1,a||this._config.alwaysShowClose?(this._titleIsShown=!0,this._$modalHeader.css(\"display\",\"\").find(\".modal-title\").html(a||\" \")):this._$modalHeader.css(\"display\",\"none\"),this._footerIsShown=!1,b?(this._footerIsShown=!0,this._$modalFooter.css(\"display\",\"\").html(b)):this._$modalFooter.css(\"display\",\"none\"),this}},{key:\"_showYoutubeVideo\",value:function(a,b){var c=this._getYoutubeId(a),d=a.indexOf(\"&\")>0?a.substr(a.indexOf(\"&\")):\"\",e=this._$element.data(\"width\")||560,f=this._$element.data(\"height\")||e/(560/315);return this._showVideoIframe(\"//www.youtube.com/embed/\"+c+\"?badge=0&autoplay=1&html5=1\"+d,e,f,b)}},{key:\"_showVimeoVideo\",value:function(a,b){var c=this._$element.data(\"width\")||500,d=this._$element.data(\"height\")||c/(560/315);return this._showVideoIframe(a+\"?autoplay=1\",c,d,b)}},{key:\"_showInstagramVideo\",value:function(a,b){var c=this._$element.data(\"width\")||612,d=c+80;return a=\"/\"!==a.substr(-1)?a+\"/\":a,b.html(''),this._resize(c,d),this._config.onContentLoaded.call(this),this._$modalArrows&&this._$modalArrows.css(\"display\",\"none\"),this._toggleLoading(!1),this}},{key:\"_showVideoIframe\",value:function(a,b,c,d){return c=c||b,d.html('
      '),this._resize(b,c),this._config.onContentLoaded.call(this),this._$modalArrows&&this._$modalArrows.css(\"display\",\"none\"),this._toggleLoading(!1),this}},{key:\"_showHtml5Video\",value:function(a,b){var c=this._$element.data(\"width\")||560,d=this._$element.data(\"height\")||c/(560/315);return b.html('
      '),this._resize(c,d),this._config.onContentLoaded.call(this),this._$modalArrows&&this._$modalArrows.css(\"display\",\"none\"),this._toggleLoading(!1),this}},{key:\"_loadRemoteContent\",value:function(b,c){var d=this,e=this._$element.data(\"width\")||560,f=this._$element.data(\"height\")||560,g=this._$element.data(\"disableExternalCheck\")||!1;return this._toggleLoading(!1),g||this._isExternal(b)?(c.html(''),this._config.onContentLoaded.call(this)):c.load(b,a.proxy(function(){return d._$element.trigger(\"loaded.bs.modal\")})),this._$modalArrows&&this._$modalArrows.css(\"display\",\"none\"),this._resize(e,f),this}},{key:\"_isExternal\",value:function(a){var b=a.match(/^([^:\\/?#]+:)?(?:\\/\\/([^\\/?#]*))?([^?#]+)?(\\?[^#]*)?(#.*)?/);return\"string\"==typeof b[1]&&b[1].length>0&&b[1].toLowerCase()!==location.protocol||\"string\"==typeof b[2]&&b[2].length>0&&b[2].replace(new RegExp(\":(\"+{\"http:\":80,\"https:\":443}[location.protocol]+\")?$\"),\"\")!==location.host}},{key:\"_error\",value:function(a){return console.error(a),this._containerToUse().html(a),this._resize(300,300),this}},{key:\"_preloadImageByIndex\",value:function(b,c){if(this._$galleryItems){var d=a(this._$galleryItems.get(b),!1);if(\"undefined\"!=typeof d){var e=d.attr(\"data-remote\")||d.attr(\"href\");return(\"image\"===d.attr(\"data-type\")||this._isImage(e))&&this._preloadImage(e,!1),c>0?this._preloadImageByIndex(b+1,c-1):void 0}}}},{key:\"_preloadImage\",value:function(b,c){var d=this;c=c||!1;var e=new Image;return c&&!function(){var f=setTimeout(function(){c.append(d._config.loadingMessage)},200);e.onload=function(){f&&clearTimeout(f),f=null;var b=a(\"\");return b.attr(\"src\",e.src),b.addClass(\"img-fluid\"),b.css(\"width\",\"100%\"),c.html(b),d._$modalArrows&&d._$modalArrows.css(\"display\",\"\"),d._resize(e.width,e.height),d._toggleLoading(!1),d._config.onContentLoaded.call(d)},e.onerror=function(){return d._toggleLoading(!1),d._error(d._config.strings.fail+(\" \"+b))}}(),e.src=b,e}},{key:\"_swipeGesure\",value:function(){return this._touchendXthis._touchstartX?this.navigateLeft():void 0}},{key:\"_resize\",value:function(b,c){c=c||b,this._wantedWidth=b,this._wantedHeight=c;var d=b/c,e=this._padding.left+this._padding.right+this._border.left+this._border.right,f=this._config.doc.body.clientWidth>575?20:0,g=this._config.doc.body.clientWidth>575?0:20,h=Math.min(b+e,this._config.doc.body.clientWidth-f,this._config.maxWidth);b+e>h?(c=(h-e-g)/d,b=h):b+=e;var i=0,j=0;this._footerIsShown&&(j=this._$modalFooter.outerHeight(!0)||55),this._titleIsShown&&(i=this._$modalHeader.outerHeight(!0)||67);var k=this._padding.top+this._padding.bottom+this._border.bottom+this._border.top,l=parseFloat(this._$modalDialog.css(\"margin-top\"))+parseFloat(this._$modalDialog.css(\"margin-bottom\")),m=Math.min(c,a(window).height()-k-l-i-j,this._config.maxHeight-k-i-j);c>m&&(b=Math.ceil(m*d)+e),this._$lightboxContainer.css(\"height\",m),this._$modalDialog.css(\"flex\",1).css(\"maxWidth\",b);var n=this._$modal.data(\"bs.modal\");if(n)try{n._handleUpdate()}catch(o){n.handleUpdate()}return this}}],[{key:\"_jQueryInterface\",value:function(b){var c=this;return b=b||{},this.each(function(){var e=a(c),f=a.extend({},d.Default,e.data(),\"object\"==typeof b&&b);new d(c,f)})}}]),d}();return a.fn[d]=g._jQueryInterface,a.fn[d].Constructor=g,a.fn[d].noConflict=function(){return a.fn[d]=e,g._jQueryInterface},g})(jQuery)}(jQuery);\n//# sourceMappingURL=ekko-lightbox.min.js.map","/*! Copyright (c) 2011 Piotr Rochala (http://rocha.la)\n * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)\n * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.\n *\n * Version: 1.3.8\n *\n */\n(function($) {\n\n $.fn.extend({\n slimScroll: function(options) {\n\n var defaults = {\n\n // width in pixels of the visible scroll area\n width : 'auto',\n\n // height in pixels of the visible scroll area\n height : '250px',\n\n // width in pixels of the scrollbar and rail\n size : '7px',\n\n // scrollbar color, accepts any hex/color value\n color: '#000',\n\n // scrollbar position - left/right\n position : 'right',\n\n // distance in pixels between the side edge and the scrollbar\n distance : '1px',\n\n // default scroll position on load - top / bottom / $('selector')\n start : 'top',\n\n // sets scrollbar opacity\n opacity : .4,\n\n // enables always-on mode for the scrollbar\n alwaysVisible : false,\n\n // check if we should hide the scrollbar when user is hovering over\n disableFadeOut : false,\n\n // sets visibility of the rail\n railVisible : false,\n\n // sets rail color\n railColor : '#333',\n\n // sets rail opacity\n railOpacity : .2,\n\n // whether we should use jQuery UI Draggable to enable bar dragging\n railDraggable : true,\n\n // defautlt CSS class of the slimscroll rail\n railClass : 'slimScrollRail',\n\n // defautlt CSS class of the slimscroll bar\n barClass : 'slimScrollBar',\n\n // defautlt CSS class of the slimscroll wrapper\n wrapperClass : 'slimScrollDiv',\n\n // check if mousewheel should scroll the window if we reach top/bottom\n allowPageScroll : false,\n\n // scroll amount applied to each mouse wheel step\n wheelStep : 20,\n\n // scroll amount applied when user is using gestures\n touchScrollStep : 200,\n\n // sets border radius\n borderRadius: '7px',\n\n // sets border radius of the rail\n railBorderRadius : '7px'\n };\n\n var o = $.extend(defaults, options);\n\n // do it for every element that matches selector\n this.each(function(){\n\n var isOverPanel, isOverBar, isDragg, queueHide, touchDif,\n barHeight, percentScroll, lastScroll,\n divS = '
      ',\n minBarHeight = 30,\n releaseScroll = false;\n\n // used in event handlers and for better minification\n var me = $(this);\n\n // ensure we are not binding it again\n if (me.parent().hasClass(o.wrapperClass))\n {\n // start from last bar position\n var offset = me.scrollTop();\n\n // find bar and rail\n bar = me.siblings('.' + o.barClass);\n rail = me.siblings('.' + o.railClass);\n\n getBarHeight();\n\n // check if we should scroll existing instance\n if ($.isPlainObject(options))\n {\n // Pass height: auto to an existing slimscroll object to force a resize after contents have changed\n if ( 'height' in options && options.height == 'auto' ) {\n me.parent().css('height', 'auto');\n me.css('height', 'auto');\n var height = me.parent().parent().height();\n me.parent().css('height', height);\n me.css('height', height);\n } else if ('height' in options) {\n var h = options.height;\n me.parent().css('height', h);\n me.css('height', h);\n }\n\n if ('scrollTo' in options)\n {\n // jump to a static point\n offset = parseInt(o.scrollTo);\n }\n else if ('scrollBy' in options)\n {\n // jump by value pixels\n offset += parseInt(o.scrollBy);\n }\n else if ('destroy' in options)\n {\n // remove slimscroll elements\n bar.remove();\n rail.remove();\n me.unwrap();\n return;\n }\n\n // scroll content by the given offset\n scrollContent(offset, false, true);\n }\n\n return;\n }\n else if ($.isPlainObject(options))\n {\n if ('destroy' in options)\n {\n \treturn;\n }\n }\n\n // optionally set height to the parent's height\n o.height = (o.height == 'auto') ? me.parent().height() : o.height;\n\n // wrap content\n var wrapper = $(divS)\n .addClass(o.wrapperClass)\n .css({\n position: 'relative',\n overflow: 'hidden',\n width: o.width,\n height: o.height\n });\n\n // update style for the div\n me.css({\n overflow: 'hidden',\n width: o.width,\n height: o.height\n });\n\n // create scrollbar rail\n var rail = $(divS)\n .addClass(o.railClass)\n .css({\n width: o.size,\n height: '100%',\n position: 'absolute',\n top: 0,\n display: (o.alwaysVisible && o.railVisible) ? 'block' : 'none',\n 'border-radius': o.railBorderRadius,\n background: o.railColor,\n opacity: o.railOpacity,\n zIndex: 90\n });\n\n // create scrollbar\n var bar = $(divS)\n .addClass(o.barClass)\n .css({\n background: o.color,\n width: o.size,\n position: 'absolute',\n top: 0,\n opacity: o.opacity,\n display: o.alwaysVisible ? 'block' : 'none',\n 'border-radius' : o.borderRadius,\n BorderRadius: o.borderRadius,\n MozBorderRadius: o.borderRadius,\n WebkitBorderRadius: o.borderRadius,\n zIndex: 99\n });\n\n // set position\n var posCss = (o.position == 'right') ? { right: o.distance } : { left: o.distance };\n rail.css(posCss);\n bar.css(posCss);\n\n // wrap it\n me.wrap(wrapper);\n\n // append to parent div\n me.parent().append(bar);\n me.parent().append(rail);\n\n // make it draggable and no longer dependent on the jqueryUI\n if (o.railDraggable){\n bar.bind(\"mousedown\", function(e) {\n var $doc = $(document);\n isDragg = true;\n t = parseFloat(bar.css('top'));\n pageY = e.pageY;\n\n $doc.bind(\"mousemove.slimscroll\", function(e){\n currTop = t + e.pageY - pageY;\n bar.css('top', currTop);\n scrollContent(0, bar.position().top, false);// scroll content\n });\n\n $doc.bind(\"mouseup.slimscroll\", function(e) {\n isDragg = false;hideBar();\n $doc.unbind('.slimscroll');\n });\n return false;\n }).bind(\"selectstart.slimscroll\", function(e){\n e.stopPropagation();\n e.preventDefault();\n return false;\n });\n }\n\n // on rail over\n rail.hover(function(){\n showBar();\n }, function(){\n hideBar();\n });\n\n // on bar over\n bar.hover(function(){\n isOverBar = true;\n }, function(){\n isOverBar = false;\n });\n\n // show on parent mouseover\n me.hover(function(){\n isOverPanel = true;\n showBar();\n hideBar();\n }, function(){\n isOverPanel = false;\n hideBar();\n });\n\n // support for mobile\n me.bind('touchstart', function(e,b){\n if (e.originalEvent.touches.length)\n {\n // record where touch started\n touchDif = e.originalEvent.touches[0].pageY;\n }\n });\n\n me.bind('touchmove', function(e){\n // prevent scrolling the page if necessary\n if(!releaseScroll)\n {\n \t\t e.originalEvent.preventDefault();\n\t\t }\n if (e.originalEvent.touches.length)\n {\n // see how far user swiped\n var diff = (touchDif - e.originalEvent.touches[0].pageY) / o.touchScrollStep;\n // scroll content\n scrollContent(diff, true);\n touchDif = e.originalEvent.touches[0].pageY;\n }\n });\n\n // set up initial height\n getBarHeight();\n\n // check start position\n if (o.start === 'bottom')\n {\n // scroll content to bottom\n bar.css({ top: me.outerHeight() - bar.outerHeight() });\n scrollContent(0, true);\n }\n else if (o.start !== 'top')\n {\n // assume jQuery selector\n scrollContent($(o.start).position().top, null, true);\n\n // make sure bar stays hidden\n if (!o.alwaysVisible) { bar.hide(); }\n }\n\n // attach scroll events\n attachWheel(this);\n\n function _onWheel(e)\n {\n // use mouse wheel only when mouse is over\n if (!isOverPanel) { return; }\n\n var e = e || window.event;\n\n var delta = 0;\n if (e.wheelDelta) { delta = -e.wheelDelta/120; }\n if (e.detail) { delta = e.detail / 3; }\n\n var target = e.target || e.srcTarget || e.srcElement;\n if ($(target).closest('.' + o.wrapperClass).is(me.parent())) {\n // scroll content\n scrollContent(delta, true);\n }\n\n // stop window scroll\n if (e.preventDefault && !releaseScroll) { e.preventDefault(); }\n if (!releaseScroll) { e.returnValue = false; }\n }\n\n function scrollContent(y, isWheel, isJump)\n {\n releaseScroll = false;\n var delta = y;\n var maxTop = me.outerHeight() - bar.outerHeight();\n\n if (isWheel)\n {\n // move bar with mouse wheel\n delta = parseInt(bar.css('top')) + y * parseInt(o.wheelStep) / 100 * bar.outerHeight();\n\n // move bar, make sure it doesn't go out\n delta = Math.min(Math.max(delta, 0), maxTop);\n\n // if scrolling down, make sure a fractional change to the\n // scroll position isn't rounded away when the scrollbar's CSS is set\n // this flooring of delta would happened automatically when\n // bar.css is set below, but we floor here for clarity\n delta = (y > 0) ? Math.ceil(delta) : Math.floor(delta);\n\n // scroll the scrollbar\n bar.css({ top: delta + 'px' });\n }\n\n // calculate actual scroll amount\n percentScroll = parseInt(bar.css('top')) / (me.outerHeight() - bar.outerHeight());\n delta = percentScroll * (me[0].scrollHeight - me.outerHeight());\n\n if (isJump)\n {\n delta = y;\n var offsetTop = delta / me[0].scrollHeight * me.outerHeight();\n offsetTop = Math.min(Math.max(offsetTop, 0), maxTop);\n bar.css({ top: offsetTop + 'px' });\n }\n\n // scroll content\n me.scrollTop(delta);\n\n // fire scrolling event\n me.trigger('slimscrolling', ~~delta);\n\n // ensure bar is visible\n showBar();\n\n // trigger hide when scroll is stopped\n hideBar();\n }\n\n function attachWheel(target)\n {\n if (window.addEventListener)\n {\n target.addEventListener('DOMMouseScroll', _onWheel, false );\n target.addEventListener('mousewheel', _onWheel, false );\n }\n else\n {\n document.attachEvent(\"onmousewheel\", _onWheel)\n }\n }\n\n function getBarHeight()\n {\n // calculate scrollbar height and make sure it is not too small\n barHeight = Math.max((me.outerHeight() / me[0].scrollHeight) * me.outerHeight(), minBarHeight);\n bar.css({ height: barHeight + 'px' });\n\n // hide scrollbar if content is not long enough\n var display = barHeight == me.outerHeight() ? 'none' : 'block';\n bar.css({ display: display });\n }\n\n function showBar()\n {\n // recalculate bar height\n getBarHeight();\n clearTimeout(queueHide);\n\n // when bar reached top or bottom\n if (percentScroll == ~~percentScroll)\n {\n //release wheel\n releaseScroll = o.allowPageScroll;\n\n // publish approporiate event\n if (lastScroll != percentScroll)\n {\n var msg = (~~percentScroll == 0) ? 'top' : 'bottom';\n me.trigger('slimscroll', msg);\n }\n }\n else\n {\n releaseScroll = false;\n }\n lastScroll = percentScroll;\n\n // show only when required\n if(barHeight >= me.outerHeight()) {\n //allow window scroll\n releaseScroll = true;\n return;\n }\n bar.stop(true,true).fadeIn('fast');\n if (o.railVisible) { rail.stop(true,true).fadeIn('fast'); }\n }\n\n function hideBar()\n {\n // only hide when options allow it\n if (!o.alwaysVisible)\n {\n queueHide = setTimeout(function(){\n if (!(o.disableFadeOut && isOverPanel) && !isOverBar && !isDragg)\n {\n bar.fadeOut('slow');\n rail.fadeOut('slow');\n }\n }, 1000);\n }\n }\n\n });\n\n // maintain chainability\n return this;\n }\n });\n\n $.fn.extend({\n slimscroll: $.fn.slimScroll\n });\n\n})(jQuery);\n","( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"jquery\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery );\n\t}\n} )( function( $ ) {\n\"use strict\";\n\n$.ui = $.ui || {};\n\nreturn $.ui.version = \"1.14.1\";\n\n} );\n","/*!\n * jQuery UI Widget 1.14.1\n * https://jqueryui.com\n *\n * Copyright OpenJS Foundation and other contributors\n * Released under the MIT license.\n * https://jquery.org/license\n */\n\n//>>label: Widget\n//>>group: Core\n//>>description: Provides a factory for creating stateful widgets with a common API.\n//>>docs: https://api.jqueryui.com/jQuery.widget/\n//>>demos: https://jqueryui.com/widget/\n\n( function( factory ) {\n\t\"use strict\";\n\n\tif ( typeof define === \"function\" && define.amd ) {\n\n\t\t// AMD. Register as an anonymous module.\n\t\tdefine( [ \"jquery\", \"./version\" ], factory );\n\t} else {\n\n\t\t// Browser globals\n\t\tfactory( jQuery );\n\t}\n} )( function( $ ) {\n\"use strict\";\n\nvar widgetUuid = 0;\nvar widgetHasOwnProperty = Array.prototype.hasOwnProperty;\nvar widgetSlice = Array.prototype.slice;\n\n$.cleanData = ( function( orig ) {\n\treturn function( elems ) {\n\t\tvar events, elem, i;\n\t\tfor ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {\n\n\t\t\t// Only trigger remove when necessary to save time\n\t\t\tevents = $._data( elem, \"events\" );\n\t\t\tif ( events && events.remove ) {\n\t\t\t\t$( elem ).triggerHandler( \"remove\" );\n\t\t\t}\n\t\t}\n\t\torig( elems );\n\t};\n} )( $.cleanData );\n\n$.widget = function( name, base, prototype ) {\n\tvar existingConstructor, constructor, basePrototype;\n\n\t// ProxiedPrototype allows the provided prototype to remain unmodified\n\t// so that it can be used as a mixin for multiple widgets (#8876)\n\tvar proxiedPrototype = {};\n\n\tvar namespace = name.split( \".\" )[ 0 ];\n\tname = name.split( \".\" )[ 1 ];\n\tif ( name === \"__proto__\" || name === \"constructor\" ) {\n\t\treturn $.error( \"Invalid widget name: \" + name );\n\t}\n\tvar fullName = namespace + \"-\" + name;\n\n\tif ( !prototype ) {\n\t\tprototype = base;\n\t\tbase = $.Widget;\n\t}\n\n\tif ( Array.isArray( prototype ) ) {\n\t\tprototype = $.extend.apply( null, [ {} ].concat( prototype ) );\n\t}\n\n\t// Create selector for plugin\n\t$.expr.pseudos[ fullName.toLowerCase() ] = function( elem ) {\n\t\treturn !!$.data( elem, fullName );\n\t};\n\n\t$[ namespace ] = $[ namespace ] || {};\n\texistingConstructor = $[ namespace ][ name ];\n\tconstructor = $[ namespace ][ name ] = function( options, element ) {\n\n\t\t// Allow instantiation without \"new\" keyword\n\t\tif ( !this || !this._createWidget ) {\n\t\t\treturn new constructor( options, element );\n\t\t}\n\n\t\t// Allow instantiation without initializing for simple inheritance\n\t\t// must use \"new\" keyword (the code above always passes args)\n\t\tif ( arguments.length ) {\n\t\t\tthis._createWidget( options, element );\n\t\t}\n\t};\n\n\t// Extend with the existing constructor to carry over any static properties\n\t$.extend( constructor, existingConstructor, {\n\t\tversion: prototype.version,\n\n\t\t// Copy the object used to create the prototype in case we need to\n\t\t// redefine the widget later\n\t\t_proto: $.extend( {}, prototype ),\n\n\t\t// Track widgets that inherit from this widget in case this widget is\n\t\t// redefined after a widget inherits from it\n\t\t_childConstructors: []\n\t} );\n\n\tbasePrototype = new base();\n\n\t// We need to make the options hash a property directly on the new instance\n\t// otherwise we'll modify the options hash on the prototype that we're\n\t// inheriting from\n\tbasePrototype.options = $.widget.extend( {}, basePrototype.options );\n\t$.each( prototype, function( prop, value ) {\n\t\tif ( typeof value !== \"function\" ) {\n\t\t\tproxiedPrototype[ prop ] = value;\n\t\t\treturn;\n\t\t}\n\t\tproxiedPrototype[ prop ] = ( function() {\n\t\t\tfunction _super() {\n\t\t\t\treturn base.prototype[ prop ].apply( this, arguments );\n\t\t\t}\n\n\t\t\tfunction _superApply( args ) {\n\t\t\t\treturn base.prototype[ prop ].apply( this, args );\n\t\t\t}\n\n\t\t\treturn function() {\n\t\t\t\tvar __super = this._super;\n\t\t\t\tvar __superApply = this._superApply;\n\t\t\t\tvar returnValue;\n\n\t\t\t\tthis._super = _super;\n\t\t\t\tthis._superApply = _superApply;\n\n\t\t\t\treturnValue = value.apply( this, arguments );\n\n\t\t\t\tthis._super = __super;\n\t\t\t\tthis._superApply = __superApply;\n\n\t\t\t\treturn returnValue;\n\t\t\t};\n\t\t} )();\n\t} );\n\tconstructor.prototype = $.widget.extend( basePrototype, {\n\n\t\t// TODO: remove support for widgetEventPrefix\n\t\t// always use the name + a colon as the prefix, e.g., draggable:start\n\t\t// don't prefix for widgets that aren't DOM-based\n\t\twidgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name\n\t}, proxiedPrototype, {\n\t\tconstructor: constructor,\n\t\tnamespace: namespace,\n\t\twidgetName: name,\n\t\twidgetFullName: fullName\n\t} );\n\n\t// If this widget is being redefined then we need to find all widgets that\n\t// are inheriting from it and redefine all of them so that they inherit from\n\t// the new version of this widget. We're essentially trying to replace one\n\t// level in the prototype chain.\n\tif ( existingConstructor ) {\n\t\t$.each( existingConstructor._childConstructors, function( i, child ) {\n\t\t\tvar childPrototype = child.prototype;\n\n\t\t\t// Redefine the child widget using the same prototype that was\n\t\t\t// originally used, but inherit from the new version of the base\n\t\t\t$.widget( childPrototype.namespace + \".\" + childPrototype.widgetName, constructor,\n\t\t\t\tchild._proto );\n\t\t} );\n\n\t\t// Remove the list of existing child constructors from the old constructor\n\t\t// so the old child constructors can be garbage collected\n\t\tdelete existingConstructor._childConstructors;\n\t} else {\n\t\tbase._childConstructors.push( constructor );\n\t}\n\n\t$.widget.bridge( name, constructor );\n\n\treturn constructor;\n};\n\n$.widget.extend = function( target ) {\n\tvar input = widgetSlice.call( arguments, 1 );\n\tvar inputIndex = 0;\n\tvar inputLength = input.length;\n\tvar key;\n\tvar value;\n\n\tfor ( ; inputIndex < inputLength; inputIndex++ ) {\n\t\tfor ( key in input[ inputIndex ] ) {\n\t\t\tvalue = input[ inputIndex ][ key ];\n\t\t\tif ( widgetHasOwnProperty.call( input[ inputIndex ], key ) && value !== undefined ) {\n\n\t\t\t\t// Clone objects\n\t\t\t\tif ( $.isPlainObject( value ) ) {\n\t\t\t\t\ttarget[ key ] = $.isPlainObject( target[ key ] ) ?\n\t\t\t\t\t\t$.widget.extend( {}, target[ key ], value ) :\n\n\t\t\t\t\t\t// Don't extend strings, arrays, etc. with objects\n\t\t\t\t\t\t$.widget.extend( {}, value );\n\n\t\t\t\t// Copy everything else by reference\n\t\t\t\t} else {\n\t\t\t\t\ttarget[ key ] = value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn target;\n};\n\n$.widget.bridge = function( name, object ) {\n\tvar fullName = object.prototype.widgetFullName || name;\n\t$.fn[ name ] = function( options ) {\n\t\tvar isMethodCall = typeof options === \"string\";\n\t\tvar args = widgetSlice.call( arguments, 1 );\n\t\tvar returnValue = this;\n\n\t\tif ( isMethodCall ) {\n\n\t\t\t// If this is an empty collection, we need to have the instance method\n\t\t\t// return undefined instead of the jQuery instance\n\t\t\tif ( !this.length && options === \"instance\" ) {\n\t\t\t\treturnValue = undefined;\n\t\t\t} else {\n\t\t\t\tthis.each( function() {\n\t\t\t\t\tvar methodValue;\n\t\t\t\t\tvar instance = $.data( this, fullName );\n\n\t\t\t\t\tif ( options === \"instance\" ) {\n\t\t\t\t\t\treturnValue = instance;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( !instance ) {\n\t\t\t\t\t\treturn $.error( \"cannot call methods on \" + name +\n\t\t\t\t\t\t\t\" prior to initialization; \" +\n\t\t\t\t\t\t\t\"attempted to call method '\" + options + \"'\" );\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( typeof instance[ options ] !== \"function\" ||\n\t\t\t\t\t\toptions.charAt( 0 ) === \"_\" ) {\n\t\t\t\t\t\treturn $.error( \"no such method '\" + options + \"' for \" + name +\n\t\t\t\t\t\t\t\" widget instance\" );\n\t\t\t\t\t}\n\n\t\t\t\t\tmethodValue = instance[ options ].apply( instance, args );\n\n\t\t\t\t\tif ( methodValue !== instance && methodValue !== undefined ) {\n\t\t\t\t\t\treturnValue = methodValue && methodValue.jquery ?\n\t\t\t\t\t\t\treturnValue.pushStack( methodValue.get() ) :\n\t\t\t\t\t\t\tmethodValue;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t\t}\n\t\t} else {\n\n\t\t\t// Allow multiple hashes to be passed on init\n\t\t\tif ( args.length ) {\n\t\t\t\toptions = $.widget.extend.apply( null, [ options ].concat( args ) );\n\t\t\t}\n\n\t\t\tthis.each( function() {\n\t\t\t\tvar instance = $.data( this, fullName );\n\t\t\t\tif ( instance ) {\n\t\t\t\t\tinstance.option( options || {} );\n\t\t\t\t\tif ( instance._init ) {\n\t\t\t\t\t\tinstance._init();\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\t$.data( this, fullName, new object( options, this ) );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn returnValue;\n\t};\n};\n\n$.Widget = function( /* options, element */ ) {};\n$.Widget._childConstructors = [];\n\n$.Widget.prototype = {\n\twidgetName: \"widget\",\n\twidgetEventPrefix: \"\",\n\tdefaultElement: \"
      \",\n\n\toptions: {\n\t\tclasses: {},\n\t\tdisabled: false,\n\n\t\t// Callbacks\n\t\tcreate: null\n\t},\n\n\t_createWidget: function( options, element ) {\n\t\telement = $( element || this.defaultElement || this )[ 0 ];\n\t\tthis.element = $( element );\n\t\tthis.uuid = widgetUuid++;\n\t\tthis.eventNamespace = \".\" + this.widgetName + this.uuid;\n\n\t\tthis.bindings = $();\n\t\tthis.hoverable = $();\n\t\tthis.focusable = $();\n\t\tthis.classesElementLookup = {};\n\n\t\tif ( element !== this ) {\n\t\t\t$.data( element, this.widgetFullName, this );\n\t\t\tthis._on( true, this.element, {\n\t\t\t\tremove: function( event ) {\n\t\t\t\t\tif ( event.target === element ) {\n\t\t\t\t\t\tthis.destroy();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} );\n\t\t\tthis.document = $( element.style ?\n\n\t\t\t\t// Element within the document\n\t\t\t\telement.ownerDocument :\n\n\t\t\t\t// Element is window or document\n\t\t\t\telement.document || element );\n\t\t\tthis.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );\n\t\t}\n\n\t\tthis.options = $.widget.extend( {},\n\t\t\tthis.options,\n\t\t\tthis._getCreateOptions(),\n\t\t\toptions );\n\n\t\tthis._create();\n\n\t\tif ( this.options.disabled ) {\n\t\t\tthis._setOptionDisabled( this.options.disabled );\n\t\t}\n\n\t\tthis._trigger( \"create\", null, this._getCreateEventData() );\n\t\tthis._init();\n\t},\n\n\t_getCreateOptions: function() {\n\t\treturn {};\n\t},\n\n\t_getCreateEventData: $.noop,\n\n\t_create: $.noop,\n\n\t_init: $.noop,\n\n\tdestroy: function() {\n\t\tvar that = this;\n\n\t\tthis._destroy();\n\t\t$.each( this.classesElementLookup, function( key, value ) {\n\t\t\tthat._removeClass( value, key );\n\t\t} );\n\n\t\t// We can probably remove the unbind calls in 2.0\n\t\t// all event bindings should go through this._on()\n\t\tthis.element\n\t\t\t.off( this.eventNamespace )\n\t\t\t.removeData( this.widgetFullName );\n\t\tthis.widget()\n\t\t\t.off( this.eventNamespace )\n\t\t\t.removeAttr( \"aria-disabled\" );\n\n\t\t// Clean up events and states\n\t\tthis.bindings.off( this.eventNamespace );\n\t},\n\n\t_destroy: $.noop,\n\n\twidget: function() {\n\t\treturn this.element;\n\t},\n\n\toption: function( key, value ) {\n\t\tvar options = key;\n\t\tvar parts;\n\t\tvar curOption;\n\t\tvar i;\n\n\t\tif ( arguments.length === 0 ) {\n\n\t\t\t// Don't return a reference to the internal hash\n\t\t\treturn $.widget.extend( {}, this.options );\n\t\t}\n\n\t\tif ( typeof key === \"string\" ) {\n\n\t\t\t// Handle nested keys, e.g., \"foo.bar\" => { foo: { bar: ___ } }\n\t\t\toptions = {};\n\t\t\tparts = key.split( \".\" );\n\t\t\tkey = parts.shift();\n\t\t\tif ( parts.length ) {\n\t\t\t\tcurOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );\n\t\t\t\tfor ( i = 0; i < parts.length - 1; i++ ) {\n\t\t\t\t\tcurOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};\n\t\t\t\t\tcurOption = curOption[ parts[ i ] ];\n\t\t\t\t}\n\t\t\t\tkey = parts.pop();\n\t\t\t\tif ( arguments.length === 1 ) {\n\t\t\t\t\treturn curOption[ key ] === undefined ? null : curOption[ key ];\n\t\t\t\t}\n\t\t\t\tcurOption[ key ] = value;\n\t\t\t} else {\n\t\t\t\tif ( arguments.length === 1 ) {\n\t\t\t\t\treturn this.options[ key ] === undefined ? null : this.options[ key ];\n\t\t\t\t}\n\t\t\t\toptions[ key ] = value;\n\t\t\t}\n\t\t}\n\n\t\tthis._setOptions( options );\n\n\t\treturn this;\n\t},\n\n\t_setOptions: function( options ) {\n\t\tvar key;\n\n\t\tfor ( key in options ) {\n\t\t\tthis._setOption( key, options[ key ] );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t_setOption: function( key, value ) {\n\t\tif ( key === \"classes\" ) {\n\t\t\tthis._setOptionClasses( value );\n\t\t}\n\n\t\tthis.options[ key ] = value;\n\n\t\tif ( key === \"disabled\" ) {\n\t\t\tthis._setOptionDisabled( value );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\t_setOptionClasses: function( value ) {\n\t\tvar classKey, elements, currentElements;\n\n\t\tfor ( classKey in value ) {\n\t\t\tcurrentElements = this.classesElementLookup[ classKey ];\n\t\t\tif ( value[ classKey ] === this.options.classes[ classKey ] ||\n\t\t\t\t\t!currentElements ||\n\t\t\t\t\t!currentElements.length ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// We are doing this to create a new jQuery object because the _removeClass() call\n\t\t\t// on the next line is going to destroy the reference to the current elements being\n\t\t\t// tracked. We need to save a copy of this collection so that we can add the new classes\n\t\t\t// below.\n\t\t\telements = $( currentElements.get() );\n\t\t\tthis._removeClass( currentElements, classKey );\n\n\t\t\t// We don't use _addClass() here, because that uses this.options.classes\n\t\t\t// for generating the string of classes. We want to use the value passed in from\n\t\t\t// _setOption(), this is the new value of the classes option which was passed to\n\t\t\t// _setOption(). We pass this value directly to _classes().\n\t\t\telements.addClass( this._classes( {\n\t\t\t\telement: elements,\n\t\t\t\tkeys: classKey,\n\t\t\t\tclasses: value,\n\t\t\t\tadd: true\n\t\t\t} ) );\n\t\t}\n\t},\n\n\t_setOptionDisabled: function( value ) {\n\t\tthis._toggleClass( this.widget(), this.widgetFullName + \"-disabled\", null, !!value );\n\n\t\t// If the widget is becoming disabled, then nothing is interactive\n\t\tif ( value ) {\n\t\t\tthis._removeClass( this.hoverable, null, \"ui-state-hover\" );\n\t\t\tthis._removeClass( this.focusable, null, \"ui-state-focus\" );\n\t\t}\n\t},\n\n\tenable: function() {\n\t\treturn this._setOptions( { disabled: false } );\n\t},\n\n\tdisable: function() {\n\t\treturn this._setOptions( { disabled: true } );\n\t},\n\n\t_classes: function( options ) {\n\t\tvar full = [];\n\t\tvar that = this;\n\n\t\toptions = $.extend( {\n\t\t\telement: this.element,\n\t\t\tclasses: this.options.classes || {}\n\t\t}, options );\n\n\t\tfunction bindRemoveEvent() {\n\t\t\tvar nodesToBind = [];\n\n\t\t\toptions.element.each( function( _, element ) {\n\t\t\t\tvar isTracked = $.map( that.classesElementLookup, function( elements ) {\n\t\t\t\t\treturn elements;\n\t\t\t\t} )\n\t\t\t\t\t.some( function( elements ) {\n\t\t\t\t\t\treturn elements.is( element );\n\t\t\t\t\t} );\n\n\t\t\t\tif ( !isTracked ) {\n\t\t\t\t\tnodesToBind.push( element );\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\tthat._on( $( nodesToBind ), {\n\t\t\t\tremove: \"_untrackClassesElement\"\n\t\t\t} );\n\t\t}\n\n\t\tfunction processClassString( classes, checkOption ) {\n\t\t\tvar current, i;\n\t\t\tfor ( i = 0; i < classes.length; i++ ) {\n\t\t\t\tcurrent = that.classesElementLookup[ classes[ i ] ] || $();\n\t\t\t\tif ( options.add ) {\n\t\t\t\t\tbindRemoveEvent();\n\t\t\t\t\tcurrent = $( $.uniqueSort( current.get().concat( options.element.get() ) ) );\n\t\t\t\t} else {\n\t\t\t\t\tcurrent = $( current.not( options.element ).get() );\n\t\t\t\t}\n\t\t\t\tthat.classesElementLookup[ classes[ i ] ] = current;\n\t\t\t\tfull.push( classes[ i ] );\n\t\t\t\tif ( checkOption && options.classes[ classes[ i ] ] ) {\n\t\t\t\t\tfull.push( options.classes[ classes[ i ] ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif ( options.keys ) {\n\t\t\tprocessClassString( options.keys.match( /\\S+/g ) || [], true );\n\t\t}\n\t\tif ( options.extra ) {\n\t\t\tprocessClassString( options.extra.match( /\\S+/g ) || [] );\n\t\t}\n\n\t\treturn full.join( \" \" );\n\t},\n\n\t_untrackClassesElement: function( event ) {\n\t\tvar that = this;\n\t\t$.each( that.classesElementLookup, function( key, value ) {\n\t\t\tif ( $.inArray( event.target, value ) !== -1 ) {\n\t\t\t\tthat.classesElementLookup[ key ] = $( value.not( event.target ).get() );\n\t\t\t}\n\t\t} );\n\n\t\tthis._off( $( event.target ) );\n\t},\n\n\t_removeClass: function( element, keys, extra ) {\n\t\treturn this._toggleClass( element, keys, extra, false );\n\t},\n\n\t_addClass: function( element, keys, extra ) {\n\t\treturn this._toggleClass( element, keys, extra, true );\n\t},\n\n\t_toggleClass: function( element, keys, extra, add ) {\n\t\tadd = ( typeof add === \"boolean\" ) ? add : extra;\n\t\tvar shift = ( typeof element === \"string\" || element === null ),\n\t\t\toptions = {\n\t\t\t\textra: shift ? keys : extra,\n\t\t\t\tkeys: shift ? element : keys,\n\t\t\t\telement: shift ? this.element : element,\n\t\t\t\tadd: add\n\t\t\t};\n\t\toptions.element.toggleClass( this._classes( options ), add );\n\t\treturn this;\n\t},\n\n\t_on: function( suppressDisabledCheck, element, handlers ) {\n\t\tvar delegateElement;\n\t\tvar instance = this;\n\n\t\t// No suppressDisabledCheck flag, shuffle arguments\n\t\tif ( typeof suppressDisabledCheck !== \"boolean\" ) {\n\t\t\thandlers = element;\n\t\t\telement = suppressDisabledCheck;\n\t\t\tsuppressDisabledCheck = false;\n\t\t}\n\n\t\t// No element argument, shuffle and use this.element\n\t\tif ( !handlers ) {\n\t\t\thandlers = element;\n\t\t\telement = this.element;\n\t\t\tdelegateElement = this.widget();\n\t\t} else {\n\t\t\telement = delegateElement = $( element );\n\t\t\tthis.bindings = this.bindings.add( element );\n\t\t}\n\n\t\t$.each( handlers, function( event, handler ) {\n\t\t\tfunction handlerProxy() {\n\n\t\t\t\t// Allow widgets to customize the disabled handling\n\t\t\t\t// - disabled as an array instead of boolean\n\t\t\t\t// - disabled class as method for disabling individual parts\n\t\t\t\tif ( !suppressDisabledCheck &&\n\t\t\t\t\t\t( instance.options.disabled === true ||\n\t\t\t\t\t\t$( this ).hasClass( \"ui-state-disabled\" ) ) ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\treturn ( typeof handler === \"string\" ? instance[ handler ] : handler )\n\t\t\t\t\t.apply( instance, arguments );\n\t\t\t}\n\n\t\t\t// Copy the guid so direct unbinding works\n\t\t\tif ( typeof handler !== \"string\" ) {\n\t\t\t\thandlerProxy.guid = handler.guid =\n\t\t\t\t\thandler.guid || handlerProxy.guid || $.guid++;\n\t\t\t}\n\n\t\t\tvar match = event.match( /^([\\w:-]*)\\s*(.*)$/ );\n\t\t\tvar eventName = match[ 1 ] + instance.eventNamespace;\n\t\t\tvar selector = match[ 2 ];\n\n\t\t\tif ( selector ) {\n\t\t\t\tdelegateElement.on( eventName, selector, handlerProxy );\n\t\t\t} else {\n\t\t\t\telement.on( eventName, handlerProxy );\n\t\t\t}\n\t\t} );\n\t},\n\n\t_off: function( element, eventName ) {\n\t\teventName = ( eventName || \"\" ).split( \" \" ).join( this.eventNamespace + \" \" ) +\n\t\t\tthis.eventNamespace;\n\t\telement.off( eventName );\n\n\t\t// Clear the stack to avoid memory leaks (#10056)\n\t\tthis.bindings = $( this.bindings.not( element ).get() );\n\t\tthis.focusable = $( this.focusable.not( element ).get() );\n\t\tthis.hoverable = $( this.hoverable.not( element ).get() );\n\t},\n\n\t_delay: function( handler, delay ) {\n\t\tfunction handlerProxy() {\n\t\t\treturn ( typeof handler === \"string\" ? instance[ handler ] : handler )\n\t\t\t\t.apply( instance, arguments );\n\t\t}\n\t\tvar instance = this;\n\t\treturn setTimeout( handlerProxy, delay || 0 );\n\t},\n\n\t_hoverable: function( element ) {\n\t\tthis.hoverable = this.hoverable.add( element );\n\t\tthis._on( element, {\n\t\t\tmouseenter: function( event ) {\n\t\t\t\tthis._addClass( $( event.currentTarget ), null, \"ui-state-hover\" );\n\t\t\t},\n\t\t\tmouseleave: function( event ) {\n\t\t\t\tthis._removeClass( $( event.currentTarget ), null, \"ui-state-hover\" );\n\t\t\t}\n\t\t} );\n\t},\n\n\t_focusable: function( element ) {\n\t\tthis.focusable = this.focusable.add( element );\n\t\tthis._on( element, {\n\t\t\tfocusin: function( event ) {\n\t\t\t\tthis._addClass( $( event.currentTarget ), null, \"ui-state-focus\" );\n\t\t\t},\n\t\t\tfocusout: function( event ) {\n\t\t\t\tthis._removeClass( $( event.currentTarget ), null, \"ui-state-focus\" );\n\t\t\t}\n\t\t} );\n\t},\n\n\t_trigger: function( type, event, data ) {\n\t\tvar prop, orig;\n\t\tvar callback = this.options[ type ];\n\n\t\tdata = data || {};\n\t\tevent = $.Event( event );\n\t\tevent.type = ( type === this.widgetEventPrefix ?\n\t\t\ttype :\n\t\t\tthis.widgetEventPrefix + type ).toLowerCase();\n\n\t\t// The original event may come from any element\n\t\t// so we need to reset the target on the new event\n\t\tevent.target = this.element[ 0 ];\n\n\t\t// Copy original event properties over to the new event\n\t\torig = event.originalEvent;\n\t\tif ( orig ) {\n\t\t\tfor ( prop in orig ) {\n\t\t\t\tif ( !( prop in event ) ) {\n\t\t\t\t\tevent[ prop ] = orig[ prop ];\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.element.trigger( event, data );\n\t\treturn !( typeof callback === \"function\" &&\n\t\t\tcallback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||\n\t\t\tevent.isDefaultPrevented() );\n\t}\n};\n\n$.each( { show: \"fadeIn\", hide: \"fadeOut\" }, function( method, defaultEffect ) {\n\t$.Widget.prototype[ \"_\" + method ] = function( element, options, callback ) {\n\t\tif ( typeof options === \"string\" ) {\n\t\t\toptions = { effect: options };\n\t\t}\n\n\t\tvar hasOptions;\n\t\tvar effectName = !options ?\n\t\t\tmethod :\n\t\t\toptions === true || typeof options === \"number\" ?\n\t\t\t\tdefaultEffect :\n\t\t\t\toptions.effect || defaultEffect;\n\n\t\toptions = options || {};\n\t\tif ( typeof options === \"number\" ) {\n\t\t\toptions = { duration: options };\n\t\t} else if ( options === true ) {\n\t\t\toptions = {};\n\t\t}\n\n\t\thasOptions = !$.isEmptyObject( options );\n\t\toptions.complete = callback;\n\n\t\tif ( options.delay ) {\n\t\t\telement.delay( options.delay );\n\t\t}\n\n\t\tif ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {\n\t\t\telement[ method ]( options );\n\t\t} else if ( effectName !== method && element[ effectName ] ) {\n\t\t\telement[ effectName ]( options.duration, options.easing, callback );\n\t\t} else {\n\t\t\telement.queue( function( next ) {\n\t\t\t\t$( this )[ method ]();\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback.call( element[ 0 ] );\n\t\t\t\t}\n\t\t\t\tnext();\n\t\t\t} );\n\t\t}\n\t};\n} );\n\nreturn $.widget;\n\n} );\n","/*!\n * jQuery Validation Plugin v1.21.0\n *\n * https://jqueryvalidation.org/\n *\n * Copyright (c) 2024 Jörn Zaefferer\n * Released under the MIT license\n */\n(function( factory ) {\n\tif ( typeof define === \"function\" && define.amd ) {\n\t\tdefine( [\"jquery\"], factory );\n\t} else if (typeof module === \"object\" && module.exports) {\n\t\tmodule.exports = factory( require( \"jquery\" ) );\n\t} else {\n\t\tfactory( jQuery );\n\t}\n}(function( $ ) {\n\n$.extend( $.fn, {\n\n\t// https://jqueryvalidation.org/validate/\n\tvalidate: function( options ) {\n\n\t\t// If nothing is selected, return nothing; can't chain anyway\n\t\tif ( !this.length ) {\n\t\t\tif ( options && options.debug && window.console ) {\n\t\t\t\tconsole.warn( \"Nothing selected, can't validate, returning nothing.\" );\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Check if a validator for this form was already created\n\t\tvar validator = $.data( this[ 0 ], \"validator\" );\n\t\tif ( validator ) {\n\t\t\treturn validator;\n\t\t}\n\n\t\t// Add novalidate tag if HTML5.\n\t\tthis.attr( \"novalidate\", \"novalidate\" );\n\n\t\tvalidator = new $.validator( options, this[ 0 ] );\n\t\t$.data( this[ 0 ], \"validator\", validator );\n\n\t\tif ( validator.settings.onsubmit ) {\n\n\t\t\tthis.on( \"click.validate\", \":submit\", function( event ) {\n\n\t\t\t\t// Track the used submit button to properly handle scripted\n\t\t\t\t// submits later.\n\t\t\t\tvalidator.submitButton = event.currentTarget;\n\n\t\t\t\t// Allow suppressing validation by adding a cancel class to the submit button\n\t\t\t\tif ( $( this ).hasClass( \"cancel\" ) ) {\n\t\t\t\t\tvalidator.cancelSubmit = true;\n\t\t\t\t}\n\n\t\t\t\t// Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button\n\t\t\t\tif ( $( this ).attr( \"formnovalidate\" ) !== undefined ) {\n\t\t\t\t\tvalidator.cancelSubmit = true;\n\t\t\t\t}\n\t\t\t} );\n\n\t\t\t// Validate the form on submit\n\t\t\tthis.on( \"submit.validate\", function( event ) {\n\t\t\t\tif ( validator.settings.debug ) {\n\n\t\t\t\t\t// Prevent form submit to be able to see console output\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\n\t\t\t\tfunction handle() {\n\t\t\t\t\tvar hidden, result;\n\n\t\t\t\t\t// Insert a hidden input as a replacement for the missing submit button\n\t\t\t\t\t// The hidden input is inserted in two cases:\n\t\t\t\t\t// - A user defined a `submitHandler`\n\t\t\t\t\t// - There was a pending request due to `remote` method and `stopRequest()`\n\t\t\t\t\t// was called to submit the form in case it's valid\n\t\t\t\t\tif ( validator.submitButton && ( validator.settings.submitHandler || validator.formSubmitted ) ) {\n\t\t\t\t\t\thidden = $( \"\" )\n\t\t\t\t\t\t\t.attr( \"name\", validator.submitButton.name )\n\t\t\t\t\t\t\t.val( $( validator.submitButton ).val() )\n\t\t\t\t\t\t\t.appendTo( validator.currentForm );\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( validator.settings.submitHandler && !validator.settings.debug ) {\n\t\t\t\t\t\tresult = validator.settings.submitHandler.call( validator, validator.currentForm, event );\n\t\t\t\t\t\tif ( hidden ) {\n\n\t\t\t\t\t\t\t// And clean up afterwards; thanks to no-block-scope, hidden can be referenced\n\t\t\t\t\t\t\thidden.remove();\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( result !== undefined ) {\n\t\t\t\t\t\t\treturn result;\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\n\t\t\t\t// Prevent submit for invalid forms or custom submit handlers\n\t\t\t\tif ( validator.cancelSubmit ) {\n\t\t\t\t\tvalidator.cancelSubmit = false;\n\t\t\t\t\treturn handle();\n\t\t\t\t}\n\t\t\t\tif ( validator.form() ) {\n\t\t\t\t\tif ( validator.pendingRequest ) {\n\t\t\t\t\t\tvalidator.formSubmitted = true;\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t\treturn handle();\n\t\t\t\t} else {\n\t\t\t\t\tvalidator.focusInvalid();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\treturn validator;\n\t},\n\n\t// https://jqueryvalidation.org/valid/\n\tvalid: function() {\n\t\tvar valid, validator, errorList;\n\n\t\tif ( $( this[ 0 ] ).is( \"form\" ) ) {\n\t\t\tvalid = this.validate().form();\n\t\t} else {\n\t\t\terrorList = [];\n\t\t\tvalid = true;\n\t\t\tvalidator = $( this[ 0 ].form ).validate();\n\t\t\tthis.each( function() {\n\t\t\t\tvalid = validator.element( this ) && valid;\n\t\t\t\tif ( !valid ) {\n\t\t\t\t\terrorList = errorList.concat( validator.errorList );\n\t\t\t\t}\n\t\t\t} );\n\t\t\tvalidator.errorList = errorList;\n\t\t}\n\t\treturn valid;\n\t},\n\n\t// https://jqueryvalidation.org/rules/\n\trules: function( command, argument ) {\n\t\tvar element = this[ 0 ],\n\t\t\tisContentEditable = typeof this.attr( \"contenteditable\" ) !== \"undefined\" && this.attr( \"contenteditable\" ) !== \"false\",\n\t\t\tsettings, staticRules, existingRules, data, param, filtered;\n\n\t\t// If nothing is selected, return empty object; can't chain anyway\n\t\tif ( element == null ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( !element.form && isContentEditable ) {\n\t\t\telement.form = this.closest( \"form\" )[ 0 ];\n\t\t\telement.name = this.attr( \"name\" );\n\t\t}\n\n\t\tif ( element.form == null ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( command ) {\n\t\t\tsettings = $.data( element.form, \"validator\" ).settings;\n\t\t\tstaticRules = settings.rules;\n\t\t\texistingRules = $.validator.staticRules( element );\n\t\t\tswitch ( command ) {\n\t\t\tcase \"add\":\n\t\t\t\t$.extend( existingRules, $.validator.normalizeRule( argument ) );\n\n\t\t\t\t// Remove messages from rules, but allow them to be set separately\n\t\t\t\tdelete existingRules.messages;\n\t\t\t\tstaticRules[ element.name ] = existingRules;\n\t\t\t\tif ( argument.messages ) {\n\t\t\t\t\tsettings.messages[ element.name ] = $.extend( settings.messages[ element.name ], argument.messages );\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase \"remove\":\n\t\t\t\tif ( !argument ) {\n\t\t\t\t\tdelete staticRules[ element.name ];\n\t\t\t\t\treturn existingRules;\n\t\t\t\t}\n\t\t\t\tfiltered = {};\n\t\t\t\t$.each( argument.split( /\\s/ ), function( index, method ) {\n\t\t\t\t\tfiltered[ method ] = existingRules[ method ];\n\t\t\t\t\tdelete existingRules[ method ];\n\t\t\t\t} );\n\t\t\t\treturn filtered;\n\t\t\t}\n\t\t}\n\n\t\tdata = $.validator.normalizeRules(\n\t\t$.extend(\n\t\t\t{},\n\t\t\t$.validator.classRules( element ),\n\t\t\t$.validator.attributeRules( element ),\n\t\t\t$.validator.dataRules( element ),\n\t\t\t$.validator.staticRules( element )\n\t\t), element );\n\n\t\t// Make sure required is at front\n\t\tif ( data.required ) {\n\t\t\tparam = data.required;\n\t\t\tdelete data.required;\n\t\t\tdata = $.extend( { required: param }, data );\n\t\t}\n\n\t\t// Make sure remote is at back\n\t\tif ( data.remote ) {\n\t\t\tparam = data.remote;\n\t\t\tdelete data.remote;\n\t\t\tdata = $.extend( data, { remote: param } );\n\t\t}\n\n\t\treturn data;\n\t}\n} );\n\n// JQuery trim is deprecated, provide a trim method based on String.prototype.trim\nvar trim = function( str ) {\n\n\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/trim#Polyfill\n\treturn str.replace( /^[\\s\\uFEFF\\xA0]+|[\\s\\uFEFF\\xA0]+$/g, \"\" );\n};\n\n// Custom selectors\n$.extend( $.expr.pseudos || $.expr[ \":\" ], {\t\t// '|| $.expr[ \":\" ]' here enables backwards compatibility to jQuery 1.7. Can be removed when dropping jQ 1.7.x support\n\n\t// https://jqueryvalidation.org/blank-selector/\n\tblank: function( a ) {\n\t\treturn !trim( \"\" + $( a ).val() );\n\t},\n\n\t// https://jqueryvalidation.org/filled-selector/\n\tfilled: function( a ) {\n\t\tvar val = $( a ).val();\n\t\treturn val !== null && !!trim( \"\" + val );\n\t},\n\n\t// https://jqueryvalidation.org/unchecked-selector/\n\tunchecked: function( a ) {\n\t\treturn !$( a ).prop( \"checked\" );\n\t}\n} );\n\n// Constructor for validator\n$.validator = function( options, form ) {\n\tthis.settings = $.extend( true, {}, $.validator.defaults, options );\n\tthis.currentForm = form;\n\tthis.init();\n};\n\n// https://jqueryvalidation.org/jQuery.validator.format/\n$.validator.format = function( source, params ) {\n\tif ( arguments.length === 1 ) {\n\t\treturn function() {\n\t\t\tvar args = $.makeArray( arguments );\n\t\t\targs.unshift( source );\n\t\t\treturn $.validator.format.apply( this, args );\n\t\t};\n\t}\n\tif ( params === undefined ) {\n\t\treturn source;\n\t}\n\tif ( arguments.length > 2 && params.constructor !== Array ) {\n\t\tparams = $.makeArray( arguments ).slice( 1 );\n\t}\n\tif ( params.constructor !== Array ) {\n\t\tparams = [ params ];\n\t}\n\t$.each( params, function( i, n ) {\n\t\tsource = source.replace( new RegExp( \"\\\\{\" + i + \"\\\\}\", \"g\" ), function() {\n\t\t\treturn n;\n\t\t} );\n\t} );\n\treturn source;\n};\n\n$.extend( $.validator, {\n\n\tdefaults: {\n\t\tmessages: {},\n\t\tgroups: {},\n\t\trules: {},\n\t\terrorClass: \"error\",\n\t\tpendingClass: \"pending\",\n\t\tvalidClass: \"valid\",\n\t\terrorElement: \"label\",\n\t\tfocusCleanup: false,\n\t\tfocusInvalid: true,\n\t\terrorContainer: $( [] ),\n\t\terrorLabelContainer: $( [] ),\n\t\tonsubmit: true,\n\t\tignore: \":hidden\",\n\t\tignoreTitle: false,\n\t\tcustomElements: [],\n\t\tonfocusin: function( element ) {\n\t\t\tthis.lastActive = element;\n\n\t\t\t// Hide error label and remove error class on focus if enabled\n\t\t\tif ( this.settings.focusCleanup ) {\n\t\t\t\tif ( this.settings.unhighlight ) {\n\t\t\t\t\tthis.settings.unhighlight.call( this, element, this.settings.errorClass, this.settings.validClass );\n\t\t\t\t}\n\t\t\t\tthis.hideThese( this.errorsFor( element ) );\n\t\t\t}\n\t\t},\n\t\tonfocusout: function( element ) {\n\t\t\tif ( !this.checkable( element ) && ( element.name in this.submitted || !this.optional( element ) ) ) {\n\t\t\t\tthis.element( element );\n\t\t\t}\n\t\t},\n\t\tonkeyup: function( element, event ) {\n\n\t\t\t// Avoid revalidate the field when pressing one of the following keys\n\t\t\t// Shift => 16\n\t\t\t// Ctrl => 17\n\t\t\t// Alt => 18\n\t\t\t// Caps lock => 20\n\t\t\t// End => 35\n\t\t\t// Home => 36\n\t\t\t// Left arrow => 37\n\t\t\t// Up arrow => 38\n\t\t\t// Right arrow => 39\n\t\t\t// Down arrow => 40\n\t\t\t// Insert => 45\n\t\t\t// Num lock => 144\n\t\t\t// AltGr key => 225\n\t\t\tvar excludedKeys = [\n\t\t\t\t16, 17, 18, 20, 35, 36, 37,\n\t\t\t\t38, 39, 40, 45, 144, 225\n\t\t\t];\n\n\t\t\tif ( event.which === 9 && this.elementValue( element ) === \"\" || $.inArray( event.keyCode, excludedKeys ) !== -1 ) {\n\t\t\t\treturn;\n\t\t\t} else if ( element.name in this.submitted || element.name in this.invalid ) {\n\t\t\t\tthis.element( element );\n\t\t\t}\n\t\t},\n\t\tonclick: function( element ) {\n\n\t\t\t// Click on selects, radiobuttons and checkboxes\n\t\t\tif ( element.name in this.submitted ) {\n\t\t\t\tthis.element( element );\n\n\t\t\t// Or option elements, check parent select in that case\n\t\t\t} else if ( element.parentNode.name in this.submitted ) {\n\t\t\t\tthis.element( element.parentNode );\n\t\t\t}\n\t\t},\n\t\thighlight: function( element, errorClass, validClass ) {\n\t\t\tif ( element.type === \"radio\" ) {\n\t\t\t\tthis.findByName( element.name ).addClass( errorClass ).removeClass( validClass );\n\t\t\t} else {\n\t\t\t\t$( element ).addClass( errorClass ).removeClass( validClass );\n\t\t\t}\n\t\t},\n\t\tunhighlight: function( element, errorClass, validClass ) {\n\t\t\tif ( element.type === \"radio\" ) {\n\t\t\t\tthis.findByName( element.name ).removeClass( errorClass ).addClass( validClass );\n\t\t\t} else {\n\t\t\t\t$( element ).removeClass( errorClass ).addClass( validClass );\n\t\t\t}\n\t\t}\n\t},\n\n\t// https://jqueryvalidation.org/jQuery.validator.setDefaults/\n\tsetDefaults: function( settings ) {\n\t\t$.extend( $.validator.defaults, settings );\n\t},\n\n\tmessages: {\n\t\trequired: \"This field is required.\",\n\t\tremote: \"Please fix this field.\",\n\t\temail: \"Please enter a valid email address.\",\n\t\turl: \"Please enter a valid URL.\",\n\t\tdate: \"Please enter a valid date.\",\n\t\tdateISO: \"Please enter a valid date (ISO).\",\n\t\tnumber: \"Please enter a valid number.\",\n\t\tdigits: \"Please enter only digits.\",\n\t\tequalTo: \"Please enter the same value again.\",\n\t\tmaxlength: $.validator.format( \"Please enter no more than {0} characters.\" ),\n\t\tminlength: $.validator.format( \"Please enter at least {0} characters.\" ),\n\t\trangelength: $.validator.format( \"Please enter a value between {0} and {1} characters long.\" ),\n\t\trange: $.validator.format( \"Please enter a value between {0} and {1}.\" ),\n\t\tmax: $.validator.format( \"Please enter a value less than or equal to {0}.\" ),\n\t\tmin: $.validator.format( \"Please enter a value greater than or equal to {0}.\" ),\n\t\tstep: $.validator.format( \"Please enter a multiple of {0}.\" )\n\t},\n\n\tautoCreateRanges: false,\n\n\tprototype: {\n\n\t\tinit: function() {\n\t\t\tthis.labelContainer = $( this.settings.errorLabelContainer );\n\t\t\tthis.errorContext = this.labelContainer.length && this.labelContainer || $( this.currentForm );\n\t\t\tthis.containers = $( this.settings.errorContainer ).add( this.settings.errorLabelContainer );\n\t\t\tthis.submitted = {};\n\t\t\tthis.valueCache = {};\n\t\t\tthis.pendingRequest = 0;\n\t\t\tthis.pending = {};\n\t\t\tthis.invalid = {};\n\t\t\tthis.reset();\n\n\t\t\tvar currentForm = this.currentForm,\n\t\t\t\tgroups = ( this.groups = {} ),\n\t\t\t\trules;\n\t\t\t$.each( this.settings.groups, function( key, value ) {\n\t\t\t\tif ( typeof value === \"string\" ) {\n\t\t\t\t\tvalue = value.split( /\\s/ );\n\t\t\t\t}\n\t\t\t\t$.each( value, function( index, name ) {\n\t\t\t\t\tgroups[ name ] = key;\n\t\t\t\t} );\n\t\t\t} );\n\t\t\trules = this.settings.rules;\n\t\t\t$.each( rules, function( key, value ) {\n\t\t\t\trules[ key ] = $.validator.normalizeRule( value );\n\t\t\t} );\n\n\t\t\tfunction delegate( event ) {\n\t\t\t\tvar isContentEditable = typeof $( this ).attr( \"contenteditable\" ) !== \"undefined\" && $( this ).attr( \"contenteditable\" ) !== \"false\";\n\n\t\t\t\t// Set form expando on contenteditable\n\t\t\t\tif ( !this.form && isContentEditable ) {\n\t\t\t\t\tthis.form = $( this ).closest( \"form\" )[ 0 ];\n\t\t\t\t\tthis.name = $( this ).attr( \"name\" );\n\t\t\t\t}\n\n\t\t\t\t// Ignore the element if it belongs to another form. This will happen mainly\n\t\t\t\t// when setting the `form` attribute of an input to the id of another form.\n\t\t\t\tif ( currentForm !== this.form ) {\n\t\t\t\t\treturn;\n\t\t\t\t}\n\n\t\t\t\tvar validator = $.data( this.form, \"validator\" ),\n\t\t\t\t\teventType = \"on\" + event.type.replace( /^validate/, \"\" ),\n\t\t\t\t\tsettings = validator.settings;\n\t\t\t\tif ( settings[ eventType ] && !$( this ).is( settings.ignore ) ) {\n\t\t\t\t\tsettings[ eventType ].call( validator, this, event );\n\t\t\t\t}\n\t\t\t}\n\t\t\tvar focusListeners = [ \":text\", \"[type='password']\", \"[type='file']\", \"select\", \"textarea\", \"[type='number']\", \"[type='search']\",\n\t\t\t\t\t\t\t\t\"[type='tel']\", \"[type='url']\", \"[type='email']\", \"[type='datetime']\", \"[type='date']\", \"[type='month']\",\n\t\t\t\t\t\t\t\t\"[type='week']\", \"[type='time']\", \"[type='datetime-local']\", \"[type='range']\", \"[type='color']\",\n\t\t\t\t\t\t\t\t\"[type='radio']\", \"[type='checkbox']\", \"[contenteditable]\", \"[type='button']\" ];\n\t\t\tvar clickListeners = [ \"select\", \"option\", \"[type='radio']\", \"[type='checkbox']\" ];\n\t\t\t$( this.currentForm )\n\t\t\t\t.on( \"focusin.validate focusout.validate keyup.validate\", focusListeners.concat( this.settings.customElements ).join( \", \" ), delegate )\n\n\t\t\t\t// Support: Chrome, oldIE\n\t\t\t\t// \"select\" is provided as event.target when clicking a option\n\t\t\t\t.on( \"click.validate\", clickListeners.concat( this.settings.customElements ).join( \", \" ), delegate );\n\n\t\t\tif ( this.settings.invalidHandler ) {\n\t\t\t\t$( this.currentForm ).on( \"invalid-form.validate\", this.settings.invalidHandler );\n\t\t\t}\n\t\t},\n\n\t\t// https://jqueryvalidation.org/Validator.form/\n\t\tform: function() {\n\t\t\tthis.checkForm();\n\t\t\t$.extend( this.submitted, this.errorMap );\n\t\t\tthis.invalid = $.extend( {}, this.errorMap );\n\t\t\tif ( !this.valid() ) {\n\t\t\t\t$( this.currentForm ).triggerHandler( \"invalid-form\", [ this ] );\n\t\t\t}\n\t\t\tthis.showErrors();\n\t\t\treturn this.valid();\n\t\t},\n\n\t\tcheckForm: function() {\n\t\t\tthis.prepareForm();\n\t\t\tfor ( var i = 0, elements = ( this.currentElements = this.elements() ); elements[ i ]; i++ ) {\n\t\t\t\tthis.check( elements[ i ] );\n\t\t\t}\n\t\t\treturn this.valid();\n\t\t},\n\n\t\t// https://jqueryvalidation.org/Validator.element/\n\t\telement: function( element ) {\n\t\t\tvar cleanElement = this.clean( element ),\n\t\t\t\tcheckElement = this.validationTargetFor( cleanElement ),\n\t\t\t\tv = this,\n\t\t\t\tresult = true,\n\t\t\t\trs, group;\n\n\t\t\tif ( checkElement === undefined ) {\n\t\t\t\tdelete this.invalid[ cleanElement.name ];\n\t\t\t} else {\n\t\t\t\tthis.prepareElement( checkElement );\n\t\t\t\tthis.currentElements = $( checkElement );\n\n\t\t\t\t// If this element is grouped, then validate all group elements already\n\t\t\t\t// containing a value\n\t\t\t\tgroup = this.groups[ checkElement.name ];\n\t\t\t\tif ( group ) {\n\t\t\t\t\t$.each( this.groups, function( name, testgroup ) {\n\t\t\t\t\t\tif ( testgroup === group && name !== checkElement.name ) {\n\t\t\t\t\t\t\tcleanElement = v.validationTargetFor( v.clean( v.findByName( name ) ) );\n\t\t\t\t\t\t\tif ( cleanElement && cleanElement.name in v.invalid ) {\n\t\t\t\t\t\t\t\tv.currentElements.push( cleanElement );\n\t\t\t\t\t\t\t\tresult = v.check( cleanElement ) && result;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t} );\n\t\t\t\t}\n\n\t\t\t\trs = this.check( checkElement ) !== false;\n\t\t\t\tresult = result && rs;\n\t\t\t\tif ( rs ) {\n\t\t\t\t\tthis.invalid[ checkElement.name ] = false;\n\t\t\t\t} else {\n\t\t\t\t\tthis.invalid[ checkElement.name ] = true;\n\t\t\t\t}\n\n\t\t\t\tif ( !this.numberOfInvalids() ) {\n\n\t\t\t\t\t// Hide error containers on last error\n\t\t\t\t\tthis.toHide = this.toHide.add( this.containers );\n\t\t\t\t}\n\t\t\t\tthis.showErrors();\n\n\t\t\t\t// Add aria-invalid status for screen readers\n\t\t\t\t$( element ).attr( \"aria-invalid\", !rs );\n\t\t\t}\n\n\t\t\treturn result;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/Validator.showErrors/\n\t\tshowErrors: function( errors ) {\n\t\t\tif ( errors ) {\n\t\t\t\tvar validator = this;\n\n\t\t\t\t// Add items to error list and map\n\t\t\t\t$.extend( this.errorMap, errors );\n\t\t\t\tthis.errorList = $.map( this.errorMap, function( message, name ) {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tmessage: message,\n\t\t\t\t\t\telement: validator.findByName( name )[ 0 ]\n\t\t\t\t\t};\n\t\t\t\t} );\n\n\t\t\t\t// Remove items from success list\n\t\t\t\tthis.successList = $.grep( this.successList, function( element ) {\n\t\t\t\t\treturn !( element.name in errors );\n\t\t\t\t} );\n\t\t\t}\n\t\t\tif ( this.settings.showErrors ) {\n\t\t\t\tthis.settings.showErrors.call( this, this.errorMap, this.errorList );\n\t\t\t} else {\n\t\t\t\tthis.defaultShowErrors();\n\t\t\t}\n\t\t},\n\n\t\t// https://jqueryvalidation.org/Validator.resetForm/\n\t\tresetForm: function() {\n\t\t\tif ( $.fn.resetForm ) {\n\t\t\t\t$( this.currentForm ).resetForm();\n\t\t\t}\n\t\t\tthis.invalid = {};\n\t\t\tthis.submitted = {};\n\t\t\tthis.prepareForm();\n\t\t\tthis.hideErrors();\n\t\t\tvar elements = this.elements()\n\t\t\t\t.removeData( \"previousValue\" )\n\t\t\t\t.removeAttr( \"aria-invalid\" );\n\n\t\t\tthis.resetElements( elements );\n\t\t},\n\n\t\tresetElements: function( elements ) {\n\t\t\tvar i;\n\n\t\t\tif ( this.settings.unhighlight ) {\n\t\t\t\tfor ( i = 0; elements[ i ]; i++ ) {\n\t\t\t\t\tthis.settings.unhighlight.call( this, elements[ i ],\n\t\t\t\t\t\tthis.settings.errorClass, \"\" );\n\t\t\t\t\tthis.findByName( elements[ i ].name ).removeClass( this.settings.validClass );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\telements\n\t\t\t\t\t.removeClass( this.settings.errorClass )\n\t\t\t\t\t.removeClass( this.settings.validClass );\n\t\t\t}\n\t\t},\n\n\t\tnumberOfInvalids: function() {\n\t\t\treturn this.objectLength( this.invalid );\n\t\t},\n\n\t\tobjectLength: function( obj ) {\n\t\t\t/* jshint unused: false */\n\t\t\tvar count = 0,\n\t\t\t\ti;\n\t\t\tfor ( i in obj ) {\n\n\t\t\t\t// This check allows counting elements with empty error\n\t\t\t\t// message as invalid elements\n\t\t\t\tif ( obj[ i ] !== undefined && obj[ i ] !== null && obj[ i ] !== false ) {\n\t\t\t\t\tcount++;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn count;\n\t\t},\n\n\t\thideErrors: function() {\n\t\t\tthis.hideThese( this.toHide );\n\t\t},\n\n\t\thideThese: function( errors ) {\n\t\t\terrors.not( this.containers ).text( \"\" );\n\t\t\tthis.addWrapper( errors ).hide();\n\t\t},\n\n\t\tvalid: function() {\n\t\t\treturn this.size() === 0;\n\t\t},\n\n\t\tsize: function() {\n\t\t\treturn this.errorList.length;\n\t\t},\n\n\t\tfocusInvalid: function() {\n\t\t\tif ( this.settings.focusInvalid ) {\n\t\t\t\ttry {\n\t\t\t\t\t$( this.findLastActive() || this.errorList.length && this.errorList[ 0 ].element || [] )\n\t\t\t\t\t.filter( \":visible\" )\n\t\t\t\t\t.trigger( \"focus\" )\n\n\t\t\t\t\t// Manually trigger focusin event; without it, focusin handler isn't called, findLastActive won't have anything to find\n\t\t\t\t\t.trigger( \"focusin\" );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// Ignore IE throwing errors when focusing hidden elements\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\n\t\tfindLastActive: function() {\n\t\t\tvar lastActive = this.lastActive;\n\t\t\treturn lastActive && $.grep( this.errorList, function( n ) {\n\t\t\t\treturn n.element.name === lastActive.name;\n\t\t\t} ).length === 1 && lastActive;\n\t\t},\n\n\t\telements: function() {\n\t\t\tvar validator = this,\n\t\t\t\trulesCache = {},\n\t\t\t\tselectors = [ \"input\", \"select\", \"textarea\", \"[contenteditable]\" ];\n\n\t\t\t// Select all valid inputs inside the form (no submit or reset buttons)\n\t\t\treturn $( this.currentForm )\n\t\t\t.find( selectors.concat( this.settings.customElements ).join( \", \" ) )\n\t\t\t.not( \":submit, :reset, :image, :disabled\" )\n\t\t\t.not( this.settings.ignore )\n\t\t\t.filter( function() {\n\t\t\t\tvar name = this.name || $( this ).attr( \"name\" ); // For contenteditable\n\t\t\t\tvar isContentEditable = typeof $( this ).attr( \"contenteditable\" ) !== \"undefined\" && $( this ).attr( \"contenteditable\" ) !== \"false\";\n\n\t\t\t\tif ( !name && validator.settings.debug && window.console ) {\n\t\t\t\t\tconsole.error( \"%o has no name assigned\", this );\n\t\t\t\t}\n\n\t\t\t\t// Set form expando on contenteditable\n\t\t\t\tif ( isContentEditable ) {\n\t\t\t\t\tthis.form = $( this ).closest( \"form\" )[ 0 ];\n\t\t\t\t\tthis.name = name;\n\t\t\t\t}\n\n\t\t\t\t// Ignore elements that belong to other/nested forms\n\t\t\t\tif ( this.form !== validator.currentForm ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\t// Select only the first element for each name, and only those with rules specified\n\t\t\t\tif ( name in rulesCache || !validator.objectLength( $( this ).rules() ) ) {\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\n\t\t\t\trulesCache[ name ] = true;\n\t\t\t\treturn true;\n\t\t\t} );\n\t\t},\n\n\t\tclean: function( selector ) {\n\t\t\treturn $( selector )[ 0 ];\n\t\t},\n\n\t\terrors: function() {\n\t\t\tvar errorClass = this.settings.errorClass.split( \" \" ).join( \".\" );\n\t\t\treturn $( this.settings.errorElement + \".\" + errorClass, this.errorContext );\n\t\t},\n\n\t\tresetInternals: function() {\n\t\t\tthis.successList = [];\n\t\t\tthis.errorList = [];\n\t\t\tthis.errorMap = {};\n\t\t\tthis.toShow = $( [] );\n\t\t\tthis.toHide = $( [] );\n\t\t},\n\n\t\treset: function() {\n\t\t\tthis.resetInternals();\n\t\t\tthis.currentElements = $( [] );\n\t\t},\n\n\t\tprepareForm: function() {\n\t\t\tthis.reset();\n\t\t\tthis.toHide = this.errors().add( this.containers );\n\t\t},\n\n\t\tprepareElement: function( element ) {\n\t\t\tthis.reset();\n\t\t\tthis.toHide = this.errorsFor( element );\n\t\t},\n\n\t\telementValue: function( element ) {\n\t\t\tvar $element = $( element ),\n\t\t\t\ttype = element.type,\n\t\t\t\tisContentEditable = typeof $element.attr( \"contenteditable\" ) !== \"undefined\" && $element.attr( \"contenteditable\" ) !== \"false\",\n\t\t\t\tval, idx;\n\n\t\t\tif ( type === \"radio\" || type === \"checkbox\" ) {\n\t\t\t\treturn this.findByName( element.name ).filter( \":checked\" ).val();\n\t\t\t} else if ( type === \"number\" && typeof element.validity !== \"undefined\" ) {\n\t\t\t\treturn element.validity.badInput ? \"NaN\" : $element.val();\n\t\t\t}\n\n\t\t\tif ( isContentEditable ) {\n\t\t\t\tval = $element.text();\n\t\t\t} else {\n\t\t\t\tval = $element.val();\n\t\t\t}\n\n\t\t\tif ( type === \"file\" ) {\n\n\t\t\t\t// Modern browser (chrome & safari)\n\t\t\t\tif ( val.substr( 0, 12 ) === \"C:\\\\fakepath\\\\\" ) {\n\t\t\t\t\treturn val.substr( 12 );\n\t\t\t\t}\n\n\t\t\t\t// Legacy browsers\n\t\t\t\t// Unix-based path\n\t\t\t\tidx = val.lastIndexOf( \"/\" );\n\t\t\t\tif ( idx >= 0 ) {\n\t\t\t\t\treturn val.substr( idx + 1 );\n\t\t\t\t}\n\n\t\t\t\t// Windows-based path\n\t\t\t\tidx = val.lastIndexOf( \"\\\\\" );\n\t\t\t\tif ( idx >= 0 ) {\n\t\t\t\t\treturn val.substr( idx + 1 );\n\t\t\t\t}\n\n\t\t\t\t// Just the file name\n\t\t\t\treturn val;\n\t\t\t}\n\n\t\t\tif ( typeof val === \"string\" ) {\n\t\t\t\treturn val.replace( /\\r/g, \"\" );\n\t\t\t}\n\t\t\treturn val;\n\t\t},\n\n\t\tcheck: function( element ) {\n\t\t\telement = this.validationTargetFor( this.clean( element ) );\n\n\t\t\tvar rules = $( element ).rules(),\n\t\t\t\trulesCount = $.map( rules, function( n, i ) {\n\t\t\t\t\treturn i;\n\t\t\t\t} ).length,\n\t\t\t\tdependencyMismatch = false,\n\t\t\t\tval = this.elementValue( element ),\n\t\t\t\tresult, method, rule, normalizer;\n\n\t\t\t// Abort any pending Ajax request from a previous call to this method.\n\t\t\tthis.abortRequest( element );\n\n\t\t\t// Prioritize the local normalizer defined for this element over the global one\n\t\t\t// if the former exists, otherwise user the global one in case it exists.\n\t\t\tif ( typeof rules.normalizer === \"function\" ) {\n\t\t\t\tnormalizer = rules.normalizer;\n\t\t\t} else if (\ttypeof this.settings.normalizer === \"function\" ) {\n\t\t\t\tnormalizer = this.settings.normalizer;\n\t\t\t}\n\n\t\t\t// If normalizer is defined, then call it to retreive the changed value instead\n\t\t\t// of using the real one.\n\t\t\t// Note that `this` in the normalizer is `element`.\n\t\t\tif ( normalizer ) {\n\t\t\t\tval = normalizer.call( element, val );\n\n\t\t\t\t// Delete the normalizer from rules to avoid treating it as a pre-defined method.\n\t\t\t\tdelete rules.normalizer;\n\t\t\t}\n\n\t\t\tfor ( method in rules ) {\n\t\t\t\trule = { method: method, parameters: rules[ method ] };\n\t\t\t\ttry {\n\t\t\t\t\tresult = $.validator.methods[ method ].call( this, val, element, rule.parameters );\n\n\t\t\t\t\t// If a method indicates that the field is optional and therefore valid,\n\t\t\t\t\t// don't mark it as valid when there are no other rules\n\t\t\t\t\tif ( result === \"dependency-mismatch\" && rulesCount === 1 ) {\n\t\t\t\t\t\tdependencyMismatch = true;\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tdependencyMismatch = false;\n\n\t\t\t\t\tif ( result === \"pending\" ) {\n\t\t\t\t\t\tthis.toHide = this.toHide.not( this.errorsFor( element ) );\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( !result ) {\n\t\t\t\t\t\tthis.formatAndAdd( element, rule );\n\t\t\t\t\t\treturn false;\n\t\t\t\t\t}\n\t\t\t\t} catch ( e ) {\n\t\t\t\t\tif ( this.settings.debug && window.console ) {\n\t\t\t\t\t\tconsole.log( \"Exception occurred when checking element \" + element.id + \", check the '\" + rule.method + \"' method.\", e );\n\t\t\t\t\t}\n\t\t\t\t\tif ( e instanceof TypeError ) {\n\t\t\t\t\t\te.message += \". Exception occurred when checking element \" + element.id + \", check the '\" + rule.method + \"' method.\";\n\t\t\t\t\t}\n\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( dependencyMismatch ) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( this.objectLength( rules ) ) {\n\t\t\t\tthis.successList.push( element );\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\n\t\t// Return the custom message for the given element and validation method\n\t\t// specified in the element's HTML5 data attribute\n\t\t// return the generic message if present and no method specific message is present\n\t\tcustomDataMessage: function( element, method ) {\n\t\t\treturn $( element ).data( \"msg\" + method.charAt( 0 ).toUpperCase() +\n\t\t\t\tmethod.substring( 1 ).toLowerCase() ) || $( element ).data( \"msg\" );\n\t\t},\n\n\t\t// Return the custom message for the given element name and validation method\n\t\tcustomMessage: function( name, method ) {\n\t\t\tvar m = this.settings.messages[ name ];\n\t\t\treturn m && ( m.constructor === String ? m : m[ method ] );\n\t\t},\n\n\t\t// Return the first defined argument, allowing empty strings\n\t\tfindDefined: function() {\n\t\t\tfor ( var i = 0; i < arguments.length; i++ ) {\n\t\t\t\tif ( arguments[ i ] !== undefined ) {\n\t\t\t\t\treturn arguments[ i ];\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn undefined;\n\t\t},\n\n\t\t// The second parameter 'rule' used to be a string, and extended to an object literal\n\t\t// of the following form:\n\t\t// rule = {\n\t\t// method: \"method name\",\n\t\t// parameters: \"the given method parameters\"\n\t\t// }\n\t\t//\n\t\t// The old behavior still supported, kept to maintain backward compatibility with\n\t\t// old code, and will be removed in the next major release.\n\t\tdefaultMessage: function( element, rule ) {\n\t\t\tif ( typeof rule === \"string\" ) {\n\t\t\t\trule = { method: rule };\n\t\t\t}\n\n\t\t\tvar message = this.findDefined(\n\t\t\t\t\tthis.customMessage( element.name, rule.method ),\n\t\t\t\t\tthis.customDataMessage( element, rule.method ),\n\n\t\t\t\t\t// 'title' is never undefined, so handle empty string as undefined\n\t\t\t\t\t!this.settings.ignoreTitle && element.title || undefined,\n\t\t\t\t\t$.validator.messages[ rule.method ],\n\t\t\t\t\t\"Warning: No message defined for \" + element.name + \"\"\n\t\t\t\t),\n\t\t\t\ttheregex = /\\$?\\{(\\d+)\\}/g;\n\t\t\tif ( typeof message === \"function\" ) {\n\t\t\t\tmessage = message.call( this, rule.parameters, element );\n\t\t\t} else if ( theregex.test( message ) ) {\n\t\t\t\tmessage = $.validator.format( message.replace( theregex, \"{$1}\" ), rule.parameters );\n\t\t\t}\n\n\t\t\treturn message;\n\t\t},\n\n\t\tformatAndAdd: function( element, rule ) {\n\t\t\tvar message = this.defaultMessage( element, rule );\n\n\t\t\tthis.errorList.push( {\n\t\t\t\tmessage: message,\n\t\t\t\telement: element,\n\t\t\t\tmethod: rule.method\n\t\t\t} );\n\n\t\t\tthis.errorMap[ element.name ] = message;\n\t\t\tthis.submitted[ element.name ] = message;\n\t\t},\n\n\t\taddWrapper: function( toToggle ) {\n\t\t\tif ( this.settings.wrapper ) {\n\t\t\t\ttoToggle = toToggle.add( toToggle.parent( this.settings.wrapper ) );\n\t\t\t}\n\t\t\treturn toToggle;\n\t\t},\n\n\t\tdefaultShowErrors: function() {\n\t\t\tvar i, elements, error;\n\t\t\tfor ( i = 0; this.errorList[ i ]; i++ ) {\n\t\t\t\terror = this.errorList[ i ];\n\t\t\t\tif ( this.settings.highlight ) {\n\t\t\t\t\tthis.settings.highlight.call( this, error.element, this.settings.errorClass, this.settings.validClass );\n\t\t\t\t}\n\t\t\t\tthis.showLabel( error.element, error.message );\n\t\t\t}\n\t\t\tif ( this.errorList.length ) {\n\t\t\t\tthis.toShow = this.toShow.add( this.containers );\n\t\t\t}\n\t\t\tif ( this.settings.success ) {\n\t\t\t\tfor ( i = 0; this.successList[ i ]; i++ ) {\n\t\t\t\t\tthis.showLabel( this.successList[ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( this.settings.unhighlight ) {\n\t\t\t\tfor ( i = 0, elements = this.validElements(); elements[ i ]; i++ ) {\n\t\t\t\t\tthis.settings.unhighlight.call( this, elements[ i ], this.settings.errorClass, this.settings.validClass );\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.toHide = this.toHide.not( this.toShow );\n\t\t\tthis.hideErrors();\n\t\t\tthis.addWrapper( this.toShow ).show();\n\t\t},\n\n\t\tvalidElements: function() {\n\t\t\treturn this.currentElements.not( this.invalidElements() );\n\t\t},\n\n\t\tinvalidElements: function() {\n\t\t\treturn $( this.errorList ).map( function() {\n\t\t\t\treturn this.element;\n\t\t\t} );\n\t\t},\n\n\t\tshowLabel: function( element, message ) {\n\t\t\tvar place, group, errorID, v,\n\t\t\t\terror = this.errorsFor( element ),\n\t\t\t\telementID = this.idOrName( element ),\n\t\t\t\tdescribedBy = $( element ).attr( \"aria-describedby\" );\n\n\t\t\tif ( error.length ) {\n\n\t\t\t\t// Refresh error/success class\n\t\t\t\terror.removeClass( this.settings.validClass ).addClass( this.settings.errorClass );\n\n\t\t\t\t// Replace message on existing label\n\t\t\t\tif ( this.settings && this.settings.escapeHtml ) {\n\t\t\t\t\terror.text( message || \"\" );\n\t\t\t\t} else {\n\t\t\t\t\terror.html( message || \"\" );\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Create error element\n\t\t\t\terror = $( \"<\" + this.settings.errorElement + \">\" )\n\t\t\t\t\t.attr( \"id\", elementID + \"-error\" )\n\t\t\t\t\t.addClass( this.settings.errorClass );\n\n\t\t\t\tif ( this.settings && this.settings.escapeHtml ) {\n\t\t\t\t\terror.text( message || \"\" );\n\t\t\t\t} else {\n\t\t\t\t\terror.html( message || \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Maintain reference to the element to be placed into the DOM\n\t\t\t\tplace = error;\n\t\t\t\tif ( this.settings.wrapper ) {\n\n\t\t\t\t\t// Make sure the element is visible, even in IE\n\t\t\t\t\t// actually showing the wrapped element is handled elsewhere\n\t\t\t\t\tplace = error.hide().show().wrap( \"<\" + this.settings.wrapper + \"/>\" ).parent();\n\t\t\t\t}\n\t\t\t\tif ( this.labelContainer.length ) {\n\t\t\t\t\tthis.labelContainer.append( place );\n\t\t\t\t} else if ( this.settings.errorPlacement ) {\n\t\t\t\t\tthis.settings.errorPlacement.call( this, place, $( element ) );\n\t\t\t\t} else {\n\t\t\t\t\tplace.insertAfter( element );\n\t\t\t\t}\n\n\t\t\t\t// Link error back to the element\n\t\t\t\tif ( error.is( \"label\" ) ) {\n\n\t\t\t\t\t// If the error is a label, then associate using 'for'\n\t\t\t\t\terror.attr( \"for\", elementID );\n\n\t\t\t\t\t// If the element is not a child of an associated label, then it's necessary\n\t\t\t\t\t// to explicitly apply aria-describedby\n\t\t\t\t} else if ( error.parents( \"label[for='\" + this.escapeCssMeta( elementID ) + \"']\" ).length === 0 ) {\n\t\t\t\t\terrorID = error.attr( \"id\" );\n\n\t\t\t\t\t// Respect existing non-error aria-describedby\n\t\t\t\t\tif ( !describedBy ) {\n\t\t\t\t\t\tdescribedBy = errorID;\n\t\t\t\t\t} else if ( !describedBy.match( new RegExp( \"\\\\b\" + this.escapeCssMeta( errorID ) + \"\\\\b\" ) ) ) {\n\n\t\t\t\t\t\t// Add to end of list if not already present\n\t\t\t\t\t\tdescribedBy += \" \" + errorID;\n\t\t\t\t\t}\n\t\t\t\t\t$( element ).attr( \"aria-describedby\", describedBy );\n\n\t\t\t\t\t// If this element is grouped, then assign to all elements in the same group\n\t\t\t\t\tgroup = this.groups[ element.name ];\n\t\t\t\t\tif ( group ) {\n\t\t\t\t\t\tv = this;\n\t\t\t\t\t\t$.each( v.groups, function( name, testgroup ) {\n\t\t\t\t\t\t\tif ( testgroup === group ) {\n\t\t\t\t\t\t\t\t$( \"[name='\" + v.escapeCssMeta( name ) + \"']\", v.currentForm )\n\t\t\t\t\t\t\t\t\t.attr( \"aria-describedby\", error.attr( \"id\" ) );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif ( !message && this.settings.success ) {\n\t\t\t\terror.text( \"\" );\n\t\t\t\tif ( typeof this.settings.success === \"string\" ) {\n\t\t\t\t\terror.addClass( this.settings.success );\n\t\t\t\t} else {\n\t\t\t\t\tthis.settings.success( error, element );\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.toShow = this.toShow.add( error );\n\t\t},\n\n\t\terrorsFor: function( element ) {\n\t\t\tvar name = this.escapeCssMeta( this.idOrName( element ) ),\n\t\t\t\tdescriber = $( element ).attr( \"aria-describedby\" ),\n\t\t\t\tselector = \"label[for='\" + name + \"'], label[for='\" + name + \"'] *\";\n\n\t\t\t// 'aria-describedby' should directly reference the error element\n\t\t\tif ( describer ) {\n\t\t\t\tselector = selector + \", #\" + this.escapeCssMeta( describer )\n\t\t\t\t\t.replace( /\\s+/g, \", #\" );\n\t\t\t}\n\n\t\t\treturn this\n\t\t\t\t.errors()\n\t\t\t\t.filter( selector );\n\t\t},\n\n\t\t// See https://api.jquery.com/category/selectors/, for CSS\n\t\t// meta-characters that should be escaped in order to be used with JQuery\n\t\t// as a literal part of a name/id or any selector.\n\t\tescapeCssMeta: function( string ) {\n\t\t\tif ( string === undefined ) {\n\t\t\t\treturn \"\";\n\t\t\t}\n\n\t\t\treturn string.replace( /([\\\\!\"#$%&'()*+,./:;<=>?@\\[\\]^`{|}~])/g, \"\\\\$1\" );\n\t\t},\n\n\t\tidOrName: function( element ) {\n\t\t\treturn this.groups[ element.name ] || ( this.checkable( element ) ? element.name : element.id || element.name );\n\t\t},\n\n\t\tvalidationTargetFor: function( element ) {\n\n\t\t\t// If radio/checkbox, validate first element in group instead\n\t\t\tif ( this.checkable( element ) ) {\n\t\t\t\telement = this.findByName( element.name );\n\t\t\t}\n\n\t\t\t// Always apply ignore filter\n\t\t\treturn $( element ).not( this.settings.ignore )[ 0 ];\n\t\t},\n\n\t\tcheckable: function( element ) {\n\t\t\treturn ( /radio|checkbox/i ).test( element.type );\n\t\t},\n\n\t\tfindByName: function( name ) {\n\t\t\treturn $( this.currentForm ).find( \"[name='\" + this.escapeCssMeta( name ) + \"']\" );\n\t\t},\n\n\t\tgetLength: function( value, element ) {\n\t\t\tswitch ( element.nodeName.toLowerCase() ) {\n\t\t\tcase \"select\":\n\t\t\t\treturn $( \"option:selected\", element ).length;\n\t\t\tcase \"input\":\n\t\t\t\tif ( this.checkable( element ) ) {\n\t\t\t\t\treturn this.findByName( element.name ).filter( \":checked\" ).length;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn value.length;\n\t\t},\n\n\t\tdepend: function( param, element ) {\n\t\t\treturn this.dependTypes[ typeof param ] ? this.dependTypes[ typeof param ]( param, element ) : true;\n\t\t},\n\n\t\tdependTypes: {\n\t\t\t\"boolean\": function( param ) {\n\t\t\t\treturn param;\n\t\t\t},\n\t\t\t\"string\": function( param, element ) {\n\t\t\t\treturn !!$( param, element.form ).length;\n\t\t\t},\n\t\t\t\"function\": function( param, element ) {\n\t\t\t\treturn param( element );\n\t\t\t}\n\t\t},\n\n\t\toptional: function( element ) {\n\t\t\tvar val = this.elementValue( element );\n\t\t\treturn !$.validator.methods.required.call( this, val, element ) && \"dependency-mismatch\";\n\t\t},\n\n\t\telementAjaxPort: function( element ) {\n\t\t\treturn \"validate\" + element.name;\n\t\t},\n\n\t\tstartRequest: function( element ) {\n\t\t\tif ( !this.pending[ element.name ] ) {\n\t\t\t\tthis.pendingRequest++;\n\t\t\t\t$( element ).addClass( this.settings.pendingClass );\n\t\t\t\tthis.pending[ element.name ] = true;\n\t\t\t}\n\t\t},\n\n\t\tstopRequest: function( element, valid ) {\n\t\t\tthis.pendingRequest--;\n\n\t\t\t// Sometimes synchronization fails, make sure pendingRequest is never < 0\n\t\t\tif ( this.pendingRequest < 0 ) {\n\t\t\t\tthis.pendingRequest = 0;\n\t\t\t}\n\t\t\tdelete this.pending[ element.name ];\n\t\t\t$( element ).removeClass( this.settings.pendingClass );\n\t\t\tif ( valid && this.pendingRequest === 0 && this.formSubmitted && this.form() && this.pendingRequest === 0 ) {\n\t\t\t\t$( this.currentForm ).trigger( \"submit\" );\n\n\t\t\t\t// Remove the hidden input that was used as a replacement for the\n\t\t\t\t// missing submit button. The hidden input is added by `handle()`\n\t\t\t\t// to ensure that the value of the used submit button is passed on\n\t\t\t\t// for scripted submits triggered by this method\n\t\t\t\tif ( this.submitButton ) {\n\t\t\t\t\t$( \"input:hidden[name='\" + this.submitButton.name + \"']\", this.currentForm ).remove();\n\t\t\t\t}\n\n\t\t\t\tthis.formSubmitted = false;\n\t\t\t} else if ( !valid && this.pendingRequest === 0 && this.formSubmitted ) {\n\t\t\t\t$( this.currentForm ).triggerHandler( \"invalid-form\", [ this ] );\n\t\t\t\tthis.formSubmitted = false;\n\t\t\t}\n\t\t},\n\n\t\tabortRequest: function( element ) {\n\t\t\tvar port;\n\n\t\t\tif ( this.pending[ element.name ] ) {\n\t\t\t\tport = this.elementAjaxPort( element );\n\t\t\t\t$.ajaxAbort( port );\n\n\t\t\t\tthis.pendingRequest--;\n\n\t\t\t\t// Sometimes synchronization fails, make sure pendingRequest is never < 0\n\t\t\t\tif ( this.pendingRequest < 0 ) {\n\t\t\t\t\tthis.pendingRequest = 0;\n\t\t\t\t}\n\n\t\t\t\tdelete this.pending[ element.name ];\n\t\t\t\t$( element ).removeClass( this.settings.pendingClass );\n\t\t\t}\n\t\t},\n\n\t\tpreviousValue: function( element, method ) {\n\t\t\tmethod = typeof method === \"string\" && method || \"remote\";\n\n\t\t\treturn $.data( element, \"previousValue\" ) || $.data( element, \"previousValue\", {\n\t\t\t\told: null,\n\t\t\t\tvalid: true,\n\t\t\t\tmessage: this.defaultMessage( element, { method: method } )\n\t\t\t} );\n\t\t},\n\n\t\t// Cleans up all forms and elements, removes validator-specific events\n\t\tdestroy: function() {\n\t\t\tthis.resetForm();\n\n\t\t\t$( this.currentForm )\n\t\t\t\t.off( \".validate\" )\n\t\t\t\t.removeData( \"validator\" )\n\t\t\t\t.find( \".validate-equalTo-blur\" )\n\t\t\t\t\t.off( \".validate-equalTo\" )\n\t\t\t\t\t.removeClass( \"validate-equalTo-blur\" )\n\t\t\t\t.find( \".validate-lessThan-blur\" )\n\t\t\t\t\t.off( \".validate-lessThan\" )\n\t\t\t\t\t.removeClass( \"validate-lessThan-blur\" )\n\t\t\t\t.find( \".validate-lessThanEqual-blur\" )\n\t\t\t\t\t.off( \".validate-lessThanEqual\" )\n\t\t\t\t\t.removeClass( \"validate-lessThanEqual-blur\" )\n\t\t\t\t.find( \".validate-greaterThanEqual-blur\" )\n\t\t\t\t\t.off( \".validate-greaterThanEqual\" )\n\t\t\t\t\t.removeClass( \"validate-greaterThanEqual-blur\" )\n\t\t\t\t.find( \".validate-greaterThan-blur\" )\n\t\t\t\t\t.off( \".validate-greaterThan\" )\n\t\t\t\t\t.removeClass( \"validate-greaterThan-blur\" );\n\t\t}\n\n\t},\n\n\tclassRuleSettings: {\n\t\trequired: { required: true },\n\t\temail: { email: true },\n\t\turl: { url: true },\n\t\tdate: { date: true },\n\t\tdateISO: { dateISO: true },\n\t\tnumber: { number: true },\n\t\tdigits: { digits: true },\n\t\tcreditcard: { creditcard: true }\n\t},\n\n\taddClassRules: function( className, rules ) {\n\t\tif ( className.constructor === String ) {\n\t\t\tthis.classRuleSettings[ className ] = rules;\n\t\t} else {\n\t\t\t$.extend( this.classRuleSettings, className );\n\t\t}\n\t},\n\n\tclassRules: function( element ) {\n\t\tvar rules = {},\n\t\t\tclasses = $( element ).attr( \"class\" );\n\n\t\tif ( classes ) {\n\t\t\t$.each( classes.split( \" \" ), function() {\n\t\t\t\tif ( this in $.validator.classRuleSettings ) {\n\t\t\t\t\t$.extend( rules, $.validator.classRuleSettings[ this ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\t\treturn rules;\n\t},\n\n\tnormalizeAttributeRule: function( rules, type, method, value ) {\n\n\t\t// Convert the value to a number for number inputs, and for text for backwards compability\n\t\t// allows type=\"date\" and others to be compared as strings\n\t\tif ( /min|max|step/.test( method ) && ( type === null || /number|range|text/.test( type ) ) ) {\n\t\t\tvalue = Number( value );\n\n\t\t\t// Support Opera Mini, which returns NaN for undefined minlength\n\t\t\tif ( isNaN( value ) ) {\n\t\t\t\tvalue = undefined;\n\t\t\t}\n\t\t}\n\n\t\tif ( value || value === 0 ) {\n\t\t\trules[ method ] = value;\n\t\t} else if ( type === method && type !== \"range\" ) {\n\n\t\t\t// Exception: the jquery validate 'range' method\n\t\t\t// does not test for the html5 'range' type\n\t\t\trules[ type === \"date\" ? \"dateISO\" : method ] = true;\n\t\t}\n\t},\n\n\tattributeRules: function( element ) {\n\t\tvar rules = {},\n\t\t\t$element = $( element ),\n\t\t\ttype = element.getAttribute( \"type\" ),\n\t\t\tmethod, value;\n\n\t\tfor ( method in $.validator.methods ) {\n\n\t\t\t// Support for in both html5 and older browsers\n\t\t\tif ( method === \"required\" ) {\n\t\t\t\tvalue = element.getAttribute( method );\n\n\t\t\t\t// Some browsers return an empty string for the required attribute\n\t\t\t\t// and non-HTML5 browsers might have required=\"\" markup\n\t\t\t\tif ( value === \"\" ) {\n\t\t\t\t\tvalue = true;\n\t\t\t\t}\n\n\t\t\t\t// Force non-HTML5 browsers to return bool\n\t\t\t\tvalue = !!value;\n\t\t\t} else {\n\t\t\t\tvalue = $element.attr( method );\n\t\t\t}\n\n\t\t\tthis.normalizeAttributeRule( rules, type, method, value );\n\t\t}\n\n\t\t// 'maxlength' may be returned as -1, 2147483647 ( IE ) and 524288 ( safari ) for text inputs\n\t\tif ( rules.maxlength && /-1|2147483647|524288/.test( rules.maxlength ) ) {\n\t\t\tdelete rules.maxlength;\n\t\t}\n\n\t\treturn rules;\n\t},\n\n\tdataRules: function( element ) {\n\t\tvar rules = {},\n\t\t\t$element = $( element ),\n\t\t\ttype = element.getAttribute( \"type\" ),\n\t\t\tmethod, value;\n\n\t\tfor ( method in $.validator.methods ) {\n\t\t\tvalue = $element.data( \"rule\" + method.charAt( 0 ).toUpperCase() + method.substring( 1 ).toLowerCase() );\n\n\t\t\t// Cast empty attributes like `data-rule-required` to `true`\n\t\t\tif ( value === \"\" ) {\n\t\t\t\tvalue = true;\n\t\t\t}\n\n\t\t\tthis.normalizeAttributeRule( rules, type, method, value );\n\t\t}\n\t\treturn rules;\n\t},\n\n\tstaticRules: function( element ) {\n\t\tvar rules = {},\n\t\t\tvalidator = $.data( element.form, \"validator\" );\n\n\t\tif ( validator.settings.rules ) {\n\t\t\trules = $.validator.normalizeRule( validator.settings.rules[ element.name ] ) || {};\n\t\t}\n\t\treturn rules;\n\t},\n\n\tnormalizeRules: function( rules, element ) {\n\n\t\t// Handle dependency check\n\t\t$.each( rules, function( prop, val ) {\n\n\t\t\t// Ignore rule when param is explicitly false, eg. required:false\n\t\t\tif ( val === false ) {\n\t\t\t\tdelete rules[ prop ];\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif ( val.param || val.depends ) {\n\t\t\t\tvar keepRule = true;\n\t\t\t\tswitch ( typeof val.depends ) {\n\t\t\t\tcase \"string\":\n\t\t\t\t\tkeepRule = !!$( val.depends, element.form ).length;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"function\":\n\t\t\t\t\tkeepRule = val.depends.call( element, element );\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tif ( keepRule ) {\n\t\t\t\t\trules[ prop ] = val.param !== undefined ? val.param : true;\n\t\t\t\t} else {\n\t\t\t\t\t$.data( element.form, \"validator\" ).resetElements( $( element ) );\n\t\t\t\t\tdelete rules[ prop ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\t// Evaluate parameters\n\t\t$.each( rules, function( rule, parameter ) {\n\t\t\trules[ rule ] = typeof parameter === \"function\" && rule !== \"normalizer\" ? parameter( element ) : parameter;\n\t\t} );\n\n\t\t// Clean number parameters\n\t\t$.each( [ \"minlength\", \"maxlength\" ], function() {\n\t\t\tif ( rules[ this ] ) {\n\t\t\t\trules[ this ] = Number( rules[ this ] );\n\t\t\t}\n\t\t} );\n\t\t$.each( [ \"rangelength\", \"range\" ], function() {\n\t\t\tvar parts;\n\t\t\tif ( rules[ this ] ) {\n\t\t\t\tif ( Array.isArray( rules[ this ] ) ) {\n\t\t\t\t\trules[ this ] = [ Number( rules[ this ][ 0 ] ), Number( rules[ this ][ 1 ] ) ];\n\t\t\t\t} else if ( typeof rules[ this ] === \"string\" ) {\n\t\t\t\t\tparts = rules[ this ].replace( /[\\[\\]]/g, \"\" ).split( /[\\s,]+/ );\n\t\t\t\t\trules[ this ] = [ Number( parts[ 0 ] ), Number( parts[ 1 ] ) ];\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\n\t\tif ( $.validator.autoCreateRanges ) {\n\n\t\t\t// Auto-create ranges\n\t\t\tif ( rules.min != null && rules.max != null ) {\n\t\t\t\trules.range = [ rules.min, rules.max ];\n\t\t\t\tdelete rules.min;\n\t\t\t\tdelete rules.max;\n\t\t\t}\n\t\t\tif ( rules.minlength != null && rules.maxlength != null ) {\n\t\t\t\trules.rangelength = [ rules.minlength, rules.maxlength ];\n\t\t\t\tdelete rules.minlength;\n\t\t\t\tdelete rules.maxlength;\n\t\t\t}\n\t\t}\n\n\t\treturn rules;\n\t},\n\n\t// Converts a simple string to a {string: true} rule, e.g., \"required\" to {required:true}\n\tnormalizeRule: function( data ) {\n\t\tif ( typeof data === \"string\" ) {\n\t\t\tvar transformed = {};\n\t\t\t$.each( data.split( /\\s/ ), function() {\n\t\t\t\ttransformed[ this ] = true;\n\t\t\t} );\n\t\t\tdata = transformed;\n\t\t}\n\t\treturn data;\n\t},\n\n\t// https://jqueryvalidation.org/jQuery.validator.addMethod/\n\taddMethod: function( name, method, message ) {\n\t\t$.validator.methods[ name ] = method;\n\t\t$.validator.messages[ name ] = message !== undefined ? message : $.validator.messages[ name ];\n\t\tif ( method.length < 3 ) {\n\t\t\t$.validator.addClassRules( name, $.validator.normalizeRule( name ) );\n\t\t}\n\t},\n\n\t// https://jqueryvalidation.org/jQuery.validator.methods/\n\tmethods: {\n\n\t\t// https://jqueryvalidation.org/required-method/\n\t\trequired: function( value, element, param ) {\n\n\t\t\t// Check if dependency is met\n\t\t\tif ( !this.depend( param, element ) ) {\n\t\t\t\treturn \"dependency-mismatch\";\n\t\t\t}\n\t\t\tif ( element.nodeName.toLowerCase() === \"select\" ) {\n\n\t\t\t\t// Could be an array for select-multiple or a string, both are fine this way\n\t\t\t\tvar val = $( element ).val();\n\t\t\t\treturn val && val.length > 0;\n\t\t\t}\n\t\t\tif ( this.checkable( element ) ) {\n\t\t\t\treturn this.getLength( value, element ) > 0;\n\t\t\t}\n\t\t\treturn value !== undefined && value !== null && value.length > 0;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/email-method/\n\t\temail: function( value, element ) {\n\n\t\t\t// From https://html.spec.whatwg.org/multipage/forms.html#valid-e-mail-address\n\t\t\t// Retrieved 2014-01-14\n\t\t\t// If you have a problem with this implementation, report a bug against the above spec\n\t\t\t// Or use custom methods to implement your own email validation\n\t\t\treturn this.optional( element ) || /^[a-zA-Z0-9.!#$%&'*+\\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/url-method/\n\t\turl: function( value, element ) {\n\n\t\t\t// Copyright (c) 2010-2013 Diego Perini, MIT licensed\n\t\t\t// https://gist.github.com/dperini/729294\n\t\t\t// see also https://mathiasbynens.be/demo/url-regex\n\t\t\t// modified to allow protocol-relative URLs\n\t\t\treturn this.optional( element ) || /^(?:(?:(?:https?|ftp):)?\\/\\/)(?:(?:[^\\]\\[?\\/<~#`!@$^&*()+=}|:\";',>{ ]|%[0-9A-Fa-f]{2})+(?::(?:[^\\]\\[?\\/<~#`!@$^&*()+=}|:\";',>{ ]|%[0-9A-Fa-f]{2})*)?@)?(?:(?!(?:10|127)(?:\\.\\d{1,3}){3})(?!(?:169\\.254|192\\.168)(?:\\.\\d{1,3}){2})(?!172\\.(?:1[6-9]|2\\d|3[0-1])(?:\\.\\d{1,3}){2})(?:[1-9]\\d?|1\\d\\d|2[01]\\d|22[0-3])(?:\\.(?:1?\\d{1,2}|2[0-4]\\d|25[0-5])){2}(?:\\.(?:[1-9]\\d?|1\\d\\d|2[0-4]\\d|25[0-4]))|(?:(?:[a-z0-9\\u00a1-\\uffff][a-z0-9\\u00a1-\\uffff_-]{0,62})?[a-z0-9\\u00a1-\\uffff]\\.)+(?:[a-z\\u00a1-\\uffff]{2,}\\.?))(?::\\d{2,5})?(?:[/?#]\\S*)?$/i.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/date-method/\n\t\tdate: ( function() {\n\t\t\tvar called = false;\n\n\t\t\treturn function( value, element ) {\n\t\t\t\tif ( !called ) {\n\t\t\t\t\tcalled = true;\n\t\t\t\t\tif ( this.settings.debug && window.console ) {\n\t\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t\t\"The `date` method is deprecated and will be removed in version '2.0.0'.\\n\" +\n\t\t\t\t\t\t\t\"Please don't use it, since it relies on the Date constructor, which\\n\" +\n\t\t\t\t\t\t\t\"behaves very differently across browsers and locales. Use `dateISO`\\n\" +\n\t\t\t\t\t\t\t\"instead or one of the locale specific methods in `localizations/`\\n\" +\n\t\t\t\t\t\t\t\"and `additional-methods.js`.\"\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn this.optional( element ) || !/Invalid|NaN/.test( new Date( value ).toString() );\n\t\t\t};\n\t\t}() ),\n\n\t\t// https://jqueryvalidation.org/dateISO-method/\n\t\tdateISO: function( value, element ) {\n\t\t\treturn this.optional( element ) || /^\\d{4}[\\/\\-](0?[1-9]|1[012])[\\/\\-](0?[1-9]|[12][0-9]|3[01])$/.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/number-method/\n\t\tnumber: function( value, element ) {\n\t\t\treturn this.optional( element ) || /^(?:-?\\d+|-?\\d{1,3}(?:,\\d{3})+)?(?:-?\\.\\d+)?$/.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/digits-method/\n\t\tdigits: function( value, element ) {\n\t\t\treturn this.optional( element ) || /^\\d+$/.test( value );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/minlength-method/\n\t\tminlength: function( value, element, param ) {\n\t\t\tvar length = Array.isArray( value ) ? value.length : this.getLength( value, element );\n\t\t\treturn this.optional( element ) || length >= param;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/maxlength-method/\n\t\tmaxlength: function( value, element, param ) {\n\t\t\tvar length = Array.isArray( value ) ? value.length : this.getLength( value, element );\n\t\t\treturn this.optional( element ) || length <= param;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/rangelength-method/\n\t\trangelength: function( value, element, param ) {\n\t\t\tvar length = Array.isArray( value ) ? value.length : this.getLength( value, element );\n\t\t\treturn this.optional( element ) || ( length >= param[ 0 ] && length <= param[ 1 ] );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/min-method/\n\t\tmin: function( value, element, param ) {\n\t\t\treturn this.optional( element ) || value >= param;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/max-method/\n\t\tmax: function( value, element, param ) {\n\t\t\treturn this.optional( element ) || value <= param;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/range-method/\n\t\trange: function( value, element, param ) {\n\t\t\treturn this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );\n\t\t},\n\n\t\t// https://jqueryvalidation.org/step-method/\n\t\tstep: function( value, element, param ) {\n\t\t\tvar type = $( element ).attr( \"type\" ),\n\t\t\t\terrorMessage = \"Step attribute on input type \" + type + \" is not supported.\",\n\t\t\t\tsupportedTypes = [ \"text\", \"number\", \"range\" ],\n\t\t\t\tre = new RegExp( \"\\\\b\" + type + \"\\\\b\" ),\n\t\t\t\tnotSupported = type && !re.test( supportedTypes.join() ),\n\t\t\t\tdecimalPlaces = function( num ) {\n\t\t\t\t\tvar match = ( \"\" + num ).match( /(?:\\.(\\d+))?$/ );\n\t\t\t\t\tif ( !match ) {\n\t\t\t\t\t\treturn 0;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Number of digits right of decimal point.\n\t\t\t\t\treturn match[ 1 ] ? match[ 1 ].length : 0;\n\t\t\t\t},\n\t\t\t\ttoInt = function( num ) {\n\t\t\t\t\treturn Math.round( num * Math.pow( 10, decimals ) );\n\t\t\t\t},\n\t\t\t\tvalid = true,\n\t\t\t\tdecimals;\n\n\t\t\t// Works only for text, number and range input types\n\t\t\t// TODO find a way to support input types date, datetime, datetime-local, month, time and week\n\t\t\tif ( notSupported ) {\n\t\t\t\tthrow new Error( errorMessage );\n\t\t\t}\n\n\t\t\tdecimals = decimalPlaces( param );\n\n\t\t\t// Value can't have too many decimals\n\t\t\tif ( decimalPlaces( value ) > decimals || toInt( value ) % toInt( param ) !== 0 ) {\n\t\t\t\tvalid = false;\n\t\t\t}\n\n\t\t\treturn this.optional( element ) || valid;\n\t\t},\n\n\t\t// https://jqueryvalidation.org/equalTo-method/\n\t\tequalTo: function( value, element, param ) {\n\n\t\t\t// Bind to the blur event of the target in order to revalidate whenever the target field is updated\n\t\t\tvar target = $( param );\n\t\t\tif ( this.settings.onfocusout && target.not( \".validate-equalTo-blur\" ).length ) {\n\t\t\t\ttarget.addClass( \"validate-equalTo-blur\" ).on( \"blur.validate-equalTo\", function() {\n\t\t\t\t\t$( element ).valid();\n\t\t\t\t} );\n\t\t\t}\n\t\t\treturn value === target.val();\n\t\t},\n\n\t\t// https://jqueryvalidation.org/remote-method/\n\t\tremote: function( value, element, param, method ) {\n\t\t\tif ( this.optional( element ) ) {\n\t\t\t\treturn \"dependency-mismatch\";\n\t\t\t}\n\n\t\t\tmethod = typeof method === \"string\" && method || \"remote\";\n\n\t\t\tvar previous = this.previousValue( element, method ),\n\t\t\t\tvalidator, data, optionDataString;\n\n\t\t\tif ( !this.settings.messages[ element.name ] ) {\n\t\t\t\tthis.settings.messages[ element.name ] = {};\n\t\t\t}\n\t\t\tprevious.originalMessage = previous.originalMessage || this.settings.messages[ element.name ][ method ];\n\t\t\tthis.settings.messages[ element.name ][ method ] = previous.message;\n\n\t\t\tparam = typeof param === \"string\" && { url: param } || param;\n\t\t\toptionDataString = $.param( $.extend( { data: value }, param.data ) );\n\t\t\tif ( previous.valid !== null && previous.old === optionDataString ) {\n\t\t\t\treturn previous.valid;\n\t\t\t}\n\n\t\t\tprevious.old = optionDataString;\n\t\t\tprevious.valid = null;\n\t\t\tvalidator = this;\n\t\t\tthis.startRequest( element );\n\t\t\tdata = {};\n\t\t\tdata[ element.name ] = value;\n\t\t\t$.ajax( $.extend( true, {\n\t\t\t\tmode: \"abort\",\n\t\t\t\tport: this.elementAjaxPort( element ),\n\t\t\t\tdataType: \"json\",\n\t\t\t\tdata: data,\n\t\t\t\tcontext: validator.currentForm,\n\t\t\t\tsuccess: function( response ) {\n\t\t\t\t\tvar valid = response === true || response === \"true\",\n\t\t\t\t\t\terrors, message, submitted;\n\n\t\t\t\t\tvalidator.settings.messages[ element.name ][ method ] = previous.originalMessage;\n\t\t\t\t\tif ( valid ) {\n\t\t\t\t\t\tsubmitted = validator.formSubmitted;\n\t\t\t\t\t\tvalidator.toHide = validator.errorsFor( element );\n\t\t\t\t\t\tvalidator.formSubmitted = submitted;\n\t\t\t\t\t\tvalidator.successList.push( element );\n\t\t\t\t\t\tvalidator.invalid[ element.name ] = false;\n\t\t\t\t\t\tvalidator.showErrors();\n\t\t\t\t\t} else {\n\t\t\t\t\t\terrors = {};\n\t\t\t\t\t\tmessage = response || validator.defaultMessage( element, { method: method, parameters: value } );\n\t\t\t\t\t\terrors[ element.name ] = previous.message = message;\n\t\t\t\t\t\tvalidator.invalid[ element.name ] = true;\n\t\t\t\t\t\tvalidator.showErrors( errors );\n\t\t\t\t\t}\n\t\t\t\t\tprevious.valid = valid;\n\t\t\t\t\tvalidator.stopRequest( element, valid );\n\t\t\t\t}\n\t\t\t}, param ) );\n\t\t\treturn \"pending\";\n\t\t}\n\t}\n\n} );\n\n// Ajax mode: abort\n// usage: $.ajax({ mode: \"abort\"[, port: \"uniqueport\"]});\n// $.ajaxAbort( port );\n// if mode:\"abort\" is used, the previous request on that port (port can be undefined) is aborted via XMLHttpRequest.abort()\n\nvar pendingRequests = {},\n\tajax;\n\n// Use a prefilter if available (1.5+)\nif ( $.ajaxPrefilter ) {\n\t$.ajaxPrefilter( function( settings, _, xhr ) {\n\t\tvar port = settings.port;\n\t\tif ( settings.mode === \"abort\" ) {\n\t\t\t$.ajaxAbort( port );\n\t\t\tpendingRequests[ port ] = xhr;\n\t\t}\n\t} );\n} else {\n\n\t// Proxy ajax\n\tajax = $.ajax;\n\t$.ajax = function( settings ) {\n\t\tvar mode = ( \"mode\" in settings ? settings : $.ajaxSettings ).mode,\n\t\t\tport = ( \"port\" in settings ? settings : $.ajaxSettings ).port;\n\t\tif ( mode === \"abort\" ) {\n\t\t\t$.ajaxAbort( port );\n\t\t\tpendingRequests[ port ] = ajax.apply( this, arguments );\n\t\t\treturn pendingRequests[ port ];\n\t\t}\n\t\treturn ajax.apply( this, arguments );\n\t};\n}\n\n// Abort the previous request without sending a new one\n$.ajaxAbort = function( port ) {\n\tif ( pendingRequests[ port ] ) {\n\t\tpendingRequests[ port ].abort();\n\t\tdelete pendingRequests[ port ];\n\t}\n};\nreturn $;\n}));","// This [jQuery](https://jquery.com/) plugin implements an `\");\n\n // The first load event gets fired after the iframe has been injected\n // into the DOM, and is used to prepare the actual submission.\n iframe.one(\"load\", function() {\n\n // The second load event gets fired when the response to the form\n // submission is received. The implementation detects whether the\n // actual payload is embedded in a `\";\n\tsupport.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;\n\n\t// Support: IE <=9 only\n\t// IE <=9 replaces \";\n\tsupport.option = !!div.lastChild;\n} )();\n\n\n// We have to close these tags to support XHTML (#13200)\nvar wrapMap = {\n\n\t// XHTML parsers do not magically insert elements in the\n\t// same way that tag soup parsers do. So we cannot shorten\n\t// this by omitting or other required elements.\n\tthead: [ 1, \"\", \"
      \" ],\n\tcol: [ 2, \"\", \"
      \" ],\n\ttr: [ 2, \"\", \"
      \" ],\n\ttd: [ 3, \"\", \"
      \" ],\n\n\t_default: [ 0, \"\", \"\" ]\n};\n\nwrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;\nwrapMap.th = wrapMap.td;\n\n// Support: IE <=9 only\nif ( !support.option ) {\n\twrapMap.optgroup = wrapMap.option = [ 1, \"\" ];\n}\n\n\nfunction getAll( context, tag ) {\n\n\t// Support: IE <=9 - 11 only\n\t// Use typeof to avoid zero-argument method invocation on host objects (#15151)\n\tvar ret;\n\n\tif ( typeof context.getElementsByTagName !== \"undefined\" ) {\n\t\tret = context.getElementsByTagName( tag || \"*\" );\n\n\t} else if ( typeof context.querySelectorAll !== \"undefined\" ) {\n\t\tret = context.querySelectorAll( tag || \"*\" );\n\n\t} else {\n\t\tret = [];\n\t}\n\n\tif ( tag === undefined || tag && nodeName( context, tag ) ) {\n\t\treturn jQuery.merge( [ context ], ret );\n\t}\n\n\treturn ret;\n}\n\n\n// Mark scripts as having already been evaluated\nfunction setGlobalEval( elems, refElements ) {\n\tvar i = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\tdataPriv.set(\n\t\t\telems[ i ],\n\t\t\t\"globalEval\",\n\t\t\t!refElements || dataPriv.get( refElements[ i ], \"globalEval\" )\n\t\t);\n\t}\n}\n\n\nvar rhtml = /<|&#?\\w+;/;\n\nfunction buildFragment( elems, context, scripts, selection, ignored ) {\n\tvar elem, tmp, tag, wrap, attached, j,\n\t\tfragment = context.createDocumentFragment(),\n\t\tnodes = [],\n\t\ti = 0,\n\t\tl = elems.length;\n\n\tfor ( ; i < l; i++ ) {\n\t\telem = elems[ i ];\n\n\t\tif ( elem || elem === 0 ) {\n\n\t\t\t// Add nodes directly\n\t\t\tif ( toType( elem ) === \"object\" ) {\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );\n\n\t\t\t// Convert non-html into a text node\n\t\t\t} else if ( !rhtml.test( elem ) ) {\n\t\t\t\tnodes.push( context.createTextNode( elem ) );\n\n\t\t\t// Convert html into DOM nodes\n\t\t\t} else {\n\t\t\t\ttmp = tmp || fragment.appendChild( context.createElement( \"div\" ) );\n\n\t\t\t\t// Deserialize a standard representation\n\t\t\t\ttag = ( rtagName.exec( elem ) || [ \"\", \"\" ] )[ 1 ].toLowerCase();\n\t\t\t\twrap = wrapMap[ tag ] || wrapMap._default;\n\t\t\t\ttmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];\n\n\t\t\t\t// Descend through wrappers to the right content\n\t\t\t\tj = wrap[ 0 ];\n\t\t\t\twhile ( j-- ) {\n\t\t\t\t\ttmp = tmp.lastChild;\n\t\t\t\t}\n\n\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\tjQuery.merge( nodes, tmp.childNodes );\n\n\t\t\t\t// Remember the top-level container\n\t\t\t\ttmp = fragment.firstChild;\n\n\t\t\t\t// Ensure the created nodes are orphaned (#12392)\n\t\t\t\ttmp.textContent = \"\";\n\t\t\t}\n\t\t}\n\t}\n\n\t// Remove wrapper from fragment\n\tfragment.textContent = \"\";\n\n\ti = 0;\n\twhile ( ( elem = nodes[ i++ ] ) ) {\n\n\t\t// Skip elements already in the context collection (trac-4087)\n\t\tif ( selection && jQuery.inArray( elem, selection ) > -1 ) {\n\t\t\tif ( ignored ) {\n\t\t\t\tignored.push( elem );\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\n\t\tattached = isAttached( elem );\n\n\t\t// Append to fragment\n\t\ttmp = getAll( fragment.appendChild( elem ), \"script\" );\n\n\t\t// Preserve script evaluation history\n\t\tif ( attached ) {\n\t\t\tsetGlobalEval( tmp );\n\t\t}\n\n\t\t// Capture executables\n\t\tif ( scripts ) {\n\t\t\tj = 0;\n\t\t\twhile ( ( elem = tmp[ j++ ] ) ) {\n\t\t\t\tif ( rscriptType.test( elem.type || \"\" ) ) {\n\t\t\t\t\tscripts.push( elem );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn fragment;\n}\n\n\nvar\n\trkeyEvent = /^key/,\n\trmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,\n\trtypenamespace = /^([^.]*)(?:\\.(.+)|)/;\n\nfunction returnTrue() {\n\treturn true;\n}\n\nfunction returnFalse() {\n\treturn false;\n}\n\n// Support: IE <=9 - 11+\n// focus() and blur() are asynchronous, except when they are no-op.\n// So expect focus to be synchronous when the element is already active,\n// and blur to be synchronous when the element is not already active.\n// (focus and blur are always synchronous in other supported browsers,\n// this just defines when we can count on it).\nfunction expectSync( elem, type ) {\n\treturn ( elem === safeActiveElement() ) === ( type === \"focus\" );\n}\n\n// Support: IE <=9 only\n// Accessing document.activeElement can throw unexpectedly\n// https://bugs.jquery.com/ticket/13393\nfunction safeActiveElement() {\n\ttry {\n\t\treturn document.activeElement;\n\t} catch ( err ) { }\n}\n\nfunction on( elem, types, selector, data, fn, one ) {\n\tvar origFn, type;\n\n\t// Types can be a map of types/handlers\n\tif ( typeof types === \"object\" ) {\n\n\t\t// ( types-Object, selector, data )\n\t\tif ( typeof selector !== \"string\" ) {\n\n\t\t\t// ( types-Object, data )\n\t\t\tdata = data || selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tfor ( type in types ) {\n\t\t\ton( elem, type, selector, data, types[ type ], one );\n\t\t}\n\t\treturn elem;\n\t}\n\n\tif ( data == null && fn == null ) {\n\n\t\t// ( types, fn )\n\t\tfn = selector;\n\t\tdata = selector = undefined;\n\t} else if ( fn == null ) {\n\t\tif ( typeof selector === \"string\" ) {\n\n\t\t\t// ( types, selector, fn )\n\t\t\tfn = data;\n\t\t\tdata = undefined;\n\t\t} else {\n\n\t\t\t// ( types, data, fn )\n\t\t\tfn = data;\n\t\t\tdata = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t}\n\tif ( fn === false ) {\n\t\tfn = returnFalse;\n\t} else if ( !fn ) {\n\t\treturn elem;\n\t}\n\n\tif ( one === 1 ) {\n\t\torigFn = fn;\n\t\tfn = function( event ) {\n\n\t\t\t// Can use an empty set, since event contains the info\n\t\t\tjQuery().off( event );\n\t\t\treturn origFn.apply( this, arguments );\n\t\t};\n\n\t\t// Use same guid so caller can remove using origFn\n\t\tfn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );\n\t}\n\treturn elem.each( function() {\n\t\tjQuery.event.add( this, types, fn, data, selector );\n\t} );\n}\n\n/*\n * Helper functions for managing events -- not part of the public interface.\n * Props to Dean Edwards' addEvent library for many of the ideas.\n */\njQuery.event = {\n\n\tglobal: {},\n\n\tadd: function( elem, types, handler, data, selector ) {\n\n\t\tvar handleObjIn, eventHandle, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.get( elem );\n\n\t\t// Only attach events to objects that accept data\n\t\tif ( !acceptData( elem ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Caller can pass in an object of custom data in lieu of the handler\n\t\tif ( handler.handler ) {\n\t\t\thandleObjIn = handler;\n\t\t\thandler = handleObjIn.handler;\n\t\t\tselector = handleObjIn.selector;\n\t\t}\n\n\t\t// Ensure that invalid selectors throw exceptions at attach time\n\t\t// Evaluate against documentElement in case elem is a non-element node (e.g., document)\n\t\tif ( selector ) {\n\t\t\tjQuery.find.matchesSelector( documentElement, selector );\n\t\t}\n\n\t\t// Make sure that the handler has a unique ID, used to find/remove it later\n\t\tif ( !handler.guid ) {\n\t\t\thandler.guid = jQuery.guid++;\n\t\t}\n\n\t\t// Init the element's event structure and main handler, if this is the first\n\t\tif ( !( events = elemData.events ) ) {\n\t\t\tevents = elemData.events = Object.create( null );\n\t\t}\n\t\tif ( !( eventHandle = elemData.handle ) ) {\n\t\t\teventHandle = elemData.handle = function( e ) {\n\n\t\t\t\t// Discard the second event of a jQuery.event.trigger() and\n\t\t\t\t// when an event is called after a page has unloaded\n\t\t\t\treturn typeof jQuery !== \"undefined\" && jQuery.event.triggered !== e.type ?\n\t\t\t\t\tjQuery.event.dispatch.apply( elem, arguments ) : undefined;\n\t\t\t};\n\t\t}\n\n\t\t// Handle multiple events separated by a space\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// There *must* be a type, no attaching namespace-only handlers\n\t\t\tif ( !type ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\t// If event changes its type, use the special event handlers for the changed type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// If selector defined, determine special event api type, otherwise given type\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\n\t\t\t// Update special based on newly reset type\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\n\t\t\t// handleObj is passed to all event handlers\n\t\t\thandleObj = jQuery.extend( {\n\t\t\t\ttype: type,\n\t\t\t\torigType: origType,\n\t\t\t\tdata: data,\n\t\t\t\thandler: handler,\n\t\t\t\tguid: handler.guid,\n\t\t\t\tselector: selector,\n\t\t\t\tneedsContext: selector && jQuery.expr.match.needsContext.test( selector ),\n\t\t\t\tnamespace: namespaces.join( \".\" )\n\t\t\t}, handleObjIn );\n\n\t\t\t// Init the event handler queue if we're the first\n\t\t\tif ( !( handlers = events[ type ] ) ) {\n\t\t\t\thandlers = events[ type ] = [];\n\t\t\t\thandlers.delegateCount = 0;\n\n\t\t\t\t// Only use addEventListener if the special events handler returns false\n\t\t\t\tif ( !special.setup ||\n\t\t\t\t\tspecial.setup.call( elem, data, namespaces, eventHandle ) === false ) {\n\n\t\t\t\t\tif ( elem.addEventListener ) {\n\t\t\t\t\t\telem.addEventListener( type, eventHandle );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif ( special.add ) {\n\t\t\t\tspecial.add.call( elem, handleObj );\n\n\t\t\t\tif ( !handleObj.handler.guid ) {\n\t\t\t\t\thandleObj.handler.guid = handler.guid;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Add to the element's handler list, delegates in front\n\t\t\tif ( selector ) {\n\t\t\t\thandlers.splice( handlers.delegateCount++, 0, handleObj );\n\t\t\t} else {\n\t\t\t\thandlers.push( handleObj );\n\t\t\t}\n\n\t\t\t// Keep track of which events have ever been used, for event optimization\n\t\t\tjQuery.event.global[ type ] = true;\n\t\t}\n\n\t},\n\n\t// Detach an event or set of events from an element\n\tremove: function( elem, types, handler, selector, mappedTypes ) {\n\n\t\tvar j, origCount, tmp,\n\t\t\tevents, t, handleObj,\n\t\t\tspecial, handlers, type, namespaces, origType,\n\t\t\telemData = dataPriv.hasData( elem ) && dataPriv.get( elem );\n\n\t\tif ( !elemData || !( events = elemData.events ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Once for each type.namespace in types; type may be omitted\n\t\ttypes = ( types || \"\" ).match( rnothtmlwhite ) || [ \"\" ];\n\t\tt = types.length;\n\t\twhile ( t-- ) {\n\t\t\ttmp = rtypenamespace.exec( types[ t ] ) || [];\n\t\t\ttype = origType = tmp[ 1 ];\n\t\t\tnamespaces = ( tmp[ 2 ] || \"\" ).split( \".\" ).sort();\n\n\t\t\t// Unbind all events (on this namespace, if provided) for the element\n\t\t\tif ( !type ) {\n\t\t\t\tfor ( type in events ) {\n\t\t\t\t\tjQuery.event.remove( elem, type + types[ t ], handler, selector, true );\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tspecial = jQuery.event.special[ type ] || {};\n\t\t\ttype = ( selector ? special.delegateType : special.bindType ) || type;\n\t\t\thandlers = events[ type ] || [];\n\t\t\ttmp = tmp[ 2 ] &&\n\t\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" );\n\n\t\t\t// Remove matching events\n\t\t\torigCount = j = handlers.length;\n\t\t\twhile ( j-- ) {\n\t\t\t\thandleObj = handlers[ j ];\n\n\t\t\t\tif ( ( mappedTypes || origType === handleObj.origType ) &&\n\t\t\t\t\t( !handler || handler.guid === handleObj.guid ) &&\n\t\t\t\t\t( !tmp || tmp.test( handleObj.namespace ) ) &&\n\t\t\t\t\t( !selector || selector === handleObj.selector ||\n\t\t\t\t\t\tselector === \"**\" && handleObj.selector ) ) {\n\t\t\t\t\thandlers.splice( j, 1 );\n\n\t\t\t\t\tif ( handleObj.selector ) {\n\t\t\t\t\t\thandlers.delegateCount--;\n\t\t\t\t\t}\n\t\t\t\t\tif ( special.remove ) {\n\t\t\t\t\t\tspecial.remove.call( elem, handleObj );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Remove generic event handler if we removed something and no more handlers exist\n\t\t\t// (avoids potential for endless recursion during removal of special event handlers)\n\t\t\tif ( origCount && !handlers.length ) {\n\t\t\t\tif ( !special.teardown ||\n\t\t\t\t\tspecial.teardown.call( elem, namespaces, elemData.handle ) === false ) {\n\n\t\t\t\t\tjQuery.removeEvent( elem, type, elemData.handle );\n\t\t\t\t}\n\n\t\t\t\tdelete events[ type ];\n\t\t\t}\n\t\t}\n\n\t\t// Remove data and the expando if it's no longer used\n\t\tif ( jQuery.isEmptyObject( events ) ) {\n\t\t\tdataPriv.remove( elem, \"handle events\" );\n\t\t}\n\t},\n\n\tdispatch: function( nativeEvent ) {\n\n\t\tvar i, j, ret, matched, handleObj, handlerQueue,\n\t\t\targs = new Array( arguments.length ),\n\n\t\t\t// Make a writable jQuery.Event from the native event object\n\t\t\tevent = jQuery.event.fix( nativeEvent ),\n\n\t\t\thandlers = (\n\t\t\t\t\tdataPriv.get( this, \"events\" ) || Object.create( null )\n\t\t\t\t)[ event.type ] || [],\n\t\t\tspecial = jQuery.event.special[ event.type ] || {};\n\n\t\t// Use the fix-ed jQuery.Event rather than the (read-only) native event\n\t\targs[ 0 ] = event;\n\n\t\tfor ( i = 1; i < arguments.length; i++ ) {\n\t\t\targs[ i ] = arguments[ i ];\n\t\t}\n\n\t\tevent.delegateTarget = this;\n\n\t\t// Call the preDispatch hook for the mapped type, and let it bail if desired\n\t\tif ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine handlers\n\t\thandlerQueue = jQuery.event.handlers.call( this, event, handlers );\n\n\t\t// Run delegates first; they may want to stop propagation beneath us\n\t\ti = 0;\n\t\twhile ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tevent.currentTarget = matched.elem;\n\n\t\t\tj = 0;\n\t\t\twhile ( ( handleObj = matched.handlers[ j++ ] ) &&\n\t\t\t\t!event.isImmediatePropagationStopped() ) {\n\n\t\t\t\t// If the event is namespaced, then each handler is only invoked if it is\n\t\t\t\t// specially universal or its namespaces are a superset of the event's.\n\t\t\t\tif ( !event.rnamespace || handleObj.namespace === false ||\n\t\t\t\t\tevent.rnamespace.test( handleObj.namespace ) ) {\n\n\t\t\t\t\tevent.handleObj = handleObj;\n\t\t\t\t\tevent.data = handleObj.data;\n\n\t\t\t\t\tret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||\n\t\t\t\t\t\thandleObj.handler ).apply( matched.elem, args );\n\n\t\t\t\t\tif ( ret !== undefined ) {\n\t\t\t\t\t\tif ( ( event.result = ret ) === false ) {\n\t\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Call the postDispatch hook for the mapped type\n\t\tif ( special.postDispatch ) {\n\t\t\tspecial.postDispatch.call( this, event );\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\thandlers: function( event, handlers ) {\n\t\tvar i, handleObj, sel, matchedHandlers, matchedSelectors,\n\t\t\thandlerQueue = [],\n\t\t\tdelegateCount = handlers.delegateCount,\n\t\t\tcur = event.target;\n\n\t\t// Find delegate handlers\n\t\tif ( delegateCount &&\n\n\t\t\t// Support: IE <=9\n\t\t\t// Black-hole SVG instance trees (trac-13180)\n\t\t\tcur.nodeType &&\n\n\t\t\t// Support: Firefox <=42\n\t\t\t// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)\n\t\t\t// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click\n\t\t\t// Support: IE 11 only\n\t\t\t// ...but not arrow key \"clicks\" of radio inputs, which can have `button` -1 (gh-2343)\n\t\t\t!( event.type === \"click\" && event.button >= 1 ) ) {\n\n\t\t\tfor ( ; cur !== this; cur = cur.parentNode || this ) {\n\n\t\t\t\t// Don't check non-elements (#13208)\n\t\t\t\t// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)\n\t\t\t\tif ( cur.nodeType === 1 && !( event.type === \"click\" && cur.disabled === true ) ) {\n\t\t\t\t\tmatchedHandlers = [];\n\t\t\t\t\tmatchedSelectors = {};\n\t\t\t\t\tfor ( i = 0; i < delegateCount; i++ ) {\n\t\t\t\t\t\thandleObj = handlers[ i ];\n\n\t\t\t\t\t\t// Don't conflict with Object.prototype properties (#13203)\n\t\t\t\t\t\tsel = handleObj.selector + \" \";\n\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] === undefined ) {\n\t\t\t\t\t\t\tmatchedSelectors[ sel ] = handleObj.needsContext ?\n\t\t\t\t\t\t\t\tjQuery( sel, this ).index( cur ) > -1 :\n\t\t\t\t\t\t\t\tjQuery.find( sel, this, null, [ cur ] ).length;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif ( matchedSelectors[ sel ] ) {\n\t\t\t\t\t\t\tmatchedHandlers.push( handleObj );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tif ( matchedHandlers.length ) {\n\t\t\t\t\t\thandlerQueue.push( { elem: cur, handlers: matchedHandlers } );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Add the remaining (directly-bound) handlers\n\t\tcur = this;\n\t\tif ( delegateCount < handlers.length ) {\n\t\t\thandlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );\n\t\t}\n\n\t\treturn handlerQueue;\n\t},\n\n\taddProp: function( name, hook ) {\n\t\tObject.defineProperty( jQuery.Event.prototype, name, {\n\t\t\tenumerable: true,\n\t\t\tconfigurable: true,\n\n\t\t\tget: isFunction( hook ) ?\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn hook( this.originalEvent );\n\t\t\t\t\t}\n\t\t\t\t} :\n\t\t\t\tfunction() {\n\t\t\t\t\tif ( this.originalEvent ) {\n\t\t\t\t\t\t\treturn this.originalEvent[ name ];\n\t\t\t\t\t}\n\t\t\t\t},\n\n\t\t\tset: function( value ) {\n\t\t\t\tObject.defineProperty( this, name, {\n\t\t\t\t\tenumerable: true,\n\t\t\t\t\tconfigurable: true,\n\t\t\t\t\twritable: true,\n\t\t\t\t\tvalue: value\n\t\t\t\t} );\n\t\t\t}\n\t\t} );\n\t},\n\n\tfix: function( originalEvent ) {\n\t\treturn originalEvent[ jQuery.expando ] ?\n\t\t\toriginalEvent :\n\t\t\tnew jQuery.Event( originalEvent );\n\t},\n\n\tspecial: {\n\t\tload: {\n\n\t\t\t// Prevent triggered image.load events from bubbling to window.load\n\t\t\tnoBubble: true\n\t\t},\n\t\tclick: {\n\n\t\t\t// Utilize native event to ensure correct state for checkable inputs\n\t\t\tsetup: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Claim the first handler\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\t// dataPriv.set( el, \"click\", ... )\n\t\t\t\t\tleverageNative( el, \"click\", returnTrue );\n\t\t\t\t}\n\n\t\t\t\t// Return false to allow normal processing in the caller\n\t\t\t\treturn false;\n\t\t\t},\n\t\t\ttrigger: function( data ) {\n\n\t\t\t\t// For mutual compressibility with _default, replace `this` access with a local var.\n\t\t\t\t// `|| data` is dead code meant only to preserve the variable through minification.\n\t\t\t\tvar el = this || data;\n\n\t\t\t\t// Force setup before triggering a click\n\t\t\t\tif ( rcheckableType.test( el.type ) &&\n\t\t\t\t\tel.click && nodeName( el, \"input\" ) ) {\n\n\t\t\t\t\tleverageNative( el, \"click\" );\n\t\t\t\t}\n\n\t\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\t\treturn true;\n\t\t\t},\n\n\t\t\t// For cross-browser consistency, suppress native .click() on links\n\t\t\t// Also prevent it if we're currently inside a leveraged native-event stack\n\t\t\t_default: function( event ) {\n\t\t\t\tvar target = event.target;\n\t\t\t\treturn rcheckableType.test( target.type ) &&\n\t\t\t\t\ttarget.click && nodeName( target, \"input\" ) &&\n\t\t\t\t\tdataPriv.get( target, \"click\" ) ||\n\t\t\t\t\tnodeName( target, \"a\" );\n\t\t\t}\n\t\t},\n\n\t\tbeforeunload: {\n\t\t\tpostDispatch: function( event ) {\n\n\t\t\t\t// Support: Firefox 20+\n\t\t\t\t// Firefox doesn't alert if the returnValue field is not set.\n\t\t\t\tif ( event.result !== undefined && event.originalEvent ) {\n\t\t\t\t\tevent.originalEvent.returnValue = event.result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Ensure the presence of an event listener that handles manually-triggered\n// synthetic events by interrupting progress until reinvoked in response to\n// *native* events that it fires directly, ensuring that state changes have\n// already occurred before other listeners are invoked.\nfunction leverageNative( el, type, expectSync ) {\n\n\t// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add\n\tif ( !expectSync ) {\n\t\tif ( dataPriv.get( el, type ) === undefined ) {\n\t\t\tjQuery.event.add( el, type, returnTrue );\n\t\t}\n\t\treturn;\n\t}\n\n\t// Register the controller as a special universal handler for all event namespaces\n\tdataPriv.set( el, type, false );\n\tjQuery.event.add( el, type, {\n\t\tnamespace: false,\n\t\thandler: function( event ) {\n\t\t\tvar notAsync, result,\n\t\t\t\tsaved = dataPriv.get( this, type );\n\n\t\t\tif ( ( event.isTrigger & 1 ) && this[ type ] ) {\n\n\t\t\t\t// Interrupt processing of the outer synthetic .trigger()ed event\n\t\t\t\t// Saved data should be false in such cases, but might be a leftover capture object\n\t\t\t\t// from an async native handler (gh-4350)\n\t\t\t\tif ( !saved.length ) {\n\n\t\t\t\t\t// Store arguments for use when handling the inner native event\n\t\t\t\t\t// There will always be at least one argument (an event object), so this array\n\t\t\t\t\t// will not be confused with a leftover capture object.\n\t\t\t\t\tsaved = slice.call( arguments );\n\t\t\t\t\tdataPriv.set( this, type, saved );\n\n\t\t\t\t\t// Trigger the native event and capture its result\n\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t// focus() and blur() are asynchronous\n\t\t\t\t\tnotAsync = expectSync( this, type );\n\t\t\t\t\tthis[ type ]();\n\t\t\t\t\tresult = dataPriv.get( this, type );\n\t\t\t\t\tif ( saved !== result || notAsync ) {\n\t\t\t\t\t\tdataPriv.set( this, type, false );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tresult = {};\n\t\t\t\t\t}\n\t\t\t\t\tif ( saved !== result ) {\n\n\t\t\t\t\t\t// Cancel the outer synthetic event\n\t\t\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\t\treturn result.value;\n\t\t\t\t\t}\n\n\t\t\t\t// If this is an inner synthetic event for an event with a bubbling surrogate\n\t\t\t\t// (focus or blur), assume that the surrogate already propagated from triggering the\n\t\t\t\t// native event and prevent that from happening again here.\n\t\t\t\t// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the\n\t\t\t\t// bubbling surrogate propagates *after* the non-bubbling base), but that seems\n\t\t\t\t// less bad than duplication.\n\t\t\t\t} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {\n\t\t\t\t\tevent.stopPropagation();\n\t\t\t\t}\n\n\t\t\t// If this is a native event triggered above, everything is now in order\n\t\t\t// Fire an inner synthetic event with the original arguments\n\t\t\t} else if ( saved.length ) {\n\n\t\t\t\t// ...and capture the result\n\t\t\t\tdataPriv.set( this, type, {\n\t\t\t\t\tvalue: jQuery.event.trigger(\n\n\t\t\t\t\t\t// Support: IE <=9 - 11+\n\t\t\t\t\t\t// Extend with the prototype to reset the above stopImmediatePropagation()\n\t\t\t\t\t\tjQuery.extend( saved[ 0 ], jQuery.Event.prototype ),\n\t\t\t\t\t\tsaved.slice( 1 ),\n\t\t\t\t\t\tthis\n\t\t\t\t\t)\n\t\t\t\t} );\n\n\t\t\t\t// Abort handling of the native event\n\t\t\t\tevent.stopImmediatePropagation();\n\t\t\t}\n\t\t}\n\t} );\n}\n\njQuery.removeEvent = function( elem, type, handle ) {\n\n\t// This \"if\" is needed for plain objects\n\tif ( elem.removeEventListener ) {\n\t\telem.removeEventListener( type, handle );\n\t}\n};\n\njQuery.Event = function( src, props ) {\n\n\t// Allow instantiation without the 'new' keyword\n\tif ( !( this instanceof jQuery.Event ) ) {\n\t\treturn new jQuery.Event( src, props );\n\t}\n\n\t// Event object\n\tif ( src && src.type ) {\n\t\tthis.originalEvent = src;\n\t\tthis.type = src.type;\n\n\t\t// Events bubbling up the document may have been marked as prevented\n\t\t// by a handler lower down the tree; reflect the correct value.\n\t\tthis.isDefaultPrevented = src.defaultPrevented ||\n\t\t\t\tsrc.defaultPrevented === undefined &&\n\n\t\t\t\t// Support: Android <=2.3 only\n\t\t\t\tsrc.returnValue === false ?\n\t\t\treturnTrue :\n\t\t\treturnFalse;\n\n\t\t// Create target properties\n\t\t// Support: Safari <=6 - 7 only\n\t\t// Target should not be a text node (#504, #13143)\n\t\tthis.target = ( src.target && src.target.nodeType === 3 ) ?\n\t\t\tsrc.target.parentNode :\n\t\t\tsrc.target;\n\n\t\tthis.currentTarget = src.currentTarget;\n\t\tthis.relatedTarget = src.relatedTarget;\n\n\t// Event type\n\t} else {\n\t\tthis.type = src;\n\t}\n\n\t// Put explicitly provided properties onto the event object\n\tif ( props ) {\n\t\tjQuery.extend( this, props );\n\t}\n\n\t// Create a timestamp if incoming event doesn't have one\n\tthis.timeStamp = src && src.timeStamp || Date.now();\n\n\t// Mark it as fixed\n\tthis[ jQuery.expando ] = true;\n};\n\n// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding\n// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html\njQuery.Event.prototype = {\n\tconstructor: jQuery.Event,\n\tisDefaultPrevented: returnFalse,\n\tisPropagationStopped: returnFalse,\n\tisImmediatePropagationStopped: returnFalse,\n\tisSimulated: false,\n\n\tpreventDefault: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isDefaultPrevented = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.preventDefault();\n\t\t}\n\t},\n\tstopPropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isPropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopPropagation();\n\t\t}\n\t},\n\tstopImmediatePropagation: function() {\n\t\tvar e = this.originalEvent;\n\n\t\tthis.isImmediatePropagationStopped = returnTrue;\n\n\t\tif ( e && !this.isSimulated ) {\n\t\t\te.stopImmediatePropagation();\n\t\t}\n\n\t\tthis.stopPropagation();\n\t}\n};\n\n// Includes all common event props including KeyEvent and MouseEvent specific props\njQuery.each( {\n\taltKey: true,\n\tbubbles: true,\n\tcancelable: true,\n\tchangedTouches: true,\n\tctrlKey: true,\n\tdetail: true,\n\teventPhase: true,\n\tmetaKey: true,\n\tpageX: true,\n\tpageY: true,\n\tshiftKey: true,\n\tview: true,\n\t\"char\": true,\n\tcode: true,\n\tcharCode: true,\n\tkey: true,\n\tkeyCode: true,\n\tbutton: true,\n\tbuttons: true,\n\tclientX: true,\n\tclientY: true,\n\toffsetX: true,\n\toffsetY: true,\n\tpointerId: true,\n\tpointerType: true,\n\tscreenX: true,\n\tscreenY: true,\n\ttargetTouches: true,\n\ttoElement: true,\n\ttouches: true,\n\n\twhich: function( event ) {\n\t\tvar button = event.button;\n\n\t\t// Add which for key events\n\t\tif ( event.which == null && rkeyEvent.test( event.type ) ) {\n\t\t\treturn event.charCode != null ? event.charCode : event.keyCode;\n\t\t}\n\n\t\t// Add which for click: 1 === left; 2 === middle; 3 === right\n\t\tif ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {\n\t\t\tif ( button & 1 ) {\n\t\t\t\treturn 1;\n\t\t\t}\n\n\t\t\tif ( button & 2 ) {\n\t\t\t\treturn 3;\n\t\t\t}\n\n\t\t\tif ( button & 4 ) {\n\t\t\t\treturn 2;\n\t\t\t}\n\n\t\t\treturn 0;\n\t\t}\n\n\t\treturn event.which;\n\t}\n}, jQuery.event.addProp );\n\njQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( type, delegateType ) {\n\tjQuery.event.special[ type ] = {\n\n\t\t// Utilize native event if possible so blur/focus sequence is correct\n\t\tsetup: function() {\n\n\t\t\t// Claim the first handler\n\t\t\t// dataPriv.set( this, \"focus\", ... )\n\t\t\t// dataPriv.set( this, \"blur\", ... )\n\t\t\tleverageNative( this, type, expectSync );\n\n\t\t\t// Return false to allow normal processing in the caller\n\t\t\treturn false;\n\t\t},\n\t\ttrigger: function() {\n\n\t\t\t// Force setup before trigger\n\t\t\tleverageNative( this, type );\n\n\t\t\t// Return non-false to allow normal event-path propagation\n\t\t\treturn true;\n\t\t},\n\n\t\tdelegateType: delegateType\n\t};\n} );\n\n// Create mouseenter/leave events using mouseover/out and event-time checks\n// so that event delegation works in jQuery.\n// Do the same for pointerenter/pointerleave and pointerover/pointerout\n//\n// Support: Safari 7 only\n// Safari sends mouseenter too often; see:\n// https://bugs.chromium.org/p/chromium/issues/detail?id=470258\n// for the description of the bug (it existed in older Chrome versions as well).\njQuery.each( {\n\tmouseenter: \"mouseover\",\n\tmouseleave: \"mouseout\",\n\tpointerenter: \"pointerover\",\n\tpointerleave: \"pointerout\"\n}, function( orig, fix ) {\n\tjQuery.event.special[ orig ] = {\n\t\tdelegateType: fix,\n\t\tbindType: fix,\n\n\t\thandle: function( event ) {\n\t\t\tvar ret,\n\t\t\t\ttarget = this,\n\t\t\t\trelated = event.relatedTarget,\n\t\t\t\thandleObj = event.handleObj;\n\n\t\t\t// For mouseenter/leave call the handler if related is outside the target.\n\t\t\t// NB: No relatedTarget if the mouse left/entered the browser window\n\t\t\tif ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {\n\t\t\t\tevent.type = handleObj.origType;\n\t\t\t\tret = handleObj.handler.apply( this, arguments );\n\t\t\t\tevent.type = fix;\n\t\t\t}\n\t\t\treturn ret;\n\t\t}\n\t};\n} );\n\njQuery.fn.extend( {\n\n\ton: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn );\n\t},\n\tone: function( types, selector, data, fn ) {\n\t\treturn on( this, types, selector, data, fn, 1 );\n\t},\n\toff: function( types, selector, fn ) {\n\t\tvar handleObj, type;\n\t\tif ( types && types.preventDefault && types.handleObj ) {\n\n\t\t\t// ( event ) dispatched jQuery.Event\n\t\t\thandleObj = types.handleObj;\n\t\t\tjQuery( types.delegateTarget ).off(\n\t\t\t\thandleObj.namespace ?\n\t\t\t\t\thandleObj.origType + \".\" + handleObj.namespace :\n\t\t\t\t\thandleObj.origType,\n\t\t\t\thandleObj.selector,\n\t\t\t\thandleObj.handler\n\t\t\t);\n\t\t\treturn this;\n\t\t}\n\t\tif ( typeof types === \"object\" ) {\n\n\t\t\t// ( types-object [, selector] )\n\t\t\tfor ( type in types ) {\n\t\t\t\tthis.off( type, selector, types[ type ] );\n\t\t\t}\n\t\t\treturn this;\n\t\t}\n\t\tif ( selector === false || typeof selector === \"function\" ) {\n\n\t\t\t// ( types [, fn] )\n\t\t\tfn = selector;\n\t\t\tselector = undefined;\n\t\t}\n\t\tif ( fn === false ) {\n\t\t\tfn = returnFalse;\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.remove( this, types, fn, selector );\n\t\t} );\n\t}\n} );\n\n\nvar\n\n\t// Support: IE <=10 - 11, Edge 12 - 13 only\n\t// In IE/Edge using regex groups here causes severe slowdowns.\n\t// See https://connect.microsoft.com/IE/feedback/details/1736512/\n\trnoInnerhtml = /\\s*$/g;\n\n// Prefer a tbody over its parent table for containing new rows\nfunction manipulationTarget( elem, content ) {\n\tif ( nodeName( elem, \"table\" ) &&\n\t\tnodeName( content.nodeType !== 11 ? content : content.firstChild, \"tr\" ) ) {\n\n\t\treturn jQuery( elem ).children( \"tbody\" )[ 0 ] || elem;\n\t}\n\n\treturn elem;\n}\n\n// Replace/restore the type attribute of script elements for safe DOM manipulation\nfunction disableScript( elem ) {\n\telem.type = ( elem.getAttribute( \"type\" ) !== null ) + \"/\" + elem.type;\n\treturn elem;\n}\nfunction restoreScript( elem ) {\n\tif ( ( elem.type || \"\" ).slice( 0, 5 ) === \"true/\" ) {\n\t\telem.type = elem.type.slice( 5 );\n\t} else {\n\t\telem.removeAttribute( \"type\" );\n\t}\n\n\treturn elem;\n}\n\nfunction cloneCopyEvent( src, dest ) {\n\tvar i, l, type, pdataOld, udataOld, udataCur, events;\n\n\tif ( dest.nodeType !== 1 ) {\n\t\treturn;\n\t}\n\n\t// 1. Copy private data: events, handlers, etc.\n\tif ( dataPriv.hasData( src ) ) {\n\t\tpdataOld = dataPriv.get( src );\n\t\tevents = pdataOld.events;\n\n\t\tif ( events ) {\n\t\t\tdataPriv.remove( dest, \"handle events\" );\n\n\t\t\tfor ( type in events ) {\n\t\t\t\tfor ( i = 0, l = events[ type ].length; i < l; i++ ) {\n\t\t\t\t\tjQuery.event.add( dest, type, events[ type ][ i ] );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t// 2. Copy user data\n\tif ( dataUser.hasData( src ) ) {\n\t\tudataOld = dataUser.access( src );\n\t\tudataCur = jQuery.extend( {}, udataOld );\n\n\t\tdataUser.set( dest, udataCur );\n\t}\n}\n\n// Fix IE bugs, see support tests\nfunction fixInput( src, dest ) {\n\tvar nodeName = dest.nodeName.toLowerCase();\n\n\t// Fails to persist the checked state of a cloned checkbox or radio button.\n\tif ( nodeName === \"input\" && rcheckableType.test( src.type ) ) {\n\t\tdest.checked = src.checked;\n\n\t// Fails to return the selected option to the default selected state when cloning options\n\t} else if ( nodeName === \"input\" || nodeName === \"textarea\" ) {\n\t\tdest.defaultValue = src.defaultValue;\n\t}\n}\n\nfunction domManip( collection, args, callback, ignored ) {\n\n\t// Flatten any nested arrays\n\targs = flat( args );\n\n\tvar fragment, first, scripts, hasScripts, node, doc,\n\t\ti = 0,\n\t\tl = collection.length,\n\t\tiNoClone = l - 1,\n\t\tvalue = args[ 0 ],\n\t\tvalueIsFunction = isFunction( value );\n\n\t// We can't cloneNode fragments that contain checked, in WebKit\n\tif ( valueIsFunction ||\n\t\t\t( l > 1 && typeof value === \"string\" &&\n\t\t\t\t!support.checkClone && rchecked.test( value ) ) ) {\n\t\treturn collection.each( function( index ) {\n\t\t\tvar self = collection.eq( index );\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\targs[ 0 ] = value.call( this, index, self.html() );\n\t\t\t}\n\t\t\tdomManip( self, args, callback, ignored );\n\t\t} );\n\t}\n\n\tif ( l ) {\n\t\tfragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );\n\t\tfirst = fragment.firstChild;\n\n\t\tif ( fragment.childNodes.length === 1 ) {\n\t\t\tfragment = first;\n\t\t}\n\n\t\t// Require either new content or an interest in ignored elements to invoke the callback\n\t\tif ( first || ignored ) {\n\t\t\tscripts = jQuery.map( getAll( fragment, \"script\" ), disableScript );\n\t\t\thasScripts = scripts.length;\n\n\t\t\t// Use the original fragment for the last item\n\t\t\t// instead of the first because it can end up\n\t\t\t// being emptied incorrectly in certain situations (#8070).\n\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\tnode = fragment;\n\n\t\t\t\tif ( i !== iNoClone ) {\n\t\t\t\t\tnode = jQuery.clone( node, true, true );\n\n\t\t\t\t\t// Keep references to cloned scripts for later restoration\n\t\t\t\t\tif ( hasScripts ) {\n\n\t\t\t\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t\t\t\t// push.apply(_, arraylike) throws on ancient WebKit\n\t\t\t\t\t\tjQuery.merge( scripts, getAll( node, \"script\" ) );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcallback.call( collection[ i ], node, i );\n\t\t\t}\n\n\t\t\tif ( hasScripts ) {\n\t\t\t\tdoc = scripts[ scripts.length - 1 ].ownerDocument;\n\n\t\t\t\t// Reenable scripts\n\t\t\t\tjQuery.map( scripts, restoreScript );\n\n\t\t\t\t// Evaluate executable scripts on first document insertion\n\t\t\t\tfor ( i = 0; i < hasScripts; i++ ) {\n\t\t\t\t\tnode = scripts[ i ];\n\t\t\t\t\tif ( rscriptType.test( node.type || \"\" ) &&\n\t\t\t\t\t\t!dataPriv.access( node, \"globalEval\" ) &&\n\t\t\t\t\t\tjQuery.contains( doc, node ) ) {\n\n\t\t\t\t\t\tif ( node.src && ( node.type || \"\" ).toLowerCase() !== \"module\" ) {\n\n\t\t\t\t\t\t\t// Optional AJAX dependency, but won't run scripts if not present\n\t\t\t\t\t\t\tif ( jQuery._evalUrl && !node.noModule ) {\n\t\t\t\t\t\t\t\tjQuery._evalUrl( node.src, {\n\t\t\t\t\t\t\t\t\tnonce: node.nonce || node.getAttribute( \"nonce\" )\n\t\t\t\t\t\t\t\t}, doc );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\tDOMEval( node.textContent.replace( rcleanScript, \"\" ), node, doc );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn collection;\n}\n\nfunction remove( elem, selector, keepData ) {\n\tvar node,\n\t\tnodes = selector ? jQuery.filter( selector, elem ) : elem,\n\t\ti = 0;\n\n\tfor ( ; ( node = nodes[ i ] ) != null; i++ ) {\n\t\tif ( !keepData && node.nodeType === 1 ) {\n\t\t\tjQuery.cleanData( getAll( node ) );\n\t\t}\n\n\t\tif ( node.parentNode ) {\n\t\t\tif ( keepData && isAttached( node ) ) {\n\t\t\t\tsetGlobalEval( getAll( node, \"script\" ) );\n\t\t\t}\n\t\t\tnode.parentNode.removeChild( node );\n\t\t}\n\t}\n\n\treturn elem;\n}\n\njQuery.extend( {\n\thtmlPrefilter: function( html ) {\n\t\treturn html;\n\t},\n\n\tclone: function( elem, dataAndEvents, deepDataAndEvents ) {\n\t\tvar i, l, srcElements, destElements,\n\t\t\tclone = elem.cloneNode( true ),\n\t\t\tinPage = isAttached( elem );\n\n\t\t// Fix IE cloning issues\n\t\tif ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&\n\t\t\t\t!jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2\n\t\t\tdestElements = getAll( clone );\n\t\t\tsrcElements = getAll( elem );\n\n\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\tfixInput( srcElements[ i ], destElements[ i ] );\n\t\t\t}\n\t\t}\n\n\t\t// Copy the events from the original to the clone\n\t\tif ( dataAndEvents ) {\n\t\t\tif ( deepDataAndEvents ) {\n\t\t\t\tsrcElements = srcElements || getAll( elem );\n\t\t\t\tdestElements = destElements || getAll( clone );\n\n\t\t\t\tfor ( i = 0, l = srcElements.length; i < l; i++ ) {\n\t\t\t\t\tcloneCopyEvent( srcElements[ i ], destElements[ i ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcloneCopyEvent( elem, clone );\n\t\t\t}\n\t\t}\n\n\t\t// Preserve script evaluation history\n\t\tdestElements = getAll( clone, \"script\" );\n\t\tif ( destElements.length > 0 ) {\n\t\t\tsetGlobalEval( destElements, !inPage && getAll( elem, \"script\" ) );\n\t\t}\n\n\t\t// Return the cloned set\n\t\treturn clone;\n\t},\n\n\tcleanData: function( elems ) {\n\t\tvar data, elem, type,\n\t\t\tspecial = jQuery.event.special,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {\n\t\t\tif ( acceptData( elem ) ) {\n\t\t\t\tif ( ( data = elem[ dataPriv.expando ] ) ) {\n\t\t\t\t\tif ( data.events ) {\n\t\t\t\t\t\tfor ( type in data.events ) {\n\t\t\t\t\t\t\tif ( special[ type ] ) {\n\t\t\t\t\t\t\t\tjQuery.event.remove( elem, type );\n\n\t\t\t\t\t\t\t// This is a shortcut to avoid jQuery.event.remove's overhead\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tjQuery.removeEvent( elem, type, data.handle );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataPriv.expando ] = undefined;\n\t\t\t\t}\n\t\t\t\tif ( elem[ dataUser.expando ] ) {\n\n\t\t\t\t\t// Support: Chrome <=35 - 45+\n\t\t\t\t\t// Assign undefined instead of using delete, see Data#remove\n\t\t\t\t\telem[ dataUser.expando ] = undefined;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n} );\n\njQuery.fn.extend( {\n\tdetach: function( selector ) {\n\t\treturn remove( this, selector, true );\n\t},\n\n\tremove: function( selector ) {\n\t\treturn remove( this, selector );\n\t},\n\n\ttext: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\treturn value === undefined ?\n\t\t\t\tjQuery.text( this ) :\n\t\t\t\tthis.empty().each( function() {\n\t\t\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\t\t\tthis.textContent = value;\n\t\t\t\t\t}\n\t\t\t\t} );\n\t\t}, null, value, arguments.length );\n\t},\n\n\tappend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.appendChild( elem );\n\t\t\t}\n\t\t} );\n\t},\n\n\tprepend: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {\n\t\t\t\tvar target = manipulationTarget( this, elem );\n\t\t\t\ttarget.insertBefore( elem, target.firstChild );\n\t\t\t}\n\t\t} );\n\t},\n\n\tbefore: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this );\n\t\t\t}\n\t\t} );\n\t},\n\n\tafter: function() {\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tif ( this.parentNode ) {\n\t\t\t\tthis.parentNode.insertBefore( elem, this.nextSibling );\n\t\t\t}\n\t\t} );\n\t},\n\n\tempty: function() {\n\t\tvar elem,\n\t\t\ti = 0;\n\n\t\tfor ( ; ( elem = this[ i ] ) != null; i++ ) {\n\t\t\tif ( elem.nodeType === 1 ) {\n\n\t\t\t\t// Prevent memory leaks\n\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\n\t\t\t\t// Remove any remaining nodes\n\t\t\t\telem.textContent = \"\";\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tclone: function( dataAndEvents, deepDataAndEvents ) {\n\t\tdataAndEvents = dataAndEvents == null ? false : dataAndEvents;\n\t\tdeepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;\n\n\t\treturn this.map( function() {\n\t\t\treturn jQuery.clone( this, dataAndEvents, deepDataAndEvents );\n\t\t} );\n\t},\n\n\thtml: function( value ) {\n\t\treturn access( this, function( value ) {\n\t\t\tvar elem = this[ 0 ] || {},\n\t\t\t\ti = 0,\n\t\t\t\tl = this.length;\n\n\t\t\tif ( value === undefined && elem.nodeType === 1 ) {\n\t\t\t\treturn elem.innerHTML;\n\t\t\t}\n\n\t\t\t// See if we can take a shortcut and just use innerHTML\n\t\t\tif ( typeof value === \"string\" && !rnoInnerhtml.test( value ) &&\n\t\t\t\t!wrapMap[ ( rtagName.exec( value ) || [ \"\", \"\" ] )[ 1 ].toLowerCase() ] ) {\n\n\t\t\t\tvalue = jQuery.htmlPrefilter( value );\n\n\t\t\t\ttry {\n\t\t\t\t\tfor ( ; i < l; i++ ) {\n\t\t\t\t\t\telem = this[ i ] || {};\n\n\t\t\t\t\t\t// Remove element nodes and prevent memory leaks\n\t\t\t\t\t\tif ( elem.nodeType === 1 ) {\n\t\t\t\t\t\t\tjQuery.cleanData( getAll( elem, false ) );\n\t\t\t\t\t\t\telem.innerHTML = value;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\telem = 0;\n\n\t\t\t\t// If using innerHTML throws an exception, use the fallback method\n\t\t\t\t} catch ( e ) {}\n\t\t\t}\n\n\t\t\tif ( elem ) {\n\t\t\t\tthis.empty().append( value );\n\t\t\t}\n\t\t}, null, value, arguments.length );\n\t},\n\n\treplaceWith: function() {\n\t\tvar ignored = [];\n\n\t\t// Make the changes, replacing each non-ignored context element with the new content\n\t\treturn domManip( this, arguments, function( elem ) {\n\t\t\tvar parent = this.parentNode;\n\n\t\t\tif ( jQuery.inArray( this, ignored ) < 0 ) {\n\t\t\t\tjQuery.cleanData( getAll( this ) );\n\t\t\t\tif ( parent ) {\n\t\t\t\t\tparent.replaceChild( elem, this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t// Force callback invocation\n\t\t}, ignored );\n\t}\n} );\n\njQuery.each( {\n\tappendTo: \"append\",\n\tprependTo: \"prepend\",\n\tinsertBefore: \"before\",\n\tinsertAfter: \"after\",\n\treplaceAll: \"replaceWith\"\n}, function( name, original ) {\n\tjQuery.fn[ name ] = function( selector ) {\n\t\tvar elems,\n\t\t\tret = [],\n\t\t\tinsert = jQuery( selector ),\n\t\t\tlast = insert.length - 1,\n\t\t\ti = 0;\n\n\t\tfor ( ; i <= last; i++ ) {\n\t\t\telems = i === last ? this : this.clone( true );\n\t\t\tjQuery( insert[ i ] )[ original ]( elems );\n\n\t\t\t// Support: Android <=4.0 only, PhantomJS 1 only\n\t\t\t// .get() because push.apply(_, arraylike) throws on ancient WebKit\n\t\t\tpush.apply( ret, elems.get() );\n\t\t}\n\n\t\treturn this.pushStack( ret );\n\t};\n} );\nvar rnumnonpx = new RegExp( \"^(\" + pnum + \")(?!px)[a-z%]+$\", \"i\" );\n\nvar getStyles = function( elem ) {\n\n\t\t// Support: IE <=11 only, Firefox <=30 (#15098, #14150)\n\t\t// IE throws on elements created in popups\n\t\t// FF meanwhile throws on frame elements through \"defaultView.getComputedStyle\"\n\t\tvar view = elem.ownerDocument.defaultView;\n\n\t\tif ( !view || !view.opener ) {\n\t\t\tview = window;\n\t\t}\n\n\t\treturn view.getComputedStyle( elem );\n\t};\n\nvar swap = function( elem, options, callback ) {\n\tvar ret, name,\n\t\told = {};\n\n\t// Remember the old values, and insert the new ones\n\tfor ( name in options ) {\n\t\told[ name ] = elem.style[ name ];\n\t\telem.style[ name ] = options[ name ];\n\t}\n\n\tret = callback.call( elem );\n\n\t// Revert the old values\n\tfor ( name in options ) {\n\t\telem.style[ name ] = old[ name ];\n\t}\n\n\treturn ret;\n};\n\n\nvar rboxStyle = new RegExp( cssExpand.join( \"|\" ), \"i\" );\n\n\n\n( function() {\n\n\t// Executing both pixelPosition & boxSizingReliable tests require only one layout\n\t// so they're executed at the same time to save the second computation.\n\tfunction computeStyleTests() {\n\n\t\t// This is a singleton, we need to execute it only once\n\t\tif ( !div ) {\n\t\t\treturn;\n\t\t}\n\n\t\tcontainer.style.cssText = \"position:absolute;left:-11111px;width:60px;\" +\n\t\t\t\"margin-top:1px;padding:0;border:0\";\n\t\tdiv.style.cssText =\n\t\t\t\"position:relative;display:block;box-sizing:border-box;overflow:scroll;\" +\n\t\t\t\"margin:auto;border:1px;padding:1px;\" +\n\t\t\t\"width:60%;top:1%\";\n\t\tdocumentElement.appendChild( container ).appendChild( div );\n\n\t\tvar divStyle = window.getComputedStyle( div );\n\t\tpixelPositionVal = divStyle.top !== \"1%\";\n\n\t\t// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44\n\t\treliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;\n\n\t\t// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3\n\t\t// Some styles come back with percentage values, even though they shouldn't\n\t\tdiv.style.right = \"60%\";\n\t\tpixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;\n\n\t\t// Support: IE 9 - 11 only\n\t\t// Detect misreporting of content dimensions for box-sizing:border-box elements\n\t\tboxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;\n\n\t\t// Support: IE 9 only\n\t\t// Detect overflow:scroll screwiness (gh-3699)\n\t\t// Support: Chrome <=64\n\t\t// Don't get tricked when zoom affects offsetWidth (gh-4029)\n\t\tdiv.style.position = \"absolute\";\n\t\tscrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;\n\n\t\tdocumentElement.removeChild( container );\n\n\t\t// Nullify the div so it wouldn't be stored in the memory and\n\t\t// it will also be a sign that checks already performed\n\t\tdiv = null;\n\t}\n\n\tfunction roundPixelMeasures( measure ) {\n\t\treturn Math.round( parseFloat( measure ) );\n\t}\n\n\tvar pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,\n\t\treliableTrDimensionsVal, reliableMarginLeftVal,\n\t\tcontainer = document.createElement( \"div\" ),\n\t\tdiv = document.createElement( \"div\" );\n\n\t// Finish early in limited (non-browser) environments\n\tif ( !div.style ) {\n\t\treturn;\n\t}\n\n\t// Support: IE <=9 - 11 only\n\t// Style of cloned element affects source element cloned (#8908)\n\tdiv.style.backgroundClip = \"content-box\";\n\tdiv.cloneNode( true ).style.backgroundClip = \"\";\n\tsupport.clearCloneStyle = div.style.backgroundClip === \"content-box\";\n\n\tjQuery.extend( support, {\n\t\tboxSizingReliable: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn boxSizingReliableVal;\n\t\t},\n\t\tpixelBoxStyles: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelBoxStylesVal;\n\t\t},\n\t\tpixelPosition: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn pixelPositionVal;\n\t\t},\n\t\treliableMarginLeft: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn reliableMarginLeftVal;\n\t\t},\n\t\tscrollboxSize: function() {\n\t\t\tcomputeStyleTests();\n\t\t\treturn scrollboxSizeVal;\n\t\t},\n\n\t\t// Support: IE 9 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Behavior in IE 9 is more subtle than in newer versions & it passes\n\t\t// some versions of this test; make sure not to make it pass there!\n\t\treliableTrDimensions: function() {\n\t\t\tvar table, tr, trChild, trStyle;\n\t\t\tif ( reliableTrDimensionsVal == null ) {\n\t\t\t\ttable = document.createElement( \"table\" );\n\t\t\t\ttr = document.createElement( \"tr\" );\n\t\t\t\ttrChild = document.createElement( \"div\" );\n\n\t\t\t\ttable.style.cssText = \"position:absolute;left:-11111px\";\n\t\t\t\ttr.style.height = \"1px\";\n\t\t\t\ttrChild.style.height = \"9px\";\n\n\t\t\t\tdocumentElement\n\t\t\t\t\t.appendChild( table )\n\t\t\t\t\t.appendChild( tr )\n\t\t\t\t\t.appendChild( trChild );\n\n\t\t\t\ttrStyle = window.getComputedStyle( tr );\n\t\t\t\treliableTrDimensionsVal = parseInt( trStyle.height ) > 3;\n\n\t\t\t\tdocumentElement.removeChild( table );\n\t\t\t}\n\t\t\treturn reliableTrDimensionsVal;\n\t\t}\n\t} );\n} )();\n\n\nfunction curCSS( elem, name, computed ) {\n\tvar width, minWidth, maxWidth, ret,\n\n\t\t// Support: Firefox 51+\n\t\t// Retrieving style before computed somehow\n\t\t// fixes an issue with getting wrong values\n\t\t// on detached elements\n\t\tstyle = elem.style;\n\n\tcomputed = computed || getStyles( elem );\n\n\t// getPropertyValue is needed for:\n\t// .css('filter') (IE 9 only, #12537)\n\t// .css('--customProperty) (#3144)\n\tif ( computed ) {\n\t\tret = computed.getPropertyValue( name ) || computed[ name ];\n\n\t\tif ( ret === \"\" && !isAttached( elem ) ) {\n\t\t\tret = jQuery.style( elem, name );\n\t\t}\n\n\t\t// A tribute to the \"awesome hack by Dean Edwards\"\n\t\t// Android Browser returns percentage for some values,\n\t\t// but width seems to be reliably pixels.\n\t\t// This is against the CSSOM draft spec:\n\t\t// https://drafts.csswg.org/cssom/#resolved-values\n\t\tif ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {\n\n\t\t\t// Remember the original values\n\t\t\twidth = style.width;\n\t\t\tminWidth = style.minWidth;\n\t\t\tmaxWidth = style.maxWidth;\n\n\t\t\t// Put in the new values to get a computed value out\n\t\t\tstyle.minWidth = style.maxWidth = style.width = ret;\n\t\t\tret = computed.width;\n\n\t\t\t// Revert the changed values\n\t\t\tstyle.width = width;\n\t\t\tstyle.minWidth = minWidth;\n\t\t\tstyle.maxWidth = maxWidth;\n\t\t}\n\t}\n\n\treturn ret !== undefined ?\n\n\t\t// Support: IE <=9 - 11 only\n\t\t// IE returns zIndex value as an integer.\n\t\tret + \"\" :\n\t\tret;\n}\n\n\nfunction addGetHookIf( conditionFn, hookFn ) {\n\n\t// Define the hook, we'll check on the first run if it's really needed.\n\treturn {\n\t\tget: function() {\n\t\t\tif ( conditionFn() ) {\n\n\t\t\t\t// Hook not needed (or it's not possible to use it due\n\t\t\t\t// to missing dependency), remove it.\n\t\t\t\tdelete this.get;\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// Hook needed; redefine it so that the support test is not executed again.\n\t\t\treturn ( this.get = hookFn ).apply( this, arguments );\n\t\t}\n\t};\n}\n\n\nvar cssPrefixes = [ \"Webkit\", \"Moz\", \"ms\" ],\n\temptyStyle = document.createElement( \"div\" ).style,\n\tvendorProps = {};\n\n// Return a vendor-prefixed property or undefined\nfunction vendorPropName( name ) {\n\n\t// Check for vendor prefixed names\n\tvar capName = name[ 0 ].toUpperCase() + name.slice( 1 ),\n\t\ti = cssPrefixes.length;\n\n\twhile ( i-- ) {\n\t\tname = cssPrefixes[ i ] + capName;\n\t\tif ( name in emptyStyle ) {\n\t\t\treturn name;\n\t\t}\n\t}\n}\n\n// Return a potentially-mapped jQuery.cssProps or vendor prefixed property\nfunction finalPropName( name ) {\n\tvar final = jQuery.cssProps[ name ] || vendorProps[ name ];\n\n\tif ( final ) {\n\t\treturn final;\n\t}\n\tif ( name in emptyStyle ) {\n\t\treturn name;\n\t}\n\treturn vendorProps[ name ] = vendorPropName( name ) || name;\n}\n\n\nvar\n\n\t// Swappable if display is none or starts with table\n\t// except \"table\", \"table-cell\", or \"table-caption\"\n\t// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display\n\trdisplayswap = /^(none|table(?!-c[ea]).+)/,\n\trcustomProp = /^--/,\n\tcssShow = { position: \"absolute\", visibility: \"hidden\", display: \"block\" },\n\tcssNormalTransform = {\n\t\tletterSpacing: \"0\",\n\t\tfontWeight: \"400\"\n\t};\n\nfunction setPositiveNumber( _elem, value, subtract ) {\n\n\t// Any relative (+/-) values have already been\n\t// normalized at this point\n\tvar matches = rcssNum.exec( value );\n\treturn matches ?\n\n\t\t// Guard against undefined \"subtract\", e.g., when used as in cssHooks\n\t\tMath.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || \"px\" ) :\n\t\tvalue;\n}\n\nfunction boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {\n\tvar i = dimension === \"width\" ? 1 : 0,\n\t\textra = 0,\n\t\tdelta = 0;\n\n\t// Adjustment may not be necessary\n\tif ( box === ( isBorderBox ? \"border\" : \"content\" ) ) {\n\t\treturn 0;\n\t}\n\n\tfor ( ; i < 4; i += 2 ) {\n\n\t\t// Both box models exclude margin\n\t\tif ( box === \"margin\" ) {\n\t\t\tdelta += jQuery.css( elem, box + cssExpand[ i ], true, styles );\n\t\t}\n\n\t\t// If we get here with a content-box, we're seeking \"padding\" or \"border\" or \"margin\"\n\t\tif ( !isBorderBox ) {\n\n\t\t\t// Add padding\n\t\t\tdelta += jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\n\t\t\t// For \"border\" or \"margin\", add border\n\t\t\tif ( box !== \"padding\" ) {\n\t\t\t\tdelta += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\n\t\t\t// But still keep track of it otherwise\n\t\t\t} else {\n\t\t\t\textra += jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\n\t\t// If we get here with a border-box (content + padding + border), we're seeking \"content\" or\n\t\t// \"padding\" or \"margin\"\n\t\t} else {\n\n\t\t\t// For \"content\", subtract padding\n\t\t\tif ( box === \"content\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"padding\" + cssExpand[ i ], true, styles );\n\t\t\t}\n\n\t\t\t// For \"content\" or \"padding\", subtract border\n\t\t\tif ( box !== \"margin\" ) {\n\t\t\t\tdelta -= jQuery.css( elem, \"border\" + cssExpand[ i ] + \"Width\", true, styles );\n\t\t\t}\n\t\t}\n\t}\n\n\t// Account for positive content-box scroll gutter when requested by providing computedVal\n\tif ( !isBorderBox && computedVal >= 0 ) {\n\n\t\t// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border\n\t\t// Assuming integer scroll gutter, subtract the rest and round down\n\t\tdelta += Math.max( 0, Math.ceil(\n\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\tcomputedVal -\n\t\t\tdelta -\n\t\t\textra -\n\t\t\t0.5\n\n\t\t// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter\n\t\t// Use an explicit zero to avoid NaN (gh-3964)\n\t\t) ) || 0;\n\t}\n\n\treturn delta;\n}\n\nfunction getWidthOrHeight( elem, dimension, extra ) {\n\n\t// Start with computed style\n\tvar styles = getStyles( elem ),\n\n\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).\n\t\t// Fake content-box until we know it's needed to know the true value.\n\t\tboxSizingNeeded = !support.boxSizingReliable() || extra,\n\t\tisBorderBox = boxSizingNeeded &&\n\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\tvalueIsBorderBox = isBorderBox,\n\n\t\tval = curCSS( elem, dimension, styles ),\n\t\toffsetProp = \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );\n\n\t// Support: Firefox <=54\n\t// Return a confounding non-pixel value or feign ignorance, as appropriate.\n\tif ( rnumnonpx.test( val ) ) {\n\t\tif ( !extra ) {\n\t\t\treturn val;\n\t\t}\n\t\tval = \"auto\";\n\t}\n\n\n\t// Support: IE 9 - 11 only\n\t// Use offsetWidth/offsetHeight for when box sizing is unreliable.\n\t// In those cases, the computed value can be trusted to be border-box.\n\tif ( ( !support.boxSizingReliable() && isBorderBox ||\n\n\t\t// Support: IE 10 - 11+, Edge 15 - 18+\n\t\t// IE/Edge misreport `getComputedStyle` of table rows with width/height\n\t\t// set in CSS while `offset*` properties report correct values.\n\t\t// Interestingly, in some cases IE 9 doesn't suffer from this issue.\n\t\t!support.reliableTrDimensions() && nodeName( elem, \"tr\" ) ||\n\n\t\t// Fall back to offsetWidth/offsetHeight when value is \"auto\"\n\t\t// This happens for inline elements with no explicit setting (gh-3571)\n\t\tval === \"auto\" ||\n\n\t\t// Support: Android <=4.1 - 4.3 only\n\t\t// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)\n\t\t!parseFloat( val ) && jQuery.css( elem, \"display\", false, styles ) === \"inline\" ) &&\n\n\t\t// Make sure the element is visible & connected\n\t\telem.getClientRects().length ) {\n\n\t\tisBorderBox = jQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\";\n\n\t\t// Where available, offsetWidth/offsetHeight approximate border box dimensions.\n\t\t// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the\n\t\t// retrieved value as a content box dimension.\n\t\tvalueIsBorderBox = offsetProp in elem;\n\t\tif ( valueIsBorderBox ) {\n\t\t\tval = elem[ offsetProp ];\n\t\t}\n\t}\n\n\t// Normalize \"\" and auto\n\tval = parseFloat( val ) || 0;\n\n\t// Adjust for the element's box model\n\treturn ( val +\n\t\tboxModelAdjustment(\n\t\t\telem,\n\t\t\tdimension,\n\t\t\textra || ( isBorderBox ? \"border\" : \"content\" ),\n\t\t\tvalueIsBorderBox,\n\t\t\tstyles,\n\n\t\t\t// Provide the current computed size to request scroll gutter calculation (gh-3589)\n\t\t\tval\n\t\t)\n\t) + \"px\";\n}\n\njQuery.extend( {\n\n\t// Add in style property hooks for overriding the default\n\t// behavior of getting and setting a style property\n\tcssHooks: {\n\t\topacity: {\n\t\t\tget: function( elem, computed ) {\n\t\t\t\tif ( computed ) {\n\n\t\t\t\t\t// We should always get a number back from opacity\n\t\t\t\t\tvar ret = curCSS( elem, \"opacity\" );\n\t\t\t\t\treturn ret === \"\" ? \"1\" : ret;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\t// Don't automatically add \"px\" to these possibly-unitless properties\n\tcssNumber: {\n\t\t\"animationIterationCount\": true,\n\t\t\"columnCount\": true,\n\t\t\"fillOpacity\": true,\n\t\t\"flexGrow\": true,\n\t\t\"flexShrink\": true,\n\t\t\"fontWeight\": true,\n\t\t\"gridArea\": true,\n\t\t\"gridColumn\": true,\n\t\t\"gridColumnEnd\": true,\n\t\t\"gridColumnStart\": true,\n\t\t\"gridRow\": true,\n\t\t\"gridRowEnd\": true,\n\t\t\"gridRowStart\": true,\n\t\t\"lineHeight\": true,\n\t\t\"opacity\": true,\n\t\t\"order\": true,\n\t\t\"orphans\": true,\n\t\t\"widows\": true,\n\t\t\"zIndex\": true,\n\t\t\"zoom\": true\n\t},\n\n\t// Add in properties whose names you wish to fix before\n\t// setting or getting the value\n\tcssProps: {},\n\n\t// Get and set the style property on a DOM Node\n\tstyle: function( elem, name, value, extra ) {\n\n\t\t// Don't set styles on text and comment nodes\n\t\tif ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Make sure that we're working with the right name\n\t\tvar ret, type, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name ),\n\t\t\tstyle = elem.style;\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to query the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Gets hook for the prefixed version, then unprefixed version\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// Check if we're setting a value\n\t\tif ( value !== undefined ) {\n\t\t\ttype = typeof value;\n\n\t\t\t// Convert \"+=\" or \"-=\" to relative numbers (#7345)\n\t\t\tif ( type === \"string\" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {\n\t\t\t\tvalue = adjustCSS( elem, name, ret );\n\n\t\t\t\t// Fixes bug #9237\n\t\t\t\ttype = \"number\";\n\t\t\t}\n\n\t\t\t// Make sure that null and NaN values aren't set (#7116)\n\t\t\tif ( value == null || value !== value ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// If a number was passed in, add the unit (except for certain CSS properties)\n\t\t\t// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append\n\t\t\t// \"px\" to a few hardcoded values.\n\t\t\tif ( type === \"number\" && !isCustomProp ) {\n\t\t\t\tvalue += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? \"\" : \"px\" );\n\t\t\t}\n\n\t\t\t// background-* props affect original clone's values\n\t\t\tif ( !support.clearCloneStyle && value === \"\" && name.indexOf( \"background\" ) === 0 ) {\n\t\t\t\tstyle[ name ] = \"inherit\";\n\t\t\t}\n\n\t\t\t// If a hook was provided, use that value, otherwise just set the specified value\n\t\t\tif ( !hooks || !( \"set\" in hooks ) ||\n\t\t\t\t( value = hooks.set( elem, value, extra ) ) !== undefined ) {\n\n\t\t\t\tif ( isCustomProp ) {\n\t\t\t\t\tstyle.setProperty( name, value );\n\t\t\t\t} else {\n\t\t\t\t\tstyle[ name ] = value;\n\t\t\t\t}\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// If a hook was provided get the non-computed value from there\n\t\t\tif ( hooks && \"get\" in hooks &&\n\t\t\t\t( ret = hooks.get( elem, false, extra ) ) !== undefined ) {\n\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\t// Otherwise just get the value from the style object\n\t\t\treturn style[ name ];\n\t\t}\n\t},\n\n\tcss: function( elem, name, extra, styles ) {\n\t\tvar val, num, hooks,\n\t\t\torigName = camelCase( name ),\n\t\t\tisCustomProp = rcustomProp.test( name );\n\n\t\t// Make sure that we're working with the right name. We don't\n\t\t// want to modify the value if it is a CSS custom property\n\t\t// since they are user-defined.\n\t\tif ( !isCustomProp ) {\n\t\t\tname = finalPropName( origName );\n\t\t}\n\n\t\t// Try prefixed name followed by the unprefixed name\n\t\thooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];\n\n\t\t// If a hook was provided get the computed value from there\n\t\tif ( hooks && \"get\" in hooks ) {\n\t\t\tval = hooks.get( elem, true, extra );\n\t\t}\n\n\t\t// Otherwise, if a way to get the computed value exists, use that\n\t\tif ( val === undefined ) {\n\t\t\tval = curCSS( elem, name, styles );\n\t\t}\n\n\t\t// Convert \"normal\" to computed value\n\t\tif ( val === \"normal\" && name in cssNormalTransform ) {\n\t\t\tval = cssNormalTransform[ name ];\n\t\t}\n\n\t\t// Make numeric if forced or a qualifier was provided and val looks numeric\n\t\tif ( extra === \"\" || extra ) {\n\t\t\tnum = parseFloat( val );\n\t\t\treturn extra === true || isFinite( num ) ? num || 0 : val;\n\t\t}\n\n\t\treturn val;\n\t}\n} );\n\njQuery.each( [ \"height\", \"width\" ], function( _i, dimension ) {\n\tjQuery.cssHooks[ dimension ] = {\n\t\tget: function( elem, computed, extra ) {\n\t\t\tif ( computed ) {\n\n\t\t\t\t// Certain elements can have dimension info if we invisibly show them\n\t\t\t\t// but it must have a current display style that would benefit\n\t\t\t\treturn rdisplayswap.test( jQuery.css( elem, \"display\" ) ) &&\n\n\t\t\t\t\t// Support: Safari 8+\n\t\t\t\t\t// Table columns in Safari have non-zero offsetWidth & zero\n\t\t\t\t\t// getBoundingClientRect().width unless display is changed.\n\t\t\t\t\t// Support: IE <=11 only\n\t\t\t\t\t// Running getBoundingClientRect on a disconnected node\n\t\t\t\t\t// in IE throws an error.\n\t\t\t\t\t( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?\n\t\t\t\t\t\tswap( elem, cssShow, function() {\n\t\t\t\t\t\t\treturn getWidthOrHeight( elem, dimension, extra );\n\t\t\t\t\t\t} ) :\n\t\t\t\t\t\tgetWidthOrHeight( elem, dimension, extra );\n\t\t\t}\n\t\t},\n\n\t\tset: function( elem, value, extra ) {\n\t\t\tvar matches,\n\t\t\t\tstyles = getStyles( elem ),\n\n\t\t\t\t// Only read styles.position if the test has a chance to fail\n\t\t\t\t// to avoid forcing a reflow.\n\t\t\t\tscrollboxSizeBuggy = !support.scrollboxSize() &&\n\t\t\t\t\tstyles.position === \"absolute\",\n\n\t\t\t\t// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)\n\t\t\t\tboxSizingNeeded = scrollboxSizeBuggy || extra,\n\t\t\t\tisBorderBox = boxSizingNeeded &&\n\t\t\t\t\tjQuery.css( elem, \"boxSizing\", false, styles ) === \"border-box\",\n\t\t\t\tsubtract = extra ?\n\t\t\t\t\tboxModelAdjustment(\n\t\t\t\t\t\telem,\n\t\t\t\t\t\tdimension,\n\t\t\t\t\t\textra,\n\t\t\t\t\t\tisBorderBox,\n\t\t\t\t\t\tstyles\n\t\t\t\t\t) :\n\t\t\t\t\t0;\n\n\t\t\t// Account for unreliable border-box dimensions by comparing offset* to computed and\n\t\t\t// faking a content-box to get border and padding (gh-3699)\n\t\t\tif ( isBorderBox && scrollboxSizeBuggy ) {\n\t\t\t\tsubtract -= Math.ceil(\n\t\t\t\t\telem[ \"offset\" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -\n\t\t\t\t\tparseFloat( styles[ dimension ] ) -\n\t\t\t\t\tboxModelAdjustment( elem, dimension, \"border\", false, styles ) -\n\t\t\t\t\t0.5\n\t\t\t\t);\n\t\t\t}\n\n\t\t\t// Convert to pixels if value adjustment is needed\n\t\t\tif ( subtract && ( matches = rcssNum.exec( value ) ) &&\n\t\t\t\t( matches[ 3 ] || \"px\" ) !== \"px\" ) {\n\n\t\t\t\telem.style[ dimension ] = value;\n\t\t\t\tvalue = jQuery.css( elem, dimension );\n\t\t\t}\n\n\t\t\treturn setPositiveNumber( elem, value, subtract );\n\t\t}\n\t};\n} );\n\njQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,\n\tfunction( elem, computed ) {\n\t\tif ( computed ) {\n\t\t\treturn ( parseFloat( curCSS( elem, \"marginLeft\" ) ) ||\n\t\t\t\telem.getBoundingClientRect().left -\n\t\t\t\t\tswap( elem, { marginLeft: 0 }, function() {\n\t\t\t\t\t\treturn elem.getBoundingClientRect().left;\n\t\t\t\t\t} )\n\t\t\t\t) + \"px\";\n\t\t}\n\t}\n);\n\n// These hooks are used by animate to expand properties\njQuery.each( {\n\tmargin: \"\",\n\tpadding: \"\",\n\tborder: \"Width\"\n}, function( prefix, suffix ) {\n\tjQuery.cssHooks[ prefix + suffix ] = {\n\t\texpand: function( value ) {\n\t\t\tvar i = 0,\n\t\t\t\texpanded = {},\n\n\t\t\t\t// Assumes a single number if not a string\n\t\t\t\tparts = typeof value === \"string\" ? value.split( \" \" ) : [ value ];\n\n\t\t\tfor ( ; i < 4; i++ ) {\n\t\t\t\texpanded[ prefix + cssExpand[ i ] + suffix ] =\n\t\t\t\t\tparts[ i ] || parts[ i - 2 ] || parts[ 0 ];\n\t\t\t}\n\n\t\t\treturn expanded;\n\t\t}\n\t};\n\n\tif ( prefix !== \"margin\" ) {\n\t\tjQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;\n\t}\n} );\n\njQuery.fn.extend( {\n\tcss: function( name, value ) {\n\t\treturn access( this, function( elem, name, value ) {\n\t\t\tvar styles, len,\n\t\t\t\tmap = {},\n\t\t\t\ti = 0;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\t\t\t\tstyles = getStyles( elem );\n\t\t\t\tlen = name.length;\n\n\t\t\t\tfor ( ; i < len; i++ ) {\n\t\t\t\t\tmap[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );\n\t\t\t\t}\n\n\t\t\t\treturn map;\n\t\t\t}\n\n\t\t\treturn value !== undefined ?\n\t\t\t\tjQuery.style( elem, name, value ) :\n\t\t\t\tjQuery.css( elem, name );\n\t\t}, name, value, arguments.length > 1 );\n\t}\n} );\n\n\nfunction Tween( elem, options, prop, end, easing ) {\n\treturn new Tween.prototype.init( elem, options, prop, end, easing );\n}\njQuery.Tween = Tween;\n\nTween.prototype = {\n\tconstructor: Tween,\n\tinit: function( elem, options, prop, end, easing, unit ) {\n\t\tthis.elem = elem;\n\t\tthis.prop = prop;\n\t\tthis.easing = easing || jQuery.easing._default;\n\t\tthis.options = options;\n\t\tthis.start = this.now = this.cur();\n\t\tthis.end = end;\n\t\tthis.unit = unit || ( jQuery.cssNumber[ prop ] ? \"\" : \"px\" );\n\t},\n\tcur: function() {\n\t\tvar hooks = Tween.propHooks[ this.prop ];\n\n\t\treturn hooks && hooks.get ?\n\t\t\thooks.get( this ) :\n\t\t\tTween.propHooks._default.get( this );\n\t},\n\trun: function( percent ) {\n\t\tvar eased,\n\t\t\thooks = Tween.propHooks[ this.prop ];\n\n\t\tif ( this.options.duration ) {\n\t\t\tthis.pos = eased = jQuery.easing[ this.easing ](\n\t\t\t\tpercent, this.options.duration * percent, 0, 1, this.options.duration\n\t\t\t);\n\t\t} else {\n\t\t\tthis.pos = eased = percent;\n\t\t}\n\t\tthis.now = ( this.end - this.start ) * eased + this.start;\n\n\t\tif ( this.options.step ) {\n\t\t\tthis.options.step.call( this.elem, this.now, this );\n\t\t}\n\n\t\tif ( hooks && hooks.set ) {\n\t\t\thooks.set( this );\n\t\t} else {\n\t\t\tTween.propHooks._default.set( this );\n\t\t}\n\t\treturn this;\n\t}\n};\n\nTween.prototype.init.prototype = Tween.prototype;\n\nTween.propHooks = {\n\t_default: {\n\t\tget: function( tween ) {\n\t\t\tvar result;\n\n\t\t\t// Use a property on the element directly when it is not a DOM element,\n\t\t\t// or when there is no matching style property that exists.\n\t\t\tif ( tween.elem.nodeType !== 1 ||\n\t\t\t\ttween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {\n\t\t\t\treturn tween.elem[ tween.prop ];\n\t\t\t}\n\n\t\t\t// Passing an empty string as a 3rd parameter to .css will automatically\n\t\t\t// attempt a parseFloat and fallback to a string if the parse fails.\n\t\t\t// Simple values such as \"10px\" are parsed to Float;\n\t\t\t// complex values such as \"rotate(1rad)\" are returned as-is.\n\t\t\tresult = jQuery.css( tween.elem, tween.prop, \"\" );\n\n\t\t\t// Empty strings, null, undefined and \"auto\" are converted to 0.\n\t\t\treturn !result || result === \"auto\" ? 0 : result;\n\t\t},\n\t\tset: function( tween ) {\n\n\t\t\t// Use step hook for back compat.\n\t\t\t// Use cssHook if its there.\n\t\t\t// Use .style if available and use plain properties where available.\n\t\t\tif ( jQuery.fx.step[ tween.prop ] ) {\n\t\t\t\tjQuery.fx.step[ tween.prop ]( tween );\n\t\t\t} else if ( tween.elem.nodeType === 1 && (\n\t\t\t\t\tjQuery.cssHooks[ tween.prop ] ||\n\t\t\t\t\ttween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {\n\t\t\t\tjQuery.style( tween.elem, tween.prop, tween.now + tween.unit );\n\t\t\t} else {\n\t\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t\t}\n\t\t}\n\t}\n};\n\n// Support: IE <=9 only\n// Panic based approach to setting things on disconnected nodes\nTween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {\n\tset: function( tween ) {\n\t\tif ( tween.elem.nodeType && tween.elem.parentNode ) {\n\t\t\ttween.elem[ tween.prop ] = tween.now;\n\t\t}\n\t}\n};\n\njQuery.easing = {\n\tlinear: function( p ) {\n\t\treturn p;\n\t},\n\tswing: function( p ) {\n\t\treturn 0.5 - Math.cos( p * Math.PI ) / 2;\n\t},\n\t_default: \"swing\"\n};\n\njQuery.fx = Tween.prototype.init;\n\n// Back compat <1.8 extension point\njQuery.fx.step = {};\n\n\n\n\nvar\n\tfxNow, inProgress,\n\trfxtypes = /^(?:toggle|show|hide)$/,\n\trrun = /queueHooks$/;\n\nfunction schedule() {\n\tif ( inProgress ) {\n\t\tif ( document.hidden === false && window.requestAnimationFrame ) {\n\t\t\twindow.requestAnimationFrame( schedule );\n\t\t} else {\n\t\t\twindow.setTimeout( schedule, jQuery.fx.interval );\n\t\t}\n\n\t\tjQuery.fx.tick();\n\t}\n}\n\n// Animations created synchronously will run synchronously\nfunction createFxNow() {\n\twindow.setTimeout( function() {\n\t\tfxNow = undefined;\n\t} );\n\treturn ( fxNow = Date.now() );\n}\n\n// Generate parameters to create a standard animation\nfunction genFx( type, includeWidth ) {\n\tvar which,\n\t\ti = 0,\n\t\tattrs = { height: type };\n\n\t// If we include width, step value is 1 to do all cssExpand values,\n\t// otherwise step value is 2 to skip over Left and Right\n\tincludeWidth = includeWidth ? 1 : 0;\n\tfor ( ; i < 4; i += 2 - includeWidth ) {\n\t\twhich = cssExpand[ i ];\n\t\tattrs[ \"margin\" + which ] = attrs[ \"padding\" + which ] = type;\n\t}\n\n\tif ( includeWidth ) {\n\t\tattrs.opacity = attrs.width = type;\n\t}\n\n\treturn attrs;\n}\n\nfunction createTween( value, prop, animation ) {\n\tvar tween,\n\t\tcollection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ \"*\" ] ),\n\t\tindex = 0,\n\t\tlength = collection.length;\n\tfor ( ; index < length; index++ ) {\n\t\tif ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {\n\n\t\t\t// We're done with this property\n\t\t\treturn tween;\n\t\t}\n\t}\n}\n\nfunction defaultPrefilter( elem, props, opts ) {\n\tvar prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,\n\t\tisBox = \"width\" in props || \"height\" in props,\n\t\tanim = this,\n\t\torig = {},\n\t\tstyle = elem.style,\n\t\thidden = elem.nodeType && isHiddenWithinTree( elem ),\n\t\tdataShow = dataPriv.get( elem, \"fxshow\" );\n\n\t// Queue-skipping animations hijack the fx hooks\n\tif ( !opts.queue ) {\n\t\thooks = jQuery._queueHooks( elem, \"fx\" );\n\t\tif ( hooks.unqueued == null ) {\n\t\t\thooks.unqueued = 0;\n\t\t\toldfire = hooks.empty.fire;\n\t\t\thooks.empty.fire = function() {\n\t\t\t\tif ( !hooks.unqueued ) {\n\t\t\t\t\toldfire();\n\t\t\t\t}\n\t\t\t};\n\t\t}\n\t\thooks.unqueued++;\n\n\t\tanim.always( function() {\n\n\t\t\t// Ensure the complete handler is called before this completes\n\t\t\tanim.always( function() {\n\t\t\t\thooks.unqueued--;\n\t\t\t\tif ( !jQuery.queue( elem, \"fx\" ).length ) {\n\t\t\t\t\thooks.empty.fire();\n\t\t\t\t}\n\t\t\t} );\n\t\t} );\n\t}\n\n\t// Detect show/hide animations\n\tfor ( prop in props ) {\n\t\tvalue = props[ prop ];\n\t\tif ( rfxtypes.test( value ) ) {\n\t\t\tdelete props[ prop ];\n\t\t\ttoggle = toggle || value === \"toggle\";\n\t\t\tif ( value === ( hidden ? \"hide\" : \"show\" ) ) {\n\n\t\t\t\t// Pretend to be hidden if this is a \"show\" and\n\t\t\t\t// there is still data from a stopped show/hide\n\t\t\t\tif ( value === \"show\" && dataShow && dataShow[ prop ] !== undefined ) {\n\t\t\t\t\thidden = true;\n\n\t\t\t\t// Ignore all other no-op show/hide data\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\torig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );\n\t\t}\n\t}\n\n\t// Bail out if this is a no-op like .hide().hide()\n\tpropTween = !jQuery.isEmptyObject( props );\n\tif ( !propTween && jQuery.isEmptyObject( orig ) ) {\n\t\treturn;\n\t}\n\n\t// Restrict \"overflow\" and \"display\" styles during box animations\n\tif ( isBox && elem.nodeType === 1 ) {\n\n\t\t// Support: IE <=9 - 11, Edge 12 - 15\n\t\t// Record all 3 overflow attributes because IE does not infer the shorthand\n\t\t// from identically-valued overflowX and overflowY and Edge just mirrors\n\t\t// the overflowX value there.\n\t\topts.overflow = [ style.overflow, style.overflowX, style.overflowY ];\n\n\t\t// Identify a display type, preferring old show/hide data over the CSS cascade\n\t\trestoreDisplay = dataShow && dataShow.display;\n\t\tif ( restoreDisplay == null ) {\n\t\t\trestoreDisplay = dataPriv.get( elem, \"display\" );\n\t\t}\n\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\tif ( display === \"none\" ) {\n\t\t\tif ( restoreDisplay ) {\n\t\t\t\tdisplay = restoreDisplay;\n\t\t\t} else {\n\n\t\t\t\t// Get nonempty value(s) by temporarily forcing visibility\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t\trestoreDisplay = elem.style.display || restoreDisplay;\n\t\t\t\tdisplay = jQuery.css( elem, \"display\" );\n\t\t\t\tshowHide( [ elem ] );\n\t\t\t}\n\t\t}\n\n\t\t// Animate inline elements as inline-block\n\t\tif ( display === \"inline\" || display === \"inline-block\" && restoreDisplay != null ) {\n\t\t\tif ( jQuery.css( elem, \"float\" ) === \"none\" ) {\n\n\t\t\t\t// Restore the original display value at the end of pure show/hide animations\n\t\t\t\tif ( !propTween ) {\n\t\t\t\t\tanim.done( function() {\n\t\t\t\t\t\tstyle.display = restoreDisplay;\n\t\t\t\t\t} );\n\t\t\t\t\tif ( restoreDisplay == null ) {\n\t\t\t\t\t\tdisplay = style.display;\n\t\t\t\t\t\trestoreDisplay = display === \"none\" ? \"\" : display;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tstyle.display = \"inline-block\";\n\t\t\t}\n\t\t}\n\t}\n\n\tif ( opts.overflow ) {\n\t\tstyle.overflow = \"hidden\";\n\t\tanim.always( function() {\n\t\t\tstyle.overflow = opts.overflow[ 0 ];\n\t\t\tstyle.overflowX = opts.overflow[ 1 ];\n\t\t\tstyle.overflowY = opts.overflow[ 2 ];\n\t\t} );\n\t}\n\n\t// Implement show/hide animations\n\tpropTween = false;\n\tfor ( prop in orig ) {\n\n\t\t// General show/hide setup for this element animation\n\t\tif ( !propTween ) {\n\t\t\tif ( dataShow ) {\n\t\t\t\tif ( \"hidden\" in dataShow ) {\n\t\t\t\t\thidden = dataShow.hidden;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tdataShow = dataPriv.access( elem, \"fxshow\", { display: restoreDisplay } );\n\t\t\t}\n\n\t\t\t// Store hidden/visible for toggle so `.stop().toggle()` \"reverses\"\n\t\t\tif ( toggle ) {\n\t\t\t\tdataShow.hidden = !hidden;\n\t\t\t}\n\n\t\t\t// Show elements before animating them\n\t\t\tif ( hidden ) {\n\t\t\t\tshowHide( [ elem ], true );\n\t\t\t}\n\n\t\t\t/* eslint-disable no-loop-func */\n\n\t\t\tanim.done( function() {\n\n\t\t\t/* eslint-enable no-loop-func */\n\n\t\t\t\t// The final step of a \"hide\" animation is actually hiding the element\n\t\t\t\tif ( !hidden ) {\n\t\t\t\t\tshowHide( [ elem ] );\n\t\t\t\t}\n\t\t\t\tdataPriv.remove( elem, \"fxshow\" );\n\t\t\t\tfor ( prop in orig ) {\n\t\t\t\t\tjQuery.style( elem, prop, orig[ prop ] );\n\t\t\t\t}\n\t\t\t} );\n\t\t}\n\n\t\t// Per-property setup\n\t\tpropTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );\n\t\tif ( !( prop in dataShow ) ) {\n\t\t\tdataShow[ prop ] = propTween.start;\n\t\t\tif ( hidden ) {\n\t\t\t\tpropTween.end = propTween.start;\n\t\t\t\tpropTween.start = 0;\n\t\t\t}\n\t\t}\n\t}\n}\n\nfunction propFilter( props, specialEasing ) {\n\tvar index, name, easing, value, hooks;\n\n\t// camelCase, specialEasing and expand cssHook pass\n\tfor ( index in props ) {\n\t\tname = camelCase( index );\n\t\teasing = specialEasing[ name ];\n\t\tvalue = props[ index ];\n\t\tif ( Array.isArray( value ) ) {\n\t\t\teasing = value[ 1 ];\n\t\t\tvalue = props[ index ] = value[ 0 ];\n\t\t}\n\n\t\tif ( index !== name ) {\n\t\t\tprops[ name ] = value;\n\t\t\tdelete props[ index ];\n\t\t}\n\n\t\thooks = jQuery.cssHooks[ name ];\n\t\tif ( hooks && \"expand\" in hooks ) {\n\t\t\tvalue = hooks.expand( value );\n\t\t\tdelete props[ name ];\n\n\t\t\t// Not quite $.extend, this won't overwrite existing keys.\n\t\t\t// Reusing 'index' because we have the correct \"name\"\n\t\t\tfor ( index in value ) {\n\t\t\t\tif ( !( index in props ) ) {\n\t\t\t\t\tprops[ index ] = value[ index ];\n\t\t\t\t\tspecialEasing[ index ] = easing;\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tspecialEasing[ name ] = easing;\n\t\t}\n\t}\n}\n\nfunction Animation( elem, properties, options ) {\n\tvar result,\n\t\tstopped,\n\t\tindex = 0,\n\t\tlength = Animation.prefilters.length,\n\t\tdeferred = jQuery.Deferred().always( function() {\n\n\t\t\t// Don't match elem in the :animated selector\n\t\t\tdelete tick.elem;\n\t\t} ),\n\t\ttick = function() {\n\t\t\tif ( stopped ) {\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tvar currentTime = fxNow || createFxNow(),\n\t\t\t\tremaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),\n\n\t\t\t\t// Support: Android 2.3 only\n\t\t\t\t// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)\n\t\t\t\ttemp = remaining / animation.duration || 0,\n\t\t\t\tpercent = 1 - temp,\n\t\t\t\tindex = 0,\n\t\t\t\tlength = animation.tweens.length;\n\n\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\tanimation.tweens[ index ].run( percent );\n\t\t\t}\n\n\t\t\tdeferred.notifyWith( elem, [ animation, percent, remaining ] );\n\n\t\t\t// If there's more to do, yield\n\t\t\tif ( percent < 1 && length ) {\n\t\t\t\treturn remaining;\n\t\t\t}\n\n\t\t\t// If this was an empty animation, synthesize a final progress notification\n\t\t\tif ( !length ) {\n\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t}\n\n\t\t\t// Resolve the animation and report its conclusion\n\t\t\tdeferred.resolveWith( elem, [ animation ] );\n\t\t\treturn false;\n\t\t},\n\t\tanimation = deferred.promise( {\n\t\t\telem: elem,\n\t\t\tprops: jQuery.extend( {}, properties ),\n\t\t\topts: jQuery.extend( true, {\n\t\t\t\tspecialEasing: {},\n\t\t\t\teasing: jQuery.easing._default\n\t\t\t}, options ),\n\t\t\toriginalProperties: properties,\n\t\t\toriginalOptions: options,\n\t\t\tstartTime: fxNow || createFxNow(),\n\t\t\tduration: options.duration,\n\t\t\ttweens: [],\n\t\t\tcreateTween: function( prop, end ) {\n\t\t\t\tvar tween = jQuery.Tween( elem, animation.opts, prop, end,\n\t\t\t\t\t\tanimation.opts.specialEasing[ prop ] || animation.opts.easing );\n\t\t\t\tanimation.tweens.push( tween );\n\t\t\t\treturn tween;\n\t\t\t},\n\t\t\tstop: function( gotoEnd ) {\n\t\t\t\tvar index = 0,\n\n\t\t\t\t\t// If we are going to the end, we want to run all the tweens\n\t\t\t\t\t// otherwise we skip this part\n\t\t\t\t\tlength = gotoEnd ? animation.tweens.length : 0;\n\t\t\t\tif ( stopped ) {\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t\tstopped = true;\n\t\t\t\tfor ( ; index < length; index++ ) {\n\t\t\t\t\tanimation.tweens[ index ].run( 1 );\n\t\t\t\t}\n\n\t\t\t\t// Resolve when we played the last frame; otherwise, reject\n\t\t\t\tif ( gotoEnd ) {\n\t\t\t\t\tdeferred.notifyWith( elem, [ animation, 1, 0 ] );\n\t\t\t\t\tdeferred.resolveWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t} else {\n\t\t\t\t\tdeferred.rejectWith( elem, [ animation, gotoEnd ] );\n\t\t\t\t}\n\t\t\t\treturn this;\n\t\t\t}\n\t\t} ),\n\t\tprops = animation.props;\n\n\tpropFilter( props, animation.opts.specialEasing );\n\n\tfor ( ; index < length; index++ ) {\n\t\tresult = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );\n\t\tif ( result ) {\n\t\t\tif ( isFunction( result.stop ) ) {\n\t\t\t\tjQuery._queueHooks( animation.elem, animation.opts.queue ).stop =\n\t\t\t\t\tresult.stop.bind( result );\n\t\t\t}\n\t\t\treturn result;\n\t\t}\n\t}\n\n\tjQuery.map( props, createTween, animation );\n\n\tif ( isFunction( animation.opts.start ) ) {\n\t\tanimation.opts.start.call( elem, animation );\n\t}\n\n\t// Attach callbacks from options\n\tanimation\n\t\t.progress( animation.opts.progress )\n\t\t.done( animation.opts.done, animation.opts.complete )\n\t\t.fail( animation.opts.fail )\n\t\t.always( animation.opts.always );\n\n\tjQuery.fx.timer(\n\t\tjQuery.extend( tick, {\n\t\t\telem: elem,\n\t\t\tanim: animation,\n\t\t\tqueue: animation.opts.queue\n\t\t} )\n\t);\n\n\treturn animation;\n}\n\njQuery.Animation = jQuery.extend( Animation, {\n\n\ttweeners: {\n\t\t\"*\": [ function( prop, value ) {\n\t\t\tvar tween = this.createTween( prop, value );\n\t\t\tadjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );\n\t\t\treturn tween;\n\t\t} ]\n\t},\n\n\ttweener: function( props, callback ) {\n\t\tif ( isFunction( props ) ) {\n\t\t\tcallback = props;\n\t\t\tprops = [ \"*\" ];\n\t\t} else {\n\t\t\tprops = props.match( rnothtmlwhite );\n\t\t}\n\n\t\tvar prop,\n\t\t\tindex = 0,\n\t\t\tlength = props.length;\n\n\t\tfor ( ; index < length; index++ ) {\n\t\t\tprop = props[ index ];\n\t\t\tAnimation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];\n\t\t\tAnimation.tweeners[ prop ].unshift( callback );\n\t\t}\n\t},\n\n\tprefilters: [ defaultPrefilter ],\n\n\tprefilter: function( callback, prepend ) {\n\t\tif ( prepend ) {\n\t\t\tAnimation.prefilters.unshift( callback );\n\t\t} else {\n\t\t\tAnimation.prefilters.push( callback );\n\t\t}\n\t}\n} );\n\njQuery.speed = function( speed, easing, fn ) {\n\tvar opt = speed && typeof speed === \"object\" ? jQuery.extend( {}, speed ) : {\n\t\tcomplete: fn || !fn && easing ||\n\t\t\tisFunction( speed ) && speed,\n\t\tduration: speed,\n\t\teasing: fn && easing || easing && !isFunction( easing ) && easing\n\t};\n\n\t// Go to the end state if fx are off\n\tif ( jQuery.fx.off ) {\n\t\topt.duration = 0;\n\n\t} else {\n\t\tif ( typeof opt.duration !== \"number\" ) {\n\t\t\tif ( opt.duration in jQuery.fx.speeds ) {\n\t\t\t\topt.duration = jQuery.fx.speeds[ opt.duration ];\n\n\t\t\t} else {\n\t\t\t\topt.duration = jQuery.fx.speeds._default;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Normalize opt.queue - true/undefined/null -> \"fx\"\n\tif ( opt.queue == null || opt.queue === true ) {\n\t\topt.queue = \"fx\";\n\t}\n\n\t// Queueing\n\topt.old = opt.complete;\n\n\topt.complete = function() {\n\t\tif ( isFunction( opt.old ) ) {\n\t\t\topt.old.call( this );\n\t\t}\n\n\t\tif ( opt.queue ) {\n\t\t\tjQuery.dequeue( this, opt.queue );\n\t\t}\n\t};\n\n\treturn opt;\n};\n\njQuery.fn.extend( {\n\tfadeTo: function( speed, to, easing, callback ) {\n\n\t\t// Show any hidden elements after setting opacity to 0\n\t\treturn this.filter( isHiddenWithinTree ).css( \"opacity\", 0 ).show()\n\n\t\t\t// Animate to the value specified\n\t\t\t.end().animate( { opacity: to }, speed, easing, callback );\n\t},\n\tanimate: function( prop, speed, easing, callback ) {\n\t\tvar empty = jQuery.isEmptyObject( prop ),\n\t\t\toptall = jQuery.speed( speed, easing, callback ),\n\t\t\tdoAnimation = function() {\n\n\t\t\t\t// Operate on a copy of prop so per-property easing won't be lost\n\t\t\t\tvar anim = Animation( this, jQuery.extend( {}, prop ), optall );\n\n\t\t\t\t// Empty animations, or finishing resolves immediately\n\t\t\t\tif ( empty || dataPriv.get( this, \"finish\" ) ) {\n\t\t\t\t\tanim.stop( true );\n\t\t\t\t}\n\t\t\t};\n\t\t\tdoAnimation.finish = doAnimation;\n\n\t\treturn empty || optall.queue === false ?\n\t\t\tthis.each( doAnimation ) :\n\t\t\tthis.queue( optall.queue, doAnimation );\n\t},\n\tstop: function( type, clearQueue, gotoEnd ) {\n\t\tvar stopQueue = function( hooks ) {\n\t\t\tvar stop = hooks.stop;\n\t\t\tdelete hooks.stop;\n\t\t\tstop( gotoEnd );\n\t\t};\n\n\t\tif ( typeof type !== \"string\" ) {\n\t\t\tgotoEnd = clearQueue;\n\t\t\tclearQueue = type;\n\t\t\ttype = undefined;\n\t\t}\n\t\tif ( clearQueue ) {\n\t\t\tthis.queue( type || \"fx\", [] );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar dequeue = true,\n\t\t\t\tindex = type != null && type + \"queueHooks\",\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tdata = dataPriv.get( this );\n\n\t\t\tif ( index ) {\n\t\t\t\tif ( data[ index ] && data[ index ].stop ) {\n\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tfor ( index in data ) {\n\t\t\t\t\tif ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {\n\t\t\t\t\t\tstopQueue( data[ index ] );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this &&\n\t\t\t\t\t( type == null || timers[ index ].queue === type ) ) {\n\n\t\t\t\t\ttimers[ index ].anim.stop( gotoEnd );\n\t\t\t\t\tdequeue = false;\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Start the next in the queue if the last step wasn't forced.\n\t\t\t// Timers currently will call their complete callbacks, which\n\t\t\t// will dequeue but only if they were gotoEnd.\n\t\t\tif ( dequeue || !gotoEnd ) {\n\t\t\t\tjQuery.dequeue( this, type );\n\t\t\t}\n\t\t} );\n\t},\n\tfinish: function( type ) {\n\t\tif ( type !== false ) {\n\t\t\ttype = type || \"fx\";\n\t\t}\n\t\treturn this.each( function() {\n\t\t\tvar index,\n\t\t\t\tdata = dataPriv.get( this ),\n\t\t\t\tqueue = data[ type + \"queue\" ],\n\t\t\t\thooks = data[ type + \"queueHooks\" ],\n\t\t\t\ttimers = jQuery.timers,\n\t\t\t\tlength = queue ? queue.length : 0;\n\n\t\t\t// Enable finishing flag on private data\n\t\t\tdata.finish = true;\n\n\t\t\t// Empty the queue first\n\t\t\tjQuery.queue( this, type, [] );\n\n\t\t\tif ( hooks && hooks.stop ) {\n\t\t\t\thooks.stop.call( this, true );\n\t\t\t}\n\n\t\t\t// Look for any active animations, and finish them\n\t\t\tfor ( index = timers.length; index--; ) {\n\t\t\t\tif ( timers[ index ].elem === this && timers[ index ].queue === type ) {\n\t\t\t\t\ttimers[ index ].anim.stop( true );\n\t\t\t\t\ttimers.splice( index, 1 );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Look for any animations in the old queue and finish them\n\t\t\tfor ( index = 0; index < length; index++ ) {\n\t\t\t\tif ( queue[ index ] && queue[ index ].finish ) {\n\t\t\t\t\tqueue[ index ].finish.call( this );\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Turn off finishing flag\n\t\t\tdelete data.finish;\n\t\t} );\n\t}\n} );\n\njQuery.each( [ \"toggle\", \"show\", \"hide\" ], function( _i, name ) {\n\tvar cssFn = jQuery.fn[ name ];\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn speed == null || typeof speed === \"boolean\" ?\n\t\t\tcssFn.apply( this, arguments ) :\n\t\t\tthis.animate( genFx( name, true ), speed, easing, callback );\n\t};\n} );\n\n// Generate shortcuts for custom animations\njQuery.each( {\n\tslideDown: genFx( \"show\" ),\n\tslideUp: genFx( \"hide\" ),\n\tslideToggle: genFx( \"toggle\" ),\n\tfadeIn: { opacity: \"show\" },\n\tfadeOut: { opacity: \"hide\" },\n\tfadeToggle: { opacity: \"toggle\" }\n}, function( name, props ) {\n\tjQuery.fn[ name ] = function( speed, easing, callback ) {\n\t\treturn this.animate( props, speed, easing, callback );\n\t};\n} );\n\njQuery.timers = [];\njQuery.fx.tick = function() {\n\tvar timer,\n\t\ti = 0,\n\t\ttimers = jQuery.timers;\n\n\tfxNow = Date.now();\n\n\tfor ( ; i < timers.length; i++ ) {\n\t\ttimer = timers[ i ];\n\n\t\t// Run the timer and safely remove it when done (allowing for external removal)\n\t\tif ( !timer() && timers[ i ] === timer ) {\n\t\t\ttimers.splice( i--, 1 );\n\t\t}\n\t}\n\n\tif ( !timers.length ) {\n\t\tjQuery.fx.stop();\n\t}\n\tfxNow = undefined;\n};\n\njQuery.fx.timer = function( timer ) {\n\tjQuery.timers.push( timer );\n\tjQuery.fx.start();\n};\n\njQuery.fx.interval = 13;\njQuery.fx.start = function() {\n\tif ( inProgress ) {\n\t\treturn;\n\t}\n\n\tinProgress = true;\n\tschedule();\n};\n\njQuery.fx.stop = function() {\n\tinProgress = null;\n};\n\njQuery.fx.speeds = {\n\tslow: 600,\n\tfast: 200,\n\n\t// Default speed\n\t_default: 400\n};\n\n\n// Based off of the plugin by Clint Helfers, with permission.\n// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/\njQuery.fn.delay = function( time, type ) {\n\ttime = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;\n\ttype = type || \"fx\";\n\n\treturn this.queue( type, function( next, hooks ) {\n\t\tvar timeout = window.setTimeout( next, time );\n\t\thooks.stop = function() {\n\t\t\twindow.clearTimeout( timeout );\n\t\t};\n\t} );\n};\n\n\n( function() {\n\tvar input = document.createElement( \"input\" ),\n\t\tselect = document.createElement( \"select\" ),\n\t\topt = select.appendChild( document.createElement( \"option\" ) );\n\n\tinput.type = \"checkbox\";\n\n\t// Support: Android <=4.3 only\n\t// Default value for a checkbox should be \"on\"\n\tsupport.checkOn = input.value !== \"\";\n\n\t// Support: IE <=11 only\n\t// Must access selectedIndex to make default options select\n\tsupport.optSelected = opt.selected;\n\n\t// Support: IE <=11 only\n\t// An input loses its value after becoming a radio\n\tinput = document.createElement( \"input\" );\n\tinput.value = \"t\";\n\tinput.type = \"radio\";\n\tsupport.radioValue = input.value === \"t\";\n} )();\n\n\nvar boolHook,\n\tattrHandle = jQuery.expr.attrHandle;\n\njQuery.fn.extend( {\n\tattr: function( name, value ) {\n\t\treturn access( this, jQuery.attr, name, value, arguments.length > 1 );\n\t},\n\n\tremoveAttr: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.removeAttr( this, name );\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tattr: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set attributes on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Fallback to prop when attributes are not supported\n\t\tif ( typeof elem.getAttribute === \"undefined\" ) {\n\t\t\treturn jQuery.prop( elem, name, value );\n\t\t}\n\n\t\t// Attribute hooks are determined by the lowercase version\n\t\t// Grab necessary hook if one is defined\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\t\t\thooks = jQuery.attrHooks[ name.toLowerCase() ] ||\n\t\t\t\t( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( value === null ) {\n\t\t\t\tjQuery.removeAttr( elem, name );\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\telem.setAttribute( name, value + \"\" );\n\t\t\treturn value;\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\tret = jQuery.find.attr( elem, name );\n\n\t\t// Non-existent attributes return null, we normalize to undefined\n\t\treturn ret == null ? undefined : ret;\n\t},\n\n\tattrHooks: {\n\t\ttype: {\n\t\t\tset: function( elem, value ) {\n\t\t\t\tif ( !support.radioValue && value === \"radio\" &&\n\t\t\t\t\tnodeName( elem, \"input\" ) ) {\n\t\t\t\t\tvar val = elem.value;\n\t\t\t\t\telem.setAttribute( \"type\", value );\n\t\t\t\t\tif ( val ) {\n\t\t\t\t\t\telem.value = val;\n\t\t\t\t\t}\n\t\t\t\t\treturn value;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t},\n\n\tremoveAttr: function( elem, value ) {\n\t\tvar name,\n\t\t\ti = 0,\n\n\t\t\t// Attribute names can contain non-HTML whitespace characters\n\t\t\t// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2\n\t\t\tattrNames = value && value.match( rnothtmlwhite );\n\n\t\tif ( attrNames && elem.nodeType === 1 ) {\n\t\t\twhile ( ( name = attrNames[ i++ ] ) ) {\n\t\t\t\telem.removeAttribute( name );\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Hooks for boolean attributes\nboolHook = {\n\tset: function( elem, value, name ) {\n\t\tif ( value === false ) {\n\n\t\t\t// Remove boolean attributes when set to false\n\t\t\tjQuery.removeAttr( elem, name );\n\t\t} else {\n\t\t\telem.setAttribute( name, name );\n\t\t}\n\t\treturn name;\n\t}\n};\n\njQuery.each( jQuery.expr.match.bool.source.match( /\\w+/g ), function( _i, name ) {\n\tvar getter = attrHandle[ name ] || jQuery.find.attr;\n\n\tattrHandle[ name ] = function( elem, name, isXML ) {\n\t\tvar ret, handle,\n\t\t\tlowercaseName = name.toLowerCase();\n\n\t\tif ( !isXML ) {\n\n\t\t\t// Avoid an infinite loop by temporarily removing this function from the getter\n\t\t\thandle = attrHandle[ lowercaseName ];\n\t\t\tattrHandle[ lowercaseName ] = ret;\n\t\t\tret = getter( elem, name, isXML ) != null ?\n\t\t\t\tlowercaseName :\n\t\t\t\tnull;\n\t\t\tattrHandle[ lowercaseName ] = handle;\n\t\t}\n\t\treturn ret;\n\t};\n} );\n\n\n\n\nvar rfocusable = /^(?:input|select|textarea|button)$/i,\n\trclickable = /^(?:a|area)$/i;\n\njQuery.fn.extend( {\n\tprop: function( name, value ) {\n\t\treturn access( this, jQuery.prop, name, value, arguments.length > 1 );\n\t},\n\n\tremoveProp: function( name ) {\n\t\treturn this.each( function() {\n\t\t\tdelete this[ jQuery.propFix[ name ] || name ];\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tprop: function( elem, name, value ) {\n\t\tvar ret, hooks,\n\t\t\tnType = elem.nodeType;\n\n\t\t// Don't get/set properties on text, comment and attribute nodes\n\t\tif ( nType === 3 || nType === 8 || nType === 2 ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {\n\n\t\t\t// Fix name and attach hooks\n\t\t\tname = jQuery.propFix[ name ] || name;\n\t\t\thooks = jQuery.propHooks[ name ];\n\t\t}\n\n\t\tif ( value !== undefined ) {\n\t\t\tif ( hooks && \"set\" in hooks &&\n\t\t\t\t( ret = hooks.set( elem, value, name ) ) !== undefined ) {\n\t\t\t\treturn ret;\n\t\t\t}\n\n\t\t\treturn ( elem[ name ] = value );\n\t\t}\n\n\t\tif ( hooks && \"get\" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {\n\t\t\treturn ret;\n\t\t}\n\n\t\treturn elem[ name ];\n\t},\n\n\tpropHooks: {\n\t\ttabIndex: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\t// Support: IE <=9 - 11 only\n\t\t\t\t// elem.tabIndex doesn't always return the\n\t\t\t\t// correct value when it hasn't been explicitly set\n\t\t\t\t// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/\n\t\t\t\t// Use proper attribute retrieval(#12072)\n\t\t\t\tvar tabindex = jQuery.find.attr( elem, \"tabindex\" );\n\n\t\t\t\tif ( tabindex ) {\n\t\t\t\t\treturn parseInt( tabindex, 10 );\n\t\t\t\t}\n\n\t\t\t\tif (\n\t\t\t\t\trfocusable.test( elem.nodeName ) ||\n\t\t\t\t\trclickable.test( elem.nodeName ) &&\n\t\t\t\t\telem.href\n\t\t\t\t) {\n\t\t\t\t\treturn 0;\n\t\t\t\t}\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t}\n\t},\n\n\tpropFix: {\n\t\t\"for\": \"htmlFor\",\n\t\t\"class\": \"className\"\n\t}\n} );\n\n// Support: IE <=11 only\n// Accessing the selectedIndex property\n// forces the browser to respect setting selected\n// on the option\n// The getter ensures a default option is selected\n// when in an optgroup\n// eslint rule \"no-unused-expressions\" is disabled for this code\n// since it considers such accessions noop\nif ( !support.optSelected ) {\n\tjQuery.propHooks.selected = {\n\t\tget: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent && parent.parentNode ) {\n\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t}\n\t\t\treturn null;\n\t\t},\n\t\tset: function( elem ) {\n\n\t\t\t/* eslint no-unused-expressions: \"off\" */\n\n\t\t\tvar parent = elem.parentNode;\n\t\t\tif ( parent ) {\n\t\t\t\tparent.selectedIndex;\n\n\t\t\t\tif ( parent.parentNode ) {\n\t\t\t\t\tparent.parentNode.selectedIndex;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\njQuery.each( [\n\t\"tabIndex\",\n\t\"readOnly\",\n\t\"maxLength\",\n\t\"cellSpacing\",\n\t\"cellPadding\",\n\t\"rowSpan\",\n\t\"colSpan\",\n\t\"useMap\",\n\t\"frameBorder\",\n\t\"contentEditable\"\n], function() {\n\tjQuery.propFix[ this.toLowerCase() ] = this;\n} );\n\n\n\n\n\t// Strip and collapse whitespace according to HTML spec\n\t// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace\n\tfunction stripAndCollapse( value ) {\n\t\tvar tokens = value.match( rnothtmlwhite ) || [];\n\t\treturn tokens.join( \" \" );\n\t}\n\n\nfunction getClass( elem ) {\n\treturn elem.getAttribute && elem.getAttribute( \"class\" ) || \"\";\n}\n\nfunction classesToArray( value ) {\n\tif ( Array.isArray( value ) ) {\n\t\treturn value;\n\t}\n\tif ( typeof value === \"string\" ) {\n\t\treturn value.match( rnothtmlwhite ) || [];\n\t}\n\treturn [];\n}\n\njQuery.fn.extend( {\n\taddClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).addClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\t\t\t\t\t\tif ( cur.indexOf( \" \" + clazz + \" \" ) < 0 ) {\n\t\t\t\t\t\t\tcur += clazz + \" \";\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\tremoveClass: function( value ) {\n\t\tvar classes, elem, cur, curValue, clazz, j, finalValue,\n\t\t\ti = 0;\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( j ) {\n\t\t\t\tjQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );\n\t\t\t} );\n\t\t}\n\n\t\tif ( !arguments.length ) {\n\t\t\treturn this.attr( \"class\", \"\" );\n\t\t}\n\n\t\tclasses = classesToArray( value );\n\n\t\tif ( classes.length ) {\n\t\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\t\tcurValue = getClass( elem );\n\n\t\t\t\t// This expression is here for better compressibility (see addClass)\n\t\t\t\tcur = elem.nodeType === 1 && ( \" \" + stripAndCollapse( curValue ) + \" \" );\n\n\t\t\t\tif ( cur ) {\n\t\t\t\t\tj = 0;\n\t\t\t\t\twhile ( ( clazz = classes[ j++ ] ) ) {\n\n\t\t\t\t\t\t// Remove *all* instances\n\t\t\t\t\t\twhile ( cur.indexOf( \" \" + clazz + \" \" ) > -1 ) {\n\t\t\t\t\t\t\tcur = cur.replace( \" \" + clazz + \" \", \" \" );\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\n\t\t\t\t\t// Only assign if different to avoid unneeded rendering.\n\t\t\t\t\tfinalValue = stripAndCollapse( cur );\n\t\t\t\t\tif ( curValue !== finalValue ) {\n\t\t\t\t\t\telem.setAttribute( \"class\", finalValue );\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn this;\n\t},\n\n\ttoggleClass: function( value, stateVal ) {\n\t\tvar type = typeof value,\n\t\t\tisValidValue = type === \"string\" || Array.isArray( value );\n\n\t\tif ( typeof stateVal === \"boolean\" && isValidValue ) {\n\t\t\treturn stateVal ? this.addClass( value ) : this.removeClass( value );\n\t\t}\n\n\t\tif ( isFunction( value ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).toggleClass(\n\t\t\t\t\tvalue.call( this, i, getClass( this ), stateVal ),\n\t\t\t\t\tstateVal\n\t\t\t\t);\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar className, i, self, classNames;\n\n\t\t\tif ( isValidValue ) {\n\n\t\t\t\t// Toggle individual class names\n\t\t\t\ti = 0;\n\t\t\t\tself = jQuery( this );\n\t\t\t\tclassNames = classesToArray( value );\n\n\t\t\t\twhile ( ( className = classNames[ i++ ] ) ) {\n\n\t\t\t\t\t// Check each className given, space separated list\n\t\t\t\t\tif ( self.hasClass( className ) ) {\n\t\t\t\t\t\tself.removeClass( className );\n\t\t\t\t\t} else {\n\t\t\t\t\t\tself.addClass( className );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t// Toggle whole class name\n\t\t\t} else if ( value === undefined || type === \"boolean\" ) {\n\t\t\t\tclassName = getClass( this );\n\t\t\t\tif ( className ) {\n\n\t\t\t\t\t// Store className if set\n\t\t\t\t\tdataPriv.set( this, \"__className__\", className );\n\t\t\t\t}\n\n\t\t\t\t// If the element has a class name or if we're passed `false`,\n\t\t\t\t// then remove the whole classname (if there was one, the above saved it).\n\t\t\t\t// Otherwise bring back whatever was previously saved (if anything),\n\t\t\t\t// falling back to the empty string if nothing was stored.\n\t\t\t\tif ( this.setAttribute ) {\n\t\t\t\t\tthis.setAttribute( \"class\",\n\t\t\t\t\t\tclassName || value === false ?\n\t\t\t\t\t\t\"\" :\n\t\t\t\t\t\tdataPriv.get( this, \"__className__\" ) || \"\"\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t} );\n\t},\n\n\thasClass: function( selector ) {\n\t\tvar className, elem,\n\t\t\ti = 0;\n\n\t\tclassName = \" \" + selector + \" \";\n\t\twhile ( ( elem = this[ i++ ] ) ) {\n\t\t\tif ( elem.nodeType === 1 &&\n\t\t\t\t( \" \" + stripAndCollapse( getClass( elem ) ) + \" \" ).indexOf( className ) > -1 ) {\n\t\t\t\t\treturn true;\n\t\t\t}\n\t\t}\n\n\t\treturn false;\n\t}\n} );\n\n\n\n\nvar rreturn = /\\r/g;\n\njQuery.fn.extend( {\n\tval: function( value ) {\n\t\tvar hooks, ret, valueIsFunction,\n\t\t\telem = this[ 0 ];\n\n\t\tif ( !arguments.length ) {\n\t\t\tif ( elem ) {\n\t\t\t\thooks = jQuery.valHooks[ elem.type ] ||\n\t\t\t\t\tjQuery.valHooks[ elem.nodeName.toLowerCase() ];\n\n\t\t\t\tif ( hooks &&\n\t\t\t\t\t\"get\" in hooks &&\n\t\t\t\t\t( ret = hooks.get( elem, \"value\" ) ) !== undefined\n\t\t\t\t) {\n\t\t\t\t\treturn ret;\n\t\t\t\t}\n\n\t\t\t\tret = elem.value;\n\n\t\t\t\t// Handle most common string cases\n\t\t\t\tif ( typeof ret === \"string\" ) {\n\t\t\t\t\treturn ret.replace( rreturn, \"\" );\n\t\t\t\t}\n\n\t\t\t\t// Handle cases where value is null/undef or number\n\t\t\t\treturn ret == null ? \"\" : ret;\n\t\t\t}\n\n\t\t\treturn;\n\t\t}\n\n\t\tvalueIsFunction = isFunction( value );\n\n\t\treturn this.each( function( i ) {\n\t\t\tvar val;\n\n\t\t\tif ( this.nodeType !== 1 ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tif ( valueIsFunction ) {\n\t\t\t\tval = value.call( this, i, jQuery( this ).val() );\n\t\t\t} else {\n\t\t\t\tval = value;\n\t\t\t}\n\n\t\t\t// Treat null/undefined as \"\"; convert numbers to string\n\t\t\tif ( val == null ) {\n\t\t\t\tval = \"\";\n\n\t\t\t} else if ( typeof val === \"number\" ) {\n\t\t\t\tval += \"\";\n\n\t\t\t} else if ( Array.isArray( val ) ) {\n\t\t\t\tval = jQuery.map( val, function( value ) {\n\t\t\t\t\treturn value == null ? \"\" : value + \"\";\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\thooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];\n\n\t\t\t// If set returns undefined, fall back to normal setting\n\t\t\tif ( !hooks || !( \"set\" in hooks ) || hooks.set( this, val, \"value\" ) === undefined ) {\n\t\t\t\tthis.value = val;\n\t\t\t}\n\t\t} );\n\t}\n} );\n\njQuery.extend( {\n\tvalHooks: {\n\t\toption: {\n\t\t\tget: function( elem ) {\n\n\t\t\t\tvar val = jQuery.find.attr( elem, \"value\" );\n\t\t\t\treturn val != null ?\n\t\t\t\t\tval :\n\n\t\t\t\t\t// Support: IE <=10 - 11 only\n\t\t\t\t\t// option.text throws exceptions (#14686, #14858)\n\t\t\t\t\t// Strip and collapse whitespace\n\t\t\t\t\t// https://html.spec.whatwg.org/#strip-and-collapse-whitespace\n\t\t\t\t\tstripAndCollapse( jQuery.text( elem ) );\n\t\t\t}\n\t\t},\n\t\tselect: {\n\t\t\tget: function( elem ) {\n\t\t\t\tvar value, option, i,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tindex = elem.selectedIndex,\n\t\t\t\t\tone = elem.type === \"select-one\",\n\t\t\t\t\tvalues = one ? null : [],\n\t\t\t\t\tmax = one ? index + 1 : options.length;\n\n\t\t\t\tif ( index < 0 ) {\n\t\t\t\t\ti = max;\n\n\t\t\t\t} else {\n\t\t\t\t\ti = one ? index : 0;\n\t\t\t\t}\n\n\t\t\t\t// Loop through all the selected options\n\t\t\t\tfor ( ; i < max; i++ ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t// IE8-9 doesn't update selected after form reset (#2551)\n\t\t\t\t\tif ( ( option.selected || i === index ) &&\n\n\t\t\t\t\t\t\t// Don't return options that are disabled or in a disabled optgroup\n\t\t\t\t\t\t\t!option.disabled &&\n\t\t\t\t\t\t\t( !option.parentNode.disabled ||\n\t\t\t\t\t\t\t\t!nodeName( option.parentNode, \"optgroup\" ) ) ) {\n\n\t\t\t\t\t\t// Get the specific value for the option\n\t\t\t\t\t\tvalue = jQuery( option ).val();\n\n\t\t\t\t\t\t// We don't need an array for one selects\n\t\t\t\t\t\tif ( one ) {\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// Multi-Selects return an array\n\t\t\t\t\t\tvalues.push( value );\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\treturn values;\n\t\t\t},\n\n\t\t\tset: function( elem, value ) {\n\t\t\t\tvar optionSet, option,\n\t\t\t\t\toptions = elem.options,\n\t\t\t\t\tvalues = jQuery.makeArray( value ),\n\t\t\t\t\ti = options.length;\n\n\t\t\t\twhile ( i-- ) {\n\t\t\t\t\toption = options[ i ];\n\n\t\t\t\t\t/* eslint-disable no-cond-assign */\n\n\t\t\t\t\tif ( option.selected =\n\t\t\t\t\t\tjQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1\n\t\t\t\t\t) {\n\t\t\t\t\t\toptionSet = true;\n\t\t\t\t\t}\n\n\t\t\t\t\t/* eslint-enable no-cond-assign */\n\t\t\t\t}\n\n\t\t\t\t// Force browsers to behave consistently when non-matching value is set\n\t\t\t\tif ( !optionSet ) {\n\t\t\t\t\telem.selectedIndex = -1;\n\t\t\t\t}\n\t\t\t\treturn values;\n\t\t\t}\n\t\t}\n\t}\n} );\n\n// Radios and checkboxes getter/setter\njQuery.each( [ \"radio\", \"checkbox\" ], function() {\n\tjQuery.valHooks[ this ] = {\n\t\tset: function( elem, value ) {\n\t\t\tif ( Array.isArray( value ) ) {\n\t\t\t\treturn ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );\n\t\t\t}\n\t\t}\n\t};\n\tif ( !support.checkOn ) {\n\t\tjQuery.valHooks[ this ].get = function( elem ) {\n\t\t\treturn elem.getAttribute( \"value\" ) === null ? \"on\" : elem.value;\n\t\t};\n\t}\n} );\n\n\n\n\n// Return jQuery for attributes-only inclusion\n\n\nsupport.focusin = \"onfocusin\" in window;\n\n\nvar rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,\n\tstopPropagationCallback = function( e ) {\n\t\te.stopPropagation();\n\t};\n\njQuery.extend( jQuery.event, {\n\n\ttrigger: function( event, data, elem, onlyHandlers ) {\n\n\t\tvar i, cur, tmp, bubbleType, ontype, handle, special, lastElement,\n\t\t\teventPath = [ elem || document ],\n\t\t\ttype = hasOwn.call( event, \"type\" ) ? event.type : event,\n\t\t\tnamespaces = hasOwn.call( event, \"namespace\" ) ? event.namespace.split( \".\" ) : [];\n\n\t\tcur = lastElement = tmp = elem = elem || document;\n\n\t\t// Don't do events on text and comment nodes\n\t\tif ( elem.nodeType === 3 || elem.nodeType === 8 ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// focus/blur morphs to focusin/out; ensure we're not firing them right now\n\t\tif ( rfocusMorph.test( type + jQuery.event.triggered ) ) {\n\t\t\treturn;\n\t\t}\n\n\t\tif ( type.indexOf( \".\" ) > -1 ) {\n\n\t\t\t// Namespaced trigger; create a regexp to match event type in handle()\n\t\t\tnamespaces = type.split( \".\" );\n\t\t\ttype = namespaces.shift();\n\t\t\tnamespaces.sort();\n\t\t}\n\t\tontype = type.indexOf( \":\" ) < 0 && \"on\" + type;\n\n\t\t// Caller can pass in a jQuery.Event object, Object, or just an event type string\n\t\tevent = event[ jQuery.expando ] ?\n\t\t\tevent :\n\t\t\tnew jQuery.Event( type, typeof event === \"object\" && event );\n\n\t\t// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)\n\t\tevent.isTrigger = onlyHandlers ? 2 : 3;\n\t\tevent.namespace = namespaces.join( \".\" );\n\t\tevent.rnamespace = event.namespace ?\n\t\t\tnew RegExp( \"(^|\\\\.)\" + namespaces.join( \"\\\\.(?:.*\\\\.|)\" ) + \"(\\\\.|$)\" ) :\n\t\t\tnull;\n\n\t\t// Clean up the event in case it is being reused\n\t\tevent.result = undefined;\n\t\tif ( !event.target ) {\n\t\t\tevent.target = elem;\n\t\t}\n\n\t\t// Clone any incoming data and prepend the event, creating the handler arg list\n\t\tdata = data == null ?\n\t\t\t[ event ] :\n\t\t\tjQuery.makeArray( data, [ event ] );\n\n\t\t// Allow special events to draw outside the lines\n\t\tspecial = jQuery.event.special[ type ] || {};\n\t\tif ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {\n\t\t\treturn;\n\t\t}\n\n\t\t// Determine event propagation path in advance, per W3C events spec (#9951)\n\t\t// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)\n\t\tif ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {\n\n\t\t\tbubbleType = special.delegateType || type;\n\t\t\tif ( !rfocusMorph.test( bubbleType + type ) ) {\n\t\t\t\tcur = cur.parentNode;\n\t\t\t}\n\t\t\tfor ( ; cur; cur = cur.parentNode ) {\n\t\t\t\teventPath.push( cur );\n\t\t\t\ttmp = cur;\n\t\t\t}\n\n\t\t\t// Only add window if we got to document (e.g., not plain obj or detached DOM)\n\t\t\tif ( tmp === ( elem.ownerDocument || document ) ) {\n\t\t\t\teventPath.push( tmp.defaultView || tmp.parentWindow || window );\n\t\t\t}\n\t\t}\n\n\t\t// Fire handlers on the event path\n\t\ti = 0;\n\t\twhile ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {\n\t\t\tlastElement = cur;\n\t\t\tevent.type = i > 1 ?\n\t\t\t\tbubbleType :\n\t\t\t\tspecial.bindType || type;\n\n\t\t\t// jQuery handler\n\t\t\thandle = (\n\t\t\t\t\tdataPriv.get( cur, \"events\" ) || Object.create( null )\n\t\t\t\t)[ event.type ] &&\n\t\t\t\tdataPriv.get( cur, \"handle\" );\n\t\t\tif ( handle ) {\n\t\t\t\thandle.apply( cur, data );\n\t\t\t}\n\n\t\t\t// Native handler\n\t\t\thandle = ontype && cur[ ontype ];\n\t\t\tif ( handle && handle.apply && acceptData( cur ) ) {\n\t\t\t\tevent.result = handle.apply( cur, data );\n\t\t\t\tif ( event.result === false ) {\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tevent.type = type;\n\n\t\t// If nobody prevented the default action, do it now\n\t\tif ( !onlyHandlers && !event.isDefaultPrevented() ) {\n\n\t\t\tif ( ( !special._default ||\n\t\t\t\tspecial._default.apply( eventPath.pop(), data ) === false ) &&\n\t\t\t\tacceptData( elem ) ) {\n\n\t\t\t\t// Call a native DOM method on the target with the same name as the event.\n\t\t\t\t// Don't do default actions on window, that's where global variables be (#6170)\n\t\t\t\tif ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {\n\n\t\t\t\t\t// Don't re-trigger an onFOO event when we call its FOO() method\n\t\t\t\t\ttmp = elem[ ontype ];\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = null;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Prevent re-triggering of the same event, since we already bubbled it above\n\t\t\t\t\tjQuery.event.triggered = type;\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.addEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\telem[ type ]();\n\n\t\t\t\t\tif ( event.isPropagationStopped() ) {\n\t\t\t\t\t\tlastElement.removeEventListener( type, stopPropagationCallback );\n\t\t\t\t\t}\n\n\t\t\t\t\tjQuery.event.triggered = undefined;\n\n\t\t\t\t\tif ( tmp ) {\n\t\t\t\t\t\telem[ ontype ] = tmp;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn event.result;\n\t},\n\n\t// Piggyback on a donor event to simulate a different one\n\t// Used only for `focus(in | out)` events\n\tsimulate: function( type, elem, event ) {\n\t\tvar e = jQuery.extend(\n\t\t\tnew jQuery.Event(),\n\t\t\tevent,\n\t\t\t{\n\t\t\t\ttype: type,\n\t\t\t\tisSimulated: true\n\t\t\t}\n\t\t);\n\n\t\tjQuery.event.trigger( e, null, elem );\n\t}\n\n} );\n\njQuery.fn.extend( {\n\n\ttrigger: function( type, data ) {\n\t\treturn this.each( function() {\n\t\t\tjQuery.event.trigger( type, data, this );\n\t\t} );\n\t},\n\ttriggerHandler: function( type, data ) {\n\t\tvar elem = this[ 0 ];\n\t\tif ( elem ) {\n\t\t\treturn jQuery.event.trigger( type, data, elem, true );\n\t\t}\n\t}\n} );\n\n\n// Support: Firefox <=44\n// Firefox doesn't have focus(in | out) events\n// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787\n//\n// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1\n// focus(in | out) events fire after focus & blur events,\n// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order\n// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857\nif ( !support.focusin ) {\n\tjQuery.each( { focus: \"focusin\", blur: \"focusout\" }, function( orig, fix ) {\n\n\t\t// Attach a single capturing handler on the document while someone wants focusin/focusout\n\t\tvar handler = function( event ) {\n\t\t\tjQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );\n\t\t};\n\n\t\tjQuery.event.special[ fix ] = {\n\t\t\tsetup: function() {\n\n\t\t\t\t// Handle: regular nodes (via `this.ownerDocument`), window\n\t\t\t\t// (via `this.document`) & document (via `this`).\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix );\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.addEventListener( orig, handler, true );\n\t\t\t\t}\n\t\t\t\tdataPriv.access( doc, fix, ( attaches || 0 ) + 1 );\n\t\t\t},\n\t\t\tteardown: function() {\n\t\t\t\tvar doc = this.ownerDocument || this.document || this,\n\t\t\t\t\tattaches = dataPriv.access( doc, fix ) - 1;\n\n\t\t\t\tif ( !attaches ) {\n\t\t\t\t\tdoc.removeEventListener( orig, handler, true );\n\t\t\t\t\tdataPriv.remove( doc, fix );\n\n\t\t\t\t} else {\n\t\t\t\t\tdataPriv.access( doc, fix, attaches );\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t} );\n}\nvar location = window.location;\n\nvar nonce = { guid: Date.now() };\n\nvar rquery = ( /\\?/ );\n\n\n\n// Cross-browser xml parsing\njQuery.parseXML = function( data ) {\n\tvar xml;\n\tif ( !data || typeof data !== \"string\" ) {\n\t\treturn null;\n\t}\n\n\t// Support: IE 9 - 11 only\n\t// IE throws on parseFromString with invalid input.\n\ttry {\n\t\txml = ( new window.DOMParser() ).parseFromString( data, \"text/xml\" );\n\t} catch ( e ) {\n\t\txml = undefined;\n\t}\n\n\tif ( !xml || xml.getElementsByTagName( \"parsererror\" ).length ) {\n\t\tjQuery.error( \"Invalid XML: \" + data );\n\t}\n\treturn xml;\n};\n\n\nvar\n\trbracket = /\\[\\]$/,\n\trCRLF = /\\r?\\n/g,\n\trsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,\n\trsubmittable = /^(?:input|select|textarea|keygen)/i;\n\nfunction buildParams( prefix, obj, traditional, add ) {\n\tvar name;\n\n\tif ( Array.isArray( obj ) ) {\n\n\t\t// Serialize array item.\n\t\tjQuery.each( obj, function( i, v ) {\n\t\t\tif ( traditional || rbracket.test( prefix ) ) {\n\n\t\t\t\t// Treat each array item as a scalar.\n\t\t\t\tadd( prefix, v );\n\n\t\t\t} else {\n\n\t\t\t\t// Item is non-scalar (array or object), encode its numeric index.\n\t\t\t\tbuildParams(\n\t\t\t\t\tprefix + \"[\" + ( typeof v === \"object\" && v != null ? i : \"\" ) + \"]\",\n\t\t\t\t\tv,\n\t\t\t\t\ttraditional,\n\t\t\t\t\tadd\n\t\t\t\t);\n\t\t\t}\n\t\t} );\n\n\t} else if ( !traditional && toType( obj ) === \"object\" ) {\n\n\t\t// Serialize object item.\n\t\tfor ( name in obj ) {\n\t\t\tbuildParams( prefix + \"[\" + name + \"]\", obj[ name ], traditional, add );\n\t\t}\n\n\t} else {\n\n\t\t// Serialize scalar item.\n\t\tadd( prefix, obj );\n\t}\n}\n\n// Serialize an array of form elements or a set of\n// key/values into a query string\njQuery.param = function( a, traditional ) {\n\tvar prefix,\n\t\ts = [],\n\t\tadd = function( key, valueOrFunction ) {\n\n\t\t\t// If value is a function, invoke it and use its return value\n\t\t\tvar value = isFunction( valueOrFunction ) ?\n\t\t\t\tvalueOrFunction() :\n\t\t\t\tvalueOrFunction;\n\n\t\t\ts[ s.length ] = encodeURIComponent( key ) + \"=\" +\n\t\t\t\tencodeURIComponent( value == null ? \"\" : value );\n\t\t};\n\n\tif ( a == null ) {\n\t\treturn \"\";\n\t}\n\n\t// If an array was passed in, assume that it is an array of form elements.\n\tif ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {\n\n\t\t// Serialize the form elements\n\t\tjQuery.each( a, function() {\n\t\t\tadd( this.name, this.value );\n\t\t} );\n\n\t} else {\n\n\t\t// If traditional, encode the \"old\" way (the way 1.3.2 or older\n\t\t// did it), otherwise encode params recursively.\n\t\tfor ( prefix in a ) {\n\t\t\tbuildParams( prefix, a[ prefix ], traditional, add );\n\t\t}\n\t}\n\n\t// Return the resulting serialization\n\treturn s.join( \"&\" );\n};\n\njQuery.fn.extend( {\n\tserialize: function() {\n\t\treturn jQuery.param( this.serializeArray() );\n\t},\n\tserializeArray: function() {\n\t\treturn this.map( function() {\n\n\t\t\t// Can add propHook for \"elements\" to filter or add form elements\n\t\t\tvar elements = jQuery.prop( this, \"elements\" );\n\t\t\treturn elements ? jQuery.makeArray( elements ) : this;\n\t\t} )\n\t\t.filter( function() {\n\t\t\tvar type = this.type;\n\n\t\t\t// Use .is( \":disabled\" ) so that fieldset[disabled] works\n\t\t\treturn this.name && !jQuery( this ).is( \":disabled\" ) &&\n\t\t\t\trsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&\n\t\t\t\t( this.checked || !rcheckableType.test( type ) );\n\t\t} )\n\t\t.map( function( _i, elem ) {\n\t\t\tvar val = jQuery( this ).val();\n\n\t\t\tif ( val == null ) {\n\t\t\t\treturn null;\n\t\t\t}\n\n\t\t\tif ( Array.isArray( val ) ) {\n\t\t\t\treturn jQuery.map( val, function( val ) {\n\t\t\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t\t\t} );\n\t\t\t}\n\n\t\t\treturn { name: elem.name, value: val.replace( rCRLF, \"\\r\\n\" ) };\n\t\t} ).get();\n\t}\n} );\n\n\nvar\n\tr20 = /%20/g,\n\trhash = /#.*$/,\n\trantiCache = /([?&])_=[^&]*/,\n\trheaders = /^(.*?):[ \\t]*([^\\r\\n]*)$/mg,\n\n\t// #7653, #8125, #8152: local protocol detection\n\trlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,\n\trnoContent = /^(?:GET|HEAD)$/,\n\trprotocol = /^\\/\\//,\n\n\t/* Prefilters\n\t * 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)\n\t * 2) These are called:\n\t * - BEFORE asking for a transport\n\t * - AFTER param serialization (s.data is a string if s.processData is true)\n\t * 3) key is the dataType\n\t * 4) the catchall symbol \"*\" can be used\n\t * 5) execution will start with transport dataType and THEN continue down to \"*\" if needed\n\t */\n\tprefilters = {},\n\n\t/* Transports bindings\n\t * 1) key is the dataType\n\t * 2) the catchall symbol \"*\" can be used\n\t * 3) selection will start with transport dataType and THEN go to \"*\" if needed\n\t */\n\ttransports = {},\n\n\t// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression\n\tallTypes = \"*/\".concat( \"*\" ),\n\n\t// Anchor tag for parsing the document origin\n\toriginAnchor = document.createElement( \"a\" );\n\toriginAnchor.href = location.href;\n\n// Base \"constructor\" for jQuery.ajaxPrefilter and jQuery.ajaxTransport\nfunction addToPrefiltersOrTransports( structure ) {\n\n\t// dataTypeExpression is optional and defaults to \"*\"\n\treturn function( dataTypeExpression, func ) {\n\n\t\tif ( typeof dataTypeExpression !== \"string\" ) {\n\t\t\tfunc = dataTypeExpression;\n\t\t\tdataTypeExpression = \"*\";\n\t\t}\n\n\t\tvar dataType,\n\t\t\ti = 0,\n\t\t\tdataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];\n\n\t\tif ( isFunction( func ) ) {\n\n\t\t\t// For each dataType in the dataTypeExpression\n\t\t\twhile ( ( dataType = dataTypes[ i++ ] ) ) {\n\n\t\t\t\t// Prepend if requested\n\t\t\t\tif ( dataType[ 0 ] === \"+\" ) {\n\t\t\t\t\tdataType = dataType.slice( 1 ) || \"*\";\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );\n\n\t\t\t\t// Otherwise append\n\t\t\t\t} else {\n\t\t\t\t\t( structure[ dataType ] = structure[ dataType ] || [] ).push( func );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t};\n}\n\n// Base inspection function for prefilters and transports\nfunction inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {\n\n\tvar inspected = {},\n\t\tseekingTransport = ( structure === transports );\n\n\tfunction inspect( dataType ) {\n\t\tvar selected;\n\t\tinspected[ dataType ] = true;\n\t\tjQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {\n\t\t\tvar dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );\n\t\t\tif ( typeof dataTypeOrTransport === \"string\" &&\n\t\t\t\t!seekingTransport && !inspected[ dataTypeOrTransport ] ) {\n\n\t\t\t\toptions.dataTypes.unshift( dataTypeOrTransport );\n\t\t\t\tinspect( dataTypeOrTransport );\n\t\t\t\treturn false;\n\t\t\t} else if ( seekingTransport ) {\n\t\t\t\treturn !( selected = dataTypeOrTransport );\n\t\t\t}\n\t\t} );\n\t\treturn selected;\n\t}\n\n\treturn inspect( options.dataTypes[ 0 ] ) || !inspected[ \"*\" ] && inspect( \"*\" );\n}\n\n// A special extend for ajax options\n// that takes \"flat\" options (not to be deep extended)\n// Fixes #9887\nfunction ajaxExtend( target, src ) {\n\tvar key, deep,\n\t\tflatOptions = jQuery.ajaxSettings.flatOptions || {};\n\n\tfor ( key in src ) {\n\t\tif ( src[ key ] !== undefined ) {\n\t\t\t( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];\n\t\t}\n\t}\n\tif ( deep ) {\n\t\tjQuery.extend( true, target, deep );\n\t}\n\n\treturn target;\n}\n\n/* Handles responses to an ajax request:\n * - finds the right dataType (mediates between content-type and expected dataType)\n * - returns the corresponding response\n */\nfunction ajaxHandleResponses( s, jqXHR, responses ) {\n\n\tvar ct, type, finalDataType, firstDataType,\n\t\tcontents = s.contents,\n\t\tdataTypes = s.dataTypes;\n\n\t// Remove auto dataType and get content-type in the process\n\twhile ( dataTypes[ 0 ] === \"*\" ) {\n\t\tdataTypes.shift();\n\t\tif ( ct === undefined ) {\n\t\t\tct = s.mimeType || jqXHR.getResponseHeader( \"Content-Type\" );\n\t\t}\n\t}\n\n\t// Check if we're dealing with a known content-type\n\tif ( ct ) {\n\t\tfor ( type in contents ) {\n\t\t\tif ( contents[ type ] && contents[ type ].test( ct ) ) {\n\t\t\t\tdataTypes.unshift( type );\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\t// Check to see if we have a response for the expected dataType\n\tif ( dataTypes[ 0 ] in responses ) {\n\t\tfinalDataType = dataTypes[ 0 ];\n\t} else {\n\n\t\t// Try convertible dataTypes\n\t\tfor ( type in responses ) {\n\t\t\tif ( !dataTypes[ 0 ] || s.converters[ type + \" \" + dataTypes[ 0 ] ] ) {\n\t\t\t\tfinalDataType = type;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif ( !firstDataType ) {\n\t\t\t\tfirstDataType = type;\n\t\t\t}\n\t\t}\n\n\t\t// Or just use first one\n\t\tfinalDataType = finalDataType || firstDataType;\n\t}\n\n\t// If we found a dataType\n\t// We add the dataType to the list if needed\n\t// and return the corresponding response\n\tif ( finalDataType ) {\n\t\tif ( finalDataType !== dataTypes[ 0 ] ) {\n\t\t\tdataTypes.unshift( finalDataType );\n\t\t}\n\t\treturn responses[ finalDataType ];\n\t}\n}\n\n/* Chain conversions given the request and the original response\n * Also sets the responseXXX fields on the jqXHR instance\n */\nfunction ajaxConvert( s, response, jqXHR, isSuccess ) {\n\tvar conv2, current, conv, tmp, prev,\n\t\tconverters = {},\n\n\t\t// Work with a copy of dataTypes in case we need to modify it for conversion\n\t\tdataTypes = s.dataTypes.slice();\n\n\t// Create converters map with lowercased keys\n\tif ( dataTypes[ 1 ] ) {\n\t\tfor ( conv in s.converters ) {\n\t\t\tconverters[ conv.toLowerCase() ] = s.converters[ conv ];\n\t\t}\n\t}\n\n\tcurrent = dataTypes.shift();\n\n\t// Convert to each sequential dataType\n\twhile ( current ) {\n\n\t\tif ( s.responseFields[ current ] ) {\n\t\t\tjqXHR[ s.responseFields[ current ] ] = response;\n\t\t}\n\n\t\t// Apply the dataFilter if provided\n\t\tif ( !prev && isSuccess && s.dataFilter ) {\n\t\t\tresponse = s.dataFilter( response, s.dataType );\n\t\t}\n\n\t\tprev = current;\n\t\tcurrent = dataTypes.shift();\n\n\t\tif ( current ) {\n\n\t\t\t// There's only work to do if current dataType is non-auto\n\t\t\tif ( current === \"*\" ) {\n\n\t\t\t\tcurrent = prev;\n\n\t\t\t// Convert response if prev dataType is non-auto and differs from current\n\t\t\t} else if ( prev !== \"*\" && prev !== current ) {\n\n\t\t\t\t// Seek a direct converter\n\t\t\t\tconv = converters[ prev + \" \" + current ] || converters[ \"* \" + current ];\n\n\t\t\t\t// If none found, seek a pair\n\t\t\t\tif ( !conv ) {\n\t\t\t\t\tfor ( conv2 in converters ) {\n\n\t\t\t\t\t\t// If conv2 outputs current\n\t\t\t\t\t\ttmp = conv2.split( \" \" );\n\t\t\t\t\t\tif ( tmp[ 1 ] === current ) {\n\n\t\t\t\t\t\t\t// If prev can be converted to accepted input\n\t\t\t\t\t\t\tconv = converters[ prev + \" \" + tmp[ 0 ] ] ||\n\t\t\t\t\t\t\t\tconverters[ \"* \" + tmp[ 0 ] ];\n\t\t\t\t\t\t\tif ( conv ) {\n\n\t\t\t\t\t\t\t\t// Condense equivalence converters\n\t\t\t\t\t\t\t\tif ( conv === true ) {\n\t\t\t\t\t\t\t\t\tconv = converters[ conv2 ];\n\n\t\t\t\t\t\t\t\t// Otherwise, insert the intermediate dataType\n\t\t\t\t\t\t\t\t} else if ( converters[ conv2 ] !== true ) {\n\t\t\t\t\t\t\t\t\tcurrent = tmp[ 0 ];\n\t\t\t\t\t\t\t\t\tdataTypes.unshift( tmp[ 1 ] );\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Apply converter (if not an equivalence)\n\t\t\t\tif ( conv !== true ) {\n\n\t\t\t\t\t// Unless errors are allowed to bubble, catch and return them\n\t\t\t\t\tif ( conv && s.throws ) {\n\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t} else {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tresponse = conv( response );\n\t\t\t\t\t\t} catch ( e ) {\n\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\tstate: \"parsererror\",\n\t\t\t\t\t\t\t\terror: conv ? e : \"No conversion from \" + prev + \" to \" + current\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\treturn { state: \"success\", data: response };\n}\n\njQuery.extend( {\n\n\t// Counter for holding the number of active queries\n\tactive: 0,\n\n\t// Last-Modified header cache for next request\n\tlastModified: {},\n\tetag: {},\n\n\tajaxSettings: {\n\t\turl: location.href,\n\t\ttype: \"GET\",\n\t\tisLocal: rlocalProtocol.test( location.protocol ),\n\t\tglobal: true,\n\t\tprocessData: true,\n\t\tasync: true,\n\t\tcontentType: \"application/x-www-form-urlencoded; charset=UTF-8\",\n\n\t\t/*\n\t\ttimeout: 0,\n\t\tdata: null,\n\t\tdataType: null,\n\t\tusername: null,\n\t\tpassword: null,\n\t\tcache: null,\n\t\tthrows: false,\n\t\ttraditional: false,\n\t\theaders: {},\n\t\t*/\n\n\t\taccepts: {\n\t\t\t\"*\": allTypes,\n\t\t\ttext: \"text/plain\",\n\t\t\thtml: \"text/html\",\n\t\t\txml: \"application/xml, text/xml\",\n\t\t\tjson: \"application/json, text/javascript\"\n\t\t},\n\n\t\tcontents: {\n\t\t\txml: /\\bxml\\b/,\n\t\t\thtml: /\\bhtml/,\n\t\t\tjson: /\\bjson\\b/\n\t\t},\n\n\t\tresponseFields: {\n\t\t\txml: \"responseXML\",\n\t\t\ttext: \"responseText\",\n\t\t\tjson: \"responseJSON\"\n\t\t},\n\n\t\t// Data converters\n\t\t// Keys separate source (or catchall \"*\") and destination types with a single space\n\t\tconverters: {\n\n\t\t\t// Convert anything to text\n\t\t\t\"* text\": String,\n\n\t\t\t// Text to html (true = no transformation)\n\t\t\t\"text html\": true,\n\n\t\t\t// Evaluate text as a json expression\n\t\t\t\"text json\": JSON.parse,\n\n\t\t\t// Parse text as xml\n\t\t\t\"text xml\": jQuery.parseXML\n\t\t},\n\n\t\t// For options that shouldn't be deep extended:\n\t\t// you can add your own custom options here if\n\t\t// and when you create one that shouldn't be\n\t\t// deep extended (see ajaxExtend)\n\t\tflatOptions: {\n\t\t\turl: true,\n\t\t\tcontext: true\n\t\t}\n\t},\n\n\t// Creates a full fledged settings object into target\n\t// with both ajaxSettings and settings fields.\n\t// If target is omitted, writes into ajaxSettings.\n\tajaxSetup: function( target, settings ) {\n\t\treturn settings ?\n\n\t\t\t// Building a settings object\n\t\t\tajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :\n\n\t\t\t// Extending ajaxSettings\n\t\t\tajaxExtend( jQuery.ajaxSettings, target );\n\t},\n\n\tajaxPrefilter: addToPrefiltersOrTransports( prefilters ),\n\tajaxTransport: addToPrefiltersOrTransports( transports ),\n\n\t// Main method\n\tajax: function( url, options ) {\n\n\t\t// If url is an object, simulate pre-1.5 signature\n\t\tif ( typeof url === \"object\" ) {\n\t\t\toptions = url;\n\t\t\turl = undefined;\n\t\t}\n\n\t\t// Force options to be an object\n\t\toptions = options || {};\n\n\t\tvar transport,\n\n\t\t\t// URL without anti-cache param\n\t\t\tcacheURL,\n\n\t\t\t// Response headers\n\t\t\tresponseHeadersString,\n\t\t\tresponseHeaders,\n\n\t\t\t// timeout handle\n\t\t\ttimeoutTimer,\n\n\t\t\t// Url cleanup var\n\t\t\turlAnchor,\n\n\t\t\t// Request state (becomes false upon send and true upon completion)\n\t\t\tcompleted,\n\n\t\t\t// To know if global events are to be dispatched\n\t\t\tfireGlobals,\n\n\t\t\t// Loop variable\n\t\t\ti,\n\n\t\t\t// uncached part of the url\n\t\t\tuncached,\n\n\t\t\t// Create the final options object\n\t\t\ts = jQuery.ajaxSetup( {}, options ),\n\n\t\t\t// Callbacks context\n\t\t\tcallbackContext = s.context || s,\n\n\t\t\t// Context for global events is callbackContext if it is a DOM node or jQuery collection\n\t\t\tglobalEventContext = s.context &&\n\t\t\t\t( callbackContext.nodeType || callbackContext.jquery ) ?\n\t\t\t\t\tjQuery( callbackContext ) :\n\t\t\t\t\tjQuery.event,\n\n\t\t\t// Deferreds\n\t\t\tdeferred = jQuery.Deferred(),\n\t\t\tcompleteDeferred = jQuery.Callbacks( \"once memory\" ),\n\n\t\t\t// Status-dependent callbacks\n\t\t\tstatusCode = s.statusCode || {},\n\n\t\t\t// Headers (they are sent all at once)\n\t\t\trequestHeaders = {},\n\t\t\trequestHeadersNames = {},\n\n\t\t\t// Default abort message\n\t\t\tstrAbort = \"canceled\",\n\n\t\t\t// Fake xhr\n\t\t\tjqXHR = {\n\t\t\t\treadyState: 0,\n\n\t\t\t\t// Builds headers hashtable if needed\n\t\t\t\tgetResponseHeader: function( key ) {\n\t\t\t\t\tvar match;\n\t\t\t\t\tif ( completed ) {\n\t\t\t\t\t\tif ( !responseHeaders ) {\n\t\t\t\t\t\t\tresponseHeaders = {};\n\t\t\t\t\t\t\twhile ( ( match = rheaders.exec( responseHeadersString ) ) ) {\n\t\t\t\t\t\t\t\tresponseHeaders[ match[ 1 ].toLowerCase() + \" \" ] =\n\t\t\t\t\t\t\t\t\t( responseHeaders[ match[ 1 ].toLowerCase() + \" \" ] || [] )\n\t\t\t\t\t\t\t\t\t\t.concat( match[ 2 ] );\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tmatch = responseHeaders[ key.toLowerCase() + \" \" ];\n\t\t\t\t\t}\n\t\t\t\t\treturn match == null ? null : match.join( \", \" );\n\t\t\t\t},\n\n\t\t\t\t// Raw string\n\t\t\t\tgetAllResponseHeaders: function() {\n\t\t\t\t\treturn completed ? responseHeadersString : null;\n\t\t\t\t},\n\n\t\t\t\t// Caches the header\n\t\t\t\tsetRequestHeader: function( name, value ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\tname = requestHeadersNames[ name.toLowerCase() ] =\n\t\t\t\t\t\t\trequestHeadersNames[ name.toLowerCase() ] || name;\n\t\t\t\t\t\trequestHeaders[ name ] = value;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Overrides response content-type header\n\t\t\t\toverrideMimeType: function( type ) {\n\t\t\t\t\tif ( completed == null ) {\n\t\t\t\t\t\ts.mimeType = type;\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Status-dependent callbacks\n\t\t\t\tstatusCode: function( map ) {\n\t\t\t\t\tvar code;\n\t\t\t\t\tif ( map ) {\n\t\t\t\t\t\tif ( completed ) {\n\n\t\t\t\t\t\t\t// Execute the appropriate callbacks\n\t\t\t\t\t\t\tjqXHR.always( map[ jqXHR.status ] );\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// Lazy-add the new callbacks in a way that preserves old ones\n\t\t\t\t\t\t\tfor ( code in map ) {\n\t\t\t\t\t\t\t\tstatusCode[ code ] = [ statusCode[ code ], map[ code ] ];\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\treturn this;\n\t\t\t\t},\n\n\t\t\t\t// Cancel the request\n\t\t\t\tabort: function( statusText ) {\n\t\t\t\t\tvar finalText = statusText || strAbort;\n\t\t\t\t\tif ( transport ) {\n\t\t\t\t\t\ttransport.abort( finalText );\n\t\t\t\t\t}\n\t\t\t\t\tdone( 0, finalText );\n\t\t\t\t\treturn this;\n\t\t\t\t}\n\t\t\t};\n\n\t\t// Attach deferreds\n\t\tdeferred.promise( jqXHR );\n\n\t\t// Add protocol if not provided (prefilters might expect it)\n\t\t// Handle falsy url in the settings object (#10093: consistency with old signature)\n\t\t// We also use the url parameter if available\n\t\ts.url = ( ( url || s.url || location.href ) + \"\" )\n\t\t\t.replace( rprotocol, location.protocol + \"//\" );\n\n\t\t// Alias method option to type as per ticket #12004\n\t\ts.type = options.method || options.type || s.method || s.type;\n\n\t\t// Extract dataTypes list\n\t\ts.dataTypes = ( s.dataType || \"*\" ).toLowerCase().match( rnothtmlwhite ) || [ \"\" ];\n\n\t\t// A cross-domain request is in order when the origin doesn't match the current origin.\n\t\tif ( s.crossDomain == null ) {\n\t\t\turlAnchor = document.createElement( \"a\" );\n\n\t\t\t// Support: IE <=8 - 11, Edge 12 - 15\n\t\t\t// IE throws exception on accessing the href property if url is malformed,\n\t\t\t// e.g. http://example.com:80x/\n\t\t\ttry {\n\t\t\t\turlAnchor.href = s.url;\n\n\t\t\t\t// Support: IE <=8 - 11 only\n\t\t\t\t// Anchor's host property isn't correctly set when s.url is relative\n\t\t\t\turlAnchor.href = urlAnchor.href;\n\t\t\t\ts.crossDomain = originAnchor.protocol + \"//\" + originAnchor.host !==\n\t\t\t\t\turlAnchor.protocol + \"//\" + urlAnchor.host;\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// If there is an error parsing the URL, assume it is crossDomain,\n\t\t\t\t// it can be rejected by the transport if it is invalid\n\t\t\t\ts.crossDomain = true;\n\t\t\t}\n\t\t}\n\n\t\t// Convert data if not already a string\n\t\tif ( s.data && s.processData && typeof s.data !== \"string\" ) {\n\t\t\ts.data = jQuery.param( s.data, s.traditional );\n\t\t}\n\n\t\t// Apply prefilters\n\t\tinspectPrefiltersOrTransports( prefilters, s, options, jqXHR );\n\n\t\t// If request was aborted inside a prefilter, stop there\n\t\tif ( completed ) {\n\t\t\treturn jqXHR;\n\t\t}\n\n\t\t// We can fire global events as of now if asked to\n\t\t// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)\n\t\tfireGlobals = jQuery.event && s.global;\n\n\t\t// Watch for a new set of requests\n\t\tif ( fireGlobals && jQuery.active++ === 0 ) {\n\t\t\tjQuery.event.trigger( \"ajaxStart\" );\n\t\t}\n\n\t\t// Uppercase the type\n\t\ts.type = s.type.toUpperCase();\n\n\t\t// Determine if request has content\n\t\ts.hasContent = !rnoContent.test( s.type );\n\n\t\t// Save the URL in case we're toying with the If-Modified-Since\n\t\t// and/or If-None-Match header later on\n\t\t// Remove hash to simplify url manipulation\n\t\tcacheURL = s.url.replace( rhash, \"\" );\n\n\t\t// More options handling for requests with no content\n\t\tif ( !s.hasContent ) {\n\n\t\t\t// Remember the hash so we can put it back\n\t\t\tuncached = s.url.slice( cacheURL.length );\n\n\t\t\t// If data is available and should be processed, append data to url\n\t\t\tif ( s.data && ( s.processData || typeof s.data === \"string\" ) ) {\n\t\t\t\tcacheURL += ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + s.data;\n\n\t\t\t\t// #9682: remove data so that it's not used in an eventual retry\n\t\t\t\tdelete s.data;\n\t\t\t}\n\n\t\t\t// Add or update anti-cache param if needed\n\t\t\tif ( s.cache === false ) {\n\t\t\t\tcacheURL = cacheURL.replace( rantiCache, \"$1\" );\n\t\t\t\tuncached = ( rquery.test( cacheURL ) ? \"&\" : \"?\" ) + \"_=\" + ( nonce.guid++ ) +\n\t\t\t\t\tuncached;\n\t\t\t}\n\n\t\t\t// Put hash and anti-cache on the URL that will be requested (gh-1732)\n\t\t\ts.url = cacheURL + uncached;\n\n\t\t// Change '%20' to '+' if this is encoded form body content (gh-2658)\n\t\t} else if ( s.data && s.processData &&\n\t\t\t( s.contentType || \"\" ).indexOf( \"application/x-www-form-urlencoded\" ) === 0 ) {\n\t\t\ts.data = s.data.replace( r20, \"+\" );\n\t\t}\n\n\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\tif ( s.ifModified ) {\n\t\t\tif ( jQuery.lastModified[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-Modified-Since\", jQuery.lastModified[ cacheURL ] );\n\t\t\t}\n\t\t\tif ( jQuery.etag[ cacheURL ] ) {\n\t\t\t\tjqXHR.setRequestHeader( \"If-None-Match\", jQuery.etag[ cacheURL ] );\n\t\t\t}\n\t\t}\n\n\t\t// Set the correct header, if data is being sent\n\t\tif ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {\n\t\t\tjqXHR.setRequestHeader( \"Content-Type\", s.contentType );\n\t\t}\n\n\t\t// Set the Accepts header for the server, depending on the dataType\n\t\tjqXHR.setRequestHeader(\n\t\t\t\"Accept\",\n\t\t\ts.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?\n\t\t\t\ts.accepts[ s.dataTypes[ 0 ] ] +\n\t\t\t\t\t( s.dataTypes[ 0 ] !== \"*\" ? \", \" + allTypes + \"; q=0.01\" : \"\" ) :\n\t\t\t\ts.accepts[ \"*\" ]\n\t\t);\n\n\t\t// Check for headers option\n\t\tfor ( i in s.headers ) {\n\t\t\tjqXHR.setRequestHeader( i, s.headers[ i ] );\n\t\t}\n\n\t\t// Allow custom headers/mimetypes and early abort\n\t\tif ( s.beforeSend &&\n\t\t\t( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {\n\n\t\t\t// Abort if not done already and return\n\t\t\treturn jqXHR.abort();\n\t\t}\n\n\t\t// Aborting is no longer a cancellation\n\t\tstrAbort = \"abort\";\n\n\t\t// Install callbacks on deferreds\n\t\tcompleteDeferred.add( s.complete );\n\t\tjqXHR.done( s.success );\n\t\tjqXHR.fail( s.error );\n\n\t\t// Get transport\n\t\ttransport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );\n\n\t\t// If no transport, we auto-abort\n\t\tif ( !transport ) {\n\t\t\tdone( -1, \"No Transport\" );\n\t\t} else {\n\t\t\tjqXHR.readyState = 1;\n\n\t\t\t// Send global event\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxSend\", [ jqXHR, s ] );\n\t\t\t}\n\n\t\t\t// If request was aborted inside ajaxSend, stop there\n\t\t\tif ( completed ) {\n\t\t\t\treturn jqXHR;\n\t\t\t}\n\n\t\t\t// Timeout\n\t\t\tif ( s.async && s.timeout > 0 ) {\n\t\t\t\ttimeoutTimer = window.setTimeout( function() {\n\t\t\t\t\tjqXHR.abort( \"timeout\" );\n\t\t\t\t}, s.timeout );\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tcompleted = false;\n\t\t\t\ttransport.send( requestHeaders, done );\n\t\t\t} catch ( e ) {\n\n\t\t\t\t// Rethrow post-completion exceptions\n\t\t\t\tif ( completed ) {\n\t\t\t\t\tthrow e;\n\t\t\t\t}\n\n\t\t\t\t// Propagate others as results\n\t\t\t\tdone( -1, e );\n\t\t\t}\n\t\t}\n\n\t\t// Callback for when everything is done\n\t\tfunction done( status, nativeStatusText, responses, headers ) {\n\t\t\tvar isSuccess, success, error, response, modified,\n\t\t\t\tstatusText = nativeStatusText;\n\n\t\t\t// Ignore repeat invocations\n\t\t\tif ( completed ) {\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tcompleted = true;\n\n\t\t\t// Clear timeout if it exists\n\t\t\tif ( timeoutTimer ) {\n\t\t\t\twindow.clearTimeout( timeoutTimer );\n\t\t\t}\n\n\t\t\t// Dereference transport for early garbage collection\n\t\t\t// (no matter how long the jqXHR object will be used)\n\t\t\ttransport = undefined;\n\n\t\t\t// Cache response headers\n\t\t\tresponseHeadersString = headers || \"\";\n\n\t\t\t// Set readyState\n\t\t\tjqXHR.readyState = status > 0 ? 4 : 0;\n\n\t\t\t// Determine if successful\n\t\t\tisSuccess = status >= 200 && status < 300 || status === 304;\n\n\t\t\t// Get response data\n\t\t\tif ( responses ) {\n\t\t\t\tresponse = ajaxHandleResponses( s, jqXHR, responses );\n\t\t\t}\n\n\t\t\t// Use a noop converter for missing script\n\t\t\tif ( !isSuccess && jQuery.inArray( \"script\", s.dataTypes ) > -1 ) {\n\t\t\t\ts.converters[ \"text script\" ] = function() {};\n\t\t\t}\n\n\t\t\t// Convert no matter what (that way responseXXX fields are always set)\n\t\t\tresponse = ajaxConvert( s, response, jqXHR, isSuccess );\n\n\t\t\t// If successful, handle type chaining\n\t\t\tif ( isSuccess ) {\n\n\t\t\t\t// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.\n\t\t\t\tif ( s.ifModified ) {\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"Last-Modified\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.lastModified[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t\tmodified = jqXHR.getResponseHeader( \"etag\" );\n\t\t\t\t\tif ( modified ) {\n\t\t\t\t\t\tjQuery.etag[ cacheURL ] = modified;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// if no content\n\t\t\t\tif ( status === 204 || s.type === \"HEAD\" ) {\n\t\t\t\t\tstatusText = \"nocontent\";\n\n\t\t\t\t// if not modified\n\t\t\t\t} else if ( status === 304 ) {\n\t\t\t\t\tstatusText = \"notmodified\";\n\n\t\t\t\t// If we have data, let's convert it\n\t\t\t\t} else {\n\t\t\t\t\tstatusText = response.state;\n\t\t\t\t\tsuccess = response.data;\n\t\t\t\t\terror = response.error;\n\t\t\t\t\tisSuccess = !error;\n\t\t\t\t}\n\t\t\t} else {\n\n\t\t\t\t// Extract error from statusText and normalize for non-aborts\n\t\t\t\terror = statusText;\n\t\t\t\tif ( status || !statusText ) {\n\t\t\t\t\tstatusText = \"error\";\n\t\t\t\t\tif ( status < 0 ) {\n\t\t\t\t\t\tstatus = 0;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Set data for the fake xhr object\n\t\t\tjqXHR.status = status;\n\t\t\tjqXHR.statusText = ( nativeStatusText || statusText ) + \"\";\n\n\t\t\t// Success/Error\n\t\t\tif ( isSuccess ) {\n\t\t\t\tdeferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );\n\t\t\t} else {\n\t\t\t\tdeferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );\n\t\t\t}\n\n\t\t\t// Status-dependent callbacks\n\t\t\tjqXHR.statusCode( statusCode );\n\t\t\tstatusCode = undefined;\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( isSuccess ? \"ajaxSuccess\" : \"ajaxError\",\n\t\t\t\t\t[ jqXHR, s, isSuccess ? success : error ] );\n\t\t\t}\n\n\t\t\t// Complete\n\t\t\tcompleteDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );\n\n\t\t\tif ( fireGlobals ) {\n\t\t\t\tglobalEventContext.trigger( \"ajaxComplete\", [ jqXHR, s ] );\n\n\t\t\t\t// Handle the global AJAX counter\n\t\t\t\tif ( !( --jQuery.active ) ) {\n\t\t\t\t\tjQuery.event.trigger( \"ajaxStop\" );\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn jqXHR;\n\t},\n\n\tgetJSON: function( url, data, callback ) {\n\t\treturn jQuery.get( url, data, callback, \"json\" );\n\t},\n\n\tgetScript: function( url, callback ) {\n\t\treturn jQuery.get( url, undefined, callback, \"script\" );\n\t}\n} );\n\njQuery.each( [ \"get\", \"post\" ], function( _i, method ) {\n\tjQuery[ method ] = function( url, data, callback, type ) {\n\n\t\t// Shift arguments if data argument was omitted\n\t\tif ( isFunction( data ) ) {\n\t\t\ttype = type || callback;\n\t\t\tcallback = data;\n\t\t\tdata = undefined;\n\t\t}\n\n\t\t// The url can be an options object (which then must have .url)\n\t\treturn jQuery.ajax( jQuery.extend( {\n\t\t\turl: url,\n\t\t\ttype: method,\n\t\t\tdataType: type,\n\t\t\tdata: data,\n\t\t\tsuccess: callback\n\t\t}, jQuery.isPlainObject( url ) && url ) );\n\t};\n} );\n\njQuery.ajaxPrefilter( function( s ) {\n\tvar i;\n\tfor ( i in s.headers ) {\n\t\tif ( i.toLowerCase() === \"content-type\" ) {\n\t\t\ts.contentType = s.headers[ i ] || \"\";\n\t\t}\n\t}\n} );\n\n\njQuery._evalUrl = function( url, options, doc ) {\n\treturn jQuery.ajax( {\n\t\turl: url,\n\n\t\t// Make this explicit, since user can override this through ajaxSetup (#11264)\n\t\ttype: \"GET\",\n\t\tdataType: \"script\",\n\t\tcache: true,\n\t\tasync: false,\n\t\tglobal: false,\n\n\t\t// Only evaluate the response if it is successful (gh-4126)\n\t\t// dataFilter is not invoked for failure responses, so using it instead\n\t\t// of the default converter is kludgy but it works.\n\t\tconverters: {\n\t\t\t\"text script\": function() {}\n\t\t},\n\t\tdataFilter: function( response ) {\n\t\t\tjQuery.globalEval( response, options, doc );\n\t\t}\n\t} );\n};\n\n\njQuery.fn.extend( {\n\twrapAll: function( html ) {\n\t\tvar wrap;\n\n\t\tif ( this[ 0 ] ) {\n\t\t\tif ( isFunction( html ) ) {\n\t\t\t\thtml = html.call( this[ 0 ] );\n\t\t\t}\n\n\t\t\t// The elements to wrap the target around\n\t\t\twrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );\n\n\t\t\tif ( this[ 0 ].parentNode ) {\n\t\t\t\twrap.insertBefore( this[ 0 ] );\n\t\t\t}\n\n\t\t\twrap.map( function() {\n\t\t\t\tvar elem = this;\n\n\t\t\t\twhile ( elem.firstElementChild ) {\n\t\t\t\t\telem = elem.firstElementChild;\n\t\t\t\t}\n\n\t\t\t\treturn elem;\n\t\t\t} ).append( this );\n\t\t}\n\n\t\treturn this;\n\t},\n\n\twrapInner: function( html ) {\n\t\tif ( isFunction( html ) ) {\n\t\t\treturn this.each( function( i ) {\n\t\t\t\tjQuery( this ).wrapInner( html.call( this, i ) );\n\t\t\t} );\n\t\t}\n\n\t\treturn this.each( function() {\n\t\t\tvar self = jQuery( this ),\n\t\t\t\tcontents = self.contents();\n\n\t\t\tif ( contents.length ) {\n\t\t\t\tcontents.wrapAll( html );\n\n\t\t\t} else {\n\t\t\t\tself.append( html );\n\t\t\t}\n\t\t} );\n\t},\n\n\twrap: function( html ) {\n\t\tvar htmlIsFunction = isFunction( html );\n\n\t\treturn this.each( function( i ) {\n\t\t\tjQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );\n\t\t} );\n\t},\n\n\tunwrap: function( selector ) {\n\t\tthis.parent( selector ).not( \"body\" ).each( function() {\n\t\t\tjQuery( this ).replaceWith( this.childNodes );\n\t\t} );\n\t\treturn this;\n\t}\n} );\n\n\njQuery.expr.pseudos.hidden = function( elem ) {\n\treturn !jQuery.expr.pseudos.visible( elem );\n};\njQuery.expr.pseudos.visible = function( elem ) {\n\treturn !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );\n};\n\n\n\n\njQuery.ajaxSettings.xhr = function() {\n\ttry {\n\t\treturn new window.XMLHttpRequest();\n\t} catch ( e ) {}\n};\n\nvar xhrSuccessStatus = {\n\n\t\t// File protocol always yields status code 0, assume 200\n\t\t0: 200,\n\n\t\t// Support: IE <=9 only\n\t\t// #1450: sometimes IE returns 1223 when it should be 204\n\t\t1223: 204\n\t},\n\txhrSupported = jQuery.ajaxSettings.xhr();\n\nsupport.cors = !!xhrSupported && ( \"withCredentials\" in xhrSupported );\nsupport.ajax = xhrSupported = !!xhrSupported;\n\njQuery.ajaxTransport( function( options ) {\n\tvar callback, errorCallback;\n\n\t// Cross domain only allowed if supported through XMLHttpRequest\n\tif ( support.cors || xhrSupported && !options.crossDomain ) {\n\t\treturn {\n\t\t\tsend: function( headers, complete ) {\n\t\t\t\tvar i,\n\t\t\t\t\txhr = options.xhr();\n\n\t\t\t\txhr.open(\n\t\t\t\t\toptions.type,\n\t\t\t\t\toptions.url,\n\t\t\t\t\toptions.async,\n\t\t\t\t\toptions.username,\n\t\t\t\t\toptions.password\n\t\t\t\t);\n\n\t\t\t\t// Apply custom fields if provided\n\t\t\t\tif ( options.xhrFields ) {\n\t\t\t\t\tfor ( i in options.xhrFields ) {\n\t\t\t\t\t\txhr[ i ] = options.xhrFields[ i ];\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Override mime type if needed\n\t\t\t\tif ( options.mimeType && xhr.overrideMimeType ) {\n\t\t\t\t\txhr.overrideMimeType( options.mimeType );\n\t\t\t\t}\n\n\t\t\t\t// X-Requested-With header\n\t\t\t\t// For cross-domain requests, seeing as conditions for a preflight are\n\t\t\t\t// akin to a jigsaw puzzle, we simply never set it to be sure.\n\t\t\t\t// (it can always be set on a per-request basis or even using ajaxSetup)\n\t\t\t\t// For same-domain requests, won't change header if already provided.\n\t\t\t\tif ( !options.crossDomain && !headers[ \"X-Requested-With\" ] ) {\n\t\t\t\t\theaders[ \"X-Requested-With\" ] = \"XMLHttpRequest\";\n\t\t\t\t}\n\n\t\t\t\t// Set headers\n\t\t\t\tfor ( i in headers ) {\n\t\t\t\t\txhr.setRequestHeader( i, headers[ i ] );\n\t\t\t\t}\n\n\t\t\t\t// Callback\n\t\t\t\tcallback = function( type ) {\n\t\t\t\t\treturn function() {\n\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\tcallback = errorCallback = xhr.onload =\n\t\t\t\t\t\t\t\txhr.onerror = xhr.onabort = xhr.ontimeout =\n\t\t\t\t\t\t\t\t\txhr.onreadystatechange = null;\n\n\t\t\t\t\t\t\tif ( type === \"abort\" ) {\n\t\t\t\t\t\t\t\txhr.abort();\n\t\t\t\t\t\t\t} else if ( type === \"error\" ) {\n\n\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t// On a manual native abort, IE9 throws\n\t\t\t\t\t\t\t\t// errors on any property access that is not readyState\n\t\t\t\t\t\t\t\tif ( typeof xhr.status !== \"number\" ) {\n\t\t\t\t\t\t\t\t\tcomplete( 0, \"error\" );\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcomplete(\n\n\t\t\t\t\t\t\t\t\t\t// File: protocol always yields status 0; see #8605, #14207\n\t\t\t\t\t\t\t\t\t\txhr.status,\n\t\t\t\t\t\t\t\t\t\txhr.statusText\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcomplete(\n\t\t\t\t\t\t\t\t\txhrSuccessStatus[ xhr.status ] || xhr.status,\n\t\t\t\t\t\t\t\t\txhr.statusText,\n\n\t\t\t\t\t\t\t\t\t// Support: IE <=9 only\n\t\t\t\t\t\t\t\t\t// IE9 has no XHR2 but throws on binary (trac-11426)\n\t\t\t\t\t\t\t\t\t// For XHR2 non-text, let the caller handle it (gh-2498)\n\t\t\t\t\t\t\t\t\t( xhr.responseType || \"text\" ) !== \"text\" ||\n\t\t\t\t\t\t\t\t\ttypeof xhr.responseText !== \"string\" ?\n\t\t\t\t\t\t\t\t\t\t{ binary: xhr.response } :\n\t\t\t\t\t\t\t\t\t\t{ text: xhr.responseText },\n\t\t\t\t\t\t\t\t\txhr.getAllResponseHeaders()\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t};\n\n\t\t\t\t// Listen to events\n\t\t\t\txhr.onload = callback();\n\t\t\t\terrorCallback = xhr.onerror = xhr.ontimeout = callback( \"error\" );\n\n\t\t\t\t// Support: IE 9 only\n\t\t\t\t// Use onreadystatechange to replace onabort\n\t\t\t\t// to handle uncaught aborts\n\t\t\t\tif ( xhr.onabort !== undefined ) {\n\t\t\t\t\txhr.onabort = errorCallback;\n\t\t\t\t} else {\n\t\t\t\t\txhr.onreadystatechange = function() {\n\n\t\t\t\t\t\t// Check readyState before timeout as it changes\n\t\t\t\t\t\tif ( xhr.readyState === 4 ) {\n\n\t\t\t\t\t\t\t// Allow onerror to be called first,\n\t\t\t\t\t\t\t// but that will not handle a native abort\n\t\t\t\t\t\t\t// Also, save errorCallback to a variable\n\t\t\t\t\t\t\t// as xhr.onerror cannot be accessed\n\t\t\t\t\t\t\twindow.setTimeout( function() {\n\t\t\t\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\t\t\t\terrorCallback();\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} );\n\t\t\t\t\t\t}\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\t// Create the abort callback\n\t\t\t\tcallback = callback( \"abort\" );\n\n\t\t\t\ttry {\n\n\t\t\t\t\t// Do send the request (this may raise an exception)\n\t\t\t\t\txhr.send( options.hasContent && options.data || null );\n\t\t\t\t} catch ( e ) {\n\n\t\t\t\t\t// #14683: Only rethrow if this hasn't been notified as an error yet\n\t\t\t\t\tif ( callback ) {\n\t\t\t\t\t\tthrow e;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\n\t\t\tabort: function() {\n\t\t\t\tif ( callback ) {\n\t\t\t\t\tcallback();\n\t\t\t\t}\n\t\t\t}\n\t\t};\n\t}\n} );\n\n\n\n\n// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)\njQuery.ajaxPrefilter( function( s ) {\n\tif ( s.crossDomain ) {\n\t\ts.contents.script = false;\n\t}\n} );\n\n// Install script dataType\njQuery.ajaxSetup( {\n\taccepts: {\n\t\tscript: \"text/javascript, application/javascript, \" +\n\t\t\t\"application/ecmascript, application/x-ecmascript\"\n\t},\n\tcontents: {\n\t\tscript: /\\b(?:java|ecma)script\\b/\n\t},\n\tconverters: {\n\t\t\"text script\": function( text ) {\n\t\t\tjQuery.globalEval( text );\n\t\t\treturn text;\n\t\t}\n\t}\n} );\n\n// Handle cache's special case and crossDomain\njQuery.ajaxPrefilter( \"script\", function( s ) {\n\tif ( s.cache === undefined ) {\n\t\ts.cache = false;\n\t}\n\tif ( s.crossDomain ) {\n\t\ts.type = \"GET\";\n\t}\n} );\n\n// Bind script tag hack transport\njQuery.ajaxTransport( \"script\", function( s ) {\n\n\t// This transport only deals with cross domain or forced-by-attrs requests\n\tif ( s.crossDomain || s.scriptAttrs ) {\n\t\tvar script, callback;\n\t\treturn {\n\t\t\tsend: function( _, complete ) {\n\t\t\t\tscript = jQuery( \" @stop diff --git a/resources/views/account/accept/index.blade.php b/resources/views/account/accept/index.blade.php index 0d36ef18ca..1957bec675 100755 --- a/resources/views/account/accept/index.blade.php +++ b/resources/views/account/accept/index.blade.php @@ -31,6 +31,8 @@ {{ trans('general.name')}} + {{ trans('general.type')}} + {{ trans('general.qty') }} {{ trans('general.serial_number')}} {{ trans('table.actions')}} @@ -40,7 +42,9 @@ @if ($acceptance->checkoutable) {{ ($acceptance->checkoutable) ? $acceptance->checkoutable->present()->name : '' }} - {{ ($acceptance->checkoutable) ? $acceptance->checkoutable->serial : '' }} + {{ $acceptance->checkoutable_item_type }} + {{ $acceptance->qty ?? '1' }} + {{ ($acceptance->checkoutable) ? $acceptance->checkoutable->serial : '' }} {{ trans('general.accept_decline') }} @else ----- diff --git a/resources/views/account/profile.blade.php b/resources/views/account/profile.blade.php index abf463ad94..b4aea49918 100755 --- a/resources/views/account/profile.blade.php +++ b/resources/views/account/profile.blade.php @@ -139,7 +139,7 @@ {!! $errors->first('gravatar', '') !!}

      - {{ $user->present()->fullName() }} avatar image + {{ $user->display_name }} avatar image {!! trans('general.gravatar_url') !!}

      diff --git a/resources/views/account/requestable-assets.blade.php b/resources/views/account/requestable-assets.blade.php index 7a969c7f70..4190a9126f 100644 --- a/resources/views/account/requestable-assets.blade.php +++ b/resources/views/account/requestable-assets.blade.php @@ -119,9 +119,9 @@ - @if ($requestableModel->image) - - + @if (($requestableModel->image) && ($requestableModel->getImageUrl())) + + @endif diff --git a/resources/views/account/view-assets.blade.php b/resources/views/account/view-assets.blade.php index 8fa949869e..7125bd0665 100755 --- a/resources/views/account/view-assets.blade.php +++ b/resources/views/account/view-assets.blade.php @@ -2,14 +2,14 @@ {{-- Page title --}} @section('title') -{{ trans('general.hello_name', array('name' => $user->present()->getFullNameAttribute())) }} +{{ trans('general.hello_name', array('name' => $user->display_name)) }} @parent @stop {{-- Account page content --}} @section('content') -@if ($acceptances = \App\Models\CheckoutAcceptance::forUser(Auth::user())->pending()->count()) +@if ($acceptanceQuantity = \App\Models\CheckoutAcceptance::forUser(Auth::user())->pending()->sum('qty'))
      @@ -37,7 +37,7 @@ {{ $asset->id }} - {{ $asset->present()->name() }} + {{ $asset->display_name }} @if ($asset->location) - {{ $asset->location->present()->name() }} + {{ $asset->location->display_name }} @elseif($asset->rtd_location) - {{ $asset->defaultLoc->present()->name() }} + {{ $asset->defaultLoc->display_name }} @endif @if ($asset->assigned) - {{ $asset->assigned->present()->name() }} + {{ $asset->assigned->display_name }} @endif diff --git a/resources/views/hardware/bulk-restore.blade.php b/resources/views/hardware/bulk-restore.blade.php index a998642685..4294cbddde 100644 --- a/resources/views/hardware/bulk-restore.blade.php +++ b/resources/views/hardware/bulk-restore.blade.php @@ -39,7 +39,7 @@ {{ $asset->id }} - {{ $asset->present()->name() }} + {{ $asset->display_name }} @if ($asset->location) {{ $asset->location->name }} diff --git a/resources/views/hardware/checkin-due.blade.php b/resources/views/hardware/checkin-due.blade.php index 602a3a780b..74ebdceb41 100644 --- a/resources/views/hardware/checkin-due.blade.php +++ b/resources/views/hardware/checkin-due.blade.php @@ -49,6 +49,7 @@ @include ('partials.forms.checkout-selector', ['user_select' => 'true','asset_select' => 'true', 'location_select' => 'true']) - - @include ('partials.forms.edit.user-select', ['translated_name' => trans('general.user'), 'fieldname' => 'assigned_user']) - + @include ('partials.forms.edit.user-select', ['translated_name' => trans('general.user'), 'fieldname' => 'assigned_user', 'style' => (session('checkout_to_type') ?: 'user') == 'user' ? '' : 'display: none;']) - @include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.asset'), 'fieldname' => 'assigned_asset', 'unselect' => 'true', 'style' => 'display:none;']) - - @include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'assigned_location', 'style' => 'display:none;']) + @include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.select_asset'), 'fieldname' => 'assigned_asset', 'company_id' => $asset->company_id, 'unselect' => 'true', 'style' => session('checkout_to_type') == 'asset' ? '' : 'display: none;']) + @include ('partials.forms.edit.location-select', ['translated_name' => trans('general.location'), 'fieldname' => 'assigned_location', 'style' => session('checkout_to_type') == 'location' ? '' : 'display: none;']) diff --git a/resources/views/hardware/index.blade.php b/resources/views/hardware/index.blade.php index fa67078b7b..fded1c3d14 100755 --- a/resources/views/hardware/index.blade.php +++ b/resources/views/hardware/index.blade.php @@ -47,6 +47,8 @@ {{-- Page content --}} @section('content') + +
      @@ -61,11 +63,11 @@ data-columns="{{ \App\Presenters\AssetPresenter::dataTableLayout() }}" data-cookie-id-table="{{ request()->has('status') ? e(request()->input('status')) : '' }}assetsListingTable" data-id-table="{{ request()->has('status') ? e(request()->input('status')) : '' }}assetsListingTable" - data-search-text="{{ e(Session::get('search')) }}" data-side-pagination="server" data-show-footer="true" data-sort-order="asc" data-sort-name="name" + data-show-columns-search="true" data-toolbar="#assetsBulkEditToolbar" data-bulk-button-id="#bulkAssetEditButton" data-bulk-form-id="#assetsBulkForm" diff --git a/resources/views/hardware/requested.blade.php b/resources/views/hardware/requested.blade.php index 4bad890633..db96b556b9 100644 --- a/resources/views/hardware/requested.blade.php +++ b/resources/views/hardware/requested.blade.php @@ -86,7 +86,7 @@
      @if ($request->requestingUser() && !$request->requestingUser()->trashed()) - {{ $request->requestingUser()->present()->fullName() }} + {{ $request->requestingUser()->display_name }} @else (deleted user) diff --git a/resources/views/hardware/view.blade.php b/resources/views/hardware/view.blade.php index 550c4b1fbf..59086075be 100755 --- a/resources/views/hardware/view.blade.php +++ b/resources/views/hardware/view.blade.php @@ -55,7 +55,9 @@ - + @@ -64,9 +66,11 @@ - + + {!! ($asset->licenses->count() > 0 ) ? ''.number_format($asset->licenses->count()).'' : '' !!} + @@ -75,9 +79,11 @@ - + + {!! ($asset->components->count() > 0 ) ? ''.number_format($asset->components->count()).'' : '' !!} + @@ -88,24 +94,22 @@ + {!! ($asset->assignedAssets()->count() > 0 ) ? ''.number_format($asset->assignedAssets()->count()).'' : '' !!} - @if ($asset->assignedAccessories->count() > 0)
    • - + {!! ($asset->assignedAccessories()->count() > 0 ) ? ''.number_format($asset->assignedAccessories()->count()).'' : '' !!}
    • @endif @@ -114,15 +118,13 @@ @if ($asset->audits->count() > 0)
    • - + {!! ($asset->audits()->count() > 0 ) ? ''.number_format($asset->audits()->count()).'' : '' !!}
    • @endif @@ -142,9 +144,10 @@ - + + {!! ($asset->maintenances()->count() > 0 ) ? ''.number_format($asset->maintenances()->count()).'' : '' !!} @@ -153,9 +156,10 @@ - + + {!! ($asset->uploads->count() > 0 ) ? ''.number_format($asset->uploads->count()).'' : '' !!} @@ -167,8 +171,8 @@ + + {!! ($asset->model) && ($asset->model->uploads->count() > 0 ) ? ''.number_format($asset->model->uploads->count()).'' : '' !!} @endcan @@ -338,7 +342,7 @@ @if (($asset->checkedOutToUser()) && ($asset->assignedTo->present()->gravatar()))
    • - {{ $asset->assignedTo->present()->fullName() }} + {{ $asset->assignedTo->display_name }} {!! $asset->assignedTo->present()->nameUrl() !!}
    • @else @@ -378,7 +382,11 @@ @if (isset($asset->location))
    • - {{ $asset->location->name }}
    • + {{ $asset->location->parent?->name }} + @if ($asset->location->parent) + + @endif + {{ $asset->location->name }}
    • {{ $asset->location->address }} @if ($asset->location->address2!='') {{ $asset->location->address2 }} @@ -547,7 +555,7 @@ {!! $asset->checkInvalidNextAuditDate() ? '' : '' !!} {{ Helper::getFormattedDateObject($audit_log->created_at, 'datetime', false) }} @if ($audit_log->user) - (by {{ link_to_route('users.show', $audit_log->user->present()->fullname(), [$audit_log->user->id]) }}) + (by {{ link_to_route('users.show', $audit_log->user->display_name, [$audit_log->user->id]) }}) @endif @@ -732,716 +740,724 @@ @if (!empty($asset->{$field->db_column_name()})) {{-- Hidden span used as copy target --}} {{-- It's tempting to break out the HTML into separate lines for this, but it results in extra spaces being added onto the end of the coipied value --}} - {{ ($field->isFieldDecryptable($asset->{$field->db_column_name()}) ? Helper::gracefulDecrypt($field, $asset->{$field->db_column_name()}) : $asset->{$field->db_column_name()}) }} - - {{-- Clipboard icon --}} - - @endif - @if (($field->field_encrypted=='1') && ($asset->{$field->db_column_name()}!='')) - - - @endif - - @if ($field->isFieldDecryptable($asset->{$field->db_column_name()} )) - @can('assets.view.encrypted_custom_fields') - @php - $fieldSize = strlen(Helper::gracefulDecrypt($field, $asset->{$field->db_column_name()})) - @endphp - @if ($fieldSize > 0) - {{ str_repeat('*', $fieldSize) }} - @if (($field->format=='URL') && ($asset->{$field->db_column_name()}!='')) - - {{ Helper::gracefulDecrypt($field, $asset->{$field->db_column_name()}) }} - - @elseif (($field->format=='DATE') && ($asset->{$field->db_column_name()}!='')) - {{ \App\Helpers\Helper::gracefulDecrypt($field, \App\Helpers\Helper::getFormattedDateObject($asset->{$field->db_column_name()}, 'date', false)) }} - @else - {{ Helper::gracefulDecrypt($field, $asset->{$field->db_column_name()}) }} - @endif - @endif + @if (($field->field_encrypted=='1') && (Gate::allows('assets.view.encrypted_custom_fields'))) + {{ ($field->isFieldDecryptable($asset->{$field->db_column_name()}) ? Helper::gracefulDecrypt($field, $asset->{$field->db_column_name()}) : $asset->{$field->db_column_name()}) }} + @elseif (($field->field_encrypted=='1') && (Gate::denies('assets.view.encrypted_custom_fields'))) + {{ strtoupper(trans('admin/custom_fields/general.encrypted')) }} @else - {{ strtoupper(trans('admin/custom_fields/general.encrypted')) }} - @endcan - - @else - @if (($field->format=='BOOLEAN') && ($asset->{$field->db_column_name()}!='')) - {!! ($asset->{$field->db_column_name()} == 1) ? "" : "" !!} - @elseif (($field->format=='URL') && ($asset->{$field->db_column_name()}!='')) - {{ $asset->{$field->db_column_name()} }} - @elseif (($field->format=='DATE') && ($asset->{$field->db_column_name()}!='')) - {{ \App\Helpers\Helper::getFormattedDateObject($asset->{$field->db_column_name()}, 'date', false) }} - @else - {!! nl2br(e($asset->{$field->db_column_name()})) !!} + {{ $asset->{$field->db_column_name()} }} @endif - @endif + {{-- Clipboard icon --}} + + @endif + @if (($field->field_encrypted=='1') && ($asset->{$field->db_column_name()}!='') && (Gate::allows('assets.view.encrypted_custom_fields'))) + + @endif - @if ($asset->{$field->db_column_name()}=='') -   + @if ($field->isFieldDecryptable($asset->{$field->db_column_name()} )) + @can('assets.view.encrypted_custom_fields') + @php + $fieldSize = strlen(Helper::gracefulDecrypt($field, $asset->{$field->db_column_name()})) + @endphp + @if ($fieldSize > 0) + *********** + @if (($field->format=='URL') && ($asset->{$field->db_column_name()}!='')) + + {{ Helper::gracefulDecrypt($field, $asset->{$field->db_column_name()}) }} + + @elseif (($field->format=='DATE') && ($asset->{$field->db_column_name()}!='')) + {{ \App\Helpers\Helper::gracefulDecrypt($field, \App\Helpers\Helper::getFormattedDateObject($asset->{$field->db_column_name()}, 'date', false)) }} + @else + {{ Helper::gracefulDecrypt($field, $asset->{$field->db_column_name()}) }} + @endif + @endif + @else + {{ strtoupper(trans('admin/custom_fields/general.encrypted')) }} + @endcan + + @else + @if (($field->format=='BOOLEAN') && ($asset->{$field->db_column_name()}!='')) + {!! ($asset->{$field->db_column_name()} == 1) ? "" : "" !!} + @elseif (($field->format=='URL') && ($asset->{$field->db_column_name()}!='')) + {{ $asset->{$field->db_column_name()} }} + @elseif (($field->format=='DATE') && ($asset->{$field->db_column_name()}!='')) + {{ \App\Helpers\Helper::getFormattedDateObject($asset->{$field->db_column_name()}, 'date', false) }} + @else + {!! nl2br(e($asset->{$field->db_column_name()})) !!} + @endif + + @endif + + @if ($asset->{$field->db_column_name()}=='') +   + @endif + + + @endforeach + @endif + + + @if ($asset->purchase_date) +
      +
      + + {{ trans('admin/hardware/form.date') }} + +
      +
      + {{ Helper::getFormattedDateObject($asset->purchase_date, 'date', false) }} + - + {{ Carbon::parse($asset->purchase_date)->diffForHumans(['parts' => 3]) }} + +
      +
      + @endif + + @if ($asset->purchase_cost) +
      +
      + + {{ trans('admin/hardware/form.cost') }} + +
      +
      + @if (($asset->id) && ($asset->location)) + {{ $asset->location->currency }} + @elseif (($asset->id) && ($asset->location)) + {{ $asset->location->currency }} + @else + {{ $snipeSettings->default_currency }} + @endif + {{ Helper::formatCurrencyOutput($asset->purchase_cost)}} + +
      +
      + @endif + @if(($asset->components->count() > 0) && ($asset->purchase_cost)) +
      +
      + + {{ trans('admin/hardware/table.components_cost') }} + +
      +
      + @if (($asset->id) && ($asset->location)) + {{ $asset->location->currency }} + @elseif (($asset->id) && ($asset->location)) + {{ $asset->location->currency }} + @else + {{ $snipeSettings->default_currency }} + @endif + {{Helper::formatCurrencyOutput($asset->getComponentCost())}} +
      +
      + @endif + @if (($asset->model) && ($asset->depreciation) && ($asset->purchase_date)) +
      +
      + + {{ trans('admin/hardware/table.current_value') }} + +
      +
      + @if (($asset->id) && ($asset->location)) + {{ $asset->location->currency }} + @elseif (($asset->id) && ($asset->location)) + {{ $asset->location->currency }} + @else + {{ $snipeSettings->default_currency }} + @endif + {{ Helper::formatCurrencyOutput($asset->getDepreciatedValue() )}} + + +
      +
      + @endif + @if ($asset->order_number) +
      +
      + + {{ trans('general.order_number') }} + +
      + +
      + @endif + + @if ($asset->supplier) +
      +
      + + {{ trans('general.supplier') }} + +
      +
      + @can ('superuser') + + {{ $asset->supplier->name }} + + @else + {{ $asset->supplier->name }} + @endcan +
      +
      + @endif + + + @if ($asset->warranty_months) +
      +
      + + {{ trans('admin/hardware/form.warranty') }} + +
      +
      + {{ trans_choice('general.months_plural', $asset->warranty_months) }} + @if (($asset->model) && ($asset->model->manufacturer) && ($asset->model->manufacturer->warranty_lookup_url!='')) + + + {{ trans('admin/hardware/general.mfg_warranty_lookup', ['manufacturer' => $asset->model->manufacturer->name]) }} + @endif
      - @endforeach - @endif + +
      +
      + + {{ trans('admin/hardware/form.warranty_expires') }} - @if ($asset->purchase_date) -
      -
      - - {{ trans('admin/hardware/form.date') }} - -
      -
      - {{ Helper::getFormattedDateObject($asset->purchase_date, 'date', false) }} - - - {{ Carbon::parse($asset->purchase_date)->diff(Carbon::now())->format('%y years, %m months and %d days')}} - -
      -
      - @endif - - @if ($asset->purchase_cost) -
      -
      - - {{ trans('admin/hardware/form.cost') }} - -
      -
      - @if (($asset->id) && ($asset->location)) - {{ $asset->location->currency }} - @elseif (($asset->id) && ($asset->location)) - {{ $asset->location->currency }} - @else - {{ $snipeSettings->default_currency }} - @endif - {{ Helper::formatCurrencyOutput($asset->purchase_cost)}} - -
      -
      - @endif - @if(($asset->components->count() > 0) && ($asset->purchase_cost)) -
      -
      - - {{ trans('admin/hardware/table.components_cost') }} - -
      -
      - @if (($asset->id) && ($asset->location)) - {{ $asset->location->currency }} - @elseif (($asset->id) && ($asset->location)) - {{ $asset->location->currency }} - @else - {{ $snipeSettings->default_currency }} - @endif - {{Helper::formatCurrencyOutput($asset->getComponentCost())}} -
      -
      - @endif - @if (($asset->model) && ($asset->depreciation) && ($asset->purchase_date)) -
      -
      - - {{ trans('admin/hardware/table.current_value') }} - -
      -
      - @if (($asset->id) && ($asset->location)) - {{ $asset->location->currency }} - @elseif (($asset->id) && ($asset->location)) - {{ $asset->location->currency }} - @else - {{ $snipeSettings->default_currency }} - @endif - {{ Helper::formatCurrencyOutput($asset->getDepreciatedValue() )}} - - -
      -
      - @endif - @if ($asset->order_number) -
      -
      - - {{ trans('general.order_number') }} - -
      - -
      - @endif - - @if ($asset->supplier) -
      -
      - - {{ trans('general.supplier') }} - -
      -
      - @can ('superuser') - - {{ $asset->supplier->name }} - - @else - {{ $asset->supplier->name }} - @endcan -
      -
      - @endif - - - @if ($asset->warranty_months) -
      -
      - - {{ trans('admin/hardware/form.warranty') }} - -
      -
      - {{ trans_choice('general.months_plural', $asset->warranty_months) }} - @if (($asset->model) && ($asset->model->manufacturer) && ($asset->model->manufacturer->warranty_lookup_url!='')) - - - {{ trans('admin/hardware/general.mfg_warranty_lookup', ['manufacturer' => $asset->model->manufacturer->name]) }} - - @endif -
      -
      - -
      -
      - - {{ trans('admin/hardware/form.warranty_expires') }} + +
      +
      @if ($asset->purchase_date) - {!! $asset->present()->warranty_expires() < date("Y-m-d") ? '' : '' !!} + {{ Helper::getFormattedDateObject($asset->present()->warranty_expires(), 'date', false) }} + - + {{ Carbon::parse($asset->present()->warranty_expires())->diffForHumans(['parts' => 3]) }} + + @if ($asset->purchase_date) + {!! $asset->present()->warranty_expires() < date("Y-m-d") ? '' : '' !!} + @endif + @else + {{ trans('general.na_no_purchase_date') }} + @endif +
      +
      + + @endif + + @if (($asset->model) && ($asset->depreciation)) +
      +
      + + {{ trans('general.depreciation') }} + +
      +
      + {{ $asset->depreciation->name }} + ({{ trans_choice('general.months_plural', $asset->depreciation->months) }}) +
      +
      +
      +
      + + {{ trans('admin/hardware/form.fully_depreciated') }} + +
      +
      + @if ($asset->purchase_date) + {{ Helper::getFormattedDateObject($asset->depreciated_date()->format('Y-m-d'), 'date', false) }} + - + {{ Carbon::parse($asset->depreciated_date())->diffForHumans(['parts' => 3]) }} + @else + {{ trans('general.na_no_purchase_date') }} @endif - +
      -
      - @if ($asset->purchase_date) - {{ Helper::getFormattedDateObject($asset->present()->warranty_expires(), 'date', false) }} - - - {{ Carbon::parse($asset->present()->warranty_expires())->diffForHumans(['parts' => 2]) }} - @else - {{ trans('general.na_no_purchase_date') }} - @endif -
      -
      + @endif - @endif + @if (($asset->asset_eol_date) && ($asset->purchase_date)) +
      +
      + + {{ trans('admin/hardware/form.eol_rate') }} + +
      +
      + {{ (int) Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date, true) }} + {{ trans('admin/hardware/form.months') }} - @if (($asset->model) && ($asset->depreciation)) -
      -
      - - {{ trans('general.depreciation') }} - +
      -
      - {{ $asset->depreciation->name }} - ({{ trans_choice('general.months_plural', $asset->depreciation->months) }}) -
      -
      -
      -
      - - {{ trans('admin/hardware/form.fully_depreciated') }} - -
      -
      - @if ($asset->purchase_date) - {{ Helper::getFormattedDateObject($asset->depreciated_date()->format('Y-m-d'), 'date', false) }} - - - {{ Carbon::parse($asset->depreciated_date())->diffForHumans(['parts' => 2]) }} - @else - {{ trans('general.na_no_purchase_date') }} - @endif - -
      -
      - @endif - - @if (($asset->asset_eol_date) && ($asset->purchase_date)) -
      -
      - - {{ trans('admin/hardware/form.eol_rate') }} - -
      -
      - {{ (int) Carbon::parse($asset->asset_eol_date)->diffInMonths($asset->purchase_date, true) }} - {{ trans('admin/hardware/form.months') }} - -
      -
      - @endif - @if ($asset->asset_eol_date) -
      -
      - - {{ trans('admin/hardware/form.eol_date') }} - @if ($asset->purchase_date) - {!! $asset->asset_eol_date < date("Y-m-d") ? '' : '' !!} + @endif + @if ($asset->asset_eol_date) +
      +
      + + {{ trans('admin/hardware/form.eol_date') }} + @if ($asset->purchase_date) + {!! $asset->asset_eol_date < date("Y-m-d") ? '' : '' !!} + @endif + +
      +
      + @if ($asset->asset_eol_date) + {{ Helper::getFormattedDateObject($asset->asset_eol_date, 'date', false) }} + - + {{ Carbon::parse($asset->asset_eol_date)->locale(app()->getLocale())->diffForHumans(['parts' => 3]) }} + @else + {{ trans('general.na_no_purchase_date') }} @endif - + @if ($asset->eol_explicit =='1') + + + + @endif +
      -
      - @if ($asset->asset_eol_date) - {{ Helper::getFormattedDateObject($asset->asset_eol_date, 'date', false) }} - - - {{ Carbon::parse($asset->asset_eol_date)->diffForHumans(['parts' => 2]) }} - @else - {{ trans('general.na_no_purchase_date') }} - @endif - @if ($asset->eol_explicit =='1') - - - - @endif -
      -
      - @endif + @endif -
      -
      - - {{ trans('admin/hardware/form.notes') }} - -
      -
      - {!! nl2br(Helper::parseEscapedMarkedownInline($asset->notes)) !!} -
      -
      - - @if ($asset->location)
      - {{ trans('general.location') }} + {{ trans('admin/hardware/form.notes') }}
      +
      + + @if ($asset->location) +
      +
      + + {{ trans('general.location') }} + +
      +
      + @can('superuser') + + {{ $asset->location->name }} + + @else {{ $asset->location->name }} - - @else - {{ $asset->location->name }} - @endcan + @endcan +
      -
      - @endif + @endif - @if ($asset->defaultLoc) -
      -
      - - {{ trans('admin/hardware/form.default_location') }} - -
      -
      - @can('superuser') - + @if ($asset->defaultLoc) +
      +
      + + {{ trans('admin/hardware/form.default_location') }} + +
      +
      + @can('superuser') + + {{ $asset->defaultLoc->name }} + + @else {{ $asset->defaultLoc->name }} - - @else - {{ $asset->defaultLoc->name }} - @endcan + @endcan +
      -
      - @endif + @endif + + @if ($asset->created_at!='') +
      +
      + + {{ trans('general.created_at') }} + +
      +
      + {{ Helper::getFormattedDateObject($asset->created_at, 'datetime', false) }} +
      +
      + @endif + + @if ($asset->updated_at!='') +
      +
      + + {{ trans('general.updated_at') }} + +
      +
      + {{ Helper::getFormattedDateObject($asset->updated_at, 'datetime', false) }} +
      +
      + @endif + + @if ($asset->expected_checkin!='') +
      +
      + + {{ trans('general.expected_checkin') }} + +
      +
      + {{ Helper::getFormattedDateObject($asset->expected_checkin, 'date', false) }} +
      +
      + @endif + + @if ($asset->last_checkin!='') +
      +
      + + {{ trans('admin/hardware/table.last_checkin_date') }} + +
      +
      + {{ Helper::getFormattedDateObject($asset->last_checkin, 'datetime', false) }} +
      +
      + @endif + + - @if ($asset->created_at!='')
      - {{ trans('general.created_at') }} + {{ trans('general.checkouts_count') }}
      - {{ Helper::getFormattedDateObject($asset->created_at, 'datetime', false) }} + {{ ($asset->checkouts) ? (int) $asset->checkouts->count() : '0' }}
      - @endif - @if ($asset->updated_at!='') +
      - {{ trans('general.updated_at') }} + {{ trans('general.checkins_count') }}
      - {{ Helper::getFormattedDateObject($asset->updated_at, 'datetime', false) }} + {{ ($asset->checkins) ? (int) $asset->checkins->count() : '0' }}
      - @endif - @if ($asset->expected_checkin!='') +
      - {{ trans('general.expected_checkin') }} + {{ trans('general.user_requests_count') }}
      - {{ Helper::getFormattedDateObject($asset->expected_checkin, 'date', false) }} + {{ ($asset->userRequests) ? (int) $asset->userRequests->count() : '0' }}
      - @endif - @if ($asset->last_checkin!='') -
      -
      - - {{ trans('admin/hardware/table.last_checkin_date') }} - -
      -
      - {{ Helper::getFormattedDateObject($asset->last_checkin, 'datetime', false) }} -
      +
      +
      +
      +
      + + +
      +
      +
      + + + + + + + + + + + + @foreach ($asset->licenseseats as $seat) + @if ($seat->license) + + + + + + + @endif + @endforeach + +
      {{ trans('general.name') }}{{ trans('admin/licenses/form.license_key') }}{{ trans('admin/licenses/form.expiration') }}{{ trans('table.actions') }}
      {{ $seat->license->name }} + @can('viewKeys', $seat->license) + + @else + ------------ + @endcan + + {{ Helper::getFormattedDateObject($seat->license->expiration_date, 'date', false) }} + + {{ trans('general.checkin') }} +
      +
      +
      +
      + +
      + +
      +
      + + + + + + + + + + + + + @foreach ($asset->components as $component) + + + @if (is_null($component->deleted_at)) + + + + + + + + purchase_cost *$component->pivot->assigned_qty) ?> + + @endif + @endforeach + + + + + + + + +
      {{ trans('general.name') }}{{ trans('general.qty') }}{{ trans('general.purchase_cost') }}{{trans('admin/hardware/form.serial')}}{{trans('general.checkin')}}
      + {{ $component->name }} + {{ $component->pivot->assigned_qty }} + @if ($component->purchase_cost!='') + {{ trans('general.cost_each', ['amount' => Helper::formatCurrencyOutput($component->purchase_cost)]) }} + @endif + {{ $component->serial }} + {{ trans('general.checkin') }} +
      + {{ $totalCost }}
      +
      +
      +
      + + +
      +
      +
      + + @include('partials.asset-bulk-actions') + + +
      + + + +
      - @endif - -
      -
      - - {{ trans('general.checkouts_count') }} - -
      -
      - {{ ($asset->checkouts) ? (int) $asset->checkouts->count() : '0' }} -
      -
      +
      +
      +
      -
      -
      - - {{ trans('general.checkins_count') }} - -
      -
      - {{ ($asset->checkins) ? (int) $asset->checkins->count() : '0' }} -
      -
      +
      -
      -
      - - {{ trans('general.user_requests_count') }} - -
      -
      - {{ ($asset->userRequests) ? (int) $asset->userRequests->count() : '0' }} -
      -
      +
      -
      -
      - - +

      + {{ trans('general.accessories_assigned') }} +

      + + +
      + + -
      -
      -
      - - - - - - - - - - - - @foreach ($asset->licenseseats as $seat) - @if ($seat->license) - - - - - - - @endif - @endforeach - + +
      +
      +
      + + +
      {{ trans('general.name') }}{{ trans('admin/licenses/form.license_key') }}{{ trans('admin/licenses/form.expiration') }}{{ trans('table.actions') }}
      {{ $seat->license->name }} - @can('viewKeys', $seat->license) - - @else - ------------ - @endcan - - {{ Helper::getFormattedDateObject($seat->license->expiration_date, 'date', false) }} - - {{ trans('general.checkin') }} -
      -
      -
      -
      - -
      - -
      -
      - - - - - - - - - - - - - @foreach ($asset->components as $component) + + + - @if (is_null($component->deleted_at)) - - - - - - - - purchase_cost *$component->pivot->assigned_qty) ?> - - @endif - @endforeach - - - - - - - - -
      {{ trans('general.name') }}{{ trans('general.qty') }}{{ trans('general.purchase_cost') }}{{trans('admin/hardware/form.serial')}}{{trans('general.checkin')}}
      - {{ $component->name }} - {{ $component->pivot->assigned_qty }} - @if ($component->purchase_cost!='') - {{ trans('general.cost_each', ['amount' => Helper::formatCurrencyOutput($component->purchase_cost)]) }} - @endif - {{ $component->serial }} - {{ trans('general.checkin') }} -
      - {{ $totalCost }}
      -
      -
      -
      - - -
      -
      -
      - - @include('partials.asset-bulk-actions') - - -
      - - - -
      -
      - - -
      -
      -
      - - -
      - - -
      - -

      - {{ trans('general.accessories_assigned') }} -

      - - -
      - -
      -
      - - -
      -
      -
      - - - -
      -
      -
      -
      - - -
      - -
      -
      - - - - - - - - - - - - - - - -
      {{ trans('general.date') }}{{ trans('general.created_by') }}{{ trans('general.file_name') }}{{ trans('general.notes') }}{{ trans('general.download') }}{{ trans('admin/hardware/table.changed')}}{{ trans('admin/settings/general.login_ip') }}{{ trans('admin/settings/general.login_user_agent') }}{{ trans('general.action_source') }}
      -
      -
      -
      - - -
      +
      + + + + + + + + + + + + + +
      {{ trans('general.date') }}{{ trans('general.created_by') }}{{ trans('general.file_name') }}{{ trans('general.notes') }}{{ trans('general.download') }}{{ trans('admin/hardware/table.changed')}}{{ trans('admin/settings/general.login_ip') }}{{ trans('admin/settings/general.login_user_agent') }}{{ trans('general.action_source') }}
      -
      -
      -
      - -
      -
      -
      - @if ($asset->model) - @can('view', $asset->model) -
      -
      -
      - -
      -
      -
      - @endcan - @endif -
      - - +
      + +
      +
      + +
      +
      +
      +
      - @can('update', \App\Models\Asset::class) - @include ('modals.upload-file', ['item_type' => 'asset', 'item_id' => $asset->id]) - @endcan -@stop - @section('moar_scripts') - @include ('partials.bootstrap-table') +
      +
      +
      + +
      +
      +
      -@stop + @if ($asset->model) + @can('view', $asset->model) +
      +
      +
      + +
      +
      +
      + @endcan + @endif + + + + + @can('update', \App\Models\Asset::class) + @include ('modals.upload-file', ['item_type' => 'asset', 'item_id' => $asset->id]) + @endcan + @stop + @section('moar_scripts') + @include ('partials.bootstrap-table') + + @stop diff --git a/resources/views/layouts/default.blade.php b/resources/views/layouts/default.blade.php index 48ecd6f00d..e4f41281e1 100644 --- a/resources/views/layouts/default.blade.php +++ b/resources/views/layouts/default.blade.php @@ -215,7 +215,7 @@ dir="{{ Helper::determineLanguageDirection() }}"> @can('create', \App\Models\Asset::class) is('hardware/create') ? ' class="active"' : '') !!}> - + {{ trans('general.asset') }}
    • @@ -223,7 +223,7 @@ dir="{{ Helper::determineLanguageDirection() }}"> @can('create', \App\Models\License::class) is('licenses/create') ? ' class="active"' : '') !!}> - + {{ trans('general.license') }} @@ -231,7 +231,7 @@ dir="{{ Helper::determineLanguageDirection() }}"> @can('create', \App\Models\Accessory::class)
    • is('accessories/create') ? 'class="active"' : '') !!}> - + {{ trans('general.accessory') }}
    • @@ -239,7 +239,7 @@ dir="{{ Helper::determineLanguageDirection() }}"> @can('create', \App\Models\Consumable::class)
    • is('consunmables/create') ? 'class="active"' : '') !!}> - + {{ trans('general.consumable') }}
    • @@ -247,7 +247,7 @@ dir="{{ Helper::determineLanguageDirection() }}"> @can('create', \App\Models\Component::class)
    • is('components/create') ? 'class="active"' : '') !!}> - + {{ trans('general.component') }}
    • @@ -255,7 +255,7 @@ dir="{{ Helper::determineLanguageDirection() }}"> @can('create', \App\Models\User::class)
    • is('users/create') ? 'class="active"' : '') !!}> - + {{ trans('general.user') }}
    • @@ -353,7 +353,7 @@ dir="{{ Helper::determineLanguageDirection() }}"> @endif @@ -985,6 +985,13 @@ dir="{{ Helper::determineLanguageDirection() }}"> @endif @endif + @if (isset($user) && ($user->isSuperUser()) && (app()->environment('local'))) + Open Telescope + @endif + + + + @if ($snipeSettings->support_footer!='off') @if (($snipeSettings->support_footer=='on') || (($snipeSettings->support_footer=='admin') && (Auth::user()->isSuperUser()=='1'))) @endcan - @include ('partials.forms.checkout-selector', ['user_select' => 'true','asset_select' => 'true']) - - @include ('partials.forms.edit.user-select', ['translated_name' => trans('general.user'), 'fieldname' => 'assigned_to']) - - @include ('partials.forms.edit.asset-select', ['translated_name' => trans('admin/licenses/form.asset'), 'fieldname' => 'asset_id', 'style' => 'display:none;']) - + @include ('partials.forms.checkout-selector', ['user_select' => 'true','asset_select' => 'true', 'location_select' => 'false']) + @include ('partials.forms.edit.user-select', ['translated_name' => trans('general.user'), 'fieldname' => 'assigned_to', 'style' => session('checkout_to_type') == 'user' ? '' : 'display: none;']) + @include ('partials.forms.edit.asset-select', ['translated_name' => trans('general.select_asset'), 'fieldname' => 'asset_id', 'style' => session('checkout_to_type') == 'asset' ? '' : 'display: none;'])
      diff --git a/resources/views/licenses/index.blade.php b/resources/views/licenses/index.blade.php index c4efc93593..8012cc2bbe 100755 --- a/resources/views/licenses/index.blade.php +++ b/resources/views/licenses/index.blade.php @@ -27,7 +27,7 @@ id="licensesTable" data-buttons="licenseButtons" class="table table-striped snipe-table" - data-url="{{ route('api.licenses.index') }}" + data-url="{{ route('api.licenses.index', ['status' => e(request('status'))]) }}" data-export-options='{ "fileName": "export-licenses-{{ date('Y-m-d') }}", "ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"] diff --git a/resources/views/licenses/view.blade.php b/resources/views/licenses/view.blade.php index 8466aebb11..43d2c697c0 100755 --- a/resources/views/licenses/view.blade.php +++ b/resources/views/licenses/view.blade.php @@ -249,6 +249,11 @@
      + @if ($license->isExpired()) + + + + @endif {{ Helper::getFormattedDateObject($license->expiration_date, 'date', false) }}
      @@ -262,6 +267,12 @@
      + @if ($license->isTerminated()) + + + + @endif + {{ Helper::getFormattedDateObject($license->termination_date, 'date', false) }}
      @@ -545,7 +556,7 @@ @can('checkout', $license) - @if ($license->availCount()->count() > 0) + @if (($license->availCount()->count() > 0) && (!$license->isInactive()))
      @@ -558,17 +569,13 @@ @else - - + {{ trans('general.checkout') }} - - - + {{ trans('admin/licenses/general.bulk.checkout_all.button') }} - @endif @endcan @@ -582,20 +589,13 @@ {{ trans('admin/licenses/general.bulk.checkin_all.button') }} - @elseif (! $license->reassignable) - - - - {{ trans('admin/licenses/general.bulk.checkin_all.button') }} - - - @else - - - {{ trans('admin/licenses/general.bulk.checkin_all.button') }} - - @endif - @endcan + @else + + + {{ trans('admin/licenses/general.bulk.checkin_all.button') }} + + @endif + @endcan @can('delete', $license) diff --git a/resources/views/livewire/importer.blade.php b/resources/views/livewire/importer.blade.php index 9162b09c72..ba6dfbfdbd 100644 --- a/resources/views/livewire/importer.blade.php +++ b/resources/views/livewire/importer.blade.php @@ -196,6 +196,7 @@ {{ trans('general.send_welcome_email_to_users') }} +

      {{ trans('general.send_welcome_email_import_help') }}

      @endif
      ' html += '
      ' return html; } @@ -1032,13 +1148,23 @@ var keys = [ '{{ trans('admin/settings/general.employee_number') }}', '{{ trans('mail.username') }}', + '{{ trans('admin/users/table.display_name') }}', '{{ trans('general.first_name') }}', '{{ trans('general.last_name') }}', - '{{ trans('general.email') }}' + '{{ trans('general.email') }}', + '{{ trans('general.phone') }}', + '{{ trans('admin/users/table.mobile') }}', + '{{ trans('admin/users/table.manager') }}', + '{{ trans('general.address') }}', + '{{ trans('general.city') }}', + '{{ trans('general.state') }}', + '{{ trans('general.zip') }}', + '{{ trans('general.country') }}', + '{{ trans('general.location') }}', ] let header = '' for (var i in keys) { - header += '' + keys[i] + '' + header += '' + keys[i] + '' } header += "" return header; @@ -1048,7 +1174,23 @@ { let body = '' for (var i in users) { - body += '' + users[i].employee_number + '' + users[i].username + '' + users[i].firstname + '' + users[i].lastname + '' + users[i].email + '' + body += ''; + body += '' + (users[i].employee_number ?? 'NULL') + ''; + body += '' + (users[i].username ?? 'NULL') + ''; + body += '' + (users[i].display_name ?? 'NULL') + ''; + body += '' + (users[i].firstname ?? 'NULL') + ''; + body += '' + (users[i].lastname ?? 'NULL') + ''; + body += '' + (users[i].email ?? 'NULL') + ''; + body += '' + (users[i].phone ?? 'NULL') + ''; + body += '' + (users[i].mobile ?? 'NULL') + ''; + body += '' + (users[i].manager ?? 'NULL') + ''; + body += '' + (users[i].address ?? 'NULL') + ''; + body += '' + (users[i].city ?? 'NULL') + ''; + body += '' + (users[i].state ?? 'NULL') + ''; + body += '' + (users[i].zip ?? 'NULL') + ''; + body += '' + (users[i].country ?? 'NULL') + ''; + body += '' + (users[i].location ?? 'NULL') + ''; + body += '' } body += "" return body; diff --git a/resources/views/settings/localization.blade.php b/resources/views/settings/localization.blade.php index c358350cd6..7f78fb8974 100644 --- a/resources/views/settings/localization.blade.php +++ b/resources/views/settings/localization.blade.php @@ -58,8 +58,12 @@
      - {!! Form::name_display_format('name_display_format', old('name_display_format', $setting->name_display_format), 'select2') !!} - + {!! $errors->first('name_display_format', '') !!}
      @@ -72,10 +76,10 @@
      - {!! Form::date_display_format('date_display_format', old('date_display_format', $setting->date_display_format), 'select2') !!} +
      - {!! Form::time_display_format('time_display_format', old('time_display_format', $setting->time_display_format), 'select2') !!} +
      {!! $errors->first('time_display_format', '
      ') !!} @@ -99,7 +103,12 @@ id="default_currency" > - {!! Form::digit_separator('digit_separator', old('digit_separator', $setting->digit_separator), 'select2') !!} + {!! $errors->first('default_currency', '') !!}
      diff --git a/resources/views/statuslabels/index.blade.php b/resources/views/statuslabels/index.blade.php index ce2a6f758b..84fcfcf283 100755 --- a/resources/views/statuslabels/index.blade.php +++ b/resources/views/statuslabels/index.blade.php @@ -23,6 +23,7 @@ data-sort-name="name" id="statuslabelsTable" data-buttons="statuslabelButtons" + data-advanced-search="false" class="table table-striped snipe-table" data-url="{{ route('api.statuslabels.index') }}" data-export-options='{ diff --git a/resources/views/statuslabels/view.blade.php b/resources/views/statuslabels/view.blade.php index f80bfa5782..46d356c3ef 100644 --- a/resources/views/statuslabels/view.blade.php +++ b/resources/views/statuslabels/view.blade.php @@ -24,6 +24,7 @@ data-bulk-button-id="#bulkAssetEditButton" data-bulk-form-id="#assetsBulkForm" id="assetsListingTable" + data-show-columns-search="true" data-buttons="assetButtons" class="table table-striped snipe-table" data-url="{{route('api.assets.index', ['status_id' => $statuslabel->id]) }}" diff --git a/resources/views/suppliers/index.blade.php b/resources/views/suppliers/index.blade.php index 35c06b99a1..920e666099 100755 --- a/resources/views/suppliers/index.blade.php +++ b/resources/views/suppliers/index.blade.php @@ -41,6 +41,7 @@ data-bulk-button-id="#bulkSupplierEditButton" data-bulk-form-id="#suppliersBulkForm" {{-- end stuff for bulk dropdown --}} + data-advanced-search="false" data-buttons="supplierButtons" class="table table-striped snipe-table" data-url="{{ route('api.suppliers.index') }}" diff --git a/resources/views/suppliers/view.blade.php b/resources/views/suppliers/view.blade.php index 9cf7d6e147..bc216a964e 100755 --- a/resources/views/suppliers/view.blade.php +++ b/resources/views/suppliers/view.blade.php @@ -114,6 +114,7 @@ id==$user->id ? ' style="text-decoration: line-through"' : '') !!}> - {{ $user->present()->fullName() }} ({{ $user->username }}) + {{ $user->display_name }} ({{ $user->username }}) {{ (Auth::id()==$user->id ? ' (cannot delete yourself)' : '') }} diff --git a/resources/views/users/confirm-merge.blade.php b/resources/views/users/confirm-merge.blade.php index 8a26311344..1b2f9171f4 100644 --- a/resources/views/users/confirm-merge.blade.php +++ b/resources/views/users/confirm-merge.blade.php @@ -76,7 +76,7 @@ @foreach ($users as $user) isSuperUser() ? ' class="danger"':'') !!}> @@ -911,11 +935,12 @@ }'> - - - - - + + + + + + @@ -923,6 +948,7 @@ + - + @@ -987,6 +1013,35 @@ +
      +
      - + {{ $user->email }} diff --git a/resources/views/users/edit.blade.php b/resources/views/users/edit.blade.php index 3df806ff7a..feeffce485 100755 --- a/resources/views/users/edit.blade.php +++ b/resources/views/users/edit.blade.php @@ -3,7 +3,7 @@ @section('title') @if ($user->id) {{ trans('admin/users/table.updateuser') }} - {{ $user->present()->fullName() }} + {{ $user->display_name }} @else {{ trans('admin/users/table.createuser') }} @endif @@ -288,6 +288,30 @@ + + + @if (!$user->id) +
      + +
      + + +

      {{ trans('general.send_welcome_email_help') }}

      + +
      +
      + @endif + @include ('partials.forms.edit.image-upload', ['fieldname' => 'avatar', 'image_path' => app('users_upload_path')]) @@ -311,6 +335,24 @@
      + + +
      + +
      + + {!! $errors->first('display_name', '') !!} +
      +
      + + @if ((Gate::allows('canEditAuthFields', $user)) && (\App\Models\Company::canManageUsersCompanies())) @include ('partials.forms.edit.company-select', ['translated_name' => trans('general.select_company'), 'fieldname' => 'company_id']) @@ -667,7 +709,28 @@ $(document).ready(function() { + // Set some defaults + $('#email_user_checkbox').prop("disabled", true); + $('#email_user_checkbox').prop("checked", false); + $("#email_user_checkbox").removeAttr('checked'); + // If the email address is longer than 5 characters, enable the "send email" checkbox + $('#email').on('keyup',function(){ + //event.preventDefault(); + + @if (!config('app.lock_passwords')) + + if (this.value.length > 5) { + $('#email_user_checkbox').prop("disabled", false); + $("#email_user_checkbox").parent().removeClass("form-control--disabled"); + } else { + $('#email_user_checkbox').prop("disabled", true); + $('#email_user_checkbox').prop("checked", false); + $("#email_user_checkbox").parent().addClass("form-control--disabled"); + } + + @endif + }); // Check/Uncheck all radio buttons in the group diff --git a/resources/views/users/index.blade.php b/resources/views/users/index.blade.php index 4e5f19c975..bfd0e56554 100755 --- a/resources/views/users/index.blade.php +++ b/resources/views/users/index.blade.php @@ -20,7 +20,7 @@ @can('create', \App\Models\User::class) @if ($snipeSettings->ldap_enabled == 1) - {{trans('general.ldap_sync')}} + {{trans('general.ldap_sync')}} @endif @endcan @stop @@ -43,6 +43,7 @@ data-toolbar="#userBulkEditToolbar" data-bulk-button-id="#bulkUserEditButton" data-bulk-form-id="#usersBulkForm" + data-show-columns-search="true" id="usersTable" data-buttons="userButtons" class="table table-striped snipe-table" diff --git a/resources/views/users/print.blade.php b/resources/views/users/print.blade.php index abd6c53912..935959a400 100644 --- a/resources/views/users/print.blade.php +++ b/resources/views/users/print.blade.php @@ -3,7 +3,7 @@ @if ((isset($users) && count($users) === 1)) - {{ trans('general.assigned_to', ['name' => $users[0]->present()->fullName()]) }} - {{ date('Y-m-d H:i', time()) }} + {{ trans('general.assigned_to', ['name' => $users[0]->display_name]) }} - {{ date('Y-m-d H:i', time()) }} @else {{ trans('admin/users/general.print_assigned') }} - {{ date('Y-m-d H:i', time()) }} @endisset @@ -96,10 +96,10 @@
      {{-- used for page breaks when printing --}}

      @if ($show_user->company) - {{ trans('admin/companies/table.name') }}: {{ $show_user->company->name }} + {{ trans('admin/companies/table.name') }}: {{ $show_user->company->name }}
      @endif - {{ trans('general.assigned_to', ['name' => $show_user->present()->fullName()]) }} + {{ trans('general.assigned_to', ['name' => $show_user->display_name]) }} {{ ($show_user->employee_num!='') ? ' (#'.$show_user->employee_num.') ' : '' }} {{ ($show_user->jobtitle!='' ? ' - '.$show_user->jobtitle : '') }}

      diff --git a/resources/views/users/view.blade.php b/resources/views/users/view.blade.php index cc944dbf65..1153061bcf 100755 --- a/resources/views/users/view.blade.php +++ b/resources/views/users/view.blade.php @@ -2,7 +2,7 @@ {{-- Page title --}} @section('title') -{{ trans('admin/users/general.view_user', ['name' => $user->present()->fullName()]) }} +{{ trans('admin/users/general.view_user', ['name' => $user->display_name]) }} @parent @stop @@ -94,6 +94,17 @@ +
    • + + + + +
    • +
    • @if ($user->isDeletable()) - + {{ trans('button.delete')}} @@ -319,34 +330,13 @@ {{ trans('admin/users/table.name') }}
      - {{ $user->present()->fullName() }} + {{ $user->first_name }} {{ $user->last_name }}
      - - @if (!is_null($user->company)) -
      - -
      - {{ trans('general.company') }} -
      -
      - @can('view', 'App\Models\Company') - - {{ $user->company->name }} - - @else - {{ $user->company->name }} - @endcan -
      - -
      - - @endif -
      @@ -366,6 +356,19 @@
      + + @if ($user->display_name) +
      + +
      + {{ trans('admin/users/table.display_name') }} +
      +
      + {{ $user->getRawOriginal('display_name') }} +
      +
      + @endif + @if (($user->address) || ($user->city) || ($user->state) || ($user->country))
      @@ -394,6 +397,26 @@
      @endif + + @if (!is_null($user->company)) +
      + +
      + {{ trans('general.company') }} +
      +
      + @can('view', 'App\Models\Company') + + {{ $user->company->name }} + + @else + {{ $user->company->name }} + @endcan +
      + +
      + + @endif
      @@ -478,7 +501,7 @@
      @@ -601,7 +624,7 @@ @if ($user->createdBy) - @if ($user->createdBy->deleted_at=='') - {{ $user->createdBy->present()->fullName }} + {{ $user->createdBy->display_name }} @else {{ $user->createdBy->present()->fullName }} @endif @@ -813,6 +836,7 @@ username) }}-assets-{{ date('Y-m-d') }}", "ignoreColumn": ["actions","image","change","checkbox","checkincheckout","icon"] }'>
      @@ -885,7 +909,7 @@
    • @can('update', $license) - {{ trans('general.checkin') }} + {{ trans('general.checkin') }} @endcan
      {{ trans('general.id') }}{{ trans('general.name') }}{{ trans('general.notes') }}{{ trans('general.purchase_cost') }}{{ trans('general.action') }}{{ trans('general.id') }}{{ trans('general.name') }}{{ trans('general.date') }}{{ trans('general.notes') }}{{ trans('general.unit_cost') }}{{ trans('general.action') }}
      {{ $accessory->pivot->id }} {!!$accessory->present()->nameUrl()!!}{{ Helper::getFormattedDateObject($accessory->pivot->created_at, 'datetime', false) }} {!! $accessory->pivot->note !!} {!! Helper::formatCurrencyOutput($accessory->purchase_cost) !!} @@ -957,7 +983,7 @@
      {{ trans('general.name') }}{{ trans('general.purchase_cost') }}{{ trans('general.unit_cost') }} {{ trans('general.date') }} {{ trans('general.notes') }}
      + + + + + + + + + +
      {{ trans('general.item') }}{{ trans('general.accepted_date') }}{{ trans('general.notes') }}{{ trans('general.download') }}
      +
      +
      diff --git a/resources/views/vendor/mail/html/message.blade.php b/resources/views/vendor/mail/html/message.blade.php index e958eca627..04489cd8ac 100644 --- a/resources/views/vendor/mail/html/message.blade.php +++ b/resources/views/vendor/mail/html/message.blade.php @@ -3,7 +3,20 @@ @slot('header') {{-- Check that the $snipeSettings variable is set, images are set to be shown, and setup is complete --}} + @if (isset($snipeSettings) && ($snipeSettings::setupCompleted())) diff --git a/routes/api.php b/routes/api.php index edde2b9b71..94c7ca3df5 100644 --- a/routes/api.php +++ b/routes/api.php @@ -137,7 +137,7 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu /** - * Categpries API routes + * Categories API routes */ Route::group(['prefix' => 'categories'], function () { @@ -571,6 +571,13 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu 'assignedAccessories' ] )->name('api.assets.assigned_accessories'); + + Route::get('{asset}/assigned/components', + [ + Api\AssetsController::class, + 'assignedComponents' + ] + )->name('api.assets.assigned_components'); /** End assigned routes */ }); @@ -583,9 +590,7 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu // the model name to be the parameter - and i think it's a good differentiation in the code while we convert the others. Route::patch('/hardware/{asset}', [Api\AssetsController::class, 'update'])->name('api.assets.update'); Route::put('/hardware/{asset}', [Api\AssetsController::class, 'update'])->name('api.assets.put-update'); - - Route::put('/hardware/{asset}', [Api\AssetsController::class, 'update'])->name('api.assets.put-update'); - + Route::resource('hardware', Api\AssetsController::class, ['names' => [ @@ -841,6 +846,28 @@ Route::group(['prefix' => 'v1', 'middleware' => ['api', 'api-throttle:api']], fu ); // end asset models API routes + /** + * Asset notes API routes + */ + Route::group(['prefix' => 'notes'], function () { + + Route::post( + '{asset}/store', + [ + Api\NotesController::class, + 'store' + ] + )->name('api.notes.store'); + + Route::get( + '{asset}/index', + [ + Api\NotesController::class, + 'index' + ] + )->name('api.notes.index'); + } + ); // end asset notes API routes /** * Settings API routes diff --git a/routes/web.php b/routes/web.php index 695dbb3f45..f784b321a5 100644 --- a/routes/web.php +++ b/routes/web.php @@ -734,7 +734,7 @@ Route::group(['middleware' => 'web'], function () { 'destroy' ] )->name('ui.files.destroy') - ->where(['object_type' => 'assets|hardware|models|users|locations|accessories|consumables|licenses|components']); + ->where(['object_type' => 'assets|maintenances|hardware|models|users|locations|accessories|consumables|licenses|components']); }); diff --git a/sample_csvs/users-sample.csv b/sample_csvs/users-sample.csv index 8ee2359cbc..9ac76f8825 100644 --- a/sample_csvs/users-sample.csv +++ b/sample_csvs/users-sample.csv @@ -1,101 +1,101 @@ -First Name,Last Name,Email,Username,Activated,Location,Address,City,State,Country,Postal Code,Website,Phone,Job Title,Notes,Employee Number,Company,Manager,Remote,VIP,Start Date,End Date,Gravatar -Reagen,Tenant,rtenant0@istockphoto.com,rtenant0,true,"Braun, Ullrich and O'Hara",0406 Emmet Drive,,,,,https://netvibes.com,895-137-2034,Nurse Practicioner,ac tellus semper interdum mauris ullamcorper purus sit amet nulla quisque arcu libero rutrum,"",,Reagen Tenant,true,true,2022-03-18,2022-12-04,rtenant0@soup.io -Kenneth,Lefeuvre,klefeuvre1@woothemes.com,klefeuvre1,false,Mueller LLC,404 Dennis Alley,,,,,,,Senior Quality Engineer,lacus at turpis donec posuere metus vitae ipsum,"",,,true,,,, -Kiel,Eland,keland2@tinyurl.com,keland2,false,"Mayer, Jacobi and Gibson",3058 Declaration Park,,,,,,,Web Developer I,eu est congue elementum in hac habitasse platea dictumst morbi vestibulum velit id,"",,,true,,,, -Susana,Kinneally,skinneally3@purevolume.com,skinneally3,false,Block Inc,1 Chive Alley,,,,,,,Software Consultant,phasellus in felis donec semper sapien a libero nam dui proin leo odio porttitor id consequat,"",,,true,,,, -Wallis,Hadcock,whadcock4@abc.net.au,whadcock4,false,Roob-Bartoletti,496 Hazelcrest Terrace,,,,,,,Information Systems Manager,nam congue risus semper porta volutpat quam pede lobortis ligula sit amet eleifend,"","Hand, Rohan and Oberbrunner",,false,,,, -Audry,Piell,apiell5@china.com.cn,apiell5,false,Schoen-Hilpert,3136 Talmadge Circle,,,,,,,Chemical Engineer,congue risus semper porta volutpat quam pede lobortis ligula sit amet eleifend pede libero quis orci nullam,"",,,false,,,, -Veronike,Poytress,vpoytress6@scribd.com,vpoytress6,false,"D'Amore, Schoen and Rogahn",3 Northwestern Hill,,,,,http://acquirethisname.com,198-980-1723,Compensation Analyst,non mattis pulvinar nulla pede ullamcorper augue a suscipit nulla elit ac nulla sed vel enim sit amet,"",,Veronike Poytress,true,true,2022-05-10,2022-08-14,vpoytress6@ed.gov -Sibel,Serris,sserris7@mayoclinic.com,sserris7,true,Swaniawski and Sons,090 Summit Road,,,,,,,,,,,,false,,,, -Aldis,Smardon,asmardon8@ifeng.com,asmardon8,false,Huels-Reinger,2 Brown Trail,,,,,,,,,,,,true,,,, -Juan,,,jlowseley9,true,Nicolas and Sons,0 Village Pass,,,,,,,Cost Accountant,phasellus id sapien in sapien,"",,,true,,,, -Thaine,Coger,tcogera@naver.com,tcogera,false,Zieme-Davis,31 Little Fleur Park,,,,,,,,,,,,true,,,, -Adrien,Ciotti,aciottib@ucoz.ru,aciottib,true,"Ward, Wolff and King",61 Graedel Hill,,,,,,,,,,,,false,,,, -Harmony,Vanetti,hvanettic@wordpress.com,hvanettic,true,"Kulas, Heller and Cormier",35 Hintze Drive,,,,,,,,,,Wyman-Jenkins,,true,,,, -Pansie,Morston,pmorstond@ebay.com,pmorstond,false,Mosciski-Graham,73222 Walton Street,,,,,,,,,,,,false,,,, -Court,Halse,chalsee@walmart.com,chalsee,true,"O'Reilly, Hilll and Stokes",61514 Pepper Wood Trail,,,,,,,,,,,,false,,,, -Gerardo,Scrowby,gscrowbyf@multiply.com,gscrowbyf,false,Cruickshank-Kling,18314 Schlimgen Point,,,,,,,,,,,,false,,,, -Imojean,Veare,iveareg@chronoengine.com,iveareg,false,Schultz-Lakin,9 Blaine Street,,,,,https://soup.io,502-710-6094,Environmental Tech,consequat lectus in est risus auctor sed,"",,Imojean Veare,false,true,2022-01-24,2022-08-06,iveareg@answers.com -Samuel,Bickley,sbickleyh@gravatar.com,sbickleyh,true,Langworth-Friesen,5891 Bunker Hill Crossing,,,,,,,,,,Corkery and Sons,,false,,,, -Niall,Ethington,nethingtoni@google.fr,nethingtoni,true,"Ledner, Klocko and Sipes",511 Springs Parkway,,,,,,,,,,,,false,,,, -Elfreda,Ilyukhov,eilyukhovj@mashable.com,eilyukhovj,false,Spinka-Ortiz,475 Bluestem Point,,,,,,,Clinical Specialist,felis ut at dolor quis odio consequat varius integer ac,"",,,true,,,, -Serena,Josling,sjoslingk@oracle.com,sjoslingk,false,Wuckert-Schuster,10512 Fuller Avenue,,,,,,,,,,"Cruickshank, Ziemann and Kreiger",,false,,,, -Sheelah,Dockwray,sdockwrayl@narod.ru,sdockwrayl,true,Orn-Koss,4241 Scofield Circle,,,,,,,Nurse,vestibulum sed magna at nunc commodo placerat praesent blandit nam nulla integer pede,"",Hermann-Anderson,,true,,,, -Lanette,Remnant,lremnantm@vinaora.com,lremnantm,false,Abshire LLC,8 Buena Vista Junction,,,,,,,General Manager,mauris ullamcorper purus sit amet,"",Bahringer-Lockman,,false,,,, -Jordan,Pritty,jprittyn@reverbnation.com,jprittyn,false,Stroman LLC,36 Becker Plaza,,,,,,,,,,Durgan-Bosco,,true,,,, -Lorrin,Boni,lbonio@msn.com,lbonio,true,Bogisich-Nolan,7 Messerschmidt Point,,,,,,,,,,,,false,,,, -Marie-ann,Waind,mwaindp@ucoz.ru,mwaindp,true,"Hartmann, Weissnat and Cassin",68082 Schmedeman Court,,,,,,,Nurse,duis faucibus accumsan odio curabitur convallis duis consequat,"",,,true,,,, -Marti,Daens,mdaensq@huffingtonpost.com,mdaensq,false,Robel-Roob,7 Knutson Pass,,,,,http://gov.uk,381-382-8857,Electrical Engineer,sapien a libero nam dui proin leo,"",,Marti Daens,false,true,2021-12-19,2022-12-08,mdaensq@themeforest.net -Scotti,Gillison,sgillisonr@intel.com,sgillisonr,true,Howe-Collins,44 Elka Terrace,,,,,,,Financial Advisor,viverra eget congue eget semper rutrum nulla nunc purus,"",,,true,,,, -Bobbe,Alven,balvens@csmonitor.com,balvens,true,Weimann-Bernhard,71 Manley Park,,,,,,,,,,Champlin-Turcotte,,false,,,, -Ferdy,Kincade,fkincadet@wsj.com,fkincadet,true,Bode Inc,3023 Novick Alley,,,,,,,Statistician IV,amet nulla quisque arcu libero,"",,,true,,,, -Rachael,Briers,rbriersu@vimeo.com,rbriersu,false,Koch and Sons,71 Shoshone Court,,,,,,,,,,,,true,,,, -Ado,Bartholin,abartholinv@ft.com,abartholinv,false,"Buckridge, Klein and Johnston",11 Jenna Avenue,,,,,,,,,,,,false,,,, -Tessy,,,tsailerw,false,Parker-Beer,0964 Vidon Way,,,,,,,Structural Engineer,aliquet ultrices erat tortor sollicitudin,"",,,true,,,, -Chloe,Gebbie,cgebbiex@cam.ac.uk,cgebbiex,false,Smith Inc,8 5th Alley,,,,,,,,,,,,true,,,, -Emlyn,Cusick,ecusicky@homestead.com,ecusicky,true,Dickens LLC,43 Canary Point,,,,,,,Health Coach II,eu tincidunt in leo maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus vivamus in,"",,,true,,,, -Kenneth,McGuire,kmcguirez@scribd.com,kmcguirez,true,"Torphy, Bednar and Davis",2 Stone Corner Park,,,,,,,Nurse Practicioner,tortor duis mattis egestas metus aenean fermentum donec ut mauris eget massa,"",,,false,,,, -Berri,Forson,bforson10@pcworld.com,bforson10,true,"D'Amore, Larkin and O'Keefe",266 Alpine Road,,,,,,,Tax Accountant,in purus eu magna vulputate luctus cum sociis natoque penatibus et,"",,,true,,,, -Bree,Jiru,bjiru11@gravatar.com,bjiru11,true,Altenwerth LLC,58 4th Alley,,,,,,,,,,Farrell and Sons,,true,,,, -Kathie,Dignan,kdignan12@bbb.org,kdignan12,true,"Pagac, Effertz and Padberg",973 Banding Point,,,,,,,,,,"Marquardt, Cummings and Bosco",,true,,,, -Filbert,Van Der Straaten,fvanderstraaten13@sourceforge.net,fvanderstraaten13,false,"Cronin, Mante and Klein",0 Stuart Junction,,,,,,,Research Assistant I,ut massa volutpat convallis morbi odio odio elementum eu interdum eu tincidunt in leo maecenas,"",Bauch-Kling,,true,,,, -Miguel,Farbrace,mfarbrace14@barnesandnoble.com,mfarbrace14,false,O'Keefe Inc,1 Mallory Avenue,,,,,,,Assistant Manager,a libero nam dui proin leo odio porttitor id consequat in consequat ut nulla sed accumsan felis,"",Schmeler-Krajcik,,false,,,, -Em,,,ekittley15,false,Schuppe-Barrows,9946 Canary Pass,,,,,,,Nuclear Power Engineer,odio curabitur convallis duis consequat dui nec nisi,"","Abshire, Goyette and Spinka",,true,,,, -Bill,Morales,bmorales16@addtoany.com,bmorales16,true,Leannon Inc,0 Hudson Circle,,,,,,,,,,,,true,,,, -Spenser,Branca,sbranca17@tripod.com,sbranca17,false,Halvorson Inc,7904 Green Road,,,,,,,,,,,,false,,,, -Dawna,Ainslee,dainslee18@nifty.com,dainslee18,true,"Strosin, Collier and O'Connell",17 Granby Center,,,,,,,,,,,,false,,,, -Lind,Fontanet,lfontanet19@lycos.com,lfontanet19,false,Bins-Kunde,84 Kenwood Junction,,,,,,,,,,"Romaguera, Adams and Schoen",,false,,,, -Ashli,Gheorghie,agheorghie1a@blogtalkradio.com,agheorghie1a,false,Hauck Inc,8 Warrior Drive,,,,,,,,,,Wisozk Inc,,false,,,, -Janice,Freddi,jfreddi1b@behance.net,jfreddi1b,true,"Stoltenberg, Aufderhar and Schaden",0 Esch Alley,,,,,,,,,,,,false,,,, -Reinwald,Ivakhin,rivakhin1c@ask.com,rivakhin1c,false,Jacobson-Mosciski,24 New Castle Alley,,,,,,,,,,Welch and Sons,,true,,,, -Lindsey,Trevance,ltrevance1d@prnewswire.com,ltrevance1d,true,Hansen-Luettgen,17443 Lindbergh Plaza,,,,,,,Web Designer II,interdum eu tincidunt in leo maecenas pulvinar lobortis est phasellus,"",,,false,,,, -Cordi,Frostdyke,cfrostdyke1e@weather.com,cfrostdyke1e,false,Kohler Inc,53066 Merchant Plaza,,,,,,,,,,,,false,,,, -Jayme,Piatto,jpiatto1f@slate.com,jpiatto1f,true,Johnson and Sons,5598 Fuller Avenue,,,,,,,Graphic Designer,accumsan felis ut at dolor quis odio consequat varius integer,"",,,true,,,, -Henriette,Glanvill,hglanvill1g@ifeng.com,hglanvill1g,true,"Mills, Kautzer and Stiedemann",6461 Stang Center,,,,,,,,,,Gibson and Sons,,true,,,, -Izak,Legen,ilegen1h@berkeley.edu,ilegen1h,true,"Schiller, Runolfsson and Gottlieb",86874 Hovde Avenue,,,,,,,,,,,,false,,,, -Silas,Vallentin,svallentin1i@zdnet.com,svallentin1i,false,Wolff Inc,15041 Graceland Park,,,,,,,,,,,,true,,,, -Ansel,Augustus,aaugustus1j@oaic.gov.au,aaugustus1j,true,"Rippin, Frami and Parker",843 Nova Alley,,,,,,,Assistant Media Planner,ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae donec,"",Morissette and Sons,,false,,,, -Annemarie,Reburn,areburn1k@networksolutions.com,areburn1k,true,Dach Group,05 Crowley Avenue,,,,,,,Administrative Assistant IV,vivamus tortor duis mattis egestas metus aenean fermentum donec,"","Murazik, Wyman and Yost",,false,,,, -Fee,Bissell,fbissell1l@comsenz.com,fbissell1l,true,Braun Group,678 Nelson Hill,,,,,,,Health Coach IV,sed augue aliquam erat volutpat in congue etiam justo etiam pretium iaculis justo in,"","Lindgren, Quitzon and Heathcote",,true,,,, -Zenia,Kordt,zkordt1m@com.com,zkordt1m,true,"Harvey, Fay and Yundt",6337 Mayer Trail,,,,,,,Associate Professor,congue etiam justo etiam pretium iaculis justo in hac habitasse platea dictumst etiam faucibus cursus urna,"",,,true,,,, -Winthrop,Eales,weales1n@stanford.edu,weales1n,true,Johns-Kshlerin,79780 Helena Lane,,,,,,,Accountant I,platea dictumst etiam faucibus cursus urna ut,"",,,false,,,, -Davis,,,dnatalie1o,false,Tillman-Marquardt,3893 Express Junction,,,,,https://answers.com,266-409-9118,Teacher,suspendisse accumsan tortor quis turpis sed ante vivamus tortor,"",Casper-Grimes,Davis Natalie,false,false,2022-04-08,2022-09-24,dnatalie1o@altervista.org -Massimiliano,Fardo,mfardo1p@imgur.com,mfardo1p,true,Kozey Group,72 Hauk Terrace,,,,,,,Account Coordinator,parturient montes nascetur ridiculus mus etiam vel augue vestibulum rutrum rutrum neque aenean auctor gravida sem praesent id,"",Bednar Inc,,false,,,, -Dacey,Larrie,dlarrie1q@digg.com,dlarrie1q,false,Jerde-Ullrich,70371 Del Mar Center,,,,,,,,,,,,true,,,, -Pattie,Melvin,pmelvin1r@discovery.com,pmelvin1r,false,"McDermott, Mayert and Kemmer",845 Anderson Point,,,,,,,Safety Technician II,sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin,"",,,true,,,, -Franny,Laughlin,flaughlin1s@blogspot.com,flaughlin1s,false,Renner-Terry,94 Northfield Pass,,,,,,,,,,"Parisian, Hudson and Bahringer",,false,,,, -Mariel,Roelvink,mroelvink1t@timesonline.co.uk,mroelvink1t,true,Russel-Blanda,434 Crest Line Road,,,,,http://amazon.de,429-401-0847,Quality Engineer,vel pede morbi porttitor lorem id ligula suspendisse ornare consequat lectus in est risus auctor sed tristique in tempus,"",,Mariel Roelvink,true,false,2022-02-21,2022-09-01,mroelvink1t@feedburner.com -Josee,Ghirardi,jghirardi1u@arizona.edu,jghirardi1u,true,Koss-Schmitt,96 Kingsford Avenue,,,,,,,,,,,,true,,,, -Felix,Pheasant,fpheasant1v@soundcloud.com,fpheasant1v,true,Rogahn Group,43 Northridge Place,,,,,,,,,,Hoppe-O'Reilly,,false,,,, -Stearne,Gwatkins,sgwatkins1w@jugem.jp,sgwatkins1w,false,"Koch, Ferry and Marks",6 Victoria Circle,,,,,,,,,,,,false,,,, -Nathaniel,Parkinson,nparkinson1x@springer.com,nparkinson1x,true,Harber Group,4589 Clarendon Way,,,,,,,Software Consultant,non mattis pulvinar nulla pede ullamcorper augue a suscipit nulla elit ac nulla sed vel enim sit amet nunc viverra,"",Koepp LLC,,true,,,, -Blondelle,Crawley,bcrawley1y@ezinearticles.com,bcrawley1y,true,"Hirthe, Bashirian and Feeney",17149 Ridge Oak Park,,,,,,,Help Desk Technician,sit amet cursus id turpis integer aliquet massa id lobortis convallis tortor risus dapibus augue vel accumsan tellus nisi eu,"",,,true,,,, -Pammi,Yair,pyair1z@virginia.edu,pyair1z,true,"Pfeffer, Schmeler and Dibbert",541 Beilfuss Alley,,,,,,,,,,,,true,,,, -Tremain,Lattimer,tlattimer20@go.com,tlattimer20,true,"Kuvalis, Kris and Howell",19 Red Cloud Parkway,,,,,,,,,,Gutkowski LLC,,true,,,, -Moreen,Fermin,mfermin21@w3.org,mfermin21,false,"Romaguera, Spinka and Bayer",50 Eagle Crest Circle,,,,,,,,,,,,true,,,, -Jena,Taborre,jtaborre22@pinterest.com,jtaborre22,true,Raynor Group,97 Helena Center,,,,,,,Dental Hygienist,vel enim sit amet nunc viverra dapibus nulla suscipit ligula in lacus curabitur at ipsum ac tellus semper interdum mauris,"",,,false,,,, -Odille,Stede,ostede23@biglobe.ne.jp,ostede23,true,"Boyle, Schowalter and Mayer",88993 Sunbrook Street,,,,,http://live.com,464-815-6024,,,,,Odille Stede,true,false,2021-12-12,2022-06-27,ostede23@lycos.com -Kori,Fulk,kfulk24@tiny.cc,kfulk24,true,Konopelski and Sons,43 Mockingbird Avenue,,,,,,,,,,"Nikolaus, Cassin and Streich",,true,,,, -Pollyanna,Cardon,pcardon25@infoseek.co.jp,pcardon25,false,Hickle Group,52088 Almo Junction,,,,,,,,,,"Cronin, Cummerata and Tromp",,false,,,, -Austin,McGeneay,amcgeneay26@tmall.com,amcgeneay26,true,Yundt-Howell,021 4th Park,,,,,,,Social Worker,est phasellus sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin eu mi nulla,"",,,true,,,, -Imogen,Hamill,ihamill27@w3.org,ihamill27,false,Herman-Schulist,802 Sunbrook Place,,,,,http://vistaprint.com,344-665-1217,Registered Nurse,curabitur convallis duis consequat dui nec nisi volutpat,"",,Imogen Hamill,false,false,2021-12-03,2023-04-16,ihamill27@over-blog.com -Hershel,Bielfeld,hbielfeld28@soup.io,hbielfeld28,true,Kreiger and Sons,6944 Buell Trail,,,,,,,Actuary,curae donec pharetra magna vestibulum aliquet ultrices erat,"",Schmitt-Abbott,,true,,,, -Korry,,,ksteckings29,true,Bogan Inc,800 Ilene Parkway,,,,,,,,,,,,true,,,, -Cookie,Warret,cwarret2a@sakura.ne.jp,cwarret2a,false,Murphy-Yost,9 Vera Terrace,,,,,,,Mechanical Systems Engineer,semper rutrum nulla nunc purus phasellus in felis donec semper sapien a libero nam dui proin leo odio,"","Lueilwitz, Beahan and Raynor",,false,,,, -Wynne,Gonnely,wgonnely2b@facebook.com,wgonnely2b,true,"Frami, Erdman and Mayert",051 Kenwood Junction,,,,,,,,,,,,true,,,, -Ethelred,Bogey,ebogey2c@infoseek.co.jp,ebogey2c,true,Christiansen and Sons,7414 2nd Pass,,,,,,,Media Manager II,donec odio justo sollicitudin ut suscipit a feugiat et eros vestibulum ac est lacinia,"",,,false,,,, -Alvera,Tunuy,atunuy2d@bizjournals.com,atunuy2d,false,"Vandervort, Veum and Walker",152 Division Park,,,,,,,,,,"Bartell, Hartmann and Jerde",,false,,,, -Martino,Rosenbusch,mrosenbusch2e@seesaa.net,mrosenbusch2e,true,Parisian-Romaguera,130 Westridge Alley,,,,,http://bravesites.com,626-888-4072,,,,"Keebler, Walter and Senger",Martino Rosenbusch,false,false,2022-01-20,2022-09-11,mrosenbusch2e@about.me -Susi,Trapp,strapp2f@ft.com,strapp2f,false,"Rogahn, Volkman and McDermott",72958 Vahlen Avenue,,,,,,,,,,Nitzsche-Langosh,,true,,,, -Gordon,Alflatt,galflatt2g@marriott.com,galflatt2g,false,Effertz-Howell,0681 International Plaza,,,,,,,Research Associate,duis aliquam convallis nunc proin,"","Farrell, Hoeger and O'Keefe",,true,,,, -Derrick,Braidon,dbraidon2h@blogs.com,dbraidon2h,false,Prosacco-Walker,8760 Del Sol Circle,,,,,,,,,,Koss-Bogisich,,true,,,, -Minnnie,Bonar,mbonar2i@biglobe.ne.jp,mbonar2i,true,Daniel LLC,5424 Karstens Alley,,,,,,,Web Designer III,faucibus orci luctus et ultrices posuere cubilia curae mauris,"",,,true,,,, -Casper,Sinnatt,csinnatt2j@hc360.com,csinnatt2j,true,Barrows-Mertz,79 Melvin Center,,,,,,,,,,,,false,,,, -Chloe,Fist,cfist2k@auda.org.au,cfist2k,false,"Kling, Streich and Kertzmann",47064 Glacier Hill Court,,,,,,,,,,Altenwerth-Leuschke,,true,,,, -Elysha,Gosenell,egosenell2l@ft.com,egosenell2l,true,Hirthe LLC,70 Old Gate Alley,,,,,,,Nuclear Power Engineer,amet cursus id turpis integer aliquet massa id lobortis convallis tortor risus dapibus augue vel accumsan tellus,"",Macejkovic and Sons,,false,,,, -Gerianna,Feirn,gfeirn2m@bing.com,gfeirn2m,true,"Collier, Kirlin and Armstrong",881 Summer Ridge Circle,,,,,,,,,,,,false,,,, -Lucas,Mulvany,lmulvany2n@deliciousdays.com,lmulvany2n,false,Bahringer Group,639 La Follette Circle,,,,,,,,,,,,true,,,, -Lenore,Menendez,lmenendez2o@cdbaby.com,lmenendez2o,true,"Nader, Harvey and Casper",02 Springs Avenue,,,,,https://a8.net,926-526-1742,Community Outreach Specialist,ut odio cras mi pede malesuada in imperdiet et commodo vulputate justo in blandit ultrices enim lorem ipsum dolor,"",,Lenore Menendez,true,false,2022-01-11,2022-07-29,lmenendez2o@ifeng.com -Collete,Brandes,cbrandes2p@accuweather.com,cbrandes2p,true,Koepp-Parisian,5 Haas Way,,,,,,,,,,,,false,,,, -Osborne,Gummory,ogummory2q@1und1.de,ogummory2q,false,Mertz and Sons,91749 Haas Alley,,,,,,,,,,,,true,,,, -Emiline,Grossman,egrossman2r@dmoz.org,egrossman2r,true,Parisian and Sons,3872 Eagle Crest Court,,,,,https://uiuc.edu,338-830-8647,Food Chemist,dolor vel est donec odio justo sollicitudin ut suscipit a feugiat et eros vestibulum ac est lacinia nisi venenatis,"",Williamson-Casper,Emiline Grossman,true,true,2021-11-10,2022-10-01,egrossman2r@spiegel.de +First Name,Last Name,Email,Username,Display Name,Activated,Location,Address,City,State,Country,Postal Code,Website,Phone,Job Title,Notes,Employee Number,Company,Manager,Remote,VIP,Start Date,End Date,Gravatar +Reagen,Tenant,rtenant0@istockphoto.com,rtenant0,Heywood,TRUE,"Braun, Ullrich and O'Hara",0406 Emmet Drive,,,,,https://netvibes.com,895-137-2034,Nurse Practicioner,ac tellus semper interdum mauris ullamcorper purus sit amet nulla quisque arcu libero rutrum,,,Reagen Tenant,TRUE,TRUE,2022-03-18,2022-12-04,rtenant0@soup.io +Kenneth,Lefeuvre,klefeuvre1@woothemes.com,klefeuvre1,,FALSE,Mueller LLC,404 Dennis Alley,,,,,,,Senior Quality Engineer,lacus at turpis donec posuere metus vitae ipsum,,,,TRUE,,,, +Kiel,Eland,keland2@tinyurl.com,keland2,,FALSE,"Mayer, Jacobi and Gibson",3058 Declaration Park,,,,,,,Web Developer I,eu est congue elementum in hac habitasse platea dictumst morbi vestibulum velit id,,,,TRUE,,,, +Susana,Kinneally,skinneally3@purevolume.com,skinneally3,George,FALSE,Block Inc,1 Chive Alley,,,,,,,Software Consultant,phasellus in felis donec semper sapien a libero nam dui proin leo odio porttitor id consequat,,,,TRUE,,,, +Wallis,Hadcock,whadcock4@abc.net.au,whadcock4,,FALSE,Roob-Bartoletti,496 Hazelcrest Terrace,,,,,,,Information Systems Manager,nam congue risus semper porta volutpat quam pede lobortis ligula sit amet eleifend,,"Hand, Rohan and Oberbrunner",,FALSE,,,, +Audry,Piell,apiell5@china.com.cn,apiell5,,FALSE,Schoen-Hilpert,3136 Talmadge Circle,,,,,,,Chemical Engineer,congue risus semper porta volutpat quam pede lobortis ligula sit amet eleifend pede libero quis orci nullam,,,,FALSE,,,, +Veronike,Poytress,vpoytress6@scribd.com,vpoytress6,Paul,FALSE,"D'Amore, Schoen and Rogahn",3 Northwestern Hill,,,,,http://acquirethisname.com,198-980-1723,Compensation Analyst,non mattis pulvinar nulla pede ullamcorper augue a suscipit nulla elit ac nulla sed vel enim sit amet,,,Veronike Poytress,TRUE,TRUE,2022-05-10,2022-08-14,vpoytress6@ed.gov +Sibel,Serris,sserris7@mayoclinic.com,sserris7,,TRUE,Swaniawski and Sons,090 Summit Road,,,,,,,,,,,,FALSE,,,, +Aldis,Smardon,asmardon8@ifeng.com,asmardon8,,FALSE,Huels-Reinger,2 Brown Trail,,,,,,,,,,,,TRUE,,,, +Juan,,,jlowseley9,Awesomesauce,TRUE,Nicolas and Sons,0 Village Pass,,,,,,,Cost Accountant,phasellus id sapien in sapien,,,,TRUE,,,, +Thaine,Coger,tcogera@naver.com,tcogera,,FALSE,Zieme-Davis,31 Little Fleur Park,,,,,,,,,,,,TRUE,,,, +Adrien,Ciotti,aciottib@ucoz.ru,aciottib,,TRUE,"Ward, Wolff and King",61 Graedel Hill,,,,,,,,,,,,FALSE,,,, +Harmony,Vanetti,hvanettic@wordpress.com,hvanettic,,TRUE,"Kulas, Heller and Cormier",35 Hintze Drive,,,,,,,,,,Wyman-Jenkins,,TRUE,,,, +Pansie,Morston,pmorstond@ebay.com,pmorstond,,FALSE,Mosciski-Graham,73222 Walton Street,,,,,,,,,,,,FALSE,,,, +Court,Halse,chalsee@walmart.com,chalsee,Test,TRUE,"O'Reilly, Hilll and Stokes",61514 Pepper Wood Trail,,,,,,,,,,,,FALSE,,,, +Gerardo,Scrowby,gscrowbyf@multiply.com,gscrowbyf,,FALSE,Cruickshank-Kling,18314 Schlimgen Point,,,,,,,,,,,,FALSE,,,, +Imojean,Veare,iveareg@chronoengine.com,iveareg,Testtest,FALSE,Schultz-Lakin,9 Blaine Street,,,,,https://soup.io,502-710-6094,Environmental Tech,consequat lectus in est risus auctor sed,,,Imojean Veare,FALSE,TRUE,2022-01-24,2022-08-06,iveareg@answers.com +Samuel,Bickley,sbickleyh@gravatar.com,sbickleyh,,TRUE,Langworth-Friesen,5891 Bunker Hill Crossing,,,,,,,,,,Corkery and Sons,,FALSE,,,, +Niall,Ethington,nethingtoni@google.fr,nethingtoni,,TRUE,"Ledner, Klocko and Sipes",511 Springs Parkway,,,,,,,,,,,,FALSE,,,, +Elfreda,Ilyukhov,eilyukhovj@mashable.com,eilyukhovj,,FALSE,Spinka-Ortiz,475 Bluestem Point,,,,,,,Clinical Specialist,felis ut at dolor quis odio consequat varius integer ac,,,,TRUE,,,, +Serena,Josling,sjoslingk@oracle.com,sjoslingk,,FALSE,Wuckert-Schuster,10512 Fuller Avenue,,,,,,,,,,"Cruickshank, Ziemann and Kreiger",,FALSE,,,, +Sheelah,Dockwray,sdockwrayl@narod.ru,sdockwrayl,,TRUE,Orn-Koss,4241 Scofield Circle,,,,,,,Nurse,vestibulum sed magna at nunc commodo placerat praesent blandit nam nulla integer pede,,Hermann-Anderson,,TRUE,,,, +Lanette,Remnant,lremnantm@vinaora.com,lremnantm,,FALSE,Abshire LLC,8 Buena Vista Junction,,,,,,,General Manager,mauris ullamcorper purus sit amet,,Bahringer-Lockman,,FALSE,,,, +Jordan,Pritty,jprittyn@reverbnation.com,jprittyn,,FALSE,Stroman LLC,36 Becker Plaza,,,,,,,,,,Durgan-Bosco,,TRUE,,,, +Lorrin,Boni,lbonio@msn.com,lbonio,,TRUE,Bogisich-Nolan,7 Messerschmidt Point,,,,,,,,,,,,FALSE,,,, +Marie-ann,Waind,mwaindp@ucoz.ru,mwaindp,,TRUE,"Hartmann, Weissnat and Cassin",68082 Schmedeman Court,,,,,,,Nurse,duis faucibus accumsan odio curabitur convallis duis consequat,,,,TRUE,,,, +Marti,Daens,mdaensq@huffingtonpost.com,mdaensq,,FALSE,Robel-Roob,7 Knutson Pass,,,,,http://gov.uk,381-382-8857,Electrical Engineer,sapien a libero nam dui proin leo,,,Marti Daens,FALSE,TRUE,2021-12-19,2022-12-08,mdaensq@themeforest.net +Scotti,Gillison,sgillisonr@intel.com,sgillisonr,,TRUE,Howe-Collins,44 Elka Terrace,,,,,,,Financial Advisor,viverra eget congue eget semper rutrum nulla nunc purus,,,,TRUE,,,, +Bobbe,Alven,balvens@csmonitor.com,balvens,,TRUE,Weimann-Bernhard,71 Manley Park,,,,,,,,,,Champlin-Turcotte,,FALSE,,,, +Ferdy,Kincade,fkincadet@wsj.com,fkincadet,,TRUE,Bode Inc,3023 Novick Alley,,,,,,,Statistician IV,amet nulla quisque arcu libero,,,,TRUE,,,, +Rachael,Briers,rbriersu@vimeo.com,rbriersu,,FALSE,Koch and Sons,71 Shoshone Court,,,,,,,,,,,,TRUE,,,, +Ado,Bartholin,abartholinv@ft.com,abartholinv,,FALSE,"Buckridge, Klein and Johnston",11 Jenna Avenue,,,,,,,,,,,,FALSE,,,, +Tessy,,,tsailerw,,FALSE,Parker-Beer,0964 Vidon Way,,,,,,,Structural Engineer,aliquet ultrices erat tortor sollicitudin,,,,TRUE,,,, +Chloe,Gebbie,cgebbiex@cam.ac.uk,cgebbiex,,FALSE,Smith Inc,8 5th Alley,,,,,,,,,,,,TRUE,,,, +Emlyn,Cusick,ecusicky@homestead.com,ecusicky,,TRUE,Dickens LLC,43 Canary Point,,,,,,,Health Coach II,eu tincidunt in leo maecenas pulvinar lobortis est phasellus sit amet erat nulla tempus vivamus in,,,,TRUE,,,, +Kenneth,McGuire,kmcguirez@scribd.com,kmcguirez,,TRUE,"Torphy, Bednar and Davis",2 Stone Corner Park,,,,,,,Nurse Practicioner,tortor duis mattis egestas metus aenean fermentum donec ut mauris eget massa,,,,FALSE,,,, +Berri,Forson,bforson10@pcworld.com,bforson10,,TRUE,"D'Amore, Larkin and O'Keefe",266 Alpine Road,,,,,,,Tax Accountant,in purus eu magna vulputate luctus cum sociis natoque penatibus et,,,,TRUE,,,, +Bree,Jiru,bjiru11@gravatar.com,bjiru11,,TRUE,Altenwerth LLC,58 4th Alley,,,,,,,,,,Farrell and Sons,,TRUE,,,, +Kathie,Dignan,kdignan12@bbb.org,kdignan12,,TRUE,"Pagac, Effertz and Padberg",973 Banding Point,,,,,,,,,,"Marquardt, Cummings and Bosco",,TRUE,,,, +Filbert,Van Der Straaten,fvanderstraaten13@sourceforge.net,fvanderstraaten13,,FALSE,"Cronin, Mante and Klein",0 Stuart Junction,,,,,,,Research Assistant I,ut massa volutpat convallis morbi odio odio elementum eu interdum eu tincidunt in leo maecenas,,Bauch-Kling,,TRUE,,,, +Miguel,Farbrace,mfarbrace14@barnesandnoble.com,mfarbrace14,,FALSE,O'Keefe Inc,1 Mallory Avenue,,,,,,,Assistant Manager,a libero nam dui proin leo odio porttitor id consequat in consequat ut nulla sed accumsan felis,,Schmeler-Krajcik,,FALSE,,,, +Em,,,ekittley15,,FALSE,Schuppe-Barrows,9946 Canary Pass,,,,,,,Nuclear Power Engineer,odio curabitur convallis duis consequat dui nec nisi,,"Abshire, Goyette and Spinka",,TRUE,,,, +Bill,Morales,bmorales16@addtoany.com,bmorales16,,TRUE,Leannon Inc,0 Hudson Circle,,,,,,,,,,,,TRUE,,,, +Spenser,Branca,sbranca17@tripod.com,sbranca17,,FALSE,Halvorson Inc,7904 Green Road,,,,,,,,,,,,FALSE,,,, +Dawna,Ainslee,dainslee18@nifty.com,dainslee18,,TRUE,"Strosin, Collier and O'Connell",17 Granby Center,,,,,,,,,,,,FALSE,,,, +Lind,Fontanet,lfontanet19@lycos.com,lfontanet19,,FALSE,Bins-Kunde,84 Kenwood Junction,,,,,,,,,,"Romaguera, Adams and Schoen",,FALSE,,,, +Ashli,Gheorghie,agheorghie1a@blogtalkradio.com,agheorghie1a,,FALSE,Hauck Inc,8 Warrior Drive,,,,,,,,,,Wisozk Inc,,FALSE,,,, +Janice,Freddi,jfreddi1b@behance.net,jfreddi1b,,TRUE,"Stoltenberg, Aufderhar and Schaden",0 Esch Alley,,,,,,,,,,,,FALSE,,,, +Reinwald,Ivakhin,rivakhin1c@ask.com,rivakhin1c,,FALSE,Jacobson-Mosciski,24 New Castle Alley,,,,,,,,,,Welch and Sons,,TRUE,,,, +Lindsey,Trevance,ltrevance1d@prnewswire.com,ltrevance1d,,TRUE,Hansen-Luettgen,17443 Lindbergh Plaza,,,,,,,Web Designer II,interdum eu tincidunt in leo maecenas pulvinar lobortis est phasellus,,,,FALSE,,,, +Cordi,Frostdyke,cfrostdyke1e@weather.com,cfrostdyke1e,,FALSE,Kohler Inc,53066 Merchant Plaza,,,,,,,,,,,,FALSE,,,, +Jayme,Piatto,jpiatto1f@slate.com,jpiatto1f,,TRUE,Johnson and Sons,5598 Fuller Avenue,,,,,,,Graphic Designer,accumsan felis ut at dolor quis odio consequat varius integer,,,,TRUE,,,, +Henriette,Glanvill,hglanvill1g@ifeng.com,hglanvill1g,,TRUE,"Mills, Kautzer and Stiedemann",6461 Stang Center,,,,,,,,,,Gibson and Sons,,TRUE,,,, +Izak,Legen,ilegen1h@berkeley.edu,ilegen1h,,TRUE,"Schiller, Runolfsson and Gottlieb",86874 Hovde Avenue,,,,,,,,,,,,FALSE,,,, +Silas,Vallentin,svallentin1i@zdnet.com,svallentin1i,,FALSE,Wolff Inc,15041 Graceland Park,,,,,,,,,,,,TRUE,,,, +Ansel,Augustus,aaugustus1j@oaic.gov.au,aaugustus1j,,TRUE,"Rippin, Frami and Parker",843 Nova Alley,,,,,,,Assistant Media Planner,ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae donec,,Morissette and Sons,,FALSE,,,, +Annemarie,Reburn,areburn1k@networksolutions.com,areburn1k,,TRUE,Dach Group,05 Crowley Avenue,,,,,,,Administrative Assistant IV,vivamus tortor duis mattis egestas metus aenean fermentum donec,,"Murazik, Wyman and Yost",,FALSE,,,, +Fee,Bissell,fbissell1l@comsenz.com,fbissell1l,,TRUE,Braun Group,678 Nelson Hill,,,,,,,Health Coach IV,sed augue aliquam erat volutpat in congue etiam justo etiam pretium iaculis justo in,,"Lindgren, Quitzon and Heathcote",,TRUE,,,, +Zenia,Kordt,zkordt1m@com.com,zkordt1m,,TRUE,"Harvey, Fay and Yundt",6337 Mayer Trail,,,,,,,Associate Professor,congue etiam justo etiam pretium iaculis justo in hac habitasse platea dictumst etiam faucibus cursus urna,,,,TRUE,,,, +Winthrop,Eales,weales1n@stanford.edu,weales1n,,TRUE,Johns-Kshlerin,79780 Helena Lane,,,,,,,Accountant I,platea dictumst etiam faucibus cursus urna ut,,,,FALSE,,,, +Davis,,,dnatalie1o,,FALSE,Tillman-Marquardt,3893 Express Junction,,,,,https://answers.com,266-409-9118,Teacher,suspendisse accumsan tortor quis turpis sed ante vivamus tortor,,Casper-Grimes,Davis Natalie,FALSE,FALSE,2022-04-08,2022-09-24,dnatalie1o@altervista.org +Massimiliano,Fardo,mfardo1p@imgur.com,mfardo1p,,TRUE,Kozey Group,72 Hauk Terrace,,,,,,,Account Coordinator,parturient montes nascetur ridiculus mus etiam vel augue vestibulum rutrum rutrum neque aenean auctor gravida sem praesent id,,Bednar Inc,,FALSE,,,, +Dacey,Larrie,dlarrie1q@digg.com,dlarrie1q,,FALSE,Jerde-Ullrich,70371 Del Mar Center,,,,,,,,,,,,TRUE,,,, +Pattie,Melvin,pmelvin1r@discovery.com,pmelvin1r,,FALSE,"McDermott, Mayert and Kemmer",845 Anderson Point,,,,,,,Safety Technician II,sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin,,,,TRUE,,,, +Franny,Laughlin,flaughlin1s@blogspot.com,flaughlin1s,,FALSE,Renner-Terry,94 Northfield Pass,,,,,,,,,,"Parisian, Hudson and Bahringer",,FALSE,,,, +Mariel,Roelvink,mroelvink1t@timesonline.co.uk,mroelvink1t,,TRUE,Russel-Blanda,434 Crest Line Road,,,,,http://amazon.de,429-401-0847,Quality Engineer,vel pede morbi porttitor lorem id ligula suspendisse ornare consequat lectus in est risus auctor sed tristique in tempus,,,Mariel Roelvink,TRUE,FALSE,2022-02-21,2022-09-01,mroelvink1t@feedburner.com +Josee,Ghirardi,jghirardi1u@arizona.edu,jghirardi1u,,TRUE,Koss-Schmitt,96 Kingsford Avenue,,,,,,,,,,,,TRUE,,,, +Felix,Pheasant,fpheasant1v@soundcloud.com,fpheasant1v,,TRUE,Rogahn Group,43 Northridge Place,,,,,,,,,,Hoppe-O'Reilly,,FALSE,,,, +Stearne,Gwatkins,sgwatkins1w@jugem.jp,sgwatkins1w,,FALSE,"Koch, Ferry and Marks",6 Victoria Circle,,,,,,,,,,,,FALSE,,,, +Nathaniel,Parkinson,nparkinson1x@springer.com,nparkinson1x,,TRUE,Harber Group,4589 Clarendon Way,,,,,,,Software Consultant,non mattis pulvinar nulla pede ullamcorper augue a suscipit nulla elit ac nulla sed vel enim sit amet nunc viverra,,Koepp LLC,,TRUE,,,, +Blondelle,Crawley,bcrawley1y@ezinearticles.com,bcrawley1y,,TRUE,"Hirthe, Bashirian and Feeney",17149 Ridge Oak Park,,,,,,,Help Desk Technician,sit amet cursus id turpis integer aliquet massa id lobortis convallis tortor risus dapibus augue vel accumsan tellus nisi eu,,,,TRUE,,,, +Pammi,Yair,pyair1z@virginia.edu,pyair1z,,TRUE,"Pfeffer, Schmeler and Dibbert",541 Beilfuss Alley,,,,,,,,,,,,TRUE,,,, +Tremain,Lattimer,tlattimer20@go.com,tlattimer20,,TRUE,"Kuvalis, Kris and Howell",19 Red Cloud Parkway,,,,,,,,,,Gutkowski LLC,,TRUE,,,, +Moreen,Fermin,mfermin21@w3.org,mfermin21,,FALSE,"Romaguera, Spinka and Bayer",50 Eagle Crest Circle,,,,,,,,,,,,TRUE,,,, +Jena,Taborre,jtaborre22@pinterest.com,jtaborre22,,TRUE,Raynor Group,97 Helena Center,,,,,,,Dental Hygienist,vel enim sit amet nunc viverra dapibus nulla suscipit ligula in lacus curabitur at ipsum ac tellus semper interdum mauris,,,,FALSE,,,, +Odille,Stede,ostede23@biglobe.ne.jp,ostede23,,TRUE,"Boyle, Schowalter and Mayer",88993 Sunbrook Street,,,,,http://live.com,464-815-6024,,,,,Odille Stede,TRUE,FALSE,2021-12-12,2022-06-27,ostede23@lycos.com +Kori,Fulk,kfulk24@tiny.cc,kfulk24,,TRUE,Konopelski and Sons,43 Mockingbird Avenue,,,,,,,,,,"Nikolaus, Cassin and Streich",,TRUE,,,, +Pollyanna,Cardon,pcardon25@infoseek.co.jp,pcardon25,,FALSE,Hickle Group,52088 Almo Junction,,,,,,,,,,"Cronin, Cummerata and Tromp",,FALSE,,,, +Austin,McGeneay,amcgeneay26@tmall.com,amcgeneay26,,TRUE,Yundt-Howell,021 4th Park,,,,,,,Social Worker,est phasellus sit amet erat nulla tempus vivamus in felis eu sapien cursus vestibulum proin eu mi nulla,,,,TRUE,,,, +Imogen,Hamill,ihamill27@w3.org,ihamill27,,FALSE,Herman-Schulist,802 Sunbrook Place,,,,,http://vistaprint.com,344-665-1217,Registered Nurse,curabitur convallis duis consequat dui nec nisi volutpat,,,Imogen Hamill,FALSE,FALSE,2021-12-03,2023-04-16,ihamill27@over-blog.com +Hershel,Bielfeld,hbielfeld28@soup.io,hbielfeld28,,TRUE,Kreiger and Sons,6944 Buell Trail,,,,,,,Actuary,curae donec pharetra magna vestibulum aliquet ultrices erat,,Schmitt-Abbott,,TRUE,,,, +Korry,,,ksteckings29,,TRUE,Bogan Inc,800 Ilene Parkway,,,,,,,,,,,,TRUE,,,, +Cookie,Warret,cwarret2a@sakura.ne.jp,cwarret2a,,FALSE,Murphy-Yost,9 Vera Terrace,,,,,,,Mechanical Systems Engineer,semper rutrum nulla nunc purus phasellus in felis donec semper sapien a libero nam dui proin leo odio,,"Lueilwitz, Beahan and Raynor",,FALSE,,,, +Wynne,Gonnely,wgonnely2b@facebook.com,wgonnely2b,,TRUE,"Frami, Erdman and Mayert",051 Kenwood Junction,,,,,,,,,,,,TRUE,,,, +Ethelred,Bogey,ebogey2c@infoseek.co.jp,ebogey2c,,TRUE,Christiansen and Sons,7414 2nd Pass,,,,,,,Media Manager II,donec odio justo sollicitudin ut suscipit a feugiat et eros vestibulum ac est lacinia,,,,FALSE,,,, +Alvera,Tunuy,atunuy2d@bizjournals.com,atunuy2d,,FALSE,"Vandervort, Veum and Walker",152 Division Park,,,,,,,,,,"Bartell, Hartmann and Jerde",,FALSE,,,, +Martino,Rosenbusch,mrosenbusch2e@seesaa.net,mrosenbusch2e,,TRUE,Parisian-Romaguera,130 Westridge Alley,,,,,http://bravesites.com,626-888-4072,,,,"Keebler, Walter and Senger",Martino Rosenbusch,FALSE,FALSE,2022-01-20,2022-09-11,mrosenbusch2e@about.me +Susi,Trapp,strapp2f@ft.com,strapp2f,,FALSE,"Rogahn, Volkman and McDermott",72958 Vahlen Avenue,,,,,,,,,,Nitzsche-Langosh,,TRUE,,,, +Gordon,Alflatt,galflatt2g@marriott.com,galflatt2g,,FALSE,Effertz-Howell,0681 International Plaza,,,,,,,Research Associate,duis aliquam convallis nunc proin,,"Farrell, Hoeger and O'Keefe",,TRUE,,,, +Derrick,Braidon,dbraidon2h@blogs.com,dbraidon2h,,FALSE,Prosacco-Walker,8760 Del Sol Circle,,,,,,,,,,Koss-Bogisich,,TRUE,,,, +Minnnie,Bonar,mbonar2i@biglobe.ne.jp,mbonar2i,,TRUE,Daniel LLC,5424 Karstens Alley,,,,,,,Web Designer III,faucibus orci luctus et ultrices posuere cubilia curae mauris,,,,TRUE,,,, +Casper,Sinnatt,csinnatt2j@hc360.com,csinnatt2j,,TRUE,Barrows-Mertz,79 Melvin Center,,,,,,,,,,,,FALSE,,,, +Chloe,Fist,cfist2k@auda.org.au,cfist2k,,FALSE,"Kling, Streich and Kertzmann",47064 Glacier Hill Court,,,,,,,,,,Altenwerth-Leuschke,,TRUE,,,, +Elysha,Gosenell,egosenell2l@ft.com,egosenell2l,,TRUE,Hirthe LLC,70 Old Gate Alley,,,,,,,Nuclear Power Engineer,amet cursus id turpis integer aliquet massa id lobortis convallis tortor risus dapibus augue vel accumsan tellus,,Macejkovic and Sons,,FALSE,,,, +Gerianna,Feirn,gfeirn2m@bing.com,gfeirn2m,,TRUE,"Collier, Kirlin and Armstrong",881 Summer Ridge Circle,,,,,,,,,,,,FALSE,,,, +Lucas,Mulvany,lmulvany2n@deliciousdays.com,lmulvany2n,,FALSE,Bahringer Group,639 La Follette Circle,,,,,,,,,,,,TRUE,,,, +Lenore,Menendez,lmenendez2o@cdbaby.com,lmenendez2o,,TRUE,"Nader, Harvey and Casper",02 Springs Avenue,,,,,https://a8.net,926-526-1742,Community Outreach Specialist,ut odio cras mi pede malesuada in imperdiet et commodo vulputate justo in blandit ultrices enim lorem ipsum dolor,,,Lenore Menendez,TRUE,FALSE,2022-01-11,2022-07-29,lmenendez2o@ifeng.com +Collete,Brandes,cbrandes2p@accuweather.com,cbrandes2p,,TRUE,Koepp-Parisian,5 Haas Way,,,,,,,,,,,,FALSE,,,, +Osborne,Gummory,ogummory2q@1und1.de,ogummory2q,,FALSE,Mertz and Sons,91749 Haas Alley,,,,,,,,,,,,TRUE,,,, +Emiline,Grossman,egrossman2r@dmoz.org,egrossman2r,,TRUE,Parisian and Sons,3872 Eagle Crest Court,,,,,https://uiuc.edu,338-830-8647,Food Chemist,dolor vel est donec odio justo sollicitudin ut suscipit a feugiat et eros vestibulum ac est lacinia nisi venenatis,,Williamson-Casper,Emiline Grossman,TRUE,TRUE,2021-11-10,2022-10-01,egrossman2r@spiegel.de \ No newline at end of file diff --git a/tests/Feature/Assets/Api/AssetNotesTest.php b/tests/Feature/Assets/Api/AssetNotesTest.php new file mode 100644 index 0000000000..b3076c2852 --- /dev/null +++ b/tests/Feature/Assets/Api/AssetNotesTest.php @@ -0,0 +1,88 @@ +actingAsForApi(User::factory()->editAssets()->create()) + ->postJson(route('api.notes.store', ['asset' => 123456789])) + ->assertStatusMessageIs('error'); + } + + public function testRequiresPermissionToAddNoteToAssetAsset() + { + $asset = Asset::factory()->create(); + + $this->actingAsForApi(User::factory()->create()) + ->postJson(route('api.notes.store', $asset), [ + 'note' => 'test' + ]) + ->assertForbidden(); + } + + public function testAssetNoteIsSaved() + { + $asset = Asset::factory()->create(); + + $this->actingAsForApi(User::factory()->editAssets()->create()) + ->postJson(route('api.notes.store', $asset), [ + 'note' => 'This is a test note.' + ]) + ->assertStatusMessageIs('success') + ->assertJson([ + 'messages' => trans('general.note_added'), + 'payload' => [ + 'note' => 'This is a test note.', + 'item_id' => e($asset->id), + ], + ]) + ->assertStatus(200); + + $note = ActionLog::where('item_id', $asset->id) + ->where('action_type', 'note added') + ->first(); + + $this->assertNotNull($note, 'The note was not saved in the database.'); + $this->assertEquals('This is a test note.', $note->note, 'The note content does not match.'); + } + + public function testAssetNotesAreRetrievable() + { + $asset = Asset::factory()->create(); + + $user = User::factory()->viewAssets()->create(); + + $assetNote = Actionlog::factory() + ->assetNote($user) + ->create([ + 'item_id' => $asset->id, + 'note' => 'This is a test note.', + ]); + + $this->actingAsForApi($user) + ->getJson(route('api.notes.index', $asset)) + ->assertOk() + ->assertJson([ + 'messages' => null, + 'payload' => [ + 'notes' => [ + [ + 'note' => 'This is a test note.', + 'created_by' => $assetNote->created_by, + 'username' => $user->username, + 'item_id' => $assetNote->item_id, + 'item_type' => Asset::class, + 'action_type' => 'note added', + ] + ] + ], + ]); + } +} diff --git a/tests/Feature/Assets/Api/AssignedAssetsTest.php b/tests/Feature/Assets/Api/AssignedAssetsTest.php new file mode 100644 index 0000000000..93d9bbbfb0 --- /dev/null +++ b/tests/Feature/Assets/Api/AssignedAssetsTest.php @@ -0,0 +1,84 @@ +actingAsForApi(User::factory()->create()) + ->getJson(route('api.assets.assigned_assets', Asset::factory()->create())) + ->assertForbidden(); + } + + public function test_adheres_to_company_scoping() + { + $this->settings->enableMultipleFullCompanySupport(); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $asset = Asset::factory()->for($companyA)->create(); + + $user = User::factory()->for($companyB)->viewAssets()->create(); + + $this->actingAsForApi($user) + ->getJson(route('api.assets.assigned_assets', $asset)) + ->assertOk() + ->assertStatusMessageIs('error') + ->assertMessagesAre('Asset not found'); + } + + public function test_can_get_assets_assigned_to_specific_asset() + { + $unassociatedAsset = Asset::factory()->create(); + + $asset = Asset::factory()->hasAssignedAssets(2)->create(); + + $assetsAssignedToAsset = Asset::where([ + 'assigned_to' => $asset->id, + 'assigned_type' => Asset::class, + ])->get(); + + $this->actingAsForApi(User::factory()->viewAssets()->create()) + ->getJson(route('api.assets.assigned_assets', $asset)) + ->assertOk() + ->assertResponseContainsInRows($assetsAssignedToAsset, 'serial') + ->assertResponseDoesNotContainInRows($unassociatedAsset, 'serial') + ->assertJson(function (AssertableJson $json) { + $json->where('total', 2) + ->count('rows', 2) + ->etc(); + }); + } + + public function test_adheres_to_offset_and_limit() + { + $asset = Asset::factory()->hasAssignedAssets(2)->create(); + + $assetsAssignedToAsset = Asset::where([ + 'assigned_to' => $asset->id, + 'assigned_type' => Asset::class, + ])->get(); + + $this->actingAsForApi(User::factory()->viewAssets()->create()) + ->getJson(route('api.assets.assigned_assets', [ + 'asset' => $asset, + 'offset' => 1, + 'limit' => 1, + ])) + ->assertOk() + ->assertResponseDoesNotContainInRows($assetsAssignedToAsset->first(), 'serial') + ->assertResponseContainsInRows($assetsAssignedToAsset->last(), 'serial') + ->assertJson(function (AssertableJson $json) { + $json->where('total', 2) + ->count('rows', 1) + ->etc(); + }); + } +} diff --git a/tests/Feature/Assets/Api/AssignedComponentsTest.php b/tests/Feature/Assets/Api/AssignedComponentsTest.php new file mode 100644 index 0000000000..ad5ce43349 --- /dev/null +++ b/tests/Feature/Assets/Api/AssignedComponentsTest.php @@ -0,0 +1,79 @@ +actingAsForApi(User::factory()->create()) + ->getJson(route('api.assets.assigned_components', Asset::factory()->create())) + ->assertForbidden(); + } + + public function test_adheres_to_company_scoping() + { + $this->settings->enableMultipleFullCompanySupport(); + + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + $asset = Asset::factory()->for($companyA)->create(); + + $user = User::factory()->for($companyB)->viewAssets()->create(); + + $this->actingAsForApi($user) + ->getJson(route('api.assets.assigned_components', $asset)) + ->assertOk() + ->assertStatusMessageIs('error') + ->assertMessagesAre('Asset not found'); + } + + public function test_can_get_components_assigned_to_specific_asset() + { + $unassociatedComponent = Component::factory()->create(); + + $asset = Asset::factory()->hasComponents(2)->create(); + + $componentsAssignedToAsset = $asset->components; + + $this->actingAsForApi(User::factory()->viewAssets()->create()) + ->getJson(route('api.assets.assigned_components', $asset)) + ->assertOk() + ->assertResponseContainsInRows($componentsAssignedToAsset) + ->assertResponseDoesNotContainInRows($unassociatedComponent) + ->assertJson(function (AssertableJson $json) { + $json->where('total', 2) + ->count('rows', 2) + ->etc(); + }); + } + + public function test_adheres_to_offset_and_limit() + { + $asset = Asset::factory()->hasComponents(2)->create(); + + $componentsAssignedToAsset = $asset->components; + + $this->actingAsForApi(User::factory()->viewAssets()->create()) + ->getJson(route('api.assets.assigned_components', [ + 'asset' => $asset, + 'offset' => 1, + 'limit' => 1, + ])) + ->assertOk() + ->assertResponseDoesNotContainInRows($componentsAssignedToAsset->first()) + ->assertResponseContainsInRows($componentsAssignedToAsset->last()) + ->assertJson(function (AssertableJson $json) { + $json->where('total', 2) + ->count('rows', 1) + ->etc(); + }); + } +} diff --git a/tests/Feature/Assets/Api/StoreAssetTest.php b/tests/Feature/Assets/Api/StoreAssetTest.php index 67ef19cbb6..29d643e1bb 100644 --- a/tests/Feature/Assets/Api/StoreAssetTest.php +++ b/tests/Feature/Assets/Api/StoreAssetTest.php @@ -11,6 +11,7 @@ use App\Models\Statuslabel; use App\Models\Supplier; use App\Models\User; use Illuminate\Support\Facades\Crypt; +use Illuminate\Support\Facades\Storage; use Illuminate\Testing\Fluent\AssertableJson; use PHPUnit\Framework\Attributes\DataProvider; use Tests\TestCase; @@ -831,4 +832,28 @@ class StoreAssetTest extends TestCase $asset = Asset::findOrFail($response['payload']['id']); $this->assertEquals('This is encrypted field', Crypt::decrypt($asset->{$field->db_column_name()})); } + + public function testBase64AssetImages() + { + $status = Statuslabel::factory()->readyToDeploy()->create(); + $model = AssetModel::factory()->create(); + $superuser = User::factory()->superuser()->create(); + + $response = $this->actingAsForApi($superuser) + ->postJson(route('api.assets.store'), [ + 'model_id' => $model->id, + 'status_id' => $status->id, + 'asset_tag' => '1234', + 'image' => 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAZAAAAEsAQMAAADXeXeBAAAABlBMVEX+AAD///+KQee0AAAACXBIWXMAAAsSAAALEgHS3X78AAAAB3RJTUUH5QQbCAoNcoiTQAAAACZJREFUaN7twTEBAAAAwqD1T20JT6AAAAAAAAAAAAAAAAAAAICnATvEAAEnf54JAAAAAElFTkSuQmCC' + ]) + ->assertStatusMessageIs('success') + ->assertOk() + ->json(); + + $asset = Asset::findOrFail($response['payload']['id']); + $this->assertEquals($asset->asset_tag, '1234'); + $image_data = Storage::disk('public')->get(app('assets_upload_path') . e($asset->image)); + //$this->assertEquals('3d67fb99a0b6926e350f7b71397525d7a6b936c1', sha1($image_data)); //this doesn't work because the image gets resized - use the resized hash instead + $this->assertEquals('db2e13ba04318c99058ca429d67777322f48566b', sha1($image_data)); + } } diff --git a/tests/Feature/Assets/Ui/BulkEditAssetsTest.php b/tests/Feature/Assets/Ui/BulkEditAssetsTest.php index 36bb9346b0..04880d4f3c 100644 --- a/tests/Feature/Assets/Ui/BulkEditAssetsTest.php +++ b/tests/Feature/Assets/Ui/BulkEditAssetsTest.php @@ -29,6 +29,25 @@ class BulkEditAssetsTest extends TestCase ])->assertStatus(200); } + public function test_handles_model_being_deleted() + { + $this->withoutExceptionHandling(); + + $user = User::factory()->viewAssets()->editAssets()->create(); + $assets = Asset::factory()->count(2)->create(); + + $assets->first()->model->forceDelete(); + + $id_array = $assets->pluck('id')->toArray(); + + $this->actingAs($user)->post('/hardware/bulkedit', [ + 'ids' => $id_array, + 'order' => 'asc', + 'bulk_actions' => 'edit', + 'sort' => 'id' + ])->assertStatus(200); + } + public function test_standard_user_cannot_access_page() { $user = User::factory()->create(); diff --git a/tests/Feature/Assets/Ui/EditAssetTest.php b/tests/Feature/Assets/Ui/EditAssetTest.php index a2645f7320..0e1432e893 100644 --- a/tests/Feature/Assets/Ui/EditAssetTest.php +++ b/tests/Feature/Assets/Ui/EditAssetTest.php @@ -75,7 +75,10 @@ class EditAssetTest extends TestCase $user = User::factory()->create(); $deployable_status = Statuslabel::factory()->rtd()->create(); $achived_status = Statuslabel::factory()->archived()->create(); - $asset = Asset::factory()->assignedToUser($user)->create(['status_id' => $deployable_status->id]); + $asset = Asset::factory()->assignedToUser($user)->create([ + 'status_id' => $deployable_status->id, + 'last_checkin' => null, + ]); $this->assertTrue($asset->assignedTo->is($user)); $currentTimestamp = now(); @@ -96,6 +99,7 @@ class EditAssetTest extends TestCase $this->assertNull($asset->assigned_to); $this->assertNull($asset->assigned_type); $this->assertEquals($achived_status->id, $asset->status_id); + $this->assertNotNull($asset->last_checkin); Event::assertDispatched(function (CheckoutableCheckedIn $event) use ($currentTimestamp) { return (int) Carbon::parse($event->action_date)->diffInSeconds($currentTimestamp, true) < 2; @@ -125,4 +129,32 @@ class EditAssetTest extends TestCase $this->assertEquals($currentLocation->id, $asset->location_id); } + + public function test_handles_model_being_deleted() + { + $this->withoutExceptionHandling(); + + $newStatus = StatusLabel::factory()->create(); + + $asset = Asset::factory()->create(); + + $asset->model()->forceDelete(); + + $this->actingAs(User::factory()->viewAssets()->editAssets()->create()) + ->from(route('hardware.edit', $asset)) + ->put(route('hardware.update', $asset), [ + 'redirect_option' => 'index', + 'purchase_date' => '2025-08-30', + 'name' => 'New name', + 'asset_tags' => 'New Asset Tag', + 'status_id' => $newStatus->id, + // triggers potential issue in AssetObserver's saving method + 'model_id' => AssetModel::factory()->create()->id, + ]); + + $this->assertDatabaseHas('assets', [ + 'id' => $asset->id, + 'status_id' => $newStatus->id, + ]); + } } diff --git a/tests/Feature/Assets/Ui/StoreAssetsTest.php b/tests/Feature/Assets/Ui/StoreAssetsTest.php index 8abea545cf..baa9babcc0 100644 --- a/tests/Feature/Assets/Ui/StoreAssetsTest.php +++ b/tests/Feature/Assets/Ui/StoreAssetsTest.php @@ -2,6 +2,8 @@ namespace Tests\Feature\Assets\Ui; +use App\Models\Asset; +use App\Models\AssetModel; use App\Models\User; use Tests\TestCase; @@ -13,4 +15,63 @@ class StoreAssetsTest extends TestCase ->get(route('hardware.create')) ->assertOk(); } + + public function testAssetCanBeStoredWithSerialRequiredAndSerialProvided() + { + $user = User::factory()->superuser()->create(); + $this->actingAs($user); + + $model = AssetModel::factory()->create([ + 'require_serial' => 1, + ]); + + $response = $this->post(route('hardware.store'), [ + 'model_id' => $model->id, + 'serials' => [1 => 'ABC123'], + 'asset_tags' =>[1 => '1234'], + 'status_id' => 1, + // other required fields... + ]); + + $response->assertRedirect(); + $response->assertSessionHas('success-unescaped'); + $this->assertNotEquals( + trans('admin/hardware/form.serial_required'), + session('error') + ); + $this->assertDatabaseHas('assets', [ + 'model_id' => $model->id, + 'serial' => 'ABC123', + 'asset_tag' => '1234', + ]); + + + } + + public function testAssetCannotBeStoredIfSerialRequiredAndMissing() + { + $user = User::factory()->superuser()->create(); + $this->actingAs($user); + + $model = AssetModel::factory()->create([ + 'require_serial' => 1, + ]); + + $response = $this->post(route('hardware.store'), [ + 'model_id' => $model->id, + 'serials' => [], // ← serial missing + 'asset_tags' => [1 => '1234'], + 'status_id' => 1, + ]); + + $response->assertRedirect(); + $response->assertSessionHasErrors(['serials.1']); + + $this->assertDatabaseMissing('assets', [ + 'model_id' => $model->id, + 'asset_tag' => '1234', + ]); + + $response->assertSessionMissing('success-unescaped'); + } } diff --git a/tests/Feature/Checkins/Ui/LicenseCheckinTest.php b/tests/Feature/Checkins/Ui/LicenseCheckinTest.php index 7a6553d8ba..f1f912cad4 100644 --- a/tests/Feature/Checkins/Ui/LicenseCheckinTest.php +++ b/tests/Feature/Checkins/Ui/LicenseCheckinTest.php @@ -20,7 +20,7 @@ class LicenseCheckinTest extends TestCase ->assertForbidden(); } - public function testCannotCheckinNonReassignableLicense() + public function testNonReassignableLicenseSeatCantBeCheckedOut() { $licenseSeat = LicenseSeat::factory() ->notReassignable() @@ -28,13 +28,11 @@ class LicenseCheckinTest extends TestCase ->create(); $this->actingAs(User::factory()->checkoutLicenses()->create()) - ->post(route('licenses.checkin.save', $licenseSeat), [ - 'notes' => 'my note', - 'redirect_option' => 'index', - ]) - ->assertSessionHas('error', trans('admin/licenses/message.checkin.not_reassignable') . '.'); + ->post(route('licenses.checkin.save', $licenseSeat)); - $this->assertNotNull($licenseSeat->fresh()->assigned_to); + $licenseSeat->refresh(); + + $this->assertEquals(true, $licenseSeat->unreassignable_seat); } public function testCannotCheckinLicenseThatIsNotAssigned() diff --git a/tests/Feature/CheckoutAcceptances/Ui/AccessoryAcceptanceTest.php b/tests/Feature/CheckoutAcceptances/Ui/AccessoryAcceptanceTest.php index fef38623f8..9e20b52475 100644 --- a/tests/Feature/CheckoutAcceptances/Ui/AccessoryAcceptanceTest.php +++ b/tests/Feature/CheckoutAcceptances/Ui/AccessoryAcceptanceTest.php @@ -3,6 +3,7 @@ namespace Tests\Feature\CheckoutAcceptances\Ui; use App\Models\Accessory; +use App\Models\AccessoryCheckout; use App\Models\Asset; use App\Models\CheckoutAcceptance; use App\Models\User; @@ -96,4 +97,47 @@ class AccessoryAcceptanceTest extends TestCase $this->assertNull($acceptance->fresh()->accepted_at); } + + /** + * @link https://github.com/grokability/snipe-it/issues/17589 + */ + public function test_all_accessory_checkout_entries_are_removed_when_user_declines_acceptance() + { + $assignee = User::factory()->create(); + + $this->actingAs(User::factory()->checkoutAccessories()->create()); + + // create accessory that requires acceptance + $accessory = Accessory::factory()->requiringAcceptance()->create(['qty' => 5]); + + // checkout 3 accessories to the user + $this->post(route('accessories.checkout.store', $accessory), [ + 'assigned_user' => $assignee->id, + 'checkout_qty' => 3, + ]); + + $originalAccessoryCheckoutCount = AccessoryCheckout::count(); + + // find the acceptance to be declined + $checkoutAcceptance = CheckoutAcceptance::query() + ->where([ + 'assigned_to_id' => $assignee->id, + 'qty' => 3, + ]) + ->whereNull('accepted_at') + ->whereNull('declined_at') + ->whereHasMorph( + 'checkoutable', + [Accessory::class], + ) + ->sole(); + + // decline the checkout + $this->actingAs($assignee) + ->post(route('account.store-acceptance', $checkoutAcceptance), [ + 'asset_acceptance' => 'declined', + ]); + + $this->assertEquals($originalAccessoryCheckoutCount - 3, AccessoryCheckout::count()); + } } diff --git a/tests/Feature/Checkouts/Ui/BulkAssetCheckoutTest.php b/tests/Feature/Checkouts/Ui/BulkAssetCheckoutTest.php index f05c4389e6..6f6f250b90 100644 --- a/tests/Feature/Checkouts/Ui/BulkAssetCheckoutTest.php +++ b/tests/Feature/Checkouts/Ui/BulkAssetCheckoutTest.php @@ -4,8 +4,11 @@ namespace Tests\Feature\Checkouts\Ui; use App\Mail\CheckoutAssetMail; use App\Models\Asset; +use App\Models\Company; +use App\Models\Location; use App\Models\User; use Illuminate\Support\Facades\Mail; +use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\ExpectationFailedException; use Tests\TestCase; @@ -89,4 +92,99 @@ class BulkAssetCheckoutTest extends TestCase $this->fail('Asset checkout email was sent when the entire checkout failed.'); } } + + public static function checkoutTargets() + { + yield 'Checkout to user' => [ + function () { + return [ + 'type' => 'user', + 'target' => User::factory()->forCompany()->create(), + ]; + } + ]; + + yield 'Checkout to asset' => [ + function () { + return [ + 'type' => 'asset', + 'target' => Asset::factory()->forCompany()->create(), + ]; + } + ]; + + yield 'Checkout to location' => [ + function () { + return [ + 'type' => 'location', + 'target' => Location::factory()->forCompany()->create(), + ]; + } + ]; + } + + #[DataProvider('checkoutTargets')] + public function test_adheres_to_full_multiple_company_support($data) + { + ['type' => $type, 'target' => $target] = $data(); + + $this->settings->enableMultipleFullCompanySupport(); + + // create two companies + [$companyA, $companyB] = Company::factory()->count(2)->create(); + + // create an asset for each company + $assetForCompanyA = Asset::factory()->for($companyA)->create(); + $assetForCompanyB = Asset::factory()->for($companyB)->create(); + + $this->assertNull($assetForCompanyA->assigned_to, 'Asset should not be assigned before attempting this test case.'); + $this->assertNull($assetForCompanyB->assigned_to, 'Asset should not be assigned before attempting this test case.'); + + // attempt to bulk checkout both items to the target + $response = $this->actingAs(User::factory()->superuser()->create()) + ->post(route('hardware.bulkcheckout.store'), [ + 'selected_assets' => [ + $assetForCompanyA->id, + $assetForCompanyB->id, + ], + 'checkout_to_type' => $type, + "assigned_$type" => $target->id, + ]); + + // ensure bulk checkout is blocked + $this->assertNull($assetForCompanyA->fresh()->assigned_to, 'Asset was checked out across companies.'); + $this->assertNull($assetForCompanyB->fresh()->assigned_to, 'Asset was checked out across companies.'); + + // ensure redirected back + $response->assertRedirectToRoute('hardware.bulkcheckout.show'); + } + + #[DataProvider('checkoutTargets')] + public function test_prevents_checkouts_of_checked_out_items($data) + { + ['type' => $type, 'target' => $target] = $data(); + + $asset = Asset::factory()->create(); + $checkedOutAsset = Asset::factory()->assignedToUser()->create(); + $existingUserId = $checkedOutAsset->assigned_to; + + $response = $this->actingAs(User::factory()->superuser()->create()) + ->post(route('hardware.bulkcheckout.store'), [ + 'selected_assets' => [ + $asset->id, + $checkedOutAsset->id, + ], + 'checkout_to_type' => $type, + "assigned_$type" => $target->id, + ]); + + $this->assertEquals( + $existingUserId, + $checkedOutAsset->fresh()->assigned_to, + 'Asset was checked out when it should have been prevented.' + ); + + // ensure redirected back + $response->assertRedirectToRoute('hardware.bulkcheckout.show'); + } } diff --git a/tests/Feature/Console/SendAcceptanceReminderTest.php b/tests/Feature/Console/SendAcceptanceReminderTest.php index ee28e09355..6d0a51dd5d 100644 --- a/tests/Feature/Console/SendAcceptanceReminderTest.php +++ b/tests/Feature/Console/SendAcceptanceReminderTest.php @@ -45,7 +45,7 @@ class SendAcceptanceReminderTest extends TestCase ]); $headers = ['ID', 'Name']; $rows = [ - [$userA->id, $userA->present()->fullName()], + [$userA->id, $userA->display_name], ]; $this->artisan('snipeit:acceptance-reminder') ->expectsOutput("The following users do not have an email address:") diff --git a/tests/Feature/CustomFields/Ui/DeleteCustomFieldsTest.php b/tests/Feature/CustomFields/Ui/DeleteCustomFieldsTest.php new file mode 100644 index 0000000000..543122104f --- /dev/null +++ b/tests/Feature/CustomFields/Ui/DeleteCustomFieldsTest.php @@ -0,0 +1,69 @@ +actingAs(User::factory()->create()) + ->delete(route('fields.destroy', CustomField::factory()->create())) + ->assertForbidden(); + } + + + public function testCanDeleteCustomField() + { + $field = CustomField::factory()->create(); + $this->assertDatabaseHas('custom_fields', ['id' => $field->id]); + + $this->actingAs(User::factory()->deleteCustomFields()->create()) + ->delete(route('fields.destroy', $field)) + ->assertRedirectToRoute('fields.index') + ->assertStatus(302) + ->assertSessionHas('success'); + + $this->assertDatabaseMissing('custom_fields', ['id' => $field->id]); + } + + public function testCannotDeleteCustomFieldThatDoesNotExist() + { + + $response = $this->actingAs(User::factory()->viewCustomFields()->deleteCustomFields()->create()) + ->delete(route('fields.destroy', '49857589')) + ->assertRedirect(route('fields.index')) + ->assertSessionHas('error'); + + $temp = $this->followRedirects($response); + $temp->assertSee(trans('general.error'))->assertSee(trans('general.generic_model_not_found', ['model' => 'custom field'])); + + } + + public function testCannotDeleteFieldThatIsAssociatedWithFieldsets() + { + $field = CustomField::factory()->create(); + $fieldset = CustomFieldset::factory()->create(); + + $this->actingAs(User::factory()->superuser()->create()) + ->post(route('fieldsets.associate', $fieldset), [ + 'field_id' => $field->id, + ]); + + $response = $this->actingAs(User::factory()->viewCustomFields()->deleteCustomFields()->create()) + ->from(route('fields.index')) + ->delete(route('fields.destroy', $field)) + ->assertStatus(302) + ->assertRedirect(route('fields.index')) + ->assertSessionHas('error'); + + $this->followRedirects($response)->assertSee(trans('general.error'))->assertSee(trans('admin/custom_fields/message.field.delete.in_use')); + + // Ensure the field is still in the database + $this->assertDatabaseHas('custom_fields', ['id' => $field->id]); + } +} diff --git a/tests/Feature/Importing/Api/ImportAssetModelsTest.php b/tests/Feature/Importing/Api/ImportAssetModelsTest.php index a3a0a9ca4d..d79062b2f6 100644 --- a/tests/Feature/Importing/Api/ImportAssetModelsTest.php +++ b/tests/Feature/Importing/Api/ImportAssetModelsTest.php @@ -113,28 +113,28 @@ class ImportAssetModelsTest extends ImportDataTestCase implements TestsPermissio #[Test] public function updateAssetModelFromImport(): void { - $assetmodel = AssetModel::factory()->create()->refresh(); - $category = Category::find($assetmodel->category->name); - $importFileBuilder = ImportFileBuilder::new(['name' => $assetmodel->name, 'model_number' => Str::random(), 'category' => $category]); + $assetmodel = AssetModel::factory()->create(); + $category = Category::find($assetmodel->category_id); + $importFileBuilder = ImportFileBuilder::new(['name' => $assetmodel->name, 'model_number' => Str::random(), 'category' => $category->name]); $row = $importFileBuilder->firstRow(); $import = Import::factory()->assetmodel()->create(['file_path' => $importFileBuilder->saveToImportsDirectory()]); $this->actingAsForApi(User::factory()->superuser()->create()); - $this->importFileResponse(['import' => $import->id, 'import-update' => true])->assertOk(); + $this->importFileResponse(['import' => $import->id, 'import-update' => true]) + ->assertOk() + ->assertExactJson([ + 'payload' => null, + 'status' => 'success', + 'messages' => ['redirect_url' => route('models.index')] + ]); $updatedAssetmodel = AssetModel::query()->find($assetmodel->id); - $updatedAttributes = [ - 'name', - 'model_number' - ]; $this->assertEquals($row['model_number'], $updatedAssetmodel->model_number); + $this->assertEquals($row['name'], $updatedAssetmodel->name); - $this->assertEquals( - Arr::except($assetmodel->attributesToArray(), array_merge($updatedAttributes, $assetmodel->getDates())), - Arr::except($updatedAssetmodel->attributesToArray(), array_merge($updatedAttributes, $assetmodel->getDates())), - ); } + } diff --git a/tests/Feature/Importing/Api/ImportUsersTest.php b/tests/Feature/Importing/Api/ImportUsersTest.php index 1f5ae7a604..42e1777ffb 100644 --- a/tests/Feature/Importing/Api/ImportUsersTest.php +++ b/tests/Feature/Importing/Api/ImportUsersTest.php @@ -77,6 +77,7 @@ class ImportUsersTest extends ImportDataTestCase implements TestsPermissionsRequ $this->assertEquals($row['email'], $newUser->email); $this->assertEquals($row['firstName'], $newUser->first_name); $this->assertEquals($row['lastName'], $newUser->last_name); + $this->assertEquals($row['displayName'], $newUser->display_name); $this->assertEquals($row['employeeNumber'], $newUser->employee_num); $this->assertEquals($row['companyName'], $newUser->company->name); $this->assertEquals($row['location'], $newUser->location->name); @@ -229,12 +230,22 @@ class ImportUsersTest extends ImportDataTestCase implements TestsPermissionsRequ $updatedUser = User::query()->with(['company', 'location'])->find($user->id); $updatedAttributes = [ - 'first_name', 'email', 'last_name', 'employee_num', 'company', - 'location_id', 'company_id', 'updated_at', 'phone', 'jobtitle' + 'first_name', + 'display_name', + 'email', + 'last_name', + 'employee_num', + 'company', + 'location_id', + 'company_id', + 'updated_at', + 'phone', + 'jobtitle', ]; $this->assertEquals($row['email'], $updatedUser->email); $this->assertEquals($row['firstName'], $updatedUser->first_name); + $this->assertEquals($row['displayName'], $updatedUser->display_name); $this->assertEquals($row['lastName'], $updatedUser->last_name); $this->assertEquals($row['employeeNumber'], $updatedUser->employee_num); $this->assertEquals($row['companyName'], $updatedUser->company->name); @@ -249,6 +260,11 @@ class ImportUsersTest extends ImportDataTestCase implements TestsPermissionsRequ ); } + + /** + * Some of these should mismatch on purpose to ensure the mapping is working + * @return void + */ #[Test] public function customColumnMapping(): void { @@ -263,6 +279,7 @@ class ImportUsersTest extends ImportDataTestCase implements TestsPermissionsRequ 'phoneNumber' => $faker['employeeNumber'], 'position' => $faker['email'], 'username' => $faker['companyName'], + 'dumbName' => $faker['displayName'], ]; $importFileBuilder = new ImportFileBuilder([$row]); @@ -282,8 +299,11 @@ class ImportUsersTest extends ImportDataTestCase implements TestsPermissionsRequ 'Phone Number' => 'employee_num', 'Job Title' => 'email', 'Username' => 'company', + 'dumbName' => 'display_name', ] - ])->assertOk(); + ])->assertOk() + ->json(); + $newUser = User::query() ->with(['company', 'location']) @@ -293,6 +313,7 @@ class ImportUsersTest extends ImportDataTestCase implements TestsPermissionsRequ $this->assertEquals($row['position'], $newUser->email); $this->assertEquals($row['location'], $newUser->first_name); $this->assertEquals($row['lastName'], $newUser->last_name); + $this->assertEquals($row['dumbName'], $newUser->display_name); $this->assertEquals($row['email'], $newUser->jobtitle); $this->assertEquals($row['phoneNumber'], $newUser->employee_num); $this->assertEquals($row['username'], $newUser->company->name); diff --git a/tests/Feature/Locations/Api/DeleteLocationsTest.php b/tests/Feature/Locations/Api/DeleteLocationsTest.php index 796b9a1977..755528ab94 100644 --- a/tests/Feature/Locations/Api/DeleteLocationsTest.php +++ b/tests/Feature/Locations/Api/DeleteLocationsTest.php @@ -2,7 +2,10 @@ namespace Tests\Feature\Locations\Api; +use App\Models\Accessory; use App\Models\Asset; +use App\Models\Component; +use App\Models\Consumable; use App\Models\Location; use App\Models\User; use Tests\Concerns\TestsPermissionsRequirement; @@ -24,11 +27,12 @@ class DeleteLocationsTest extends TestCase implements TestsPermissionsRequiremen public function testErrorReturnedViaApiIfLocationDoesNotExist() { $this->actingAsForApi(User::factory()->superuser()->create()) - ->deleteJson(route('api.users.destroy', 'invalid-id')) + ->deleteJson(route('api.locations.destroy', 'invalid-id')) ->assertOk() ->assertStatus(200) ->assertStatusMessageIs('error') ->json(); + } public function testErrorReturnedViaApiIfLocationIsAlreadyDeleted() @@ -55,9 +59,10 @@ class DeleteLocationsTest extends TestCase implements TestsPermissionsRequiremen ->assertStatus(200) ->assertStatusMessageIs('error') ->json(); + $this->assertNotSoftDeleted($location); } - public function testDisallowUserDeletionViaApiIfStillHasChildLocations() + public function testDisallowLocationDeletionViaApiIfStillHasChildLocations() { $parent = Location::factory()->create(); Location::factory()->count(5)->create(['parent_id' => $parent->id]); @@ -69,9 +74,10 @@ class DeleteLocationsTest extends TestCase implements TestsPermissionsRequiremen ->assertStatus(200) ->assertStatusMessageIs('error') ->json(); + $this->assertNotSoftDeleted($parent); } - public function testDisallowUserDeletionViaApiIfStillHasAssetsAssigned() + public function testDisallowLocationDeletionViaApiIfStillHasAssetsAssigned() { $location = Location::factory()->create(); Asset::factory()->count(5)->assignedToLocation($location)->create(); @@ -84,9 +90,10 @@ class DeleteLocationsTest extends TestCase implements TestsPermissionsRequiremen ->assertStatus(200) ->assertStatusMessageIs('error') ->json(); + $this->assertNotSoftDeleted($location); } - public function testDisallowUserDeletionViaApiIfStillHasAssetsAsLocation() + public function testDisallowLocationDeletionViaApiIfStillHasAssetsAsLocation() { $location = Location::factory()->create(); Asset::factory()->count(5)->create(['location_id' => $location->id]); @@ -99,6 +106,73 @@ class DeleteLocationsTest extends TestCase implements TestsPermissionsRequiremen ->assertStatus(200) ->assertStatusMessageIs('error') ->json(); + $this->assertNotSoftDeleted($location); + } + + public function testDisallowLocationDeletionViaApiIfStillHasConsumablesAsLocation() + { + $location = Location::factory()->create(); + Consumable::factory()->count(5)->create(['location_id' => $location->id]); + + $this->assertFalse($location->isDeletable()); + + $this->actingAsForApi(User::factory()->superuser()->create()) + ->deleteJson(route('api.locations.destroy', $location->id)) + ->assertOk() + ->assertStatus(200) + ->assertStatusMessageIs('error') + ->json(); + $this->assertNotSoftDeleted($location); + } + + public function testDisallowLocationDeletionViaApiIfStillHasComponentsAsLocation() + { + $location = Location::factory()->create(); + Component::factory()->count(5)->create(['location_id' => $location->id]); + + $this->assertFalse($location->isDeletable()); + + $this->actingAsForApi(User::factory()->superuser()->create()) + ->deleteJson(route('api.locations.destroy', $location->id)) + ->assertOk() + ->assertStatus(200) + ->assertStatusMessageIs('error') + ->json(); + + $this->assertNotSoftDeleted($location); + } + + public function testDisallowLocationDeletionViaApiIfStillHasAccessoriesAssigned() + { + $location = Location::factory()->create(); + Accessory::factory()->count(5)->checkedOutToLocation($location)->create(); + + $this->assertFalse($location->isDeletable()); + + $this->actingAsForApi(User::factory()->superuser()->create()) + ->deleteJson(route('api.locations.destroy', $location->id)) + ->assertOk() + ->assertStatus(200) + ->assertStatusMessageIs('error') + ->json(); + $this->assertNotSoftDeleted($location); + } + + public function testDisallowLocationDeletionViaApiIfStillHasAccessoriesAsLocation() + { + $location = Location::factory()->create(); + Accessory::factory()->count(5)->create(['location_id' => $location->id]); + + $this->assertFalse($location->isDeletable()); + + $this->actingAsForApi(User::factory()->superuser()->create()) + ->deleteJson(route('api.locations.destroy', $location->id)) + ->assertOk() + ->assertStatus(200) + ->assertStatusMessageIs('error') + ->json(); + + $this->assertNotSoftDeleted($location); } public function testCanDeleteLocation() diff --git a/tests/Feature/Locations/Ui/DeleteLocationsTest.php b/tests/Feature/Locations/Ui/DeleteLocationsTest.php new file mode 100644 index 0000000000..f0edb866f7 --- /dev/null +++ b/tests/Feature/Locations/Ui/DeleteLocationsTest.php @@ -0,0 +1,139 @@ +actingAs(User::factory()->create()) + ->delete(route('locations.destroy', Location::factory()->create())) + ->assertForbidden(); + } + + public function testCanDeleteLocation() + { + $location = Location::factory()->create(); + + $this->actingAs(User::factory()->deleteLocations()->create()) + ->delete(route('locations.destroy', $location)) + ->assertRedirectToRoute('locations.index') + ->assertSessionHas('success') + ->assertStatus(302) + ->assertRedirect(route('locations.index')); + + $this->assertSoftDeleted($location); + } + + + public function testCannotDeleteLocationWithAssetsAsLocation() + { + $location = Location::factory()->create(); + Asset::factory()->count(5)->create(['location_id' => $location->id]); + + $this->actingAs(User::factory()->deleteLocations()->create()) + ->delete(route('locations.destroy', $location)) + ->assertStatus(302) + ->assertRedirectToRoute('locations.index') + ->assertSessionHas('error'); + + $this->assertNotSoftDeleted($location); + } + + public function testCannotDeleteLocationWithAssetsAssigned() + { + $location = Location::factory()->create(); + Asset::factory()->count(5)->assignedToLocation($location)->create(); + + $this->actingAs(User::factory()->deleteLocations()->create()) + ->delete(route('locations.destroy', $location)) + ->assertStatus(302) + ->assertRedirectToRoute('locations.index') + ->assertSessionHas('error'); + + $this->assertNotSoftDeleted($location); + } + + public function testCannotDeleteLocationWithChildren() + { + $parent = Location::factory()->create(); + Location::factory()->count(5)->create(['parent_id' => $parent->id]); + + $this->actingAs(User::factory()->deleteLocations()->create()) + ->delete(route('locations.destroy', $parent)) + ->assertStatus(302) + ->assertRedirectToRoute('locations.index') + ->assertSessionHas('error'); + + $this->assertNotSoftDeleted($parent); + } + + public function testCannotDeleteLocationWithConsumableAsLocation() + { + $location = Location::factory()->create(); + Consumable::factory()->count(5)->create(['location_id' => $location->id]); + + $this->actingAs(User::factory()->deleteLocations()->create()) + ->delete(route('locations.destroy', $location)) + ->assertStatus(302) + ->assertRedirectToRoute('locations.index') + ->assertSessionHas('error'); + + $this->assertNotSoftDeleted($location); + } + + public function testCannotDeleteLocationWithAccessoriesAssigned() + { + $location = Location::factory()->create(); + Accessory::factory()->count(5)->checkedOutToLocation($location)->create(); + + $this->actingAs(User::factory()->deleteLocations()->create()) + ->delete(route('locations.destroy', $location)) + ->assertStatus(302) + ->assertRedirectToRoute('locations.index') + ->assertSessionHas('error'); + + $this->assertNotSoftDeleted($location); + } + + public function testCannotDeleteLocationWithAccessoriesAsLocation() + { + $location = Location::factory()->create(); + Accessory::factory()->count(5)->create(['location_id' => $location->id]); + + $this->actingAs(User::factory()->deleteLocations()->create()) + ->delete(route('locations.destroy', $location)) + ->assertStatus(302) + ->assertRedirectToRoute('locations.index') + ->assertSessionHas('error'); + + $this->assertNotSoftDeleted($location); + } + + public function testCannotDeleteLocationWithPeople() + { + $location = Location::factory()->create(); + User::factory()->count(5)->create(['location_id' => $location->id]); + + $this->actingAs(User::factory()->deleteLocations()->create()) + ->delete(route('locations.destroy', $location)) + ->assertStatus(302) + ->assertRedirectToRoute('locations.index') + ->assertSessionHas('error'); + + $this->assertNotSoftDeleted($location); + } + + + + + +} diff --git a/tests/Feature/Maintenances/Api/CreateMaintenanceTest.php b/tests/Feature/Maintenances/Api/CreateMaintenanceTest.php index 594d89466f..5924b1c1fa 100644 --- a/tests/Feature/Maintenances/Api/CreateMaintenanceTest.php +++ b/tests/Feature/Maintenances/Api/CreateMaintenanceTest.php @@ -41,6 +41,7 @@ class CreateMaintenanceTest extends TestCase 'completion_date' => '2021-01-10', 'is_warranty' => '1', 'cost' => '100.00', + 'url' => 'https://snipeitapp.com', 'image' => UploadedFile::fake()->image('test_image.png'), 'notes' => 'A note', ]) @@ -62,6 +63,7 @@ class CreateMaintenanceTest extends TestCase 'start_date' => '2021-01-01', 'completion_date' => '2021-01-10', 'notes' => 'A note', + 'url' => 'https://snipeitapp.com', 'image' => $maintenance->image, 'created_by' => $actor->id, ]); diff --git a/tests/Feature/Maintenances/Api/EditMaintenanceTest.php b/tests/Feature/Maintenances/Api/EditMaintenanceTest.php index 4ca589bec2..c3a4dd337f 100644 --- a/tests/Feature/Maintenances/Api/EditMaintenanceTest.php +++ b/tests/Feature/Maintenances/Api/EditMaintenanceTest.php @@ -38,6 +38,7 @@ class EditMaintenanceTest extends TestCase 'is_warranty' => '1', 'image' => UploadedFile::fake()->image('test_image.png'), 'notes' => 'A note', + 'url' => 'https://snipeitapp.com', ]) ->assertOk(); @@ -57,6 +58,7 @@ class EditMaintenanceTest extends TestCase 'completion_date' => '2021-01-10', 'asset_maintenance_time' => '9', 'notes' => 'A note', + 'url' => 'https://snipeitapp.com', 'image' => $maintenance->image, ]); diff --git a/tests/Feature/Maintenances/Ui/CreateMaintenanceTest.php b/tests/Feature/Maintenances/Ui/CreateMaintenanceTest.php index de1201e17f..a731828899 100644 --- a/tests/Feature/Maintenances/Ui/CreateMaintenanceTest.php +++ b/tests/Feature/Maintenances/Ui/CreateMaintenanceTest.php @@ -46,6 +46,7 @@ class CreateMaintenanceTest extends TestCase 'cost' => '100.00', 'image' => UploadedFile::fake()->image('test_image.png'), 'notes' => 'A note', + 'url' => 'https://snipeitapp.com', ]) ->assertSessionHasNoErrors() ->assertRedirect(route('maintenances.index')); @@ -67,6 +68,7 @@ class CreateMaintenanceTest extends TestCase 'completion_date' => '2021-01-10', 'asset_maintenance_time' => '9', 'notes' => 'A note', + 'url' => 'https://snipeitapp.com', 'cost' => '100.00', 'image' => $maintenance->image, 'created_by' => $actor->id, diff --git a/tests/Feature/Maintenances/Ui/EditMaintenanceTest.php b/tests/Feature/Maintenances/Ui/EditMaintenanceTest.php index ad8aea4a56..cf92a10499 100644 --- a/tests/Feature/Maintenances/Ui/EditMaintenanceTest.php +++ b/tests/Feature/Maintenances/Ui/EditMaintenanceTest.php @@ -38,6 +38,7 @@ class EditMaintenanceTest extends TestCase 'image' => UploadedFile::fake()->image('test_image.png'), 'cost' => '100.99', 'notes' => 'A note', + 'url' => 'https://snipeitapp.com', ]) ->assertSessionHasNoErrors() ->assertRedirect(route('maintenances.index')); @@ -58,6 +59,7 @@ class EditMaintenanceTest extends TestCase 'completion_date' => '2021-01-10', 'asset_maintenance_time' => '9', 'notes' => 'A note', + 'url' => 'https://snipeitapp.com', 'cost' => '100.99', ]); diff --git a/tests/Feature/Notifications/Email/EmailNotificationsToAdminAlertEmailUponCheckinTest.php b/tests/Feature/Notifications/Email/EmailNotificationsToAdminAlertEmailUponCheckinTest.php index 1bdbf0b673..cc9a6cb244 100644 --- a/tests/Feature/Notifications/Email/EmailNotificationsToAdminAlertEmailUponCheckinTest.php +++ b/tests/Feature/Notifications/Email/EmailNotificationsToAdminAlertEmailUponCheckinTest.php @@ -51,8 +51,12 @@ class EmailNotificationsToAdminAlertEmailUponCheckinTest extends TestCase $this->fireCheckInEvent($this->asset, $this->user); + Mail::assertSentCount(2); Mail::assertSent(CheckinAssetMail::class, function ($mail) { - return $mail->hasTo($this->user->email) && $mail->hasCc('cc@example.com'); + return $mail->hasTo($this->user->email); + }); + Mail::assertSent(CheckinAssetMail::class, function ($mail) { + return $mail->hasTo('cc@example.com'); }); } diff --git a/tests/Feature/Notifications/Email/EmailNotificationsToAdminAlertEmailUponCheckoutTest.php b/tests/Feature/Notifications/Email/EmailNotificationsToAdminAlertEmailUponCheckoutTest.php index d881ae7dab..3da0b21621 100644 --- a/tests/Feature/Notifications/Email/EmailNotificationsToAdminAlertEmailUponCheckoutTest.php +++ b/tests/Feature/Notifications/Email/EmailNotificationsToAdminAlertEmailUponCheckoutTest.php @@ -48,7 +48,7 @@ class EmailNotificationsToAdminAlertEmailUponCheckoutTest extends TestCase $this->fireCheckoutEvent(); Mail::assertSent(CheckoutAssetMail::class, function (CheckoutAssetMail $mail) { - return $mail->hasCc('cc@example.com'); + return $mail->hasTo('cc@example.com'); }); } diff --git a/tests/Feature/Notifications/Email/ExpiringAlertsNotificationTest.php b/tests/Feature/Notifications/Email/ExpiringAlertsNotificationTest.php index 1d91cf2557..707f5468d4 100644 --- a/tests/Feature/Notifications/Email/ExpiringAlertsNotificationTest.php +++ b/tests/Feature/Notifications/Email/ExpiringAlertsNotificationTest.php @@ -8,7 +8,6 @@ use App\Mail\SendUpcomingAuditMail; use App\Models\Asset; use App\Models\License; use App\Models\Setting; -use App\Models\User; use Illuminate\Support\Facades\Mail; use Tests\TestCase; @@ -17,7 +16,6 @@ class ExpiringAlertsNotificationTest extends TestCase { public function testExpiringAssetsEmailNotification() { - $this->markIncompleteIfSqlite(); Mail::fake(); $this->settings->enableAlertEmail('admin@example.com'); @@ -25,41 +23,52 @@ class ExpiringAlertsNotificationTest extends TestCase $alert_email = Setting::first()->alert_email; - $expiringAsset = Asset::factory()->create([ - 'purchase_date' => now()->subDays(350)->format('Y-m-d'), + $expiringWarrantyAsset = Asset::factory()->create([ + 'purchase_date' => now()->subDays(356)->format('Y-m-d'), 'warranty_months' => 12, 'archived' => 0, - 'deleted_at' => null, ]); - $expiredAsset = Asset::factory()->create([ - 'purchase_date' => now()->subDays(370)->format('Y-m-d'), + + $alreadyExpiredAsset = Asset::factory()->create([ + 'purchase_date' => now()->subDays(396)->format('Y-m-d'), 'warranty_months' => 12, 'archived' => 0, - 'deleted_at' => null, ]); + // Asset has a manually entered EOL date that's coming up + $expiringEOLAsset = Asset::factory()->create([ + 'archived' => 0, + ]); + + // We have to set this here because of the configure() method in the Asset factory :( + $expiringEOLAsset->asset_eol_date = now()->addDays(5)->format('Y-m-d'); + $expiringEOLAsset->save(); + $notExpiringAsset = Asset::factory()->create([ - 'purchase_date' => now()->subDays(330)->format('Y-m-d'), + 'purchase_date' => now()->addDays(330)->format('Y-m-d'), 'warranty_months' => 12, 'archived' => 0, - 'deleted_at' => null, ]); + // We have to set this here because of the configure() method in the Asset factory :( + $notExpiringAsset->asset_eol_date = null; + $expiringEOLAsset->save(); + $this->artisan('snipeit:expiring-alerts')->assertExitCode(0); - Mail::assertSent(ExpiringAssetsMail::class, function($mail) use ($alert_email, $expiringAsset) { - return $mail->hasTo($alert_email) && $mail->assets->contains($expiringAsset); + Mail::assertSent(ExpiringAssetsMail::class, function($mail) use ($alert_email, $expiringWarrantyAsset, $expiringEOLAsset) { + return $mail->hasTo($alert_email) && ($mail->assets->contains($expiringEOLAsset) || $mail->assets->contains($expiringWarrantyAsset)); }); + - Mail::assertNotSent(ExpiringAssetsMail::class, function($mail) use ($expiredAsset, $notExpiringAsset) { - return $mail->assets->contains($expiredAsset) || $mail->assets->contains($notExpiringAsset); + Mail::assertNotSent(ExpiringAssetsMail::class, function($mail) use ($alert_email, $notExpiringAsset, $alreadyExpiredAsset) { + return $mail->assets->contains($alert_email) || ($mail->assets->contains($alreadyExpiredAsset) && ($mail->assets->contains($notExpiringAsset))); }); } public function testExpiringLicensesEmailNotification() { - $this->markIncompleteIfSqlite(); Mail::fake(); $this->settings->enableAlertEmail('admin@example.com'); $this->settings->setAlertInterval(60); @@ -69,6 +78,7 @@ class ExpiringAlertsNotificationTest extends TestCase $expiringLicense = License::factory()->create([ 'expiration_date' => now()->addDays(30)->format('Y-m-d'), 'deleted_at' => null, + 'termination_date' => null, ]); $expiredLicense = License::factory()->create([ @@ -80,20 +90,43 @@ class ExpiringAlertsNotificationTest extends TestCase 'deleted_at' => null, ]); + $expiringButTerminatedLicense = License::factory()->create([ + 'termination_date' => now()->subDays(10)->format('Y-m-d'), + 'expiration_date' => now()->subDays(10)->format('Y-m-d'), + 'deleted_at' => null, + ]); + + $deletedExpiringLicense = License::factory()->create([ + 'expiration_date' => now()->addDays(30)->format('Y-m-d'), + 'deleted_at' => now()->subDays(10)->format('Y-m-d'), + ]); + $this->artisan('snipeit:expiring-alerts')->assertExitCode(0); Mail::assertSent(ExpiringLicenseMail::class, function($mail) use ($alert_email, $expiringLicense) { return $mail->hasTo($alert_email) && $mail->licenses->contains($expiringLicense); }); - Mail::assertNotSent(ExpiringLicenseMail::class, function($mail) use ($expiredLicense, $notExpiringLicense) { - return $mail->licenses->contains($expiredLicense) || $mail->licenses->contains($notExpiringLicense); + Mail::assertNotSent(ExpiringLicenseMail::class, function($mail) use ($alert_email, $expiredLicense) { + return $mail->hasTo($alert_email) && $mail->licenses->contains($expiredLicense); }); + + Mail::assertNotSent(ExpiringLicenseMail::class, function($mail) use ($alert_email, $notExpiringLicense) { + return $mail->licenses->contains($alert_email) || $mail->licenses->contains($notExpiringLicense); + }); + + Mail::assertNotSent(ExpiringLicenseMail::class, function($mail) use ($alert_email, $expiringButTerminatedLicense) { + return $mail->licenses->contains($alert_email) || $mail->licenses->contains($expiringButTerminatedLicense); + }); + + Mail::assertNotSent(ExpiringLicenseMail::class, function($mail) use ($alert_email, $deletedExpiringLicense) { + return $mail->licenses->contains($alert_email) || $mail->licenses->contains($deletedExpiringLicense); + }); + } public function testAuditWarningThresholdEmailNotification() { - $this->markIncompleteIfSqlite(); Mail::fake(); $this->settings->enableAlertEmail('admin@example.com'); $this->settings->setAuditWarningDays(15); diff --git a/tests/Feature/Users/Api/StoreUsersTest.php b/tests/Feature/Users/Api/CreateUserTest.php similarity index 52% rename from tests/Feature/Users/Api/StoreUsersTest.php rename to tests/Feature/Users/Api/CreateUserTest.php index 41cb04e3c4..bbed8479d5 100644 --- a/tests/Feature/Users/Api/StoreUsersTest.php +++ b/tests/Feature/Users/Api/CreateUserTest.php @@ -5,10 +5,12 @@ namespace Tests\Feature\Users\Api; use App\Models\Company; use App\Models\Department; use App\Models\User; +use App\Notifications\WelcomeNotification; +use Illuminate\Support\Facades\Notification; use Illuminate\Testing\Fluent\AssertableJson; use Tests\TestCase; -class StoreUsersTest extends TestCase +class CreateUserTest extends TestCase { public function testRequiresPermission() { @@ -58,21 +60,66 @@ class StoreUsersTest extends TestCase }); } - public function testCanStoreUser() + public function testCanCreateUser() { + Notification::fake(); + $this->actingAsForApi(User::factory()->createUsers()->create()) ->postJson(route('api.users.store'), [ - 'first_name' => 'Darth', - 'username' => 'darthvader', - 'password' => 'darth_password', - 'password_confirmation' => 'darth_password', + 'first_name' => 'Test First Name', + 'last_name' => 'Test Last Name', + 'username' => 'testuser', + 'password' => 'testpassword1235!!', + 'password_confirmation' => 'testpassword1235!!', + 'activated' => '1', + 'email' => 'foo@example.org', + 'notes' => 'Test Note', ]) ->assertStatusMessageIs('success') ->assertOk(); $this->assertDatabaseHas('users', [ - 'first_name' => 'Darth', - 'username' => 'darthvader', + 'first_name' => 'Test First Name', + 'last_name' => 'Test Last Name', + 'username' => 'testuser', + 'activated' => '1', + 'email' => 'foo@example.org', + 'notes' => 'Test Note', + ]); + + Notification::assertNothingSent(); + } + + public function testCanCreateAndNotifyUser() + { + Notification::fake(); + + $this->actingAsForApi(User::factory()->createUsers()->create()) + ->postJson(route('api.users.store'), [ + 'first_name' => 'Test First Name', + 'last_name' => 'Test Last Name', + 'username' => 'testuser', + 'password' => 'testpassword1235!!', + 'password_confirmation' => 'testpassword1235!!', + 'send_welcome' => '1', + 'activated' => '1', + 'email' => 'foo@example.org', + 'notes' => 'Test Note', + ]) + ->assertStatusMessageIs('success') + ->assertOk(); + + $this->assertDatabaseHas('users', [ + 'first_name' => 'Test First Name', + 'last_name' => 'Test Last Name', + 'username' => 'testuser', + 'activated' => '1', + 'email' => 'foo@example.org', + 'notes' => 'Test Note', + ]); + + $user = User::where('username', 'testuser')->first(); + Notification::assertSentTo($user, WelcomeNotification::class); } } diff --git a/tests/Feature/Users/Ui/CreateUserTest.php b/tests/Feature/Users/Ui/CreateUserTest.php index d63dc40f9e..f2f5c2ed67 100644 --- a/tests/Feature/Users/Ui/CreateUserTest.php +++ b/tests/Feature/Users/Ui/CreateUserTest.php @@ -3,6 +3,8 @@ namespace Tests\Feature\Users\Ui; use App\Models\User; +use App\Notifications\WelcomeNotification; +use Illuminate\Support\Facades\Notification; use Tests\TestCase; class CreateUserTest extends TestCase @@ -25,6 +27,7 @@ class CreateUserTest extends TestCase public function testCanCreateUser() { + Notification::fake(); $response = $this->actingAs(User::factory()->createUsers()->viewUsers()->create()) ->from(route('users.index')) @@ -33,11 +36,62 @@ class CreateUserTest extends TestCase 'last_name' => 'Test Last Name', 'username' => 'testuser', 'password' => 'testpassword1235!!', - //'notes' => 'Test Note', + 'password_confirmation' => 'testpassword1235!!', + 'activated' => '1', + 'email' => 'foo@example.org', + 'notes' => 'Test Note', ]) + ->assertSessionHasNoErrors() ->assertStatus(302) ->assertRedirect(route('users.index')); + $this->assertDatabaseHas('users', [ + 'first_name' => 'Test First Name', + 'last_name' => 'Test Last Name', + 'username' => 'testuser', + 'activated' => '1', + 'email' => 'foo@example.org', + 'notes' => 'Test Note', + + ]); + Notification::assertNothingSent(); + $this->followRedirects($response)->assertSee('Success'); + + } + + public function testCanCreateAndNotifyUser() + { + + Notification::fake(); + + $response = $this->actingAs(User::factory()->createUsers()->viewUsers()->create()) + ->from(route('users.index')) + ->post(route('users.store'), [ + 'first_name' => 'Test First Name', + 'last_name' => 'Test Last Name', + 'username' => 'testuser', + 'password' => 'testpassword1235!!', + 'password_confirmation' => 'testpassword1235!!', + 'send_welcome' => '1', + 'activated' => '1', + 'email' => 'foo@example.org', + 'notes' => 'Test Note', + ]) + ->assertSessionHasNoErrors() + ->assertStatus(302) + ->assertRedirect(route('users.index')); + + $this->assertDatabaseHas('users', [ + 'first_name' => 'Test First Name', + 'last_name' => 'Test Last Name', + 'username' => 'testuser', + 'activated' => '1', + 'email' => 'foo@example.org', + 'notes' => 'Test Note', + ]); + + $user = User::where('username', 'testuser')->first(); + Notification::assertSentTo($user, WelcomeNotification::class); $this->followRedirects($response)->assertSee('Success'); } diff --git a/tests/Support/CustomTestMacros.php b/tests/Support/CustomTestMacros.php index 956235f461..be9a527f4c 100644 --- a/tests/Support/CustomTestMacros.php +++ b/tests/Support/CustomTestMacros.php @@ -21,13 +21,19 @@ trait CustomTestMacros TestResponse::macro( 'assertResponseContainsInRows', - function (Model $model, string $property = 'name') use ($guardAgainstNullProperty) { - $guardAgainstNullProperty($model, $property); + function (iterable|Model $models, string $property = 'name') use ($guardAgainstNullProperty) { + if ($models instanceof Model) { + $models = [$models]; + } - Assert::assertTrue( - collect($this['rows'])->pluck($property)->contains(e($model->{$property})), - "Response did not contain the expected value: {$model->{$property}}" - ); + foreach ($models as $model) { + $guardAgainstNullProperty($model, $property); + + Assert::assertTrue( + collect($this['rows'])->pluck($property)->contains(e($model->{$property})), + "Response did not contain the expected value: {$model->{$property}}" + ); + } return $this; } diff --git a/tests/Support/Importing/UsersImportFileBuilder.php b/tests/Support/Importing/UsersImportFileBuilder.php index 0a00c995c2..0490cf230a 100644 --- a/tests/Support/Importing/UsersImportFileBuilder.php +++ b/tests/Support/Importing/UsersImportFileBuilder.php @@ -31,15 +31,16 @@ class UsersImportFileBuilder extends FileBuilder protected function getDictionary(): array { return [ - 'companyName' => 'Company', - 'email' => 'email', - 'employeeNumber' => 'Employee Number', + 'companyName' => 'Company', + 'email' => 'email', + 'employeeNumber' => 'Employee Number', 'firstName' => 'First Name', - 'lastName' => 'Last Name', - 'location' => 'Location', - 'phoneNumber' => 'Phone Number', - 'position' => 'Job Title', - 'username' => 'Username', + 'lastName' => 'Last Name', + 'displayName' => 'Display Name', + 'location' => 'Location', + 'phoneNumber' => 'Phone Number', + 'position' => 'Job Title', + 'username' => 'Username', ]; } @@ -51,15 +52,16 @@ class UsersImportFileBuilder extends FileBuilder $faker = fake(); return [ - 'companyName' => $faker->company, - 'email' => Str::random(32) . "@{$faker->freeEmailDomain}", - 'employeeNumber' => $faker->uuid, + 'companyName' => $faker->company, + 'email' => $faker->safeEmail(), + 'employeeNumber' => $faker->uuid, 'firstName' => $faker->firstName, - 'lastName' => $faker->lastName, - 'location' => "{$faker->city}, {$faker->country}", - 'phoneNumber' => $faker->phoneNumber, - 'position' => $faker->jobTitle, - 'username' => Str::random(), + 'lastName' => $faker->lastName, + 'displayName' => $faker->firstName, + 'location' => "{$faker->city}, {$faker->country}", + 'phoneNumber' => $faker->phoneNumber, + 'position' => $faker->jobTitle, + 'username' => $faker->userName(), ]; } } diff --git a/tests/Unit/BladeComponents/UserFullNameTest.php b/tests/Unit/BladeComponents/UserFullNameTest.php index bbd74c7fa1..feb88ff71d 100644 --- a/tests/Unit/BladeComponents/UserFullNameTest.php +++ b/tests/Unit/BladeComponents/UserFullNameTest.php @@ -17,7 +17,7 @@ class UserFullNameTest extends TestCase function () { return [ 'actor' => User::factory()->viewUsers()->create(), - 'user' => User::factory()->create(['first_name' => 'Jim', 'last_name' => 'Bagg']), + 'user' => User::factory()->create(['first_name' => 'Jim', 'last_name' => 'Bagg', 'display_name' => null]), 'assertions' => function ($rendered) { Assert::assertStringContainsString(' User::factory()->viewUsers()->create(), - 'user' => User::factory()->deleted()->create(['first_name' => 'Jim', 'last_name' => 'Bagg']), + 'user' => User::factory()->deleted()->create(['first_name' => 'Jim', 'last_name' => 'Bagg', 'display_name' => 'Jim Baggins']), 'assertions' => function ($rendered) { Assert::assertStringContainsString(' User::factory()->create(), - 'user' => User::factory()->create(['first_name' => 'Jim', 'last_name' => 'Bagg']), + 'user' => User::factory()->create(['first_name' => 'Jim', 'last_name' => 'Bagg', 'display_name' => 'Jim Bagg']), 'assertions' => function ($rendered) { Assert::assertStringContainsString('Jim Bagg', $rendered); Assert::assertStringNotContainsString(' User::factory()->create(), - 'user' => User::factory()->deleted()->create(['first_name' => 'Jim', 'last_name' => 'Bagg']), + 'user' => User::factory()->deleted()->create(['first_name' => 'Jim', 'last_name' => 'Bagg', 'display_name' => 'Jim Bagg']), 'assertions' => function ($rendered) { Assert::assertStringContainsString('Jim Bagg', $rendered); }, @@ -82,6 +82,10 @@ class UserFullNameTest extends TestCase { ['actor' => $actor, 'user' => $user, 'assertions' => $assertions] = $provided(); + // $user->displayName(); + + // \Log::error($user->toArray()); + $this->actingAs($actor); $renderedTemplateString = View::make('blade.full-user-name', ['user' => $user])->render(); diff --git a/tests/Unit/LdapTest.php b/tests/Unit/LdapTest.php index 538f542ebb..3f01160976 100644 --- a/tests/Unit/LdapTest.php +++ b/tests/Unit/LdapTest.php @@ -20,7 +20,7 @@ class LdapTest extends TestCase $ldap_connect->expects($this->once())->willReturn('hello'); $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); - $ldap_set_option->expects($this->exactly(3)); + $ldap_set_option->expects($this->exactly(4)); $blah = Ldap::connectToLdap(); @@ -84,7 +84,7 @@ class LdapTest extends TestCase $ldap_connect->expects($this->once())->willReturn('hello'); $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); - $ldap_set_option->expects($this->exactly(3)); + $ldap_set_option->expects($this->exactly(4)); $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); @@ -114,7 +114,7 @@ class LdapTest extends TestCase $ldap_connect->expects($this->once())->willReturn('hello'); $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); - $ldap_set_option->expects($this->exactly(3)); + $ldap_set_option->expects($this->exactly(4)); // note - we return FALSE first, to simulate a bad-bind, then TRUE the second time to simulate a successful admin bind $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->exactly(2))->willReturn(false, true); @@ -135,7 +135,7 @@ class LdapTest extends TestCase $ldap_connect->expects($this->once())->willReturn('hello'); $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); - $ldap_set_option->expects($this->exactly(3)); + $ldap_set_option->expects($this->exactly(4)); $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); @@ -156,7 +156,7 @@ class LdapTest extends TestCase $ldap_connect->expects($this->once())->willReturn('hello'); $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); - $ldap_set_option->expects($this->exactly(3)); + $ldap_set_option->expects($this->exactly(4)); $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); @@ -179,7 +179,7 @@ class LdapTest extends TestCase $ldap_connect->expects($this->once())->willReturn('hello'); $ldap_set_option = $this->getFunctionMock("App\\Models", "ldap_set_option"); - $ldap_set_option->expects($this->exactly(3)); + $ldap_set_option->expects($this->exactly(4)); $this->getFunctionMock("App\\Models", "ldap_bind")->expects($this->once())->willReturn(true); diff --git a/tests/Unit/Mail/CheckoutAssetMailTest.php b/tests/Unit/Mail/CheckoutAssetMailTest.php index af198b2cd1..f2e5b34b53 100644 --- a/tests/Unit/Mail/CheckoutAssetMailTest.php +++ b/tests/Unit/Mail/CheckoutAssetMailTest.php @@ -20,7 +20,7 @@ class CheckoutAssetMailTest extends TestCase 'asset' => $asset, 'acceptance' => CheckoutAcceptance::factory()->for($asset, 'checkoutable')->create(), 'first_time_sending' => true, - 'expected_subject' => 'Asset checked out', + 'expected_subject' => trans('mail.Asset_Checkout_Notification', ['tag' => $asset->asset_tag]), 'expected_opening' => 'A new item has been checked out under your name that requires acceptance, details are below.' ]; } @@ -28,11 +28,12 @@ class CheckoutAssetMailTest extends TestCase yield 'Asset not requiring acceptance' => [ function () { + $asset = Asset::factory()->doesNotRequireAcceptance()->create(); return [ - 'asset' => Asset::factory()->doesNotRequireAcceptance()->create(), + 'asset' => $asset, 'acceptance' => null, 'first_time_sending' => true, - 'expected_subject' => 'Asset checked out', + 'expected_subject' => trans('mail.Asset_Checkout_Notification', ['tag' => $asset->asset_tag]), 'expected_opening' => 'A new item has been checked out under your name, details are below.' ]; } diff --git a/tests/Unit/NotificationTest.php b/tests/Unit/NotificationTest.php index 5b420a6753..302c0b3a8b 100644 --- a/tests/Unit/NotificationTest.php +++ b/tests/Unit/NotificationTest.php @@ -31,8 +31,8 @@ class NotificationTest extends TestCase Mail::fake(); $asset->checkOut($user, $admin->id); - Mail::assertSent(CheckoutAssetMail::class, function (CheckoutAssetMail $mail) use ($user) { - return $mail->hasTo($user->email) && $mail->hasSubject(trans('mail.Asset_Checkout_Notification')); + Mail::assertSent(CheckoutAssetMail::class, function (CheckoutAssetMail $mail) use ($user, $asset) { + return $mail->hasTo($user->email) && $mail->hasSubject(trans('mail.Asset_Checkout_Notification', ['tag' => $asset->asset_tag])); }); } public function testDefaultEulaIsSentWhenSetInCategory() diff --git a/tests/Unit/SnipeModelTest.php b/tests/Unit/SnipeModelTest.php index 2bc81da61b..bfc81a5670 100644 --- a/tests/Unit/SnipeModelTest.php +++ b/tests/Unit/SnipeModelTest.php @@ -10,20 +10,25 @@ class SnipeModelTest extends TestCase { $c = new SnipeModel; $c->purchase_date = ''; - $this->assertTrue($c->purchase_date === null); - $c->purchase_date = '2016-03-25 12:35:50'; - $this->assertTrue($c->purchase_date === '2016-03-25 12:35:50'); + $this->assertNull($c->purchase_date); + $c->purchase_date = null; + $this->assertNull($c->purchase_date); + $c->purchase_date = '2016-03-25'; + $this->assertTrue($c->purchase_date === '2016-03-25'); + $this->assertEquals('2016-03-25', $c->purchase_date); } public function testSetsPurchaseCostsAppropriately() { $c = new SnipeModel; + $c->purchase_cost = ''; + $this->assertTrue($c->purchase_cost == null); $c->purchase_cost = '0.00'; - $this->assertTrue($c->purchase_cost === null); + $this->assertTrue($c->purchase_cost == 0.00); $c->purchase_cost = '9.54'; - $this->assertTrue($c->purchase_cost === 9.54); + $this->assertTrue($c->purchase_cost == 9.54); $c->purchase_cost = '9.50'; - $this->assertTrue($c->purchase_cost === 9.5); + $this->assertTrue($c->purchase_cost == 9.5); } public function testNullsBlankLocationIdsButNotOthers() diff --git a/upgrade.php b/upgrade.php index b98162ed96..6bbe543e9f 100644 --- a/upgrade.php +++ b/upgrade.php @@ -62,6 +62,7 @@ if ($argc > 1){ break; case '--no-interactive': $no_interactive = true; + putenv("COMPOSER_NO_INTERACTION=1"); //put composer in non-interactive mode aswell break; default: // for legacy support from before we started using --branch $branch = $argv[$arg]; @@ -443,7 +444,8 @@ if ((strpos('git version', $git_version)) === false) { echo $git_fetch; echo '-- '.$git_stash; echo '-- '.$git_checkout; - echo '-- '.$git_pull."\n"; + echo '-- '.$git_pull; + echo "\n"; } else { echo "Git is NOT installed. You can still use this upgrade script to run common \n"; echo "migration commands, but you will have to manually download the updated files. \n\n"; @@ -539,7 +541,7 @@ echo "--------------------------------------------------------\e[39m\n\n"; exec('php artisan down', $down_results, $return_code); echo '-- ' . implode("\n", $down_results) . "\n"; if ($return_code > 0) { - die("Something went wrong with downing your site. This can't be good. Please investigate the error. Aborting!\n\n"); + die("Something went wrong with downing your site. This can't be good. Please investigate the error and be sure to check https://snipe-it.readme.io/docs/common-issues and https://snipe-it.readme.io/docs/installation-issues for solutions to common upgrading issues. Aborting!\n\n"); } unset($return_code);