commit c885bbc947dfe11bc317c33bcb7f4360c6c03179
parent 63fb0e5a57dadc2b581a513c7824f25e3d55ba2a
Author: BlackDex <black.dex@gmail.com>
Date: Thu, 1 Dec 2022 17:18:29 +0100
Update dependencies for Rust and Admin interface.
- Updated Rust deps and one small change regarding chrono
- Updated bootstrap 5 css
- Updated datatables
- Replaced identicon.js with jdenticon.
identicon.js is unmaintained ( https://github.com/stewartlord/identicon.js/issues/52 )
The icon's are very different, but nice. It also doesn't need custom
code to find and update the icons our selfs.
Diffstat:
11 files changed, 1757 insertions(+), 497 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
@@ -54,9 +54,9 @@ dependencies = [
[[package]]
name = "aho-corasick"
-version = "0.7.19"
+version = "0.7.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b4f55bd91a0978cbfd91c457a164bab8b4001c833b7f323132c0a4e1922dd44e"
+checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac"
dependencies = [
"memchr",
]
@@ -122,9 +122,9 @@ dependencies = [
[[package]]
name = "async-trait"
-version = "0.1.58"
+version = "0.1.59"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c"
+checksum = "31e6e93155431f3931513b243d371981bb2770112b370c82745a1d19d2f99364"
dependencies = [
"proc-macro2",
"quote",
@@ -173,7 +173,7 @@ dependencies = [
"cc",
"cfg-if",
"libc",
- "miniz_oxide",
+ "miniz_oxide 0.5.4",
"object",
"rustc-demangle",
]
@@ -240,9 +240,9 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
-version = "1.2.1"
+version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec8a7b6a70fde80372154c65702f00a0f56f3e1c36abbc6c440484be248856db"
+checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
[[package]]
name = "cached"
@@ -283,9 +283,9 @@ checksum = "3a4f925191b4367301851c6d99b09890311d74b0d43f274c0b34c86d308a3663"
[[package]]
name = "cc"
-version = "1.0.75"
+version = "1.0.77"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41ca34107f97baef6cfb231b32f36115781856b8f8208e8c580e0bcaea374842"
+checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4"
[[package]]
name = "cfg-if"
@@ -295,9 +295,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "chrono"
-version = "0.4.22"
+version = "0.4.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bfd4d1b31faaa3a89d7934dbded3111da0d2ef28e3ebccdb4f0179f5929d1ef1"
+checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
dependencies = [
"iana-time-zone",
"num-integer",
@@ -308,9 +308,9 @@ dependencies = [
[[package]]
name = "chrono-tz"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a87b30366b6766751277791b473b674f3bf7fb75696841c784a3eb7e7fbf44ee"
+checksum = "fa48fa079165080f11d7753fd0bc175b7d391f276b965fe4b55bfad67856e463"
dependencies = [
"chrono",
"chrono-tz-build",
@@ -445,9 +445,9 @@ dependencies = [
[[package]]
name = "crossbeam-utils"
-version = "0.8.12"
+version = "0.8.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "edbafec5fa1f196ca66527c1b12c2ec4745ca14b50f1ad8f9f6f720b55d11fac"
+checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f"
dependencies = [
"cfg-if",
]
@@ -484,9 +484,9 @@ dependencies = [
[[package]]
name = "cxx"
-version = "1.0.81"
+version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97abf9f0eca9e52b7f81b945524e76710e6cb2366aead23b7d4fbf72e281f888"
+checksum = "bdf07d07d6531bfcdbe9b8b739b104610c6508dcc4d63b410585faf338241daf"
dependencies = [
"cc",
"cxxbridge-flags",
@@ -496,9 +496,9 @@ dependencies = [
[[package]]
name = "cxx-build"
-version = "1.0.81"
+version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cc32cc5fea1d894b77d269ddb9f192110069a8a9c1f1d441195fba90553dea3"
+checksum = "d2eb5b96ecdc99f72657332953d4d9c50135af1bac34277801cc3937906ebd39"
dependencies = [
"cc",
"codespan-reporting",
@@ -511,15 +511,15 @@ dependencies = [
[[package]]
name = "cxxbridge-flags"
-version = "1.0.81"
+version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ca220e4794c934dc6b1207c3b42856ad4c302f2df1712e9f8d2eec5afaacf1f"
+checksum = "ac040a39517fd1674e0f32177648334b0f4074625b5588a64519804ba0553b12"
[[package]]
name = "cxxbridge-macro"
-version = "1.0.81"
+version = "1.0.83"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b846f081361125bfc8dc9d3940c84e1fd83ba54bbca7b17cd29483c828be0704"
+checksum = "1362b0ddcfc4eb0a1f57b68bd77dd99f0e826958a96abd0ae9bd092e114ffed6"
dependencies = [
"proc-macro2",
"quote",
@@ -663,9 +663,9 @@ dependencies = [
[[package]]
name = "digest"
-version = "0.10.5"
+version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adfbc57365a37acbd2ebf2b64d7e69bb766e2fea813521ed536f5d0520dcf86c"
+checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer",
"crypto-common",
@@ -714,9 +714,9 @@ dependencies = [
[[package]]
name = "enum-as-inner"
-version = "0.4.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21cdad81446a7f7dc43f6a77409efeb9733d2fa65553efef6018ef257c959b73"
+checksum = "c9720bba047d567ffc8a3cba48bf19126600e249ab7f128e9233e6376976a116"
dependencies = [
"heck",
"proc-macro2",
@@ -768,12 +768,12 @@ dependencies = [
[[package]]
name = "flate2"
-version = "1.0.24"
+version = "1.0.25"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f82b0f4c27ad9f8bfd1f3208d882da2b09c301bc1c828fd3a00d0216d2fbbff6"
+checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841"
dependencies = [
"crc32fast",
- "miniz_oxide",
+ "miniz_oxide 0.6.2",
]
[[package]]
@@ -959,9 +959,9 @@ checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
[[package]]
name = "governor"
-version = "0.5.0"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "de1b4626e87b9eb1d603ed23067ba1e29ec1d0b35325a2b96c3fe1cf20871f56"
+checksum = "c390a940a5d157878dd057c78680a33ce3415bcd05b4799509ea44210914b4d5"
dependencies = [
"cfg-if",
"dashmap",
@@ -1198,9 +1198,9 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "1.9.1"
+version = "1.9.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
+checksum = "1885e79c1fc4b10f0e172c475f458b7f7b93061064d98c3293e98c5ba0c8b399"
dependencies = [
"autocfg",
"hashbrown",
@@ -1233,14 +1233,14 @@ dependencies = [
[[package]]
name = "ipconfig"
-version = "0.3.0"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "723519edce41262b05d4143ceb95050e4c614f483e78e9fd9e39a8275a84ad98"
+checksum = "bd302af1b90f2463a98fa5ad469fc212c8e3175a41c3068601bfa2727591c5be"
dependencies = [
"socket2",
"widestring",
"winapi",
- "winreg 0.7.0",
+ "winreg",
]
[[package]]
@@ -1283,9 +1283,9 @@ dependencies = [
[[package]]
name = "jsonwebtoken"
-version = "8.1.1"
+version = "8.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1aa4b4af834c6cfd35d8763d359661b90f2e45d8f750a0849156c7f4671af09c"
+checksum = "09f4f04699947111ec1733e71778d763555737579e44b85844cae8e1940a1828"
dependencies = [
"base64",
"pem",
@@ -1331,17 +1331,18 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.137"
+version = "0.2.138"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc7fcc620a3bff7cdd7a365be3376c97191aeaccc2a603e600951e452615bf89"
+checksum = "db6d7e329c562c5dfab7a46a2afabc8b987ab9a4834c9d1ca04dc54c1546cef8"
[[package]]
name = "libmimalloc-sys"
-version = "0.1.27"
+version = "0.1.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c37567b180c1af25924b303ddf1ee4467653783440c62360beb2b322a4d93361"
+checksum = "04d1c67deb83e6b75fa4fe3309e09cfeade12e7721d95322af500d3814ea60c9"
dependencies = [
"cc",
+ "libc",
]
[[package]]
@@ -1472,9 +1473,9 @@ dependencies = [
[[package]]
name = "mimalloc"
-version = "0.1.31"
+version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b32d6a9ac92d0239d7bfa31137fb47634ac7272a3c11bcee91379ac100781670"
+checksum = "9b2374e2999959a7b583e1811a1ddbf1d3a4b9496eceb9746f1192a59d871eca"
dependencies = [
"libmimalloc-sys",
]
@@ -1501,6 +1502,15 @@ dependencies = [
]
[[package]]
+name = "miniz_oxide"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
+dependencies = [
+ "adler",
+]
+
+[[package]]
name = "mio"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1561,9 +1571,9 @@ dependencies = [
[[package]]
name = "nix"
-version = "0.25.0"
+version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e322c04a9e3440c327fca7b6c8a63e6890a32fa2ad689db972425f07e0d22abb"
+checksum = "f346ff70e7dbfd675fe90590b92d59ef2de15a8779ae305ebcbfd3f0caf59be4"
dependencies = [
"autocfg",
"bitflags",
@@ -1686,9 +1696,9 @@ checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
[[package]]
name = "openssl"
-version = "0.10.42"
+version = "0.10.43"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13"
+checksum = "020433887e44c27ff16365eaa2d380547a94544ad509aff6eb5b6e3e0b27b376"
dependencies = [
"bitflags",
"cfg-if",
@@ -1727,9 +1737,9 @@ dependencies = [
[[package]]
name = "openssl-sys"
-version = "0.9.77"
+version = "0.9.78"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a"
+checksum = "07d5c8cb6e57b3a3612064d7b18b117912b4ce70955c2504d4b741c9e244b132"
dependencies = [
"autocfg",
"cc",
@@ -1757,9 +1767,9 @@ dependencies = [
[[package]]
name = "parking_lot_core"
-version = "0.9.4"
+version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4dc9e0dc2adc1c69d09143aff38d3d30c5c3f0df0dad82e6d25547af174ebec0"
+checksum = "7ff9f3fef3968a3ec5945535ed654cb38ff72d7495a25619e2247fb15a2ed9ba"
dependencies = [
"cfg-if",
"libc",
@@ -1823,9 +1833,9 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]]
name = "pest"
-version = "2.4.1"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a528564cc62c19a7acac4d81e01f39e53e25e17b934878f4c6d25cc2836e62f8"
+checksum = "cc8bed3549e0f9b0a2a78bf7c0018237a2cdf085eecbbc048e52612438e4e9d0"
dependencies = [
"thiserror",
"ucd-trie",
@@ -1833,9 +1843,9 @@ dependencies = [
[[package]]
name = "pest_derive"
-version = "2.4.1"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5fd9bc6500181952d34bd0b2b0163a54d794227b498be0b7afa7698d0a7b18f"
+checksum = "cdc078600d06ff90d4ed238f0119d84ab5d43dbaad278b0e33a8820293b32344"
dependencies = [
"pest",
"pest_generator",
@@ -1843,9 +1853,9 @@ dependencies = [
[[package]]
name = "pest_generator"
-version = "2.4.1"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d2610d5ac5156217b4ff8e46ddcef7cdf44b273da2ac5bca2ecbfa86a330e7c4"
+checksum = "28a1af60b1c4148bb269006a750cff8e2ea36aff34d2d96cf7be0b14d1bed23c"
dependencies = [
"pest",
"pest_meta",
@@ -1856,9 +1866,9 @@ dependencies = [
[[package]]
name = "pest_meta"
-version = "2.4.1"
+version = "2.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "824749bf7e21dd66b36fbe26b3f45c713879cccd4a009a917ab8e045ca8246fe"
+checksum = "fec8605d59fc2ae0c6c1aefc0c7c7a9769732017c0ce07f7a9cfffa7b4404f20"
dependencies = [
"once_cell",
"pest",
@@ -2055,9 +2065,9 @@ dependencies = [
[[package]]
name = "quoted_printable"
-version = "0.4.5"
+version = "0.4.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fee2dce59f7a43418e3382c766554c614e06a552d53a8f07ef499ea4b332c0f"
+checksum = "20f14e071918cbeefc5edc986a7aa92c425dae244e003a35e1cdddb5ca39b5cb"
[[package]]
name = "r2d2"
@@ -2175,9 +2185,9 @@ dependencies = [
[[package]]
name = "reqwest"
-version = "0.11.12"
+version = "0.11.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc"
+checksum = "68cc60575865c7831548863cc02356512e3f1dc2f3f82cb837d7fc4cc8f3c97c"
dependencies = [
"async-compression",
"base64",
@@ -2214,7 +2224,7 @@ dependencies = [
"wasm-bindgen",
"wasm-bindgen-futures",
"web-sys",
- "winreg 0.10.1",
+ "winreg",
]
[[package]]
@@ -2474,9 +2484,9 @@ checksum = "e25dfac463d778e353db5be2449d1cce89bd6fd23c9f1ea21310ce6e5a1b29c4"
[[package]]
name = "serde"
-version = "1.0.147"
+version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d193d69bae983fc11a79df82342761dfbf28a99fc8d203dca4c3c1b590948965"
+checksum = "e53f64bb4ba0191d6d0676e1b141ca55047d83b74f5607e6d8eb88126c52c2dc"
dependencies = [
"serde_derive",
]
@@ -2493,9 +2503,9 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.147"
+version = "1.0.148"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4f1d362ca8fc9c3e3a7484440752472d68a6caa98f1ab81d99b5dfe517cec852"
+checksum = "a55492425aa53521babf6137309e7d34c20bbfbbfcfe2c7f3a047fd1f6b92c0c"
dependencies = [
"proc-macro2",
"quote",
@@ -2504,9 +2514,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.87"
+version = "1.0.89"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ce777b7b150d76b9cf60d28b55f5847135a003f7d7350c6be7a773508ce7d45"
+checksum = "020ff22c755c2ed3f8cf162dbb41a7268d934702f3ed3631656ea597e08fc3db"
dependencies = [
"itoa",
"ryu",
@@ -2527,9 +2537,9 @@ dependencies = [
[[package]]
name = "sha-1"
-version = "0.10.0"
+version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f"
+checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -2663,9 +2673,9 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
[[package]]
name = "syn"
-version = "1.0.103"
+version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a864042229133ada95abf3b54fdc62ef5ccabe9515b64717bcb9a1919e59445d"
+checksum = "60b9b43d45702de4c839cb9b51d9f529c5dd26a4aff255b42b1ebc03e88ee908"
dependencies = [
"proc-macro2",
"quote",
@@ -2792,9 +2802,9 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c"
[[package]]
name = "tokio"
-version = "1.21.2"
+version = "1.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9e03c497dc955702ba729190dc4aac6f2a0ce97f913e5b1b5912fc5039d9099"
+checksum = "d76ce4a75fb488c605c54bf610f221cea8b0dafb53333c1a67e8ee199dcd2ae3"
dependencies = [
"autocfg",
"bytes",
@@ -2812,9 +2822,9 @@ dependencies = [
[[package]]
name = "tokio-macros"
-version = "1.8.0"
+version = "1.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9724f9a975fb987ef7a3cd9be0350edcbe130698af5b8f7a631e23d42d052484"
+checksum = "d266c00fde287f55d3f1c3e96c500c362a2b8c695076ec180f27918820bc6df8"
dependencies = [
"proc-macro2",
"quote",
@@ -2867,9 +2877,9 @@ dependencies = [
[[package]]
name = "tokio-tungstenite"
-version = "0.17.2"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181"
+checksum = "54319c93411147bced34cb5609a80e0a8e44c5999c93903a81cd866630ec0bfd"
dependencies = [
"futures-util",
"log",
@@ -2983,9 +2993,9 @@ dependencies = [
[[package]]
name = "trust-dns-proto"
-version = "0.21.2"
+version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c31f240f59877c3d4bb3b3ea0ec5a6a0cff07323580ff8c7a605cd7d08b255d"
+checksum = "4f7f83d1e4a0e4358ac54c5c3681e5d7da5efc5a7a632c90bb6d6669ddd9bc26"
dependencies = [
"async-trait",
"cfg-if",
@@ -2997,32 +3007,32 @@ dependencies = [
"idna 0.2.3",
"ipnet",
"lazy_static",
- "log",
"rand",
"smallvec",
"thiserror",
"tinyvec",
"tokio",
+ "tracing",
"url",
]
[[package]]
name = "trust-dns-resolver"
-version = "0.21.2"
+version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e4ba72c2ea84515690c9fcef4c6c660bb9df3036ed1051686de84605b74fd558"
+checksum = "aff21aa4dcefb0a1afbfac26deb0adc93888c7d295fb63ab273ef276ba2b7cfe"
dependencies = [
"cfg-if",
"futures-util",
"ipconfig",
"lazy_static",
- "log",
"lru-cache",
"parking_lot",
"resolv-conf",
"smallvec",
"thiserror",
"tokio",
+ "tracing",
"trust-dns-proto",
]
@@ -3034,9 +3044,9 @@ checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
[[package]]
name = "tungstenite"
-version = "0.17.3"
+version = "0.18.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0"
+checksum = "30ee6ab729cd4cf0fd55218530c4522ed30b7b6081752839b68fcec8d0960788"
dependencies = [
"base64",
"byteorder",
@@ -3045,7 +3055,7 @@ dependencies = [
"httparse",
"log",
"rand",
- "sha-1",
+ "sha1",
"thiserror",
"url",
"utf-8",
@@ -3151,9 +3161,9 @@ checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "uuid"
-version = "1.2.1"
+version = "1.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "feb41e78f93363bb2df8b0e86a2ca30eed7806ea16ea0c790d757cf93f79be83"
+checksum = "422ee0de9031b5b948b97a8fc04e3aa35230001a722ddd27943e0be31564ce4c"
dependencies = [
"getrandom",
]
@@ -3554,15 +3564,6 @@ checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
[[package]]
name = "winreg"
-version = "0.7.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69"
-dependencies = [
- "winapi",
-]
-
-[[package]]
-name = "winreg"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
diff --git a/Cargo.toml b/Cargo.toml
@@ -55,17 +55,17 @@ num-derive = "0.3.3"
rocket = { version = "0.5.0-rc.2", features = ["tls", "json"], default-features = false }
# WebSockets libraries
-tokio-tungstenite = "0.17.2"
+tokio-tungstenite = "0.18.0"
rmpv = "1.0.0" # MessagePack library
dashmap = "5.4.0"
# Async futures
futures = "0.3.25"
-tokio = { version = "1.21.2", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time"] }
+tokio = { version = "1.22.0", features = ["rt-multi-thread", "fs", "io-util", "parking_lot", "time"] }
# A generic serialization/deserialization framework
-serde = { version = "1.0.147", features = ["derive"] }
-serde_json = "1.0.87"
+serde = { version = "1.0.148", features = ["derive"] }
+serde_json = "1.0.89"
# A safe, extensible ORM and Query builder
diesel = { version = "2.0.2", features = ["chrono", "r2d2"] }
@@ -79,11 +79,11 @@ rand = { version = "0.8.5", features = ["small_rng"] }
ring = "0.16.20"
# UUID generation
-uuid = { version = "1.2.1", features = ["v4"] }
+uuid = { version = "1.2.2", features = ["v4"] }
# Date and time libraries
-chrono = { version = "0.4.22", features = ["clock", "serde"], default-features = false }
-chrono-tz = "0.8.0"
+chrono = { version = "0.4.23", features = ["clock", "serde"], default-features = false }
+chrono-tz = "0.8.1"
time = "0.3.17"
# Job scheduler
@@ -116,13 +116,13 @@ email_address = "0.2.4"
handlebars = { version = "4.3.5", features = ["dir_source"] }
# HTTP client
-reqwest = { version = "0.11.12", features = ["stream", "json", "gzip", "brotli", "socks", "cookies", "trust-dns"] }
+reqwest = { version = "0.11.13", features = ["stream", "json", "gzip", "brotli", "socks", "cookies", "trust-dns"] }
# For favicon extraction from main website
html5gum = "0.5.2"
regex = { version = "1.7.0", features = ["std", "perf", "unicode-perl"], default-features = false }
data-url = "0.2.0"
-bytes = "1.2.1"
+bytes = "1.3.0"
cached = "0.40.0"
# Used for custom short lived cookie jar during favicon extraction
@@ -130,14 +130,14 @@ cookie = "0.16.1"
cookie_store = "0.19.0"
# Used by U2F, JWT and Postgres
-openssl = "0.10.42"
+openssl = "0.10.43"
# CLI argument parsing
pico-args = "0.5.0"
# Macro ident concatenation
paste = "1.0.9"
-governor = "0.5.0"
+governor = "0.5.1"
# Capture CTRL+C
ctrlc = { version = "3.2.3", features = ["termination"] }
@@ -147,7 +147,7 @@ semver = "1.0.14"
# Allow overriding the default memory allocator
# Mainly used for the musl builds, since the default musl malloc is very slow
-mimalloc = { version = "0.1.31", features = ["secure"], default-features = false, optional = true }
+mimalloc = { version = "0.1.32", features = ["secure"], default-features = false, optional = true }
[patch.crates-io]
# Using a patched version of multer-rs (Used by Rocket) to fix attachment/send file uploads
diff --git a/src/api/web.rs b/src/api/web.rs
@@ -98,7 +98,7 @@ pub fn static_files(filename: String) -> Result<(ContentType, &'static [u8]), Er
"vaultwarden-icon.png" => Ok((ContentType::PNG, include_bytes!("../static/images/vaultwarden-icon.png"))),
"bootstrap.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/bootstrap.css"))),
"bootstrap-native.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/bootstrap-native.js"))),
- "identicon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/identicon.js"))),
+ "jdenticon.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/jdenticon.js"))),
"datatables.js" => Ok((ContentType::JavaScript, include_bytes!("../static/scripts/datatables.js"))),
"datatables.css" => Ok((ContentType::CSS, include_bytes!("../static/scripts/datatables.css"))),
"jquery-3.6.1.slim.js" => {
diff --git a/src/static/scripts/bootstrap.css b/src/static/scripts/bootstrap.css
@@ -1,6 +1,6 @@
@charset "UTF-8";
/*!
- * Bootstrap v5.2.0 (https://getbootstrap.com/)
+ * Bootstrap v5.2.3 (https://getbootstrap.com/)
* Copyright 2011-2022 The Bootstrap Authors
* Copyright 2011-2022 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
@@ -2468,6 +2468,7 @@ textarea.form-control-lg {
height: 100%;
padding: 1rem 0.75rem;
overflow: hidden;
+ text-align: start;
text-overflow: ellipsis;
white-space: nowrap;
pointer-events: none;
@@ -2547,14 +2548,14 @@ textarea.form-control-lg {
.input-group > .form-control:focus,
.input-group > .form-select:focus,
.input-group > .form-floating:focus-within {
- z-index: 3;
+ z-index: 5;
}
.input-group .btn {
position: relative;
z-index: 2;
}
.input-group .btn:focus {
- z-index: 3;
+ z-index: 5;
}
.input-group-text {
@@ -2609,10 +2610,13 @@ textarea.form-control-lg {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
-.input-group > :not(:first-child):not(.dropdown-menu):not(.form-floating):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback),
+.input-group > :not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback) {
+ margin-left: -1px;
+ border-top-left-radius: 0;
+ border-bottom-left-radius: 0;
+}
.input-group > .form-floating:not(:first-child) > .form-control,
.input-group > .form-floating:not(:first-child) > .form-select {
- margin-left: -1px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
@@ -2699,14 +2703,11 @@ textarea.form-control-lg {
margin-left: 0.5em;
}
-.was-validated .input-group .form-control:valid, .input-group .form-control.is-valid,
-.was-validated .input-group .form-select:valid,
-.input-group .form-select.is-valid {
- z-index: 1;
-}
-.was-validated .input-group .form-control:valid:focus, .input-group .form-control.is-valid:focus,
-.was-validated .input-group .form-select:valid:focus,
-.input-group .form-select.is-valid:focus {
+.was-validated .input-group > .form-control:not(:focus):valid, .input-group > .form-control:not(:focus).is-valid,
+.was-validated .input-group > .form-select:not(:focus):valid,
+.input-group > .form-select:not(:focus).is-valid,
+.was-validated .input-group > .form-floating:not(:focus-within):valid,
+.input-group > .form-floating:not(:focus-within).is-valid {
z-index: 3;
}
@@ -2792,15 +2793,12 @@ textarea.form-control-lg {
margin-left: 0.5em;
}
-.was-validated .input-group .form-control:invalid, .input-group .form-control.is-invalid,
-.was-validated .input-group .form-select:invalid,
-.input-group .form-select.is-invalid {
- z-index: 2;
-}
-.was-validated .input-group .form-control:invalid:focus, .input-group .form-control.is-invalid:focus,
-.was-validated .input-group .form-select:invalid:focus,
-.input-group .form-select.is-invalid:focus {
- z-index: 3;
+.was-validated .input-group > .form-control:not(:focus):invalid, .input-group > .form-control:not(:focus).is-invalid,
+.was-validated .input-group > .form-select:not(:focus):invalid,
+.input-group > .form-select:not(:focus).is-invalid,
+.was-validated .input-group > .form-floating:not(:focus-within):invalid,
+.input-group > .form-floating:not(:focus-within).is-invalid {
+ z-index: 4;
}
.btn {
@@ -2815,6 +2813,7 @@ textarea.form-control-lg {
--bs-btn-border-width: 1px;
--bs-btn-border-color: transparent;
--bs-btn-border-radius: 0.375rem;
+ --bs-btn-hover-border-color: transparent;
--bs-btn-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.15), 0 1px 1px rgba(0, 0, 0, 0.075);
--bs-btn-disabled-opacity: 0.65;
--bs-btn-focus-box-shadow: 0 0 0 0.25rem rgba(var(--bs-btn-focus-shadow-rgb), .5);
@@ -2847,19 +2846,29 @@ textarea.form-control-lg {
background-color: var(--bs-btn-hover-bg);
border-color: var(--bs-btn-hover-border-color);
}
-.btn-check:focus + .btn, .btn:focus {
+.btn-check + .btn:hover {
+ color: var(--bs-btn-color);
+ background-color: var(--bs-btn-bg);
+ border-color: var(--bs-btn-border-color);
+}
+.btn:focus-visible {
color: var(--bs-btn-hover-color);
background-color: var(--bs-btn-hover-bg);
border-color: var(--bs-btn-hover-border-color);
outline: 0;
box-shadow: var(--bs-btn-focus-box-shadow);
}
-.btn-check:checked + .btn, .btn-check:active + .btn, .btn:active, .btn.active, .btn.show {
+.btn-check:focus-visible + .btn {
+ border-color: var(--bs-btn-hover-border-color);
+ outline: 0;
+ box-shadow: var(--bs-btn-focus-box-shadow);
+}
+.btn-check:checked + .btn, :not(.btn-check) + .btn:active, .btn:first-child:active, .btn.active, .btn.show {
color: var(--bs-btn-active-color);
background-color: var(--bs-btn-active-bg);
border-color: var(--bs-btn-active-border-color);
}
-.btn-check:checked + .btn:focus, .btn-check:active + .btn:focus, .btn:active:focus, .btn.active:focus, .btn.show:focus {
+.btn-check:checked + .btn:focus-visible, :not(.btn-check) + .btn:active:focus-visible, .btn:first-child:active:focus-visible, .btn.active:focus-visible, .btn.show:focus-visible {
box-shadow: var(--bs-btn-focus-box-shadow);
}
.btn:disabled, .btn.disabled, fieldset:disabled .btn {
@@ -3157,7 +3166,7 @@ textarea.form-control-lg {
--bs-btn-focus-shadow-rgb: 49, 132, 253;
text-decoration: underline;
}
-.btn-link:focus {
+.btn-link:focus-visible {
color: var(--bs-btn-color);
}
.btn-link:hover {
@@ -3242,6 +3251,7 @@ textarea.form-control-lg {
}
.dropdown-menu {
+ --bs-dropdown-zindex: 1000;
--bs-dropdown-min-width: 10rem;
--bs-dropdown-padding-x: 0;
--bs-dropdown-padding-y: 0.5rem;
@@ -3268,7 +3278,7 @@ textarea.form-control-lg {
--bs-dropdown-header-padding-x: 1rem;
--bs-dropdown-header-padding-y: 0.5rem;
position: absolute;
- z-index: 1000;
+ z-index: var(--bs-dropdown-zindex);
display: none;
min-width: var(--bs-dropdown-min-width);
padding: var(--bs-dropdown-padding-y) var(--bs-dropdown-padding-x);
@@ -3568,7 +3578,7 @@ textarea.form-control-lg {
.btn-group {
border-radius: 0.375rem;
}
-.btn-group > .btn:not(:first-child),
+.btn-group > :not(.btn-check:first-child) + .btn,
.btn-group > .btn-group:not(:first-child) {
margin-left: -1px;
}
@@ -3678,7 +3688,7 @@ textarea.form-control-lg {
border-bottom: var(--bs-nav-tabs-border-width) solid var(--bs-nav-tabs-border-color);
}
.nav-tabs .nav-link {
- margin-bottom: calc(var(--bs-nav-tabs-border-width) * -1);
+ margin-bottom: calc(-1 * var(--bs-nav-tabs-border-width));
background: none;
border: var(--bs-nav-tabs-border-width) solid transparent;
border-top-left-radius: var(--bs-nav-tabs-border-radius);
@@ -3700,7 +3710,7 @@ textarea.form-control-lg {
border-color: var(--bs-nav-tabs-link-active-border-color);
}
.nav-tabs .dropdown-menu {
- margin-top: calc(var(--bs-nav-tabs-border-width) * -1);
+ margin-top: calc(-1 * var(--bs-nav-tabs-border-width));
border-top-left-radius: 0;
border-top-right-radius: 0;
}
@@ -4357,7 +4367,7 @@ textarea.form-control-lg {
}
.accordion {
- --bs-accordion-color: #000;
+ --bs-accordion-color: #212529;
--bs-accordion-bg: #fff;
--bs-accordion-transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, border-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out, border-radius 0.15s ease;
--bs-accordion-border-color: var(--bs-border-color);
@@ -4366,9 +4376,9 @@ textarea.form-control-lg {
--bs-accordion-inner-border-radius: calc(0.375rem - 1px);
--bs-accordion-btn-padding-x: 1.25rem;
--bs-accordion-btn-padding-y: 1rem;
- --bs-accordion-btn-color: var(--bs-body-color);
+ --bs-accordion-btn-color: #212529;
--bs-accordion-btn-bg: var(--bs-accordion-bg);
- --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='var%28--bs-body-color%29'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
+ --bs-accordion-btn-icon: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23212529'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");
--bs-accordion-btn-icon-width: 1.25rem;
--bs-accordion-btn-icon-transform: rotate(-180deg);
--bs-accordion-btn-icon-transition: transform 0.2s ease-in-out;
@@ -4404,7 +4414,7 @@ textarea.form-control-lg {
.accordion-button:not(.collapsed) {
color: var(--bs-accordion-active-color);
background-color: var(--bs-accordion-active-bg);
- box-shadow: inset 0 calc(var(--bs-accordion-border-width) * -1) 0 var(--bs-accordion-border-color);
+ box-shadow: inset 0 calc(-1 * var(--bs-accordion-border-width)) 0 var(--bs-accordion-border-color);
}
.accordion-button:not(.collapsed)::after {
background-image: var(--bs-accordion-btn-active-icon);
@@ -4487,7 +4497,7 @@ textarea.form-control-lg {
.accordion-flush .accordion-item:last-child {
border-bottom: 0;
}
-.accordion-flush .accordion-item .accordion-button {
+.accordion-flush .accordion-item .accordion-button, .accordion-flush .accordion-item .accordion-button.collapsed {
border-radius: 0;
}
@@ -4753,12 +4763,6 @@ textarea.form-control-lg {
color: #101214;
}
-@-webkit-keyframes progress-bar-stripes {
- 0% {
- background-position-x: 1rem;
- }
-}
-
@keyframes progress-bar-stripes {
0% {
background-position-x: 1rem;
@@ -4804,12 +4808,10 @@ textarea.form-control-lg {
}
.progress-bar-animated {
- -webkit-animation: 1s linear infinite progress-bar-stripes;
animation: 1s linear infinite progress-bar-stripes;
}
@media (prefers-reduced-motion: reduce) {
.progress-bar-animated {
- -webkit-animation: none;
animation: none;
}
}
@@ -4896,18 +4898,18 @@ textarea.form-control-lg {
border-top-width: 0;
}
.list-group-item + .list-group-item.active {
- margin-top: calc(var(--bs-list-group-border-width) * -1);
+ margin-top: calc(-1 * var(--bs-list-group-border-width));
border-top-width: var(--bs-list-group-border-width);
}
.list-group-horizontal {
flex-direction: row;
}
-.list-group-horizontal > .list-group-item:first-child {
+.list-group-horizontal > .list-group-item:first-child:not(:last-child) {
border-bottom-left-radius: var(--bs-list-group-border-radius);
border-top-right-radius: 0;
}
-.list-group-horizontal > .list-group-item:last-child {
+.list-group-horizontal > .list-group-item:last-child:not(:first-child) {
border-top-right-radius: var(--bs-list-group-border-radius);
border-bottom-left-radius: 0;
}
@@ -4919,7 +4921,7 @@ textarea.form-control-lg {
border-left-width: 0;
}
.list-group-horizontal > .list-group-item + .list-group-item.active {
- margin-left: calc(var(--bs-list-group-border-width) * -1);
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
border-left-width: var(--bs-list-group-border-width);
}
@@ -4927,11 +4929,11 @@ textarea.form-control-lg {
.list-group-horizontal-sm {
flex-direction: row;
}
- .list-group-horizontal-sm > .list-group-item:first-child {
+ .list-group-horizontal-sm > .list-group-item:first-child:not(:last-child) {
border-bottom-left-radius: var(--bs-list-group-border-radius);
border-top-right-radius: 0;
}
- .list-group-horizontal-sm > .list-group-item:last-child {
+ .list-group-horizontal-sm > .list-group-item:last-child:not(:first-child) {
border-top-right-radius: var(--bs-list-group-border-radius);
border-bottom-left-radius: 0;
}
@@ -4943,7 +4945,7 @@ textarea.form-control-lg {
border-left-width: 0;
}
.list-group-horizontal-sm > .list-group-item + .list-group-item.active {
- margin-left: calc(var(--bs-list-group-border-width) * -1);
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
border-left-width: var(--bs-list-group-border-width);
}
}
@@ -4951,11 +4953,11 @@ textarea.form-control-lg {
.list-group-horizontal-md {
flex-direction: row;
}
- .list-group-horizontal-md > .list-group-item:first-child {
+ .list-group-horizontal-md > .list-group-item:first-child:not(:last-child) {
border-bottom-left-radius: var(--bs-list-group-border-radius);
border-top-right-radius: 0;
}
- .list-group-horizontal-md > .list-group-item:last-child {
+ .list-group-horizontal-md > .list-group-item:last-child:not(:first-child) {
border-top-right-radius: var(--bs-list-group-border-radius);
border-bottom-left-radius: 0;
}
@@ -4967,7 +4969,7 @@ textarea.form-control-lg {
border-left-width: 0;
}
.list-group-horizontal-md > .list-group-item + .list-group-item.active {
- margin-left: calc(var(--bs-list-group-border-width) * -1);
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
border-left-width: var(--bs-list-group-border-width);
}
}
@@ -4975,11 +4977,11 @@ textarea.form-control-lg {
.list-group-horizontal-lg {
flex-direction: row;
}
- .list-group-horizontal-lg > .list-group-item:first-child {
+ .list-group-horizontal-lg > .list-group-item:first-child:not(:last-child) {
border-bottom-left-radius: var(--bs-list-group-border-radius);
border-top-right-radius: 0;
}
- .list-group-horizontal-lg > .list-group-item:last-child {
+ .list-group-horizontal-lg > .list-group-item:last-child:not(:first-child) {
border-top-right-radius: var(--bs-list-group-border-radius);
border-bottom-left-radius: 0;
}
@@ -4991,7 +4993,7 @@ textarea.form-control-lg {
border-left-width: 0;
}
.list-group-horizontal-lg > .list-group-item + .list-group-item.active {
- margin-left: calc(var(--bs-list-group-border-width) * -1);
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
border-left-width: var(--bs-list-group-border-width);
}
}
@@ -4999,11 +5001,11 @@ textarea.form-control-lg {
.list-group-horizontal-xl {
flex-direction: row;
}
- .list-group-horizontal-xl > .list-group-item:first-child {
+ .list-group-horizontal-xl > .list-group-item:first-child:not(:last-child) {
border-bottom-left-radius: var(--bs-list-group-border-radius);
border-top-right-radius: 0;
}
- .list-group-horizontal-xl > .list-group-item:last-child {
+ .list-group-horizontal-xl > .list-group-item:last-child:not(:first-child) {
border-top-right-radius: var(--bs-list-group-border-radius);
border-bottom-left-radius: 0;
}
@@ -5015,7 +5017,7 @@ textarea.form-control-lg {
border-left-width: 0;
}
.list-group-horizontal-xl > .list-group-item + .list-group-item.active {
- margin-left: calc(var(--bs-list-group-border-width) * -1);
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
border-left-width: var(--bs-list-group-border-width);
}
}
@@ -5023,11 +5025,11 @@ textarea.form-control-lg {
.list-group-horizontal-xxl {
flex-direction: row;
}
- .list-group-horizontal-xxl > .list-group-item:first-child {
+ .list-group-horizontal-xxl > .list-group-item:first-child:not(:last-child) {
border-bottom-left-radius: var(--bs-list-group-border-radius);
border-top-right-radius: 0;
}
- .list-group-horizontal-xxl > .list-group-item:last-child {
+ .list-group-horizontal-xxl > .list-group-item:last-child:not(:first-child) {
border-top-right-radius: var(--bs-list-group-border-radius);
border-bottom-left-radius: 0;
}
@@ -5039,7 +5041,7 @@ textarea.form-control-lg {
border-left-width: 0;
}
.list-group-horizontal-xxl > .list-group-item + .list-group-item.active {
- margin-left: calc(var(--bs-list-group-border-width) * -1);
+ margin-left: calc(-1 * var(--bs-list-group-border-width));
border-left-width: var(--bs-list-group-border-width);
}
}
@@ -5199,6 +5201,7 @@ textarea.form-control-lg {
}
.toast {
+ --bs-toast-zindex: 1090;
--bs-toast-padding-x: 0.75rem;
--bs-toast-padding-y: 0.5rem;
--bs-toast-spacing: 1.5rem;
@@ -5232,8 +5235,9 @@ textarea.form-control-lg {
}
.toast-container {
+ --bs-toast-zindex: 1090;
position: absolute;
- z-index: 1090;
+ z-index: var(--bs-toast-zindex);
width: -webkit-max-content;
width: -moz-max-content;
width: max-content;
@@ -5256,7 +5260,7 @@ textarea.form-control-lg {
border-top-right-radius: calc(var(--bs-toast-border-radius) - var(--bs-toast-border-width));
}
.toast-header .btn-close {
- margin-right: calc(var(--bs-toast-padding-x) * -0.5);
+ margin-right: calc(-0.5 * var(--bs-toast-padding-x));
margin-left: var(--bs-toast-padding-x);
}
@@ -5383,7 +5387,7 @@ textarea.form-control-lg {
}
.modal-header .btn-close {
padding: calc(var(--bs-modal-header-padding-y) * 0.5) calc(var(--bs-modal-header-padding-x) * 0.5);
- margin: calc(var(--bs-modal-header-padding-y) * -0.5) calc(var(--bs-modal-header-padding-x) * -0.5) calc(var(--bs-modal-header-padding-y) * -0.5) auto;
+ margin: calc(-0.5 * var(--bs-modal-header-padding-y)) calc(-0.5 * var(--bs-modal-header-padding-x)) calc(-0.5 * var(--bs-modal-header-padding-y)) auto;
}
.modal-title {
@@ -5673,7 +5677,7 @@ textarea.form-control-lg {
--bs-popover-header-padding-x: 1rem;
--bs-popover-header-padding-y: 0.5rem;
--bs-popover-header-font-size: 1rem;
- --bs-popover-header-color: var(--bs-heading-color);
+ --bs-popover-header-color: ;
--bs-popover-header-bg: #f0f0f0;
--bs-popover-body-padding-x: 1rem;
--bs-popover-body-padding-y: 1rem;
@@ -5720,7 +5724,7 @@ textarea.form-control-lg {
}
.bs-popover-top > .popover-arrow, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow {
- bottom: calc(var(--bs-popover-arrow-height) * -1 - var(--bs-popover-border-width));
+ bottom: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));
}
.bs-popover-top > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::before, .bs-popover-top > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=top] > .popover-arrow::after {
border-width: var(--bs-popover-arrow-height) calc(var(--bs-popover-arrow-width) * 0.5) 0;
@@ -5736,7 +5740,7 @@ textarea.form-control-lg {
/* rtl:begin:ignore */
.bs-popover-end > .popover-arrow, .bs-popover-auto[data-popper-placement^=right] > .popover-arrow {
- left: calc(var(--bs-popover-arrow-height) * -1 - var(--bs-popover-border-width));
+ left: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));
width: var(--bs-popover-arrow-height);
height: var(--bs-popover-arrow-width);
}
@@ -5754,7 +5758,7 @@ textarea.form-control-lg {
/* rtl:end:ignore */
.bs-popover-bottom > .popover-arrow, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow {
- top: calc(var(--bs-popover-arrow-height) * -1 - var(--bs-popover-border-width));
+ top: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));
}
.bs-popover-bottom > .popover-arrow::before, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::before, .bs-popover-bottom > .popover-arrow::after, .bs-popover-auto[data-popper-placement^=bottom] > .popover-arrow::after {
border-width: 0 calc(var(--bs-popover-arrow-width) * 0.5) var(--bs-popover-arrow-height);
@@ -5773,14 +5777,14 @@ textarea.form-control-lg {
left: 50%;
display: block;
width: var(--bs-popover-arrow-width);
- margin-left: calc(var(--bs-popover-arrow-width) * -0.5);
+ margin-left: calc(-0.5 * var(--bs-popover-arrow-width));
content: "";
border-bottom: var(--bs-popover-border-width) solid var(--bs-popover-header-bg);
}
/* rtl:begin:ignore */
.bs-popover-start > .popover-arrow, .bs-popover-auto[data-popper-placement^=left] > .popover-arrow {
- right: calc(var(--bs-popover-arrow-height) * -1 - var(--bs-popover-border-width));
+ right: calc(-1 * (var(--bs-popover-arrow-height)) - var(--bs-popover-border-width));
width: var(--bs-popover-arrow-height);
height: var(--bs-popover-arrow-width);
}
@@ -5857,7 +5861,6 @@ textarea.form-control-lg {
display: block;
}
-/* rtl:begin:ignore */
.carousel-item-next:not(.carousel-item-start),
.active.carousel-item-end {
transform: translateX(100%);
@@ -5868,7 +5871,6 @@ textarea.form-control-lg {
transform: translateX(-100%);
}
-/* rtl:end:ignore */
.carousel-fade .carousel-item {
opacity: 0;
transition-property: opacity;
@@ -6030,16 +6032,9 @@ textarea.form-control-lg {
height: var(--bs-spinner-height);
vertical-align: var(--bs-spinner-vertical-align);
border-radius: 50%;
- -webkit-animation: var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name);
animation: var(--bs-spinner-animation-speed) linear infinite var(--bs-spinner-animation-name);
}
-@-webkit-keyframes spinner-border {
- to {
- transform: rotate(360deg) /* rtl:ignore */;
- }
-}
-
@keyframes spinner-border {
to {
transform: rotate(360deg) /* rtl:ignore */;
@@ -6062,16 +6057,6 @@ textarea.form-control-lg {
--bs-spinner-border-width: 0.2em;
}
-@-webkit-keyframes spinner-grow {
- 0% {
- transform: scale(0);
- }
- 50% {
- opacity: 1;
- transform: none;
- }
-}
-
@keyframes spinner-grow {
0% {
transform: scale(0);
@@ -6103,6 +6088,7 @@ textarea.form-control-lg {
}
}
.offcanvas, .offcanvas-xxl, .offcanvas-xl, .offcanvas-lg, .offcanvas-md, .offcanvas-sm {
+ --bs-offcanvas-zindex: 1045;
--bs-offcanvas-width: 400px;
--bs-offcanvas-height: 30vh;
--bs-offcanvas-padding-x: 1rem;
@@ -6118,7 +6104,7 @@ textarea.form-control-lg {
.offcanvas-sm {
position: fixed;
bottom: 0;
- z-index: 1045;
+ z-index: var(--bs-offcanvas-zindex);
display: flex;
flex-direction: column;
max-width: 100%;
@@ -6206,7 +6192,7 @@ textarea.form-control-lg {
.offcanvas-md {
position: fixed;
bottom: 0;
- z-index: 1045;
+ z-index: var(--bs-offcanvas-zindex);
display: flex;
flex-direction: column;
max-width: 100%;
@@ -6294,7 +6280,7 @@ textarea.form-control-lg {
.offcanvas-lg {
position: fixed;
bottom: 0;
- z-index: 1045;
+ z-index: var(--bs-offcanvas-zindex);
display: flex;
flex-direction: column;
max-width: 100%;
@@ -6382,7 +6368,7 @@ textarea.form-control-lg {
.offcanvas-xl {
position: fixed;
bottom: 0;
- z-index: 1045;
+ z-index: var(--bs-offcanvas-zindex);
display: flex;
flex-direction: column;
max-width: 100%;
@@ -6470,7 +6456,7 @@ textarea.form-control-lg {
.offcanvas-xxl {
position: fixed;
bottom: 0;
- z-index: 1045;
+ z-index: var(--bs-offcanvas-zindex);
display: flex;
flex-direction: column;
max-width: 100%;
@@ -6557,7 +6543,7 @@ textarea.form-control-lg {
.offcanvas {
position: fixed;
bottom: 0;
- z-index: 1045;
+ z-index: var(--bs-offcanvas-zindex);
display: flex;
flex-direction: column;
max-width: 100%;
@@ -6635,9 +6621,9 @@ textarea.form-control-lg {
}
.offcanvas-header .btn-close {
padding: calc(var(--bs-offcanvas-padding-y) * 0.5) calc(var(--bs-offcanvas-padding-x) * 0.5);
- margin-top: calc(var(--bs-offcanvas-padding-y) * -0.5);
- margin-right: calc(var(--bs-offcanvas-padding-x) * -0.5);
- margin-bottom: calc(var(--bs-offcanvas-padding-y) * -0.5);
+ margin-top: calc(-0.5 * var(--bs-offcanvas-padding-y));
+ margin-right: calc(-0.5 * var(--bs-offcanvas-padding-x));
+ margin-bottom: calc(-0.5 * var(--bs-offcanvas-padding-y));
}
.offcanvas-title {
@@ -6677,16 +6663,9 @@ textarea.form-control-lg {
}
.placeholder-glow .placeholder {
- -webkit-animation: placeholder-glow 2s ease-in-out infinite;
animation: placeholder-glow 2s ease-in-out infinite;
}
-@-webkit-keyframes placeholder-glow {
- 50% {
- opacity: 0.2;
- }
-}
-
@keyframes placeholder-glow {
50% {
opacity: 0.2;
@@ -6697,17 +6676,9 @@ textarea.form-control-lg {
mask-image: linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);
-webkit-mask-size: 200% 100%;
mask-size: 200% 100%;
- -webkit-animation: placeholder-wave 2s linear infinite;
animation: placeholder-wave 2s linear infinite;
}
-@-webkit-keyframes placeholder-wave {
- 100% {
- -webkit-mask-position: -200% 0%;
- mask-position: -200% 0%;
- }
-}
-
@keyframes placeholder-wave {
100% {
-webkit-mask-position: -200% 0%;
diff --git a/src/static/scripts/datatables.css b/src/static/scripts/datatables.css
@@ -4,10 +4,10 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
- * https://datatables.net/download/#bs5/dt-1.12.1
+ * https://datatables.net/download/#bs5/dt-1.13.1
*
* Included libraries:
- * DataTables 1.12.1
+ * DataTables 1.13.1
*/
@charset "UTF-8";
@@ -63,7 +63,7 @@ table.dataTable thead > tr > td.sorting_desc_disabled:after {
opacity: 0.125;
right: 10px;
line-height: 9px;
- font-size: 0.9em;
+ font-size: 0.8em;
}
table.dataTable thead > tr > th.sorting:before, table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:before, table.dataTable thead > tr > th.sorting_asc_disabled:before, table.dataTable thead > tr > th.sorting_desc_disabled:before,
table.dataTable thead > tr > td.sorting:before,
@@ -72,7 +72,7 @@ table.dataTable thead > tr > td.sorting_desc:before,
table.dataTable thead > tr > td.sorting_asc_disabled:before,
table.dataTable thead > tr > td.sorting_desc_disabled:before {
bottom: 50%;
- content: "â–´";
+ content: "â–²";
}
table.dataTable thead > tr > th.sorting:after, table.dataTable thead > tr > th.sorting_asc:after, table.dataTable thead > tr > th.sorting_desc:after, table.dataTable thead > tr > th.sorting_asc_disabled:after, table.dataTable thead > tr > th.sorting_desc_disabled:after,
table.dataTable thead > tr > td.sorting:after,
@@ -81,7 +81,7 @@ table.dataTable thead > tr > td.sorting_desc:after,
table.dataTable thead > tr > td.sorting_asc_disabled:after,
table.dataTable thead > tr > td.sorting_desc_disabled:after {
top: 50%;
- content: "â–¾";
+ content: "â–¼";
}
table.dataTable thead > tr > th.sorting_asc:before, table.dataTable thead > tr > th.sorting_desc:after,
table.dataTable thead > tr > td.sorting_asc:before,
@@ -287,6 +287,9 @@ table.dataTable > tbody > tr.selected > * {
box-shadow: inset 0 0 0 9999px rgba(13, 110, 253, 0.9);
color: white;
}
+table.dataTable > tbody > tr.selected a {
+ color: #090a0b;
+}
table.dataTable.table-striped > tbody > tr.odd > * {
box-shadow: inset 0 0 0 9999px rgba(0, 0, 0, 0.05);
}
@@ -335,6 +338,9 @@ div.dataTables_wrapper div.dataTables_paginate ul.pagination {
white-space: nowrap;
justify-content: flex-end;
}
+div.dataTables_wrapper div.dt-row {
+ position: relative;
+}
div.dataTables_scrollHead table.dataTable {
margin-bottom: 0 !important;
diff --git a/src/static/scripts/datatables.js b/src/static/scripts/datatables.js
@@ -4,20 +4,20 @@
*
* To rebuild or modify this file with the latest versions of the included
* software please visit:
- * https://datatables.net/download/#bs5/dt-1.12.1
+ * https://datatables.net/download/#bs5/dt-1.13.1
*
* Included libraries:
- * DataTables 1.12.1
+ * DataTables 1.13.1
*/
-/*! DataTables 1.12.1
+/*! DataTables 1.13.1
* ©2008-2022 SpryMedia Ltd - datatables.net/license
*/
/**
* @summary DataTables
* @description Paginate, search and order HTML tables
- * @version 1.12.1
+ * @version 1.13.1
* @author SpryMedia Ltd
* @contact www.datatables.net
* @copyright SpryMedia Ltd.
@@ -1162,6 +1162,10 @@
$( rowOne[0] ).children('th, td').each( function (i, cell) {
var col = oSettings.aoColumns[i];
+ if (! col) {
+ _fnLog( oSettings, 0, 'Incorrect column count', 18 );
+ }
+
if ( col.mData === i ) {
var sort = a( cell, 'sort' ) || a( cell, 'order' );
var filter = a( cell, 'filter' ) || a( cell, 'search' );
@@ -3166,6 +3170,11 @@
create = nTrIn ? false : true;
nTd = create ? document.createElement( oCol.sCellType ) : anTds[i];
+
+ if (! nTd) {
+ _fnLog( oSettings, 0, 'Incorrect column count', 18 );
+ }
+
nTd._DT_CellIndex = {
row: iRow,
column: i
@@ -3316,10 +3325,16 @@
for ( i=0, ien=cells.length ; i<ien ; i++ ) {
column = columns[i];
- column.nTf = cells[i].cell;
- if ( column.sClass ) {
- $(column.nTf).addClass( column.sClass );
+ if (column) {
+ column.nTf = cells[i].cell;
+
+ if ( column.sClass ) {
+ $(column.nTf).addClass( column.sClass );
+ }
+ }
+ else {
+ _fnLog( oSettings, 0, 'Incorrect column count', 18 );
}
}
}
@@ -5079,6 +5094,10 @@
_fnDraw( settings );
}
}
+ else {
+ // No change event - paging was called, but no change
+ _fnCallbackFire( settings, null, 'page-nc', [settings] );
+ }
return changed;
}
@@ -8334,8 +8353,12 @@
$(document).on('plugin-init.dt', function (e, context) {
var api = new _Api( context );
+
+ const namespace = 'on-plugin-init';
+ const stateSaveParamsEvent = `stateSaveParams.${namespace}`;
+ const destroyEvent = `destroy.${namespace}`;
- api.on( 'stateSaveParams', function ( e, settings, d ) {
+ api.on( stateSaveParamsEvent, function ( e, settings, d ) {
// This could be more compact with the API, but it is a lot faster as a simple
// internal loop
var idFn = settings.rowIdFn;
@@ -8349,7 +8372,11 @@
}
d.childRows = ids;
- })
+ });
+
+ api.on( destroyEvent, function () {
+ api.off(`${stateSaveParamsEvent} ${destroyEvent}`);
+ });
var loaded = api.state.loaded();
@@ -9670,7 +9697,7 @@
* @type string
* @default Version number
*/
- DataTable.version = "1.12.1";
+ DataTable.version = "1.13.1";
/**
* Private data store, containing all of the settings objects that are
@@ -14094,7 +14121,7 @@
*
* @type string
*/
- build:"bs5/dt-1.12.1",
+ build:"bs5/dt-1.13.1",
/**
@@ -14732,7 +14759,7 @@
var classes = settings.oClasses;
var lang = settings.oLanguage.oPaginate;
var aria = settings.oLanguage.oAria.paginate || {};
- var btnDisplay, btnClass, counter=0;
+ var btnDisplay, btnClass;
var attach = function( container, buttons ) {
var i, ien, node, button, tabIndex;
@@ -14807,7 +14834,7 @@
'class': classes.sPageButton+' '+btnClass,
'aria-controls': settings.sTableId,
'aria-label': aria[ button ],
- 'data-dt-idx': counter,
+ 'data-dt-idx': button,
'tabindex': tabIndex,
'id': idx === 0 && typeof button === 'string' ?
settings.sTableId +'_'+ button :
@@ -14819,8 +14846,6 @@
_fnBindAction(
node, {action: button}, clickHandler
);
-
- counter++;
}
}
}
@@ -15165,7 +15190,7 @@
}
}
else if (window.luxon) {
- dt = format
+ dt = format && typeof d === 'string'
? window.luxon.DateTime.fromFormat( d, format )
: window.luxon.DateTime.fromISO( d );
@@ -15587,7 +15612,7 @@
$.each( DataTable, function ( prop, val ) {
$.fn.DataTable[ prop ] = val;
} );
-
+
return DataTable;
}));
@@ -15596,14 +15621,6 @@
* 2020 SpryMedia Ltd - datatables.net/license
*/
-/**
- * DataTables integration for Bootstrap 4. This requires Bootstrap 5 and
- * DataTables 1.10 or newer.
- *
- * This file sets the defaults and adds options to DataTables to style its
- * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
- * for further information.
- */
(function( factory ){
if ( typeof define === 'function' && define.amd ) {
// AMD
@@ -15615,16 +15632,22 @@
// CommonJS
module.exports = function (root, $) {
if ( ! root ) {
+ // CommonJS environments without a window global must pass a
+ // root. This will give an error otherwise
root = window;
}
- if ( ! $ || ! $.fn.dataTable ) {
- // Require DataTables, which attaches to jQuery, including
- // jQuery if needed and have a $ property so we can access the
- // jQuery object that is used
- $ = require('datatables.net')(root, $).$;
+ if ( ! $ ) {
+ $ = typeof window !== 'undefined' ? // jQuery's factory checks for a global window
+ require('jquery') :
+ require('jquery')( root );
+ }
+
+ if ( ! $.fn.dataTable ) {
+ require('datatables.net')(root, $);
}
+
return factory( $, root, root.document );
};
}
@@ -15637,11 +15660,21 @@
var DataTable = $.fn.dataTable;
+
+/**
+ * DataTables integration for Bootstrap 5. This requires Bootstrap 5 and
+ * DataTables 1.10 or newer.
+ *
+ * This file sets the defaults and adds options to DataTables to style its
+ * controls using Bootstrap. See http://datatables.net/manual/styling/bootstrap
+ * for further information.
+ */
+
/* Set the defaults for DataTables initialisation */
$.extend( true, DataTable.defaults, {
dom:
"<'row'<'col-sm-12 col-md-6'l><'col-sm-12 col-md-6'f>>" +
- "<'row'<'col-sm-12'tr>>" +
+ "<'row dt-row'<'col-sm-12'tr>>" +
"<'row'<'col-sm-12 col-md-5'i><'col-sm-12 col-md-7'p>>",
renderer: 'bootstrap'
} );
@@ -15663,7 +15696,7 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
var classes = settings.oClasses;
var lang = settings.oLanguage.oPaginate;
var aria = settings.oLanguage.oAria.paginate || {};
- var btnDisplay, btnClass, counter=0;
+ var btnDisplay, btnClass;
var attach = function( container, buttons ) {
var i, ien, node, button;
@@ -15732,7 +15765,7 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
'href': '#',
'aria-controls': settings.sTableId,
'aria-label': aria[ button ],
- 'data-dt-idx': counter,
+ 'data-dt-idx': button,
'tabindex': settings.iTabIndex,
'class': 'page-link'
} )
@@ -15743,13 +15776,12 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
settings.oApi._fnBindAction(
node, {action: button}, clickHandler
);
-
- counter++;
}
}
}
};
+ var hostEl = $(host);
// IE9 throws an 'unknown error' if document.activeElement is used
// inside an iframe or frame.
var activeEl;
@@ -15759,17 +15791,26 @@ DataTable.ext.renderer.pageButton.bootstrap = function ( settings, host, idx, bu
// elements, focus is lost on the select button which is bad for
// accessibility. So we want to restore focus once the draw has
// completed
- activeEl = $(host).find(document.activeElement).data('dt-idx');
+ activeEl = hostEl.find(document.activeElement).data('dt-idx');
}
catch (e) {}
+ var paginationEl = hostEl.children('ul.pagination');
+
+ if (paginationEl.length) {
+ paginationEl.empty();
+ }
+ else {
+ paginationEl = hostEl.html('<ul/>').children('ul').addClass('pagination');
+ }
+
attach(
- $(host).empty().html('<ul class="pagination"/>').children('ul'),
+ paginationEl,
buttons
);
if ( activeEl !== undefined ) {
- $(host).find( '[data-dt-idx='+activeEl+']' ).trigger('focus');
+ hostEl.find('[data-dt-idx='+activeEl+']').trigger('focus');
}
};
diff --git a/src/static/scripts/identicon.js b/src/static/scripts/identicon.js
@@ -1,205 +0,0 @@
-/**
- * Identicon.js 2.3.3
- * http://github.com/stewartlord/identicon.js
- *
- * PNGLib required for PNG output
- * http://www.xarg.org/download/pnglib.js
- *
- * Copyright 2018, Stewart Lord
- * Released under the BSD license
- * http://www.opensource.org/licenses/bsd-license.php
- */
-
-(function() {
- var PNGlib;
- if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
- PNGlib = require('./pnglib');
- } else {
- PNGlib = window.PNGlib;
- }
-
- var Identicon = function(hash, options){
- if (typeof(hash) !== 'string' || hash.length < 15) {
- throw 'A hash of at least 15 characters is required.';
- }
-
- this.defaults = {
- background: [240, 240, 240, 255],
- margin: 0.08,
- size: 64,
- saturation: 0.7,
- brightness: 0.5,
- format: 'png'
- };
-
- this.options = typeof(options) === 'object' ? options : this.defaults;
-
- // backward compatibility with old constructor (hash, size, margin)
- if (typeof(arguments[1]) === 'number') { this.options.size = arguments[1]; }
- if (arguments[2]) { this.options.margin = arguments[2]; }
-
- this.hash = hash
- this.background = this.options.background || this.defaults.background;
- this.size = this.options.size || this.defaults.size;
- this.format = this.options.format || this.defaults.format;
- this.margin = this.options.margin !== undefined ? this.options.margin : this.defaults.margin;
-
- // foreground defaults to last 7 chars as hue at 70% saturation, 50% brightness
- var hue = parseInt(this.hash.substr(-7), 16) / 0xfffffff;
- var saturation = this.options.saturation || this.defaults.saturation;
- var brightness = this.options.brightness || this.defaults.brightness;
- this.foreground = this.options.foreground || this.hsl2rgb(hue, saturation, brightness);
- };
-
- Identicon.prototype = {
- background: null,
- foreground: null,
- hash: null,
- margin: null,
- size: null,
- format: null,
-
- image: function(){
- return this.isSvg()
- ? new Svg(this.size, this.foreground, this.background)
- : new PNGlib(this.size, this.size, 256);
- },
-
- render: function(){
- var image = this.image(),
- size = this.size,
- baseMargin = Math.floor(size * this.margin),
- cell = Math.floor((size - (baseMargin * 2)) / 5),
- margin = Math.floor((size - cell * 5) / 2),
- bg = image.color.apply(image, this.background),
- fg = image.color.apply(image, this.foreground);
-
- // the first 15 characters of the hash control the pixels (even/odd)
- // they are drawn down the middle first, then mirrored outwards
- var i, color;
- for (i = 0; i < 15; i++) {
- color = parseInt(this.hash.charAt(i), 16) % 2 ? bg : fg;
- if (i < 5) {
- this.rectangle(2 * cell + margin, i * cell + margin, cell, cell, color, image);
- } else if (i < 10) {
- this.rectangle(1 * cell + margin, (i - 5) * cell + margin, cell, cell, color, image);
- this.rectangle(3 * cell + margin, (i - 5) * cell + margin, cell, cell, color, image);
- } else if (i < 15) {
- this.rectangle(0 * cell + margin, (i - 10) * cell + margin, cell, cell, color, image);
- this.rectangle(4 * cell + margin, (i - 10) * cell + margin, cell, cell, color, image);
- }
- }
-
- return image;
- },
-
- rectangle: function(x, y, w, h, color, image){
- if (this.isSvg()) {
- image.rectangles.push({x: x, y: y, w: w, h: h, color: color});
- } else {
- var i, j;
- for (i = x; i < x + w; i++) {
- for (j = y; j < y + h; j++) {
- image.buffer[image.index(i, j)] = color;
- }
- }
- }
- },
-
- // adapted from: https://gist.github.com/aemkei/1325937
- hsl2rgb: function(h, s, b){
- h *= 6;
- s = [
- b += s *= b < .5 ? b : 1 - b,
- b - h % 1 * s * 2,
- b -= s *= 2,
- b,
- b + h % 1 * s,
- b + s
- ];
-
- return[
- s[ ~~h % 6 ] * 255, // red
- s[ (h|16) % 6 ] * 255, // green
- s[ (h|8) % 6 ] * 255 // blue
- ];
- },
-
- toString: function(raw){
- // backward compatibility with old toString, default to base64
- if (raw) {
- return this.render().getDump();
- } else {
- return this.render().getBase64();
- }
- },
-
- isSvg: function(){
- return this.format.match(/svg/i)
- }
- };
-
- var Svg = function(size, foreground, background){
- this.size = size;
- this.foreground = this.color.apply(this, foreground);
- this.background = this.color.apply(this, background);
- this.rectangles = [];
- };
-
- Svg.prototype = {
- size: null,
- foreground: null,
- background: null,
- rectangles: null,
-
- color: function(r, g, b, a){
- var values = [r, g, b].map(Math.round);
- values.push((a >= 0) && (a <= 255) ? a/255 : 1);
- return 'rgba(' + values.join(',') + ')';
- },
-
- getDump: function(){
- var i,
- xml,
- rect,
- fg = this.foreground,
- bg = this.background,
- stroke = this.size * 0.005;
-
- xml = "<svg xmlns='http://www.w3.org/2000/svg'"
- + " width='" + this.size + "' height='" + this.size + "'"
- + " style='background-color:" + bg + ";'>"
- + "<g style='fill:" + fg + "; stroke:" + fg + "; stroke-width:" + stroke + ";'>";
-
- for (i = 0; i < this.rectangles.length; i++) {
- rect = this.rectangles[i];
- if (rect.color == bg) continue;
- xml += "<rect "
- + " x='" + rect.x + "'"
- + " y='" + rect.y + "'"
- + " width='" + rect.w + "'"
- + " height='" + rect.h + "'"
- + "/>";
- }
- xml += "</g></svg>"
-
- return xml;
- },
-
- getBase64: function(){
- if ('function' === typeof btoa) {
- return btoa(this.getDump());
- } else if (Buffer) {
- return new Buffer(this.getDump(), 'binary').toString('base64');
- } else {
- throw 'Cannot generate base64 output';
- }
- }
- };
-
- if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') {
- module.exports = Identicon;
- } else {
- window.Identicon = Identicon;
- }
-})();
diff --git a/src/static/scripts/jdenticon.js b/src/static/scripts/jdenticon.js
@@ -0,0 +1,1462 @@
+/**
+ * Jdenticon 3.2.0
+ * http://jdenticon.com
+ *
+ * Built: 2022-08-07T11:23:11.640Z
+ *
+ * MIT License
+ *
+ * Copyright (c) 2014-2021 Daniel Mester Pirttijärvi
+ *
+ * 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 NONINFRINGEMENT. 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.
+ */
+
+(function (umdGlobal, factory) {
+ var jdenticon = factory(umdGlobal);
+
+ // Node.js
+ if (typeof module !== "undefined" && "exports" in module) {
+ module["exports"] = jdenticon;
+ }
+ // RequireJS
+ else if (typeof define === "function" && define["amd"]) {
+ define([], function () { return jdenticon; });
+ }
+ // No module loader
+ else {
+ umdGlobal["jdenticon"] = jdenticon;
+ }
+})(typeof self !== "undefined" ? self : this, function (umdGlobal) {
+'use strict';
+
+/**
+ * Parses a substring of the hash as a number.
+ * @param {number} startPosition
+ * @param {number=} octets
+ */
+function parseHex(hash, startPosition, octets) {
+ return parseInt(hash.substr(startPosition, octets), 16);
+}
+
+function decToHex(v) {
+ v |= 0; // Ensure integer value
+ return v < 0 ? "00" :
+ v < 16 ? "0" + v.toString(16) :
+ v < 256 ? v.toString(16) :
+ "ff";
+}
+
+function hueToRgb(m1, m2, h) {
+ h = h < 0 ? h + 6 : h > 6 ? h - 6 : h;
+ return decToHex(255 * (
+ h < 1 ? m1 + (m2 - m1) * h :
+ h < 3 ? m2 :
+ h < 4 ? m1 + (m2 - m1) * (4 - h) :
+ m1));
+}
+
+/**
+ * @param {string} color Color value to parse. Currently hexadecimal strings on the format #rgb[a] and #rrggbb[aa] are supported.
+ * @returns {string}
+ */
+function parseColor(color) {
+ if (/^#[0-9a-f]{3,8}$/i.test(color)) {
+ var result;
+ var colorLength = color.length;
+
+ if (colorLength < 6) {
+ var r = color[1],
+ g = color[2],
+ b = color[3],
+ a = color[4] || "";
+ result = "#" + r + r + g + g + b + b + a + a;
+ }
+ if (colorLength == 7 || colorLength > 8) {
+ result = color;
+ }
+
+ return result;
+ }
+}
+
+/**
+ * Converts a hexadecimal color to a CSS3 compatible color.
+ * @param {string} hexColor Color on the format "#RRGGBB" or "#RRGGBBAA"
+ * @returns {string}
+ */
+function toCss3Color(hexColor) {
+ var a = parseHex(hexColor, 7, 2);
+ var result;
+
+ if (isNaN(a)) {
+ result = hexColor;
+ } else {
+ var r = parseHex(hexColor, 1, 2),
+ g = parseHex(hexColor, 3, 2),
+ b = parseHex(hexColor, 5, 2);
+ result = "rgba(" + r + "," + g + "," + b + "," + (a / 255).toFixed(2) + ")";
+ }
+
+ return result;
+}
+
+/**
+ * Converts an HSL color to a hexadecimal RGB color.
+ * @param {number} hue Hue in range [0, 1]
+ * @param {number} saturation Saturation in range [0, 1]
+ * @param {number} lightness Lightness in range [0, 1]
+ * @returns {string}
+ */
+function hsl(hue, saturation, lightness) {
+ // Based on http://www.w3.org/TR/2011/REC-css3-color-20110607/#hsl-color
+ var result;
+
+ if (saturation == 0) {
+ var partialHex = decToHex(lightness * 255);
+ result = partialHex + partialHex + partialHex;
+ }
+ else {
+ var m2 = lightness <= 0.5 ? lightness * (saturation + 1) : lightness + saturation - lightness * saturation,
+ m1 = lightness * 2 - m2;
+ result =
+ hueToRgb(m1, m2, hue * 6 + 2) +
+ hueToRgb(m1, m2, hue * 6) +
+ hueToRgb(m1, m2, hue * 6 - 2);
+ }
+
+ return "#" + result;
+}
+
+/**
+ * Converts an HSL color to a hexadecimal RGB color. This function will correct the lightness for the "dark" hues
+ * @param {number} hue Hue in range [0, 1]
+ * @param {number} saturation Saturation in range [0, 1]
+ * @param {number} lightness Lightness in range [0, 1]
+ * @returns {string}
+ */
+function correctedHsl(hue, saturation, lightness) {
+ // The corrector specifies the perceived middle lightness for each hue
+ var correctors = [ 0.55, 0.5, 0.5, 0.46, 0.6, 0.55, 0.55 ],
+ corrector = correctors[(hue * 6 + 0.5) | 0];
+
+ // Adjust the input lightness relative to the corrector
+ lightness = lightness < 0.5 ? lightness * corrector * 2 : corrector + (lightness - 0.5) * (1 - corrector) * 2;
+
+ return hsl(hue, saturation, lightness);
+}
+
+/* global umdGlobal */
+
+// In the future we can replace `GLOBAL` with `globalThis`, but for now use the old school global detection for
+// backward compatibility.
+var GLOBAL = umdGlobal;
+
+/**
+ * @typedef {Object} ParsedConfiguration
+ * @property {number} colorSaturation
+ * @property {number} grayscaleSaturation
+ * @property {string} backColor
+ * @property {number} iconPadding
+ * @property {function(number):number} hue
+ * @property {function(number):number} colorLightness
+ * @property {function(number):number} grayscaleLightness
+ */
+
+var CONFIG_PROPERTIES = {
+ G/*GLOBAL*/: "jdenticon_config",
+ n/*MODULE*/: "config",
+};
+
+var rootConfigurationHolder = {};
+
+/**
+ * Defines the deprecated `config` property on the root Jdenticon object without printing a warning in the console
+ * when it is being used.
+ * @param {!Object} rootObject
+ */
+function defineConfigProperty(rootObject) {
+ rootConfigurationHolder = rootObject;
+}
+
+/**
+ * Sets a new icon style configuration. The new configuration is not merged with the previous one. *
+ * @param {Object} newConfiguration - New configuration object.
+ */
+function configure(newConfiguration) {
+ if (arguments.length) {
+ rootConfigurationHolder[CONFIG_PROPERTIES.n/*MODULE*/] = newConfiguration;
+ }
+ return rootConfigurationHolder[CONFIG_PROPERTIES.n/*MODULE*/];
+}
+
+/**
+ * Gets the normalized current Jdenticon color configuration. Missing fields have default values.
+ * @param {Object|number|undefined} paddingOrLocalConfig - Configuration passed to the called API method. A
+ * local configuration overrides the global configuration in it entirety. This parameter can for backward
+ * compatibility also contain a padding value. A padding value only overrides the global padding, not the
+ * entire global configuration.
+ * @param {number} defaultPadding - Padding used if no padding is specified in neither the configuration nor
+ * explicitly to the API method.
+ * @returns {ParsedConfiguration}
+ */
+function getConfiguration(paddingOrLocalConfig, defaultPadding) {
+ var configObject =
+ typeof paddingOrLocalConfig == "object" && paddingOrLocalConfig ||
+ rootConfigurationHolder[CONFIG_PROPERTIES.n/*MODULE*/] ||
+ GLOBAL[CONFIG_PROPERTIES.G/*GLOBAL*/] ||
+ { },
+
+ lightnessConfig = configObject["lightness"] || { },
+
+ // In versions < 2.1.0 there was no grayscale saturation -
+ // saturation was the color saturation.
+ saturation = configObject["saturation"] || { },
+ colorSaturation = "color" in saturation ? saturation["color"] : saturation,
+ grayscaleSaturation = saturation["grayscale"],
+
+ backColor = configObject["backColor"],
+ padding = configObject["padding"];
+
+ /**
+ * Creates a lightness range.
+ */
+ function lightness(configName, defaultRange) {
+ var range = lightnessConfig[configName];
+
+ // Check if the lightness range is an array-like object. This way we ensure the
+ // array contain two values at the same time.
+ if (!(range && range.length > 1)) {
+ range = defaultRange;
+ }
+
+ /**
+ * Gets a lightness relative the specified value in the specified lightness range.
+ */
+ return function (value) {
+ value = range[0] + value * (range[1] - range[0]);
+ return value < 0 ? 0 : value > 1 ? 1 : value;
+ };
+ }
+
+ /**
+ * Gets a hue allowed by the configured hue restriction,
+ * provided the originally computed hue.
+ */
+ function hueFunction(originalHue) {
+ var hueConfig = configObject["hues"];
+ var hue;
+
+ // Check if 'hues' is an array-like object. This way we also ensure that
+ // the array is not empty, which would mean no hue restriction.
+ if (hueConfig && hueConfig.length > 0) {
+ // originalHue is in the range [0, 1]
+ // Multiply with 0.999 to change the range to [0, 1) and then truncate the index.
+ hue = hueConfig[0 | (0.999 * originalHue * hueConfig.length)];
+ }
+
+ return typeof hue == "number" ?
+
+ // A hue was specified. We need to convert the hue from
+ // degrees on any turn - e.g. 746° is a perfectly valid hue -
+ // to turns in the range [0, 1).
+ ((((hue / 360) % 1) + 1) % 1) :
+
+ // No hue configured => use original hue
+ originalHue;
+ }
+
+ return {
+ X/*hue*/: hueFunction,
+ p/*colorSaturation*/: typeof colorSaturation == "number" ? colorSaturation : 0.5,
+ H/*grayscaleSaturation*/: typeof grayscaleSaturation == "number" ? grayscaleSaturation : 0,
+ q/*colorLightness*/: lightness("color", [0.4, 0.8]),
+ I/*grayscaleLightness*/: lightness("grayscale", [0.3, 0.9]),
+ J/*backColor*/: parseColor(backColor),
+ Y/*iconPadding*/:
+ typeof paddingOrLocalConfig == "number" ? paddingOrLocalConfig :
+ typeof padding == "number" ? padding :
+ defaultPadding
+ }
+}
+
+var ICON_TYPE_SVG = 1;
+
+var ICON_TYPE_CANVAS = 2;
+
+var ATTRIBUTES = {
+ t/*HASH*/: "data-jdenticon-hash",
+ o/*VALUE*/: "data-jdenticon-value"
+};
+
+var ICON_SELECTOR = "[" + ATTRIBUTES.t/*HASH*/ +"],[" + ATTRIBUTES.o/*VALUE*/ +"]";
+
+var documentQuerySelectorAll = /** @type {!Function} */ (
+ typeof document !== "undefined" && document.querySelectorAll.bind(document));
+
+function getIdenticonType(el) {
+ if (el) {
+ var tagName = el["tagName"];
+
+ if (/^svg$/i.test(tagName)) {
+ return ICON_TYPE_SVG;
+ }
+
+ if (/^canvas$/i.test(tagName) && "getContext" in el) {
+ return ICON_TYPE_CANVAS;
+ }
+ }
+}
+
+function observer(updateCallback) {
+ if (typeof MutationObserver != "undefined") {
+ var mutationObserver = new MutationObserver(function onmutation(mutations) {
+ for (var mutationIndex = 0; mutationIndex < mutations.length; mutationIndex++) {
+ var mutation = mutations[mutationIndex];
+ var addedNodes = mutation.addedNodes;
+
+ for (var addedNodeIndex = 0; addedNodes && addedNodeIndex < addedNodes.length; addedNodeIndex++) {
+ var addedNode = addedNodes[addedNodeIndex];
+
+ // Skip other types of nodes than element nodes, since they might not support
+ // the querySelectorAll method => runtime error.
+ if (addedNode.nodeType == 1) {
+ if (getIdenticonType(addedNode)) {
+ updateCallback(addedNode);
+ }
+ else {
+ var icons = /** @type {Element} */(addedNode).querySelectorAll(ICON_SELECTOR);
+ for (var iconIndex = 0; iconIndex < icons.length; iconIndex++) {
+ updateCallback(icons[iconIndex]);
+ }
+ }
+ }
+ }
+
+ if (mutation.type == "attributes" && getIdenticonType(mutation.target)) {
+ updateCallback(mutation.target);
+ }
+ }
+ });
+
+ mutationObserver.observe(document.body, {
+ "childList": true,
+ "attributes": true,
+ "attributeFilter": [ATTRIBUTES.o/*VALUE*/, ATTRIBUTES.t/*HASH*/, "width", "height"],
+ "subtree": true,
+ });
+ }
+}
+
+/**
+ * Represents a point.
+ */
+function Point(x, y) {
+ this.x = x;
+ this.y = y;
+}
+
+/**
+ * Translates and rotates a point before being passed on to the canvas context. This was previously done by the canvas context itself,
+ * but this caused a rendering issue in Chrome on sizes > 256 where the rotation transformation of inverted paths was not done properly.
+ */
+function Transform(x, y, size, rotation) {
+ this.u/*_x*/ = x;
+ this.v/*_y*/ = y;
+ this.K/*_size*/ = size;
+ this.Z/*_rotation*/ = rotation;
+}
+
+/**
+ * Transforms the specified point based on the translation and rotation specification for this Transform.
+ * @param {number} x x-coordinate
+ * @param {number} y y-coordinate
+ * @param {number=} w The width of the transformed rectangle. If greater than 0, this will ensure the returned point is of the upper left corner of the transformed rectangle.
+ * @param {number=} h The height of the transformed rectangle. If greater than 0, this will ensure the returned point is of the upper left corner of the transformed rectangle.
+ */
+Transform.prototype.L/*transformIconPoint*/ = function transformIconPoint (x, y, w, h) {
+ var right = this.u/*_x*/ + this.K/*_size*/,
+ bottom = this.v/*_y*/ + this.K/*_size*/,
+ rotation = this.Z/*_rotation*/;
+ return rotation === 1 ? new Point(right - y - (h || 0), this.v/*_y*/ + x) :
+ rotation === 2 ? new Point(right - x - (w || 0), bottom - y - (h || 0)) :
+ rotation === 3 ? new Point(this.u/*_x*/ + y, bottom - x - (w || 0)) :
+ new Point(this.u/*_x*/ + x, this.v/*_y*/ + y);
+};
+
+var NO_TRANSFORM = new Transform(0, 0, 0, 0);
+
+
+
+/**
+ * Provides helper functions for rendering common basic shapes.
+ */
+function Graphics(renderer) {
+ /**
+ * @type {Renderer}
+ * @private
+ */
+ this.M/*_renderer*/ = renderer;
+
+ /**
+ * @type {Transform}
+ */
+ this.A/*currentTransform*/ = NO_TRANSFORM;
+}
+var Graphics__prototype = Graphics.prototype;
+
+/**
+ * Adds a polygon to the underlying renderer.
+ * @param {Array<number>} points The points of the polygon clockwise on the format [ x0, y0, x1, y1, ..., xn, yn ]
+ * @param {boolean=} invert Specifies if the polygon will be inverted.
+ */
+Graphics__prototype.g/*addPolygon*/ = function addPolygon (points, invert) {
+ var this$1 = this;
+
+ var di = invert ? -2 : 2,
+ transformedPoints = [];
+
+ for (var i = invert ? points.length - 2 : 0; i < points.length && i >= 0; i += di) {
+ transformedPoints.push(this$1.A/*currentTransform*/.L/*transformIconPoint*/(points[i], points[i + 1]));
+ }
+
+ this.M/*_renderer*/.g/*addPolygon*/(transformedPoints);
+};
+
+/**
+ * Adds a polygon to the underlying renderer.
+ * Source: http://stackoverflow.com/a/2173084
+ * @param {number} x The x-coordinate of the upper left corner of the rectangle holding the entire ellipse.
+ * @param {number} y The y-coordinate of the upper left corner of the rectangle holding the entire ellipse.
+ * @param {number} size The size of the ellipse.
+ * @param {boolean=} invert Specifies if the ellipse will be inverted.
+ */
+Graphics__prototype.h/*addCircle*/ = function addCircle (x, y, size, invert) {
+ var p = this.A/*currentTransform*/.L/*transformIconPoint*/(x, y, size, size);
+ this.M/*_renderer*/.h/*addCircle*/(p, size, invert);
+};
+
+/**
+ * Adds a rectangle to the underlying renderer.
+ * @param {number} x The x-coordinate of the upper left corner of the rectangle.
+ * @param {number} y The y-coordinate of the upper left corner of the rectangle.
+ * @param {number} w The width of the rectangle.
+ * @param {number} h The height of the rectangle.
+ * @param {boolean=} invert Specifies if the rectangle will be inverted.
+ */
+Graphics__prototype.i/*addRectangle*/ = function addRectangle (x, y, w, h, invert) {
+ this.g/*addPolygon*/([
+ x, y,
+ x + w, y,
+ x + w, y + h,
+ x, y + h
+ ], invert);
+};
+
+/**
+ * Adds a right triangle to the underlying renderer.
+ * @param {number} x The x-coordinate of the upper left corner of the rectangle holding the triangle.
+ * @param {number} y The y-coordinate of the upper left corner of the rectangle holding the triangle.
+ * @param {number} w The width of the triangle.
+ * @param {number} h The height of the triangle.
+ * @param {number} r The rotation of the triangle (clockwise). 0 = right corner of the triangle in the lower left corner of the bounding rectangle.
+ * @param {boolean=} invert Specifies if the triangle will be inverted.
+ */
+Graphics__prototype.j/*addTriangle*/ = function addTriangle (x, y, w, h, r, invert) {
+ var points = [
+ x + w, y,
+ x + w, y + h,
+ x, y + h,
+ x, y
+ ];
+ points.splice(((r || 0) % 4) * 2, 2);
+ this.g/*addPolygon*/(points, invert);
+};
+
+/**
+ * Adds a rhombus to the underlying renderer.
+ * @param {number} x The x-coordinate of the upper left corner of the rectangle holding the rhombus.
+ * @param {number} y The y-coordinate of the upper left corner of the rectangle holding the rhombus.
+ * @param {number} w The width of the rhombus.
+ * @param {number} h The height of the rhombus.
+ * @param {boolean=} invert Specifies if the rhombus will be inverted.
+ */
+Graphics__prototype.N/*addRhombus*/ = function addRhombus (x, y, w, h, invert) {
+ this.g/*addPolygon*/([
+ x + w / 2, y,
+ x + w, y + h / 2,
+ x + w / 2, y + h,
+ x, y + h / 2
+ ], invert);
+};
+
+/**
+ * @param {number} index
+ * @param {Graphics} g
+ * @param {number} cell
+ * @param {number} positionIndex
+ */
+function centerShape(index, g, cell, positionIndex) {
+ index = index % 14;
+
+ var k, m, w, h, inner, outer;
+
+ !index ? (
+ k = cell * 0.42,
+ g.g/*addPolygon*/([
+ 0, 0,
+ cell, 0,
+ cell, cell - k * 2,
+ cell - k, cell,
+ 0, cell
+ ])) :
+
+ index == 1 ? (
+ w = 0 | (cell * 0.5),
+ h = 0 | (cell * 0.8),
+
+ g.j/*addTriangle*/(cell - w, 0, w, h, 2)) :
+
+ index == 2 ? (
+ w = 0 | (cell / 3),
+ g.i/*addRectangle*/(w, w, cell - w, cell - w)) :
+
+ index == 3 ? (
+ inner = cell * 0.1,
+ // Use fixed outer border widths in small icons to ensure the border is drawn
+ outer =
+ cell < 6 ? 1 :
+ cell < 8 ? 2 :
+ (0 | (cell * 0.25)),
+
+ inner =
+ inner > 1 ? (0 | inner) : // large icon => truncate decimals
+ inner > 0.5 ? 1 : // medium size icon => fixed width
+ inner, // small icon => anti-aliased border
+
+ g.i/*addRectangle*/(outer, outer, cell - inner - outer, cell - inner - outer)) :
+
+ index == 4 ? (
+ m = 0 | (cell * 0.15),
+ w = 0 | (cell * 0.5),
+ g.h/*addCircle*/(cell - w - m, cell - w - m, w)) :
+
+ index == 5 ? (
+ inner = cell * 0.1,
+ outer = inner * 4,
+
+ // Align edge to nearest pixel in large icons
+ outer > 3 && (outer = 0 | outer),
+
+ g.i/*addRectangle*/(0, 0, cell, cell),
+ g.g/*addPolygon*/([
+ outer, outer,
+ cell - inner, outer,
+ outer + (cell - outer - inner) / 2, cell - inner
+ ], true)) :
+
+ index == 6 ?
+ g.g/*addPolygon*/([
+ 0, 0,
+ cell, 0,
+ cell, cell * 0.7,
+ cell * 0.4, cell * 0.4,
+ cell * 0.7, cell,
+ 0, cell
+ ]) :
+
+ index == 7 ?
+ g.j/*addTriangle*/(cell / 2, cell / 2, cell / 2, cell / 2, 3) :
+
+ index == 8 ? (
+ g.i/*addRectangle*/(0, 0, cell, cell / 2),
+ g.i/*addRectangle*/(0, cell / 2, cell / 2, cell / 2),
+ g.j/*addTriangle*/(cell / 2, cell / 2, cell / 2, cell / 2, 1)) :
+
+ index == 9 ? (
+ inner = cell * 0.14,
+ // Use fixed outer border widths in small icons to ensure the border is drawn
+ outer =
+ cell < 4 ? 1 :
+ cell < 6 ? 2 :
+ (0 | (cell * 0.35)),
+
+ inner =
+ cell < 8 ? inner : // small icon => anti-aliased border
+ (0 | inner), // large icon => truncate decimals
+
+ g.i/*addRectangle*/(0, 0, cell, cell),
+ g.i/*addRectangle*/(outer, outer, cell - outer - inner, cell - outer - inner, true)) :
+
+ index == 10 ? (
+ inner = cell * 0.12,
+ outer = inner * 3,
+
+ g.i/*addRectangle*/(0, 0, cell, cell),
+ g.h/*addCircle*/(outer, outer, cell - inner - outer, true)) :
+
+ index == 11 ?
+ g.j/*addTriangle*/(cell / 2, cell / 2, cell / 2, cell / 2, 3) :
+
+ index == 12 ? (
+ m = cell * 0.25,
+ g.i/*addRectangle*/(0, 0, cell, cell),
+ g.N/*addRhombus*/(m, m, cell - m, cell - m, true)) :
+
+ // 13
+ (
+ !positionIndex && (
+ m = cell * 0.4, w = cell * 1.2,
+ g.h/*addCircle*/(m, m, w)
+ )
+ );
+}
+
+/**
+ * @param {number} index
+ * @param {Graphics} g
+ * @param {number} cell
+ */
+function outerShape(index, g, cell) {
+ index = index % 4;
+
+ var m;
+
+ !index ?
+ g.j/*addTriangle*/(0, 0, cell, cell, 0) :
+
+ index == 1 ?
+ g.j/*addTriangle*/(0, cell / 2, cell, cell / 2, 0) :
+
+ index == 2 ?
+ g.N/*addRhombus*/(0, 0, cell, cell) :
+
+ // 3
+ (
+ m = cell / 6,
+ g.h/*addCircle*/(m, m, cell - 2 * m)
+ );
+}
+
+/**
+ * Gets a set of identicon color candidates for a specified hue and config.
+ * @param {number} hue
+ * @param {ParsedConfiguration} config
+ */
+function colorTheme(hue, config) {
+ hue = config.X/*hue*/(hue);
+ return [
+ // Dark gray
+ correctedHsl(hue, config.H/*grayscaleSaturation*/, config.I/*grayscaleLightness*/(0)),
+ // Mid color
+ correctedHsl(hue, config.p/*colorSaturation*/, config.q/*colorLightness*/(0.5)),
+ // Light gray
+ correctedHsl(hue, config.H/*grayscaleSaturation*/, config.I/*grayscaleLightness*/(1)),
+ // Light color
+ correctedHsl(hue, config.p/*colorSaturation*/, config.q/*colorLightness*/(1)),
+ // Dark color
+ correctedHsl(hue, config.p/*colorSaturation*/, config.q/*colorLightness*/(0))
+ ];
+}
+
+/**
+ * Draws an identicon to a specified renderer.
+ * @param {Renderer} renderer
+ * @param {string} hash
+ * @param {Object|number=} config
+ */
+function iconGenerator(renderer, hash, config) {
+ var parsedConfig = getConfiguration(config, 0.08);
+
+ // Set background color
+ if (parsedConfig.J/*backColor*/) {
+ renderer.m/*setBackground*/(parsedConfig.J/*backColor*/);
+ }
+
+ // Calculate padding and round to nearest integer
+ var size = renderer.k/*iconSize*/;
+ var padding = (0.5 + size * parsedConfig.Y/*iconPadding*/) | 0;
+ size -= padding * 2;
+
+ var graphics = new Graphics(renderer);
+
+ // Calculate cell size and ensure it is an integer
+ var cell = 0 | (size / 4);
+
+ // Since the cell size is integer based, the actual icon will be slightly smaller than specified => center icon
+ var x = 0 | (padding + size / 2 - cell * 2);
+ var y = 0 | (padding + size / 2 - cell * 2);
+
+ function renderShape(colorIndex, shapes, index, rotationIndex, positions) {
+ var shapeIndex = parseHex(hash, index, 1);
+ var r = rotationIndex ? parseHex(hash, rotationIndex, 1) : 0;
+
+ renderer.O/*beginShape*/(availableColors[selectedColorIndexes[colorIndex]]);
+
+ for (var i = 0; i < positions.length; i++) {
+ graphics.A/*currentTransform*/ = new Transform(x + positions[i][0] * cell, y + positions[i][1] * cell, cell, r++ % 4);
+ shapes(shapeIndex, graphics, cell, i);
+ }
+
+ renderer.P/*endShape*/();
+ }
+
+ // AVAILABLE COLORS
+ var hue = parseHex(hash, -7) / 0xfffffff,
+
+ // Available colors for this icon
+ availableColors = colorTheme(hue, parsedConfig),
+
+ // The index of the selected colors
+ selectedColorIndexes = [];
+
+ var index;
+
+ function isDuplicate(values) {
+ if (values.indexOf(index) >= 0) {
+ for (var i = 0; i < values.length; i++) {
+ if (selectedColorIndexes.indexOf(values[i]) >= 0) {
+ return true;
+ }
+ }
+ }
+ }
+
+ for (var i = 0; i < 3; i++) {
+ index = parseHex(hash, 8 + i, 1) % availableColors.length;
+ if (isDuplicate([0, 4]) || // Disallow dark gray and dark color combo
+ isDuplicate([2, 3])) { // Disallow light gray and light color combo
+ index = 1;
+ }
+ selectedColorIndexes.push(index);
+ }
+
+ // ACTUAL RENDERING
+ // Sides
+ renderShape(0, outerShape, 2, 3, [[1, 0], [2, 0], [2, 3], [1, 3], [0, 1], [3, 1], [3, 2], [0, 2]]);
+ // Corners
+ renderShape(1, outerShape, 4, 5, [[0, 0], [3, 0], [3, 3], [0, 3]]);
+ // Center
+ renderShape(2, centerShape, 1, null, [[1, 1], [2, 1], [2, 2], [1, 2]]);
+
+ renderer.finish();
+}
+
+/**
+ * Computes a SHA1 hash for any value and returns it as a hexadecimal string.
+ *
+ * This function is optimized for minimal code size and rather short messages.
+ *
+ * @param {string} message
+ */
+function sha1(message) {
+ var HASH_SIZE_HALF_BYTES = 40;
+ var BLOCK_SIZE_WORDS = 16;
+
+ // Variables
+ // `var` is used to be able to minimize the number of `var` keywords.
+ var i = 0,
+ f = 0,
+
+ // Use `encodeURI` to UTF8 encode the message without any additional libraries
+ // We could use `unescape` + `encodeURI` to minimize the code, but that would be slightly risky
+ // since `unescape` is deprecated.
+ urlEncodedMessage = encodeURI(message) + "%80", // trailing '1' bit padding
+
+ // This can be changed to a preallocated Uint32Array array for greater performance and larger code size
+ data = [],
+ dataSize,
+
+ hashBuffer = [],
+
+ a = 0x67452301,
+ b = 0xefcdab89,
+ c = ~a,
+ d = ~b,
+ e = 0xc3d2e1f0,
+ hash = [a, b, c, d, e],
+
+ blockStartIndex = 0,
+ hexHash = "";
+
+ /**
+ * Rotates the value a specified number of bits to the left.
+ * @param {number} value Value to rotate
+ * @param {number} shift Bit count to shift.
+ */
+ function rotl(value, shift) {
+ return (value << shift) | (value >>> (32 - shift));
+ }
+
+ // Message data
+ for ( ; i < urlEncodedMessage.length; f++) {
+ data[f >> 2] = data[f >> 2] |
+ (
+ (
+ urlEncodedMessage[i] == "%"
+ // Percent encoded byte
+ ? parseInt(urlEncodedMessage.substring(i + 1, i += 3), 16)
+ // Unencoded byte
+ : urlEncodedMessage.charCodeAt(i++)
+ )
+
+ // Read bytes in reverse order (big endian words)
+ << ((3 - (f & 3)) * 8)
+ );
+ }
+
+ // f is now the length of the utf8 encoded message
+ // 7 = 8 bytes (64 bit) for message size, -1 to round down
+ // >> 6 = integer division with block size
+ dataSize = (((f + 7) >> 6) + 1) * BLOCK_SIZE_WORDS;
+
+ // Message size in bits.
+ // SHA1 uses a 64 bit integer to represent the size, but since we only support short messages only the least
+ // significant 32 bits are set. -8 is for the '1' bit padding byte.
+ data[dataSize - 1] = f * 8 - 8;
+
+ // Compute hash
+ for ( ; blockStartIndex < dataSize; blockStartIndex += BLOCK_SIZE_WORDS) {
+ for (i = 0; i < 80; i++) {
+ f = rotl(a, 5) + e + (
+ // Ch
+ i < 20 ? ((b & c) ^ ((~b) & d)) + 0x5a827999 :
+
+ // Parity
+ i < 40 ? (b ^ c ^ d) + 0x6ed9eba1 :
+
+ // Maj
+ i < 60 ? ((b & c) ^ (b & d) ^ (c & d)) + 0x8f1bbcdc :
+
+ // Parity
+ (b ^ c ^ d) + 0xca62c1d6
+ ) + (
+ hashBuffer[i] = i < BLOCK_SIZE_WORDS
+ // Bitwise OR is used to coerse `undefined` to 0
+ ? (data[blockStartIndex + i] | 0)
+ : rotl(hashBuffer[i - 3] ^ hashBuffer[i - 8] ^ hashBuffer[i - 14] ^ hashBuffer[i - 16], 1)
+ );
+
+ e = d;
+ d = c;
+ c = rotl(b, 30);
+ b = a;
+ a = f;
+ }
+
+ hash[0] = a = ((hash[0] + a) | 0);
+ hash[1] = b = ((hash[1] + b) | 0);
+ hash[2] = c = ((hash[2] + c) | 0);
+ hash[3] = d = ((hash[3] + d) | 0);
+ hash[4] = e = ((hash[4] + e) | 0);
+ }
+
+ // Format hex hash
+ for (i = 0; i < HASH_SIZE_HALF_BYTES; i++) {
+ hexHash += (
+ (
+ // Get word (2^3 half-bytes per word)
+ hash[i >> 3] >>>
+
+ // Append half-bytes in reverse order
+ ((7 - (i & 7)) * 4)
+ )
+ // Clamp to half-byte
+ & 0xf
+ ).toString(16);
+ }
+
+ return hexHash;
+}
+
+/**
+ * Inputs a value that might be a valid hash string for Jdenticon and returns it
+ * if it is determined valid, otherwise a falsy value is returned.
+ */
+function isValidHash(hashCandidate) {
+ return /^[0-9a-f]{11,}$/i.test(hashCandidate) && hashCandidate;
+}
+
+/**
+ * Computes a hash for the specified value. Currently SHA1 is used. This function
+ * always returns a valid hash.
+ */
+function computeHash(value) {
+ return sha1(value == null ? "" : "" + value);
+}
+
+
+
+/**
+ * Renderer redirecting drawing commands to a canvas context.
+ * @implements {Renderer}
+ */
+function CanvasRenderer(ctx, iconSize) {
+ var canvas = ctx.canvas;
+ var width = canvas.width;
+ var height = canvas.height;
+
+ ctx.save();
+
+ if (!iconSize) {
+ iconSize = Math.min(width, height);
+
+ ctx.translate(
+ ((width - iconSize) / 2) | 0,
+ ((height - iconSize) / 2) | 0);
+ }
+
+ /**
+ * @private
+ */
+ this.l/*_ctx*/ = ctx;
+ this.k/*iconSize*/ = iconSize;
+
+ ctx.clearRect(0, 0, iconSize, iconSize);
+}
+var CanvasRenderer__prototype = CanvasRenderer.prototype;
+
+/**
+ * Fills the background with the specified color.
+ * @param {string} fillColor Fill color on the format #rrggbb[aa].
+ */
+CanvasRenderer__prototype.m/*setBackground*/ = function setBackground (fillColor) {
+ var ctx = this.l/*_ctx*/;
+ var iconSize = this.k/*iconSize*/;
+
+ ctx.fillStyle = toCss3Color(fillColor);
+ ctx.fillRect(0, 0, iconSize, iconSize);
+};
+
+/**
+ * Marks the beginning of a new shape of the specified color. Should be ended with a call to endShape.
+ * @param {string} fillColor Fill color on format #rrggbb[aa].
+ */
+CanvasRenderer__prototype.O/*beginShape*/ = function beginShape (fillColor) {
+ var ctx = this.l/*_ctx*/;
+ ctx.fillStyle = toCss3Color(fillColor);
+ ctx.beginPath();
+};
+
+/**
+ * Marks the end of the currently drawn shape. This causes the queued paths to be rendered on the canvas.
+ */
+CanvasRenderer__prototype.P/*endShape*/ = function endShape () {
+ this.l/*_ctx*/.fill();
+};
+
+/**
+ * Adds a polygon to the rendering queue.
+ * @param points An array of Point objects.
+ */
+CanvasRenderer__prototype.g/*addPolygon*/ = function addPolygon (points) {
+ var ctx = this.l/*_ctx*/;
+ ctx.moveTo(points[0].x, points[0].y);
+ for (var i = 1; i < points.length; i++) {
+ ctx.lineTo(points[i].x, points[i].y);
+ }
+ ctx.closePath();
+};
+
+/**
+ * Adds a circle to the rendering queue.
+ * @param {Point} point The upper left corner of the circle bounding box.
+ * @param {number} diameter The diameter of the circle.
+ * @param {boolean} counterClockwise True if the circle is drawn counter-clockwise (will result in a hole if rendered on a clockwise path).
+ */
+CanvasRenderer__prototype.h/*addCircle*/ = function addCircle (point, diameter, counterClockwise) {
+ var ctx = this.l/*_ctx*/,
+ radius = diameter / 2;
+ ctx.moveTo(point.x + radius, point.y + radius);
+ ctx.arc(point.x + radius, point.y + radius, radius, 0, Math.PI * 2, counterClockwise);
+ ctx.closePath();
+};
+
+/**
+ * Called when the icon has been completely drawn.
+ */
+CanvasRenderer__prototype.finish = function finish () {
+ this.l/*_ctx*/.restore();
+};
+
+/**
+ * Draws an identicon to a context.
+ * @param {CanvasRenderingContext2D} ctx - Canvas context on which the icon will be drawn at location (0, 0).
+ * @param {*} hashOrValue - A hexadecimal hash string or any value that will be hashed by Jdenticon.
+ * @param {number} size - Icon size in pixels.
+ * @param {Object|number=} config - Optional configuration. If specified, this configuration object overrides any
+ * global configuration in its entirety. For backward compatibility a padding value in the range [0.0, 0.5) can be
+ * specified in place of a configuration object.
+ */
+function drawIcon(ctx, hashOrValue, size, config) {
+ if (!ctx) {
+ throw new Error("No canvas specified.");
+ }
+
+ iconGenerator(new CanvasRenderer(ctx, size),
+ isValidHash(hashOrValue) || computeHash(hashOrValue),
+ config);
+}
+
+/**
+ * Prepares a measure to be used as a measure in an SVG path, by
+ * rounding the measure to a single decimal. This reduces the file
+ * size of the generated SVG with more than 50% in some cases.
+ */
+function svgValue(value) {
+ return ((value * 10 + 0.5) | 0) / 10;
+}
+
+/**
+ * Represents an SVG path element.
+ */
+function SvgPath() {
+ /**
+ * This property holds the data string (path.d) of the SVG path.
+ * @type {string}
+ */
+ this.B/*dataString*/ = "";
+}
+var SvgPath__prototype = SvgPath.prototype;
+
+/**
+ * Adds a polygon with the current fill color to the SVG path.
+ * @param points An array of Point objects.
+ */
+SvgPath__prototype.g/*addPolygon*/ = function addPolygon (points) {
+ var dataString = "";
+ for (var i = 0; i < points.length; i++) {
+ dataString += (i ? "L" : "M") + svgValue(points[i].x) + " " + svgValue(points[i].y);
+ }
+ this.B/*dataString*/ += dataString + "Z";
+};
+
+/**
+ * Adds a circle with the current fill color to the SVG path.
+ * @param {Point} point The upper left corner of the circle bounding box.
+ * @param {number} diameter The diameter of the circle.
+ * @param {boolean} counterClockwise True if the circle is drawn counter-clockwise (will result in a hole if rendered on a clockwise path).
+ */
+SvgPath__prototype.h/*addCircle*/ = function addCircle (point, diameter, counterClockwise) {
+ var sweepFlag = counterClockwise ? 0 : 1,
+ svgRadius = svgValue(diameter / 2),
+ svgDiameter = svgValue(diameter),
+ svgArc = "a" + svgRadius + "," + svgRadius + " 0 1," + sweepFlag + " ";
+
+ this.B/*dataString*/ +=
+ "M" + svgValue(point.x) + " " + svgValue(point.y + diameter / 2) +
+ svgArc + svgDiameter + ",0" +
+ svgArc + (-svgDiameter) + ",0";
+};
+
+
+
+/**
+ * Renderer producing SVG output.
+ * @implements {Renderer}
+ */
+function SvgRenderer(target) {
+ /**
+ * @type {SvgPath}
+ * @private
+ */
+ this.C/*_path*/;
+
+ /**
+ * @type {Object.<string,SvgPath>}
+ * @private
+ */
+ this.D/*_pathsByColor*/ = { };
+
+ /**
+ * @type {SvgElement|SvgWriter}
+ * @private
+ */
+ this.R/*_target*/ = target;
+
+ /**
+ * @type {number}
+ */
+ this.k/*iconSize*/ = target.k/*iconSize*/;
+}
+var SvgRenderer__prototype = SvgRenderer.prototype;
+
+/**
+ * Fills the background with the specified color.
+ * @param {string} fillColor Fill color on the format #rrggbb[aa].
+ */
+SvgRenderer__prototype.m/*setBackground*/ = function setBackground (fillColor) {
+ var match = /^(#......)(..)?/.exec(fillColor),
+ opacity = match[2] ? parseHex(match[2], 0) / 255 : 1;
+ this.R/*_target*/.m/*setBackground*/(match[1], opacity);
+};
+
+/**
+ * Marks the beginning of a new shape of the specified color. Should be ended with a call to endShape.
+ * @param {string} color Fill color on format #xxxxxx.
+ */
+SvgRenderer__prototype.O/*beginShape*/ = function beginShape (color) {
+ this.C/*_path*/ = this.D/*_pathsByColor*/[color] || (this.D/*_pathsByColor*/[color] = new SvgPath());
+};
+
+/**
+ * Marks the end of the currently drawn shape.
+ */
+SvgRenderer__prototype.P/*endShape*/ = function endShape () { };
+
+/**
+ * Adds a polygon with the current fill color to the SVG.
+ * @param points An array of Point objects.
+ */
+SvgRenderer__prototype.g/*addPolygon*/ = function addPolygon (points) {
+ this.C/*_path*/.g/*addPolygon*/(points);
+};
+
+/**
+ * Adds a circle with the current fill color to the SVG.
+ * @param {Point} point The upper left corner of the circle bounding box.
+ * @param {number} diameter The diameter of the circle.
+ * @param {boolean} counterClockwise True if the circle is drawn counter-clockwise (will result in a hole if rendered on a clockwise path).
+ */
+SvgRenderer__prototype.h/*addCircle*/ = function addCircle (point, diameter, counterClockwise) {
+ this.C/*_path*/.h/*addCircle*/(point, diameter, counterClockwise);
+};
+
+/**
+ * Called when the icon has been completely drawn.
+ */
+SvgRenderer__prototype.finish = function finish () {
+ var this$1 = this;
+
+ var pathsByColor = this.D/*_pathsByColor*/;
+ for (var color in pathsByColor) {
+ // hasOwnProperty cannot be shadowed in pathsByColor
+ // eslint-disable-next-line no-prototype-builtins
+ if (pathsByColor.hasOwnProperty(color)) {
+ this$1.R/*_target*/.S/*appendPath*/(color, pathsByColor[color].B/*dataString*/);
+ }
+ }
+};
+
+var SVG_CONSTANTS = {
+ T/*XMLNS*/: "http://www.w3.org/2000/svg",
+ U/*WIDTH*/: "width",
+ V/*HEIGHT*/: "height",
+};
+
+/**
+ * Renderer producing SVG output.
+ */
+function SvgWriter(iconSize) {
+ /**
+ * @type {number}
+ */
+ this.k/*iconSize*/ = iconSize;
+
+ /**
+ * @type {string}
+ * @private
+ */
+ this.F/*_s*/ =
+ '<svg xmlns="' + SVG_CONSTANTS.T/*XMLNS*/ + '" width="' +
+ iconSize + '" height="' + iconSize + '" viewBox="0 0 ' +
+ iconSize + ' ' + iconSize + '">';
+}
+var SvgWriter__prototype = SvgWriter.prototype;
+
+/**
+ * Fills the background with the specified color.
+ * @param {string} fillColor Fill color on the format #rrggbb.
+ * @param {number} opacity Opacity in the range [0.0, 1.0].
+ */
+SvgWriter__prototype.m/*setBackground*/ = function setBackground (fillColor, opacity) {
+ if (opacity) {
+ this.F/*_s*/ += '<rect width="100%" height="100%" fill="' +
+ fillColor + '" opacity="' + opacity.toFixed(2) + '"/>';
+ }
+};
+
+/**
+ * Writes a path to the SVG string.
+ * @param {string} color Fill color on format #rrggbb.
+ * @param {string} dataString The SVG path data string.
+ */
+SvgWriter__prototype.S/*appendPath*/ = function appendPath (color, dataString) {
+ this.F/*_s*/ += '<path fill="' + color + '" d="' + dataString + '"/>';
+};
+
+/**
+ * Gets the rendered image as an SVG string.
+ */
+SvgWriter__prototype.toString = function toString () {
+ return this.F/*_s*/ + "</svg>";
+};
+
+/**
+ * Draws an identicon as an SVG string.
+ * @param {*} hashOrValue - A hexadecimal hash string or any value that will be hashed by Jdenticon.
+ * @param {number} size - Icon size in pixels.
+ * @param {Object|number=} config - Optional configuration. If specified, this configuration object overrides any
+ * global configuration in its entirety. For backward compatibility a padding value in the range [0.0, 0.5) can be
+ * specified in place of a configuration object.
+ * @returns {string} SVG string
+ */
+function toSvg(hashOrValue, size, config) {
+ var writer = new SvgWriter(size);
+ iconGenerator(new SvgRenderer(writer),
+ isValidHash(hashOrValue) || computeHash(hashOrValue),
+ config);
+ return writer.toString();
+}
+
+/**
+ * Creates a new element and adds it to the specified parent.
+ * @param {Element} parentNode
+ * @param {string} name
+ * @param {...(string|number)} keyValuePairs
+ */
+function SvgElement_append(parentNode, name) {
+ var keyValuePairs = [], len = arguments.length - 2;
+ while ( len-- > 0 ) keyValuePairs[ len ] = arguments[ len + 2 ];
+
+ var el = document.createElementNS(SVG_CONSTANTS.T/*XMLNS*/, name);
+
+ for (var i = 0; i + 1 < keyValuePairs.length; i += 2) {
+ el.setAttribute(
+ /** @type {string} */(keyValuePairs[i]),
+ /** @type {string} */(keyValuePairs[i + 1])
+ );
+ }
+
+ parentNode.appendChild(el);
+}
+
+
+/**
+ * Renderer producing SVG output.
+ */
+function SvgElement(element) {
+ // Don't use the clientWidth and clientHeight properties on SVG elements
+ // since Firefox won't serve a proper value of these properties on SVG
+ // elements (https://bugzilla.mozilla.org/show_bug.cgi?id=874811)
+ // Instead use 100px as a hardcoded size (the svg viewBox will rescale
+ // the icon to the correct dimensions)
+ var iconSize = this.k/*iconSize*/ = Math.min(
+ (Number(element.getAttribute(SVG_CONSTANTS.U/*WIDTH*/)) || 100),
+ (Number(element.getAttribute(SVG_CONSTANTS.V/*HEIGHT*/)) || 100)
+ );
+
+ /**
+ * @type {Element}
+ * @private
+ */
+ this.W/*_el*/ = element;
+
+ // Clear current SVG child elements
+ while (element.firstChild) {
+ element.removeChild(element.firstChild);
+ }
+
+ // Set viewBox attribute to ensure the svg scales nicely.
+ element.setAttribute("viewBox", "0 0 " + iconSize + " " + iconSize);
+ element.setAttribute("preserveAspectRatio", "xMidYMid meet");
+}
+var SvgElement__prototype = SvgElement.prototype;
+
+/**
+ * Fills the background with the specified color.
+ * @param {string} fillColor Fill color on the format #rrggbb.
+ * @param {number} opacity Opacity in the range [0.0, 1.0].
+ */
+SvgElement__prototype.m/*setBackground*/ = function setBackground (fillColor, opacity) {
+ if (opacity) {
+ SvgElement_append(this.W/*_el*/, "rect",
+ SVG_CONSTANTS.U/*WIDTH*/, "100%",
+ SVG_CONSTANTS.V/*HEIGHT*/, "100%",
+ "fill", fillColor,
+ "opacity", opacity);
+ }
+};
+
+/**
+ * Appends a path to the SVG element.
+ * @param {string} color Fill color on format #xxxxxx.
+ * @param {string} dataString The SVG path data string.
+ */
+SvgElement__prototype.S/*appendPath*/ = function appendPath (color, dataString) {
+ SvgElement_append(this.W/*_el*/, "path",
+ "fill", color,
+ "d", dataString);
+};
+
+/**
+ * Updates all canvas elements with the `data-jdenticon-hash` or `data-jdenticon-value` attribute.
+ */
+function updateAll() {
+ if (documentQuerySelectorAll) {
+ update(ICON_SELECTOR);
+ }
+}
+
+/**
+ * Updates the identicon in the specified `<canvas>` or `<svg>` elements.
+ * @param {(string|Element)} el - Specifies the container in which the icon is rendered as a DOM element of the type
+ * `<svg>` or `<canvas>`, or a CSS selector to such an element.
+ * @param {*=} hashOrValue - Optional hash or value to be rendered. If not specified, the `data-jdenticon-hash` or
+ * `data-jdenticon-value` attribute will be evaluated.
+ * @param {Object|number=} config - Optional configuration. If specified, this configuration object overrides any
+ * global configuration in its entirety. For backward compability a padding value in the range [0.0, 0.5) can be
+ * specified in place of a configuration object.
+ */
+function update(el, hashOrValue, config) {
+ renderDomElement(el, hashOrValue, config, function (el, iconType) {
+ if (iconType) {
+ return iconType == ICON_TYPE_SVG ?
+ new SvgRenderer(new SvgElement(el)) :
+ new CanvasRenderer(/** @type {HTMLCanvasElement} */(el).getContext("2d"));
+ }
+ });
+}
+
+/**
+ * Updates the identicon in the specified canvas or svg elements.
+ * @param {(string|Element)} el - Specifies the container in which the icon is rendered as a DOM element of the type
+ * `<svg>` or `<canvas>`, or a CSS selector to such an element.
+ * @param {*} hashOrValue - Optional hash or value to be rendered. If not specified, the `data-jdenticon-hash` or
+ * `data-jdenticon-value` attribute will be evaluated.
+ * @param {Object|number|undefined} config
+ * @param {function(Element,number):Renderer} rendererFactory - Factory function for creating an icon renderer.
+ */
+function renderDomElement(el, hashOrValue, config, rendererFactory) {
+ if (typeof el === "string") {
+ if (documentQuerySelectorAll) {
+ var elements = documentQuerySelectorAll(el);
+ for (var i = 0; i < elements.length; i++) {
+ renderDomElement(elements[i], hashOrValue, config, rendererFactory);
+ }
+ }
+ return;
+ }
+
+ // Hash selection. The result from getValidHash or computeHash is
+ // accepted as a valid hash.
+ var hash =
+ // 1. Explicit valid hash
+ isValidHash(hashOrValue) ||
+
+ // 2. Explicit value (`!= null` catches both null and undefined)
+ hashOrValue != null && computeHash(hashOrValue) ||
+
+ // 3. `data-jdenticon-hash` attribute
+ isValidHash(el.getAttribute(ATTRIBUTES.t/*HASH*/)) ||
+
+ // 4. `data-jdenticon-value` attribute.
+ // We want to treat an empty attribute as an empty value.
+ // Some browsers return empty string even if the attribute
+ // is not specified, so use hasAttribute to determine if
+ // the attribute is specified.
+ el.hasAttribute(ATTRIBUTES.o/*VALUE*/) && computeHash(el.getAttribute(ATTRIBUTES.o/*VALUE*/));
+
+ if (!hash) {
+ // No hash specified. Don't render an icon.
+ return;
+ }
+
+ var renderer = rendererFactory(el, getIdenticonType(el));
+ if (renderer) {
+ // Draw icon
+ iconGenerator(renderer, hash, config);
+ }
+}
+
+/**
+ * Renders an identicon for all matching supported elements.
+ *
+ * @param {*} hashOrValue - A hexadecimal hash string or any value that will be hashed by Jdenticon. If not
+ * specified the `data-jdenticon-hash` and `data-jdenticon-value` attributes of each element will be
+ * evaluated.
+ * @param {Object|number=} config - Optional configuration. If specified, this configuration object overrides any global
+ * configuration in its entirety. For backward compatibility a padding value in the range [0.0, 0.5) can be
+ * specified in place of a configuration object.
+ */
+function jdenticonJqueryPlugin(hashOrValue, config) {
+ this["each"](function (index, el) {
+ update(el, hashOrValue, config);
+ });
+ return this;
+}
+
+// This file is compiled to dist/jdenticon.js and dist/jdenticon.min.js
+
+var jdenticon = updateAll;
+
+defineConfigProperty(jdenticon);
+
+// Export public API
+jdenticon["configure"] = configure;
+jdenticon["drawIcon"] = drawIcon;
+jdenticon["toSvg"] = toSvg;
+jdenticon["update"] = update;
+jdenticon["updateCanvas"] = update;
+jdenticon["updateSvg"] = update;
+
+/**
+ * Specifies the version of the Jdenticon package in use.
+ * @type {string}
+ */
+jdenticon["version"] = "3.2.0";
+
+/**
+ * Specifies which bundle of Jdenticon that is used.
+ * @type {string}
+ */
+jdenticon["bundle"] = "browser-umd";
+
+// Basic jQuery plugin
+var jQuery = GLOBAL["jQuery"];
+if (jQuery) {
+ jQuery["fn"]["jdenticon"] = jdenticonJqueryPlugin;
+}
+
+/**
+ * This function is called once upon page load.
+ */
+function jdenticonStartup() {
+ var replaceMode = (
+ jdenticon[CONFIG_PROPERTIES.n/*MODULE*/] ||
+ GLOBAL[CONFIG_PROPERTIES.G/*GLOBAL*/] ||
+ { }
+ )["replaceMode"];
+
+ if (replaceMode != "never") {
+ updateAll();
+
+ if (replaceMode == "observe") {
+ observer(update);
+ }
+ }
+}
+
+// Schedule to render all identicons on the page once it has been loaded.
+if (typeof setTimeout === "function") {
+ setTimeout(jdenticonStartup, 0);
+}
+
+return jdenticon;
+
+});
+\ No newline at end of file
diff --git a/src/static/templates/admin/base.hbs b/src/static/templates/admin/base.hbs
@@ -28,7 +28,7 @@
border: var(--bs-alert-border);
}
</style>
- <script src="{{urlpath}}/vw_static/identicon.js"></script>
+ <script src="{{urlpath}}/vw_static/jdenticon.js"></script>
<script>
'use strict';
@@ -49,11 +49,6 @@
const hashHex = hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
return hashHex;
}
- async function identicon(email) {
- const hash = await sha256(email);
- const data = new Identicon(hash, { size: 48, format: 'svg' });
- return "data:image/svg+xml;base64," + data.toString();
- }
function toggleVis(input_id) {
const elem = document.getElementById(input_id);
const type = elem.getAttribute("type");
diff --git a/src/static/templates/admin/organizations.hbs b/src/static/templates/admin/organizations.hbs
@@ -16,7 +16,7 @@
{{#each page_data}}
<tr>
<td>
- <img class="float-start me-2 rounded identicon" data-src="{{Id}}">
+ <svg width="48" height="48" class="float-start me-2 rounded" data-jdenticon-value="{{Id}}">
<div class="float-start">
<strong>{{Name}}</strong>
<span class="me-2">({{BillingEmail}})</span>
@@ -73,12 +73,6 @@
return false;
}
- (async () => {
- for (let e of document.querySelectorAll("img.identicon")) {
- e.src = await identicon(e.dataset.src);
- }
- })();
-
document.addEventListener("DOMContentLoaded", function() {
$('#orgs-table').DataTable({
"responsive": true,
diff --git a/src/static/templates/admin/users.hbs b/src/static/templates/admin/users.hbs
@@ -19,7 +19,7 @@
{{#each page_data}}
<tr>
<td>
- <img class="float-start me-2 rounded identicon" data-src="{{Email}}">
+ <svg width="48" height="48" class="float-start me-2 rounded" data-jdenticon-value="{{Email}}">
<div class="float-start">
<strong>{{Name}}</strong>
<span class="d-block">{{Email}}</span>
@@ -206,12 +206,6 @@
"3": { "name": "Manager", "color": "green" },
};
- (async () => {
- for (let e of document.querySelectorAll("img.identicon")) {
- e.src = await identicon(e.dataset.src);
- }
- })();
-
document.querySelectorAll("[data-orgtype]").forEach(function (e) {
let orgtype = OrgTypes[e.dataset.orgtype];
e.style.backgroundColor = orgtype.color;