From 0095604bb3d7846046b768a3e7c133e74c959d94 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 14 Nov 2023 12:29:17 +1100 Subject: [PATCH 001/348] Update pom.xml --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 54f72ac0c..1cfa9fa51 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ io.mapsmessaging message_daemon 4.0.0 - 3.3.5 + 3.3.6-SNAPSHOT jar Maps Messaging Server From 6f0714bf21b4bfac2c5f66713e3fb53bbbc1d175 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 14 Nov 2023 16:42:00 +1100 Subject: [PATCH 002/348] standard way of handling system properties --- .../java/io/mapsmessaging/MessageDaemon.java | 12 ++-- .../utilities/SystemProperties.java | 62 +++++++++++++++++++ 2 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 src/main/java/io/mapsmessaging/utilities/SystemProperties.java diff --git a/src/main/java/io/mapsmessaging/MessageDaemon.java b/src/main/java/io/mapsmessaging/MessageDaemon.java index cef36f785..84ade06b4 100644 --- a/src/main/java/io/mapsmessaging/MessageDaemon.java +++ b/src/main/java/io/mapsmessaging/MessageDaemon.java @@ -40,6 +40,7 @@ import io.mapsmessaging.routing.RoutingManager; import io.mapsmessaging.utilities.Agent; import io.mapsmessaging.utilities.AgentOrder; +import io.mapsmessaging.utilities.SystemProperties; import io.mapsmessaging.utilities.admin.JMXManager; import io.mapsmessaging.utilities.admin.SimpleTaskSchedulerJMX; import io.mapsmessaging.utilities.configuration.ConfigurationManager; @@ -89,7 +90,7 @@ public static MessageDaemon getInstance(){ public MessageDaemon() throws IOException { agentMap = new LinkedHashMap<>(); isStarted = new AtomicBoolean(false); - String tmpHome = System.getProperty("MAPS_HOME", "."); + String tmpHome = SystemProperties.getProperty("MAPS_HOME", "."); File testHome = new File(tmpHome); if (!testHome.exists()) { logger.log(ServerLogMessages.MESSAGE_DAEMON_NO_HOME_DIRECTORY, testHome); @@ -112,12 +113,7 @@ public MessageDaemon() throws IOException { if (serverId != null) { uniqueId = serverId; } else { - serverId = System.getProperty("SERVER_ID"); - if (serverId == null) { - uniqueId = generateUniqueId(); - } else { - uniqueId = serverId; - } + uniqueId = SystemProperties.getProperty("SERVER_ID", generateUniqueId()); instanceConfig.setServerName(uniqueId); instanceConfig.saveState(); logger.log(MESSAGE_DAEMON_STARTUP_BOOTSTRAP, uniqueId); @@ -295,7 +291,7 @@ private String generateUniqueId() { return env; } - boolean useUUID = Boolean.parseBoolean(System.getProperty("USE_UUID", "TRUE")); + boolean useUUID = SystemProperties.getBooleanProperty("USE_UUID", true); if (useUUID) { return UUID.randomUUID().toString(); } diff --git a/src/main/java/io/mapsmessaging/utilities/SystemProperties.java b/src/main/java/io/mapsmessaging/utilities/SystemProperties.java new file mode 100644 index 000000000..a4ba1f0ed --- /dev/null +++ b/src/main/java/io/mapsmessaging/utilities/SystemProperties.java @@ -0,0 +1,62 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.utilities; + +public class SystemProperties { + + public static String getProperty(String key, String defaultValue) { + String value = System.getProperty(key); + if (value != null && !value.isEmpty()) { + return value; + } + return defaultValue; + } + + public static boolean getBooleanProperty(String key, boolean defaultValue) { + String value = System.getProperty(key); + if (value != null && !value.isEmpty()) { + return Boolean.parseBoolean(value); + } + return defaultValue; + } + + public static long getLongProperty(String key, long defaultValue) { + String value = System.getProperty(key); + if (value != null && !value.isEmpty()) { + try { + return Long.parseLong(value); + } catch (NumberFormatException e) { + // ignore + } + } + return defaultValue; + } + + public static double getDoubleProperty(String key, double defaultValue) { + String value = System.getProperty(key); + if (value != null && !value.isEmpty()) { + try { + return Double.parseDouble(value); + } catch (NumberFormatException e) { + // ignore + } + } + return defaultValue; + } + +} From ef4c8ee281bd96aa1b2a037630dcd45f713c4fca Mon Sep 17 00:00:00 2001 From: krital Date: Tue, 14 Nov 2023 15:00:48 +0200 Subject: [PATCH 003/348] Enable the discovery manager by default --- .../io/mapsmessaging/network/discovery/DiscoveryManager.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java index 8ef9dea51..38e7e56d1 100644 --- a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java +++ b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java @@ -56,7 +56,7 @@ public DiscoveryManager(String serverName) { logger = LoggerFactory.getLogger(DiscoveryManager.class); boundedNetworks = new ArrayList<>(); properties = ConfigurationManager.getInstance().getProperties("DiscoveryManager"); - enabled = properties.getBooleanProperty("enabled", false); + enabled = properties.getBooleanProperty("enabled", true); } public void registerListener(String type, ServiceListener listener){ From cd322a12c416459fe563cb9443c014c5f00477a9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 14 Nov 2023 18:48:57 +0000 Subject: [PATCH 004/348] Bump com.orbitz.consul:consul-client from 1.4.2 to 1.5.3 Bumps [com.orbitz.consul:consul-client](https://github.com/OrbitzWorldwide/consul-client) from 1.4.2 to 1.5.3. - [Changelog](https://github.com/rickfast/consul-client/blob/master/CHANGELOG.md) - [Commits](https://github.com/OrbitzWorldwide/consul-client/commits/1.5.3) --- updated-dependencies: - dependency-name: com.orbitz.consul:consul-client dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1cfa9fa51..1a00b430b 100644 --- a/pom.xml +++ b/pom.xml @@ -596,7 +596,7 @@ com.orbitz.consul consul-client - 1.4.2 + 1.5.3 From 6b47f6931cc41cd3af3904e74558e252cb4cc65f Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 15 Nov 2023 11:44:36 +1100 Subject: [PATCH 005/348] remove direct access to System.properties --- .../java/io/mapsmessaging/MessageDaemon.java | 2 +- .../consul/ConsulConfiguration.java | 17 +++++++++++------ .../consul/ConsulManagerFactory.java | 3 ++- .../utilities/SystemProperties.java | 14 ++++++++++++++ .../configuration/ConfigurationManager.java | 16 ++++++++-------- 5 files changed, 36 insertions(+), 16 deletions(-) diff --git a/src/main/java/io/mapsmessaging/MessageDaemon.java b/src/main/java/io/mapsmessaging/MessageDaemon.java index 84ade06b4..8fe10c1cb 100644 --- a/src/main/java/io/mapsmessaging/MessageDaemon.java +++ b/src/main/java/io/mapsmessaging/MessageDaemon.java @@ -286,7 +286,7 @@ public String getId() { } private String generateUniqueId() { - String env = System.getenv("SERVER_ID"); + String env = SystemProperties.getEnvProperty("SERVER_ID", null); if (env != null) { return env; } diff --git a/src/main/java/io/mapsmessaging/consul/ConsulConfiguration.java b/src/main/java/io/mapsmessaging/consul/ConsulConfiguration.java index 2475c1fda..e219ef525 100644 --- a/src/main/java/io/mapsmessaging/consul/ConsulConfiguration.java +++ b/src/main/java/io/mapsmessaging/consul/ConsulConfiguration.java @@ -17,6 +17,7 @@ package io.mapsmessaging.consul; +import io.mapsmessaging.utilities.SystemProperties; import lombok.Data; import lombok.ToString; @@ -37,7 +38,7 @@ public ConsulConfiguration() { String tokencfg; String path = "/"; - String urlCfg = System.getProperty("ConsulUrl"); + String urlCfg = SystemProperties.getProperty("ConsulUrl"); if (urlCfg != null) { tokencfg = extractToken(urlCfg); path = extractPath(urlCfg); @@ -47,23 +48,27 @@ public ConsulConfiguration() { urlCfg = removePath(urlCfg); } else { tokencfg = null; - String host = System.getProperty("ConsulHost", "127.0.0.1"); - int port = Integer.parseInt(System.getProperty("ConsulPort", "8500")); + String host = SystemProperties.getProperty("ConsulHost", "127.0.0.1"); + int port = (int) SystemProperties.getLongProperty("ConsulPort", 8500); urlCfg = "http://" + host + ":" + port; } - consulAcl = System.getProperty("ConsulAcl"); + consulAcl = SystemProperties.getProperty("ConsulAcl"); consulToken = parseToken(tokencfg); consulUrl = urlCfg; urlPath = path; } + public String getUrlPath() { + return SystemProperties.getProperty("ConsulPath", urlPath); + } + public boolean registerAgent() { - return Boolean.parseBoolean(System.getProperty("ConsulAgentRegister", "false")); + return SystemProperties.getBooleanProperty("ConsulAgentRegister", false); } private String parseToken(String tokencfg) { - String tokenProp = System.getProperty("ConsulToken", tokencfg); + String tokenProp = SystemProperties.getProperty("ConsulToken", tokencfg); if (tokenProp != null && !tokenProp.isEmpty()) { tokencfg = tokenProp; } diff --git a/src/main/java/io/mapsmessaging/consul/ConsulManagerFactory.java b/src/main/java/io/mapsmessaging/consul/ConsulManagerFactory.java index d4d3b0c2e..43ef513e4 100644 --- a/src/main/java/io/mapsmessaging/consul/ConsulManagerFactory.java +++ b/src/main/java/io/mapsmessaging/consul/ConsulManagerFactory.java @@ -23,6 +23,7 @@ import io.mapsmessaging.logging.ServerLogMessages; import io.mapsmessaging.network.io.EndPointServer; import io.mapsmessaging.rest.RestApiServerManager; +import io.mapsmessaging.utilities.SystemProperties; import java.io.IOException; import java.net.ConnectException; @@ -111,7 +112,7 @@ public synchronized boolean isStarted() { private ConsulManagerFactory() { boolean config; try { - config = Boolean.parseBoolean(System.getProperty("ForceConsul", "FALSE")); + config = SystemProperties.getBooleanProperty("ForceConsul", false); } catch (Exception e) { config = false; } diff --git a/src/main/java/io/mapsmessaging/utilities/SystemProperties.java b/src/main/java/io/mapsmessaging/utilities/SystemProperties.java index a4ba1f0ed..873b0549f 100644 --- a/src/main/java/io/mapsmessaging/utilities/SystemProperties.java +++ b/src/main/java/io/mapsmessaging/utilities/SystemProperties.java @@ -19,6 +19,11 @@ public class SystemProperties { + + public static String getProperty(String key) { + return getProperty(key, null); + } + public static String getProperty(String key, String defaultValue) { String value = System.getProperty(key); if (value != null && !value.isEmpty()) { @@ -59,4 +64,13 @@ public static double getDoubleProperty(String key, double defaultValue) { return defaultValue; } + public static String getEnvProperty(String key, String defaultValue) { + String value = System.getenv(key); + if (value != null && !value.isEmpty()) { + return value; + } + return defaultValue; + } + + } diff --git a/src/main/java/io/mapsmessaging/utilities/configuration/ConfigurationManager.java b/src/main/java/io/mapsmessaging/utilities/configuration/ConfigurationManager.java index f2a6340b3..07afbaf27 100644 --- a/src/main/java/io/mapsmessaging/utilities/configuration/ConfigurationManager.java +++ b/src/main/java/io/mapsmessaging/utilities/configuration/ConfigurationManager.java @@ -56,16 +56,16 @@ public static ConfigurationManager getInstance() { public void initialise(@NonNull @NotNull String serverId) { ConsulPropertyManager defaultConsulManager = null; if (ConsulManagerFactory.getInstance().isStarted()) { - String consulConfigPath = System.getProperty("ConsulPath",ConsulManagerFactory.getInstance().getPath()); - if (consulConfigPath.trim().isEmpty()) consulConfigPath=ConsulManagerFactory.getInstance().getPath(); + String consulConfigPath = ConsulManagerFactory.getInstance().getPath(); + if (consulConfigPath == null) { + consulConfigPath = "/"; + } String defaultName = "default"; - if(consulConfigPath != null){ - if(!consulConfigPath.endsWith("/")){ - consulConfigPath = consulConfigPath+"/"; - } - serverId = consulConfigPath+serverId; - defaultName = consulConfigPath+defaultName; + if (!consulConfigPath.endsWith("/")) { + consulConfigPath = consulConfigPath + "/"; } + serverId = consulConfigPath + serverId; + defaultName = consulConfigPath + defaultName; authoritative = new ConsulPropertyManager(serverId); authoritative.load(); String locatedDefault = ConsulManagerFactory.getInstance().getManager().scanForDefaultConfig(consulConfigPath); From f8d7a20355de2370d2927ac34c9b71c8168dc353 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 15 Nov 2023 13:08:27 +1100 Subject: [PATCH 006/348] log access to system properties and the results --- .../java/io/mapsmessaging/MessageDaemon.java | 15 +++-- .../consul/ConsulConfiguration.java | 14 ++--- .../consul/ConsulManagerFactory.java | 2 +- .../logging/ServerLogMessages.java | 4 ++ .../utilities/SystemProperties.java | 58 +++++++++++++------ .../configuration/ConsulPropertyManager.java | 1 - 6 files changed, 60 insertions(+), 34 deletions(-) diff --git a/src/main/java/io/mapsmessaging/MessageDaemon.java b/src/main/java/io/mapsmessaging/MessageDaemon.java index 8fe10c1cb..6cd7b93fd 100644 --- a/src/main/java/io/mapsmessaging/MessageDaemon.java +++ b/src/main/java/io/mapsmessaging/MessageDaemon.java @@ -62,12 +62,11 @@ public class MessageDaemon { - public static MessageDaemon getInstance(){ - return instance; - } + @Getter private static MessageDaemon instance; + static { - MessageDaemon tmp = null; + MessageDaemon tmp; try { tmp = new MessageDaemon(); } catch (IOException e) { @@ -90,7 +89,7 @@ public static MessageDaemon getInstance(){ public MessageDaemon() throws IOException { agentMap = new LinkedHashMap<>(); isStarted = new AtomicBoolean(false); - String tmpHome = SystemProperties.getProperty("MAPS_HOME", "."); + String tmpHome = SystemProperties.getInstance().getProperty("MAPS_HOME", "."); File testHome = new File(tmpHome); if (!testHome.exists()) { logger.log(ServerLogMessages.MESSAGE_DAEMON_NO_HOME_DIRECTORY, testHome); @@ -113,7 +112,7 @@ public MessageDaemon() throws IOException { if (serverId != null) { uniqueId = serverId; } else { - uniqueId = SystemProperties.getProperty("SERVER_ID", generateUniqueId()); + uniqueId = SystemProperties.getInstance().getProperty("SERVER_ID", generateUniqueId()); instanceConfig.setServerName(uniqueId); instanceConfig.saveState(); logger.log(MESSAGE_DAEMON_STARTUP_BOOTSTRAP, uniqueId); @@ -286,12 +285,12 @@ public String getId() { } private String generateUniqueId() { - String env = SystemProperties.getEnvProperty("SERVER_ID", null); + String env = SystemProperties.getInstance().getEnvProperty("SERVER_ID"); if (env != null) { return env; } - boolean useUUID = SystemProperties.getBooleanProperty("USE_UUID", true); + boolean useUUID = SystemProperties.getInstance().getBooleanProperty("USE_UUID", true); if (useUUID) { return UUID.randomUUID().toString(); } diff --git a/src/main/java/io/mapsmessaging/consul/ConsulConfiguration.java b/src/main/java/io/mapsmessaging/consul/ConsulConfiguration.java index e219ef525..38a1200f4 100644 --- a/src/main/java/io/mapsmessaging/consul/ConsulConfiguration.java +++ b/src/main/java/io/mapsmessaging/consul/ConsulConfiguration.java @@ -38,7 +38,7 @@ public ConsulConfiguration() { String tokencfg; String path = "/"; - String urlCfg = SystemProperties.getProperty("ConsulUrl"); + String urlCfg = SystemProperties.getInstance().getProperty("ConsulUrl"); if (urlCfg != null) { tokencfg = extractToken(urlCfg); path = extractPath(urlCfg); @@ -48,27 +48,27 @@ public ConsulConfiguration() { urlCfg = removePath(urlCfg); } else { tokencfg = null; - String host = SystemProperties.getProperty("ConsulHost", "127.0.0.1"); - int port = (int) SystemProperties.getLongProperty("ConsulPort", 8500); + String host = SystemProperties.getInstance().getProperty("ConsulHost", "127.0.0.1"); + int port = (int) SystemProperties.getInstance().getLongProperty("ConsulPort", 8500); urlCfg = "http://" + host + ":" + port; } - consulAcl = SystemProperties.getProperty("ConsulAcl"); + consulAcl = SystemProperties.getInstance().getProperty("ConsulAcl"); consulToken = parseToken(tokencfg); consulUrl = urlCfg; urlPath = path; } public String getUrlPath() { - return SystemProperties.getProperty("ConsulPath", urlPath); + return SystemProperties.getInstance().getProperty("ConsulPath", urlPath); } public boolean registerAgent() { - return SystemProperties.getBooleanProperty("ConsulAgentRegister", false); + return SystemProperties.getInstance().getBooleanProperty("ConsulAgentRegister", false); } private String parseToken(String tokencfg) { - String tokenProp = SystemProperties.getProperty("ConsulToken", tokencfg); + String tokenProp = SystemProperties.getInstance().getProperty("ConsulToken", tokencfg); if (tokenProp != null && !tokenProp.isEmpty()) { tokencfg = tokenProp; } diff --git a/src/main/java/io/mapsmessaging/consul/ConsulManagerFactory.java b/src/main/java/io/mapsmessaging/consul/ConsulManagerFactory.java index 43ef513e4..d1753d960 100644 --- a/src/main/java/io/mapsmessaging/consul/ConsulManagerFactory.java +++ b/src/main/java/io/mapsmessaging/consul/ConsulManagerFactory.java @@ -112,7 +112,7 @@ public synchronized boolean isStarted() { private ConsulManagerFactory() { boolean config; try { - config = SystemProperties.getBooleanProperty("ForceConsul", false); + config = SystemProperties.getInstance().getBooleanProperty("ForceConsul", false); } catch (Exception e) { config = false; } diff --git a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java index 12381e0ff..82a392a26 100644 --- a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java +++ b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java @@ -567,6 +567,10 @@ public enum ServerLogMessages implements LogMessage { CONSUL_PROPERTY_MANAGER_INVALID_JSON(LEVEL.ERROR, SERVER_CATEGORY.ENGINE, "Value returned is not valid json for key {}"), CONSUL_PROPERTY_MANAGER_SAVE_ALL(LEVEL.ERROR, SERVER_CATEGORY.ENGINE, "Saving all entries for {}"), CONSUL_PROPERTY_MANAGER_STORE(LEVEL.ERROR, SERVER_CATEGORY.ENGINE, "Storing entry for {}"), + // + // + CONFIG_PROPERTY_ACCESS(LEVEL.ERROR, SERVER_CATEGORY.ENGINE, "Getting property {} from system resulted in {}"), + // // diff --git a/src/main/java/io/mapsmessaging/utilities/SystemProperties.java b/src/main/java/io/mapsmessaging/utilities/SystemProperties.java index 873b0549f..8634aabc0 100644 --- a/src/main/java/io/mapsmessaging/utilities/SystemProperties.java +++ b/src/main/java/io/mapsmessaging/utilities/SystemProperties.java @@ -17,60 +17,84 @@ package io.mapsmessaging.utilities; +import io.mapsmessaging.logging.Logger; +import io.mapsmessaging.logging.LoggerFactory; +import lombok.Getter; + +import static io.mapsmessaging.logging.ServerLogMessages.CONFIG_PROPERTY_ACCESS; + public class SystemProperties { + static { + instance = new SystemProperties(); + } + + @Getter + private static final SystemProperties instance; + + private final Logger logger = LoggerFactory.getLogger(SystemProperties.class); - public static String getProperty(String key) { + private SystemProperties() { + } + + + public String getProperty(String key) { return getProperty(key, null); } - public static String getProperty(String key, String defaultValue) { + public String getProperty(String key, String defaultValue) { String value = System.getProperty(key); - if (value != null && !value.isEmpty()) { - return value; + if (value == null || value.isEmpty()) { + value = defaultValue; } - return defaultValue; + logger.log(CONFIG_PROPERTY_ACCESS, key, defaultValue); + return value; } - public static boolean getBooleanProperty(String key, boolean defaultValue) { + public boolean getBooleanProperty(String key, boolean defaultValue) { String value = System.getProperty(key); + boolean result = defaultValue; if (value != null && !value.isEmpty()) { - return Boolean.parseBoolean(value); + result = Boolean.parseBoolean(value); } - return defaultValue; + logger.log(CONFIG_PROPERTY_ACCESS, key, result); + return result; } - public static long getLongProperty(String key, long defaultValue) { + public long getLongProperty(String key, long defaultValue) { String value = System.getProperty(key); + long result = defaultValue; if (value != null && !value.isEmpty()) { try { - return Long.parseLong(value); + result = Long.parseLong(value); } catch (NumberFormatException e) { // ignore } } - return defaultValue; + logger.log(CONFIG_PROPERTY_ACCESS, key, result); + return result; } - public static double getDoubleProperty(String key, double defaultValue) { + public double getDoubleProperty(String key, double defaultValue) { String value = System.getProperty(key); + double result = defaultValue; if (value != null && !value.isEmpty()) { try { - return Double.parseDouble(value); + result = Double.parseDouble(value); } catch (NumberFormatException e) { // ignore } } - return defaultValue; + logger.log(CONFIG_PROPERTY_ACCESS, key, result); + return result; } - public static String getEnvProperty(String key, String defaultValue) { + public String getEnvProperty(String key) { String value = System.getenv(key); if (value != null && !value.isEmpty()) { return value; } - return defaultValue; + return null; } - } diff --git a/src/main/java/io/mapsmessaging/utilities/configuration/ConsulPropertyManager.java b/src/main/java/io/mapsmessaging/utilities/configuration/ConsulPropertyManager.java index 1af84efb1..90a413813 100644 --- a/src/main/java/io/mapsmessaging/utilities/configuration/ConsulPropertyManager.java +++ b/src/main/java/io/mapsmessaging/utilities/configuration/ConsulPropertyManager.java @@ -108,6 +108,5 @@ public void save() throws IOException { String key = serverPrefix.trim() + entry.getKey().trim(); ConsulManagerFactory.getInstance().getManager().putValue(key, source); } - // Now lets Store it in key value pairs in consul } } From b1dd42fe5dd872ca0f5ffecf545e40a269666483 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 15 Nov 2023 13:08:54 +1100 Subject: [PATCH 007/348] fix spelling --- src/main/java/io/mapsmessaging/logging/ServerLogMessages.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java index 82a392a26..8a965d480 100644 --- a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java +++ b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java @@ -556,7 +556,7 @@ public enum ServerLogMessages implements LogMessage { CONSUL_INVALID_KEY(LEVEL.ERROR, SERVER_CATEGORY.ENGINE, "Consul Key/Value, invalid key received {}, changed to {}"), CONSUL_MANAGER_START_ABORTED(LEVEL.ERROR, SERVER_CATEGORY.ENGINE, "Startup aborted due to configuration, id {}"), CONSUL_MANAGER_START_DELAYED(LEVEL.ERROR, SERVER_CATEGORY.ENGINE, "Startup delaying server startup due to configuration for id {}"), - CONSUL_MANAGER_START_SERVER_NOT_FOUND(LEVEL.ERROR, SERVER_CATEGORY.ENGINE, "Startup aborted since Consol Server is not responding, id {}"), + CONSUL_MANAGER_START_SERVER_NOT_FOUND(LEVEL.ERROR, SERVER_CATEGORY.ENGINE, "Startup aborted since Consul Server is not responding, id {}"), // // From 5ee60dd985a0d10fb252a35271a1b07086cdc760 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 15 Nov 2023 13:12:33 +1100 Subject: [PATCH 008/348] cleanup --- .../network/discovery/DiscoveryManager.java | 29 +++++++++---------- 1 file changed, 14 insertions(+), 15 deletions(-) diff --git a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java index 38e7e56d1..7eb8163d6 100644 --- a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java +++ b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java @@ -32,23 +32,25 @@ import io.mapsmessaging.utilities.configuration.ConfigurationManager; import io.mapsmessaging.utilities.configuration.ConfigurationProperties; import io.mapsmessaging.utilities.service.Service; -import java.io.IOException; -import java.net.InetAddress; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; +import lombok.Getter; + import javax.jmdns.JmDNS; import javax.jmdns.ServiceInfo; import javax.jmdns.ServiceListener; +import java.io.IOException; +import java.net.InetAddress; +import java.util.*; + +import static io.mapsmessaging.logging.ServerLogMessages.DISCOVERY_FAILED_TO_REGISTER; public class DiscoveryManager implements Agent { + private static final String ALL_HOSTS = "0.0.0.0"; private final Logger logger; private final String serverName; private final List boundedNetworks; private final ConfigurationProperties properties; + @Getter private final boolean enabled; public DiscoveryManager(String serverName) { @@ -131,11 +133,12 @@ public ServiceInfo[] register(RestApiServerManager restApiServerManager) { ServiceInfo serviceInfo = ServiceInfo.create(service, serverName, restApiServerManager.getPort(), 0, 0, map); String host = restApiServerManager.getHost(); - if (host.equals("0.0.0.0") || host.equals(manager.getAdapter())) { + if (host.equals(ALL_HOSTS) || host.equals(manager.getAdapter())) { try { manager.register(serviceInfo); } catch (IOException e) { - throw new RuntimeException(e); + logger.log(DISCOVERY_FAILED_TO_REGISTER, e); + return new ServiceInfo[0]; } } registeredServices.add(serviceInfo); @@ -155,7 +158,7 @@ public void register(EndPointServer endPointServer) { List protocolList = createProtocolList(protocolConfig, transport); String endPointHostName = endPointServer.getUrl().getHost(); for(AdapterManager manager:boundedNetworks){ - if(endPointHostName.equals("0.0.0.0") || endPointHostName.equals(manager.getAdapter())){ + if (endPointHostName.equals(ALL_HOSTS) || endPointHostName.equals(manager.getAdapter())) { manager.register(endPointServer, transport, protocolList); } } @@ -190,7 +193,7 @@ private void createProtocolList(String protocol, String transport, List public synchronized List register(String host, String type, String name, int port, String text) throws IOException { List list = new ArrayList<>(); for(AdapterManager manager:boundedNetworks) { - if (host.equals("0.0.0.0") || host.equals(manager.getAdapter())) { + if (host.equals(ALL_HOSTS) || host.equals(manager.getAdapter())) { ServiceInfo serviceInfo = ServiceInfo.create(type, name, port, text); manager.register(serviceInfo); list.add(serviceInfo); @@ -216,8 +219,4 @@ public synchronized void deregisterAll() { manager.deregisterAll(); } } - - public boolean isEnabled() { - return enabled; - } } From 4956e0a401984748bc9f1110ad786336955275aa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:10:56 +0000 Subject: [PATCH 009/348] Bump software.amazon.awssdk:bom from 2.21.22 to 2.21.23 Bumps software.amazon.awssdk:bom from 2.21.22 to 2.21.23. --- updated-dependencies: - dependency-name: software.amazon.awssdk:bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1a00b430b..de6d0c59f 100644 --- a/pom.xml +++ b/pom.xml @@ -521,7 +521,7 @@ software.amazon.awssdk bom - 2.21.22 + 2.21.23 pom import From 52213fba804ed15dfaa86716e278001631f02234 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:11:48 +0000 Subject: [PATCH 010/348] Bump com.amazonaws:aws-java-sdk-cognitoidp from 1.12.588 to 1.12.589 Bumps [com.amazonaws:aws-java-sdk-cognitoidp](https://github.com/aws/aws-sdk-java) from 1.12.588 to 1.12.589. - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.588...1.12.589) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-cognitoidp dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1a00b430b..77ff1287d 100644 --- a/pom.xml +++ b/pom.xml @@ -865,7 +865,7 @@ com.amazonaws aws-java-sdk-cognitoidp - 1.12.588 + 1.12.589 test From 6aaa6d0a25de4d5204809a7660aed086014a32ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Nov 2023 18:12:06 +0000 Subject: [PATCH 011/348] Bump org.jetbrains:annotations from 24.0.1 to 24.1.0 Bumps [org.jetbrains:annotations](https://github.com/JetBrains/java-annotations) from 24.0.1 to 24.1.0. - [Release notes](https://github.com/JetBrains/java-annotations/releases) - [Changelog](https://github.com/JetBrains/java-annotations/blob/master/CHANGELOG.md) - [Commits](https://github.com/JetBrains/java-annotations/compare/24.0.1...24.1.0) --- updated-dependencies: - dependency-name: org.jetbrains:annotations dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1a00b430b..cdd40d393 100644 --- a/pom.xml +++ b/pom.xml @@ -742,7 +742,7 @@ org.jetbrains annotations - 24.0.1 + 24.1.0 From 22f3a5a23be4b1be6bed371311146b5808588ba3 Mon Sep 17 00:00:00 2001 From: krital Date: Thu, 16 Nov 2023 10:30:30 +0200 Subject: [PATCH 012/348] Adding DNS utilities --- src/main/docker/Dockerfile | 35 +++++++++++++++++++--------------- src/main/docker/arm/Dockerfile | 5 +++++ 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/main/docker/Dockerfile b/src/main/docker/Dockerfile index f033e375e..ce67ed4cb 100644 --- a/src/main/docker/Dockerfile +++ b/src/main/docker/Dockerfile @@ -18,6 +18,11 @@ ENV JAVA_HOME=/usr/lib/jvm/zulu-17 #---------------------------------------------------------------------------------------------- #RUN apk --no-cache add curl +#---------------------------------------------------------------------------------------------- +# Install DNS tools +#---------------------------------------------------------------------------------------------- +RUN apk add --update bind-tools + #---------------------------------------------------------------------------------------------- # Install locales #---------------------------------------------------------------------------------------------- @@ -87,24 +92,24 @@ EXPOSE 2442/udp #---------------------------------------------------------------------------------------------- # Install the maps messaging daemon image #---------------------------------------------------------------------------------------------- -RUN wget -q https://github.com/Maps-Messaging/mapsmessaging_server/releases/download/%%MAPS_VERSION%%/message_daemon-%%MAPS_VERSION%%-install.tar.gz && \ - tar -xf message_daemon-%%MAPS_VERSION%%-install.tar.gz && \ - rm message_daemon-%%MAPS_VERSION%%-install.tar.gz +RUN wget -q https://github.com/Maps-Messaging/mapsmessaging_server/releases/download/3.3.6-SNAPSHOT/message_daemon-3.3.6-SNAPSHOT-install.tar.gz && \ + tar -xf message_daemon-3.3.6-SNAPSHOT-install.tar.gz && \ + rm message_daemon-3.3.6-SNAPSHOT-install.tar.gz #---------------------------------------------------------------------------------------------- # Now configure the scripts #---------------------------------------------------------------------------------------------- -RUN chmod +x message_daemon-%%MAPS_VERSION%%/bin/startDocker.sh && \ - dos2unix message_daemon-%%MAPS_VERSION%%/bin/startDocker.sh +RUN chmod +x message_daemon-3.3.6-SNAPSHOT/bin/startDocker.sh && \ + dos2unix message_daemon-3.3.6-SNAPSHOT/bin/startDocker.sh -RUN mv message_daemon-%%MAPS_VERSION%%/conf/logback.xml message_daemon-%%MAPS_VERSION%%/conf/logback.xml_orig && \ - mv message_daemon-%%MAPS_VERSION%%/conf/docker_logback.xml message_daemon-%%MAPS_VERSION%%/conf/logback.xml +RUN mv message_daemon-3.3.6-SNAPSHOT/conf/logback.xml message_daemon-3.3.6-SNAPSHOT/conf/logback.xml_orig && \ + mv message_daemon-3.3.6-SNAPSHOT/conf/docker_logback.xml message_daemon-3.3.6-SNAPSHOT/conf/logback.xml -RUN mv message_daemon-%%MAPS_VERSION%%/conf/NetworkManager.yaml message_daemon-%%MAPS_VERSION%%/conf/NetworkManager.yaml_orig && \ - mv message_daemon-%%MAPS_VERSION%%/conf/NetworkManagerDocker.yaml message_daemon-%%MAPS_VERSION%%/conf/NetworkManager.yaml +RUN mv message_daemon-3.3.6-SNAPSHOT/conf/NetworkManager.yaml message_daemon-3.3.6-SNAPSHOT/conf/NetworkManager.yaml_orig && \ + mv message_daemon-3.3.6-SNAPSHOT/conf/NetworkManagerDocker.yaml message_daemon-3.3.6-SNAPSHOT/conf/NetworkManager.yaml -RUN mv message_daemon-%%MAPS_VERSION%%/conf/DestinationManager.yaml message_daemon-%%MAPS_VERSION%%/conf/DestinationManager.yaml_orig && \ - mv message_daemon-%%MAPS_VERSION%%/conf/DestinationManagerDocker.yaml message_daemon-%%MAPS_VERSION%%/conf/DestinationManager.yaml +RUN mv message_daemon-3.3.6-SNAPSHOT/conf/DestinationManager.yaml message_daemon-3.3.6-SNAPSHOT/conf/DestinationManager.yaml_orig && \ + mv message_daemon-3.3.6-SNAPSHOT/conf/DestinationManagerDocker.yaml message_daemon-3.3.6-SNAPSHOT/conf/DestinationManager.yaml @@ -112,9 +117,9 @@ RUN mv message_daemon-%%MAPS_VERSION%%/conf/DestinationManager.yaml message_daem #---------------------------------------------------------------------------------------------- # Now configure and download hawtio for web/JMX/Rest administration #---------------------------------------------------------------------------------------------- -RUN cd ./message_daemon-%%MAPS_VERSION%% && \ +RUN cd ./message_daemon-3.3.6-SNAPSHOT && \ mv conf/hawtio.yaml conf/hawtio.yaml_old && \ - sed 's|/Users/matthew/Downloads/hawtio-war-2.15.0.war|./message_daemon-%%MAPS_VERSION%%/hawtio-default-2.17.7.war|' conf/hawtio.yaml_old > conf/hawtio.yaml && \ + sed 's|/Users/matthew/Downloads/hawtio-war-2.15.0.war|./message_daemon-3.3.6-SNAPSHOT/hawtio-default-2.17.7.war|' conf/hawtio.yaml_old > conf/hawtio.yaml && \ rm conf/hawtio.yaml_old && \ wget https://repo1.maven.org/maven2/io/hawt/hawtio-default/2.17.7/hawtio-default-2.17.7.war @@ -127,7 +132,7 @@ VOLUME /data # We can now simply start the server # Increase the file descriptor count #---------------------------------------------------------------------------------------------- -CMD export MAPS_HOME=./message_daemon-%%MAPS_VERSION%%/ && \ +CMD export MAPS_HOME=./message_daemon-3.3.6-SNAPSHOT/ && \ ulimit -n 100000 && \ export PATH=${JAVA_HOME}/bin:${PATH} && \ - message_daemon-%%MAPS_VERSION%%/bin/startDocker.sh + message_daemon-3.3.6-SNAPSHOT/bin/startDocker.sh diff --git a/src/main/docker/arm/Dockerfile b/src/main/docker/arm/Dockerfile index cff91c85b..300d2d537 100644 --- a/src/main/docker/arm/Dockerfile +++ b/src/main/docker/arm/Dockerfile @@ -8,6 +8,11 @@ ENV LANG en_US.UTF-8 ENV LANGUAGE en_US:en ENV LC_ALL en_US.UTF-8 +#---------------------------------------------------------------------------------------------- +# Install DNS tools +#---------------------------------------------------------------------------------------------- +RUN apk add --update bind-tools + # https://cdn.azul.com/zulu/bin/zulu11.56.19-ca-jdk11.0.15-linux_musl_aarch64.tar.gz # Setup the repos # From 121c36f59e2c8e7ce1d7bf12419d0b7a911b2e04 Mon Sep 17 00:00:00 2001 From: krital Date: Thu, 16 Nov 2023 14:18:51 +0200 Subject: [PATCH 013/348] Added replacement token again (had accidentally committed the processed version) --- src/main/docker/Dockerfile | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/main/docker/Dockerfile b/src/main/docker/Dockerfile index ce67ed4cb..8354b5743 100644 --- a/src/main/docker/Dockerfile +++ b/src/main/docker/Dockerfile @@ -92,24 +92,24 @@ EXPOSE 2442/udp #---------------------------------------------------------------------------------------------- # Install the maps messaging daemon image #---------------------------------------------------------------------------------------------- -RUN wget -q https://github.com/Maps-Messaging/mapsmessaging_server/releases/download/3.3.6-SNAPSHOT/message_daemon-3.3.6-SNAPSHOT-install.tar.gz && \ - tar -xf message_daemon-3.3.6-SNAPSHOT-install.tar.gz && \ - rm message_daemon-3.3.6-SNAPSHOT-install.tar.gz +RUN wget -q https://github.com/Maps-Messaging/mapsmessaging_server/releases/download/%%MAPS_VERSION%%/message_daemon-%%MAPS_VERSION%%-install.tar.gz && \ + tar -xf message_daemon-%%MAPS_VERSION%%-install.tar.gz && \ + rm message_daemon-%%MAPS_VERSION%%-install.tar.gz #---------------------------------------------------------------------------------------------- # Now configure the scripts #---------------------------------------------------------------------------------------------- -RUN chmod +x message_daemon-3.3.6-SNAPSHOT/bin/startDocker.sh && \ - dos2unix message_daemon-3.3.6-SNAPSHOT/bin/startDocker.sh +RUN chmod +x message_daemon-%%MAPS_VERSION%%/bin/startDocker.sh && \ + dos2unix message_daemon-%%MAPS_VERSION%%/bin/startDocker.sh -RUN mv message_daemon-3.3.6-SNAPSHOT/conf/logback.xml message_daemon-3.3.6-SNAPSHOT/conf/logback.xml_orig && \ - mv message_daemon-3.3.6-SNAPSHOT/conf/docker_logback.xml message_daemon-3.3.6-SNAPSHOT/conf/logback.xml +RUN mv message_daemon-%%MAPS_VERSION%%/conf/logback.xml message_daemon-%%MAPS_VERSION%%/conf/logback.xml_orig && \ + mv message_daemon-%%MAPS_VERSION%%/conf/docker_logback.xml message_daemon-%%MAPS_VERSION%%/conf/logback.xml -RUN mv message_daemon-3.3.6-SNAPSHOT/conf/NetworkManager.yaml message_daemon-3.3.6-SNAPSHOT/conf/NetworkManager.yaml_orig && \ - mv message_daemon-3.3.6-SNAPSHOT/conf/NetworkManagerDocker.yaml message_daemon-3.3.6-SNAPSHOT/conf/NetworkManager.yaml +RUN mv message_daemon-%%MAPS_VERSION%%/conf/NetworkManager.yaml message_daemon-%%MAPS_VERSION%%/conf/NetworkManager.yaml_orig && \ + mv message_daemon-%%MAPS_VERSION%%/conf/NetworkManagerDocker.yaml message_daemon-%%MAPS_VERSION%%/conf/NetworkManager.yaml -RUN mv message_daemon-3.3.6-SNAPSHOT/conf/DestinationManager.yaml message_daemon-3.3.6-SNAPSHOT/conf/DestinationManager.yaml_orig && \ - mv message_daemon-3.3.6-SNAPSHOT/conf/DestinationManagerDocker.yaml message_daemon-3.3.6-SNAPSHOT/conf/DestinationManager.yaml +RUN mv message_daemon-%%MAPS_VERSION%%/conf/DestinationManager.yaml message_daemon-%%MAPS_VERSION%%/conf/DestinationManager.yaml_orig && \ + mv message_daemon-%%MAPS_VERSION%%/conf/DestinationManagerDocker.yaml message_daemon-%%MAPS_VERSION%%/conf/DestinationManager.yaml @@ -117,9 +117,9 @@ RUN mv message_daemon-3.3.6-SNAPSHOT/conf/DestinationManager.yaml message_daemon #---------------------------------------------------------------------------------------------- # Now configure and download hawtio for web/JMX/Rest administration #---------------------------------------------------------------------------------------------- -RUN cd ./message_daemon-3.3.6-SNAPSHOT && \ +RUN cd ./message_daemon-%%MAPS_VERSION%% && \ mv conf/hawtio.yaml conf/hawtio.yaml_old && \ - sed 's|/Users/matthew/Downloads/hawtio-war-2.15.0.war|./message_daemon-3.3.6-SNAPSHOT/hawtio-default-2.17.7.war|' conf/hawtio.yaml_old > conf/hawtio.yaml && \ + sed 's|/Users/matthew/Downloads/hawtio-war-2.15.0.war|./message_daemon-%%MAPS_VERSION%%/hawtio-default-2.17.7.war|' conf/hawtio.yaml_old > conf/hawtio.yaml && \ rm conf/hawtio.yaml_old && \ wget https://repo1.maven.org/maven2/io/hawt/hawtio-default/2.17.7/hawtio-default-2.17.7.war @@ -132,7 +132,7 @@ VOLUME /data # We can now simply start the server # Increase the file descriptor count #---------------------------------------------------------------------------------------------- -CMD export MAPS_HOME=./message_daemon-3.3.6-SNAPSHOT/ && \ +CMD export MAPS_HOME=./message_daemon-%%MAPS_VERSION%%/ && \ ulimit -n 100000 && \ export PATH=${JAVA_HOME}/bin:${PATH} && \ - message_daemon-3.3.6-SNAPSHOT/bin/startDocker.sh + message_daemon-%%MAPS_VERSION%%/bin/startDocker.sh From 7d9e3e61be693a1b8740970e9d541291ef56137b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:49:52 +0000 Subject: [PATCH 014/348] Bump com.fasterxml.jackson.datatype:jackson-datatype-jsr310 Bumps com.fasterxml.jackson.datatype:jackson-datatype-jsr310 from 2.15.3 to 2.16.0. --- updated-dependencies: - dependency-name: com.fasterxml.jackson.datatype:jackson-datatype-jsr310 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 39768e323..e6cb09fa2 100644 --- a/pom.xml +++ b/pom.xml @@ -562,7 +562,7 @@ com.fasterxml.jackson.datatype jackson-datatype-jsr310 - 2.15.3 + 2.16.0 From f5e8c838d72120ee8ee672ad6a7d894d4d4d6e24 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:50:37 +0000 Subject: [PATCH 015/348] Bump com.fasterxml.jackson.core:jackson-databind from 2.15.3 to 2.16.0 Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.15.3 to 2.16.0. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 39768e323..de16fb918 100644 --- a/pom.xml +++ b/pom.xml @@ -689,7 +689,7 @@ com.fasterxml.jackson.core jackson-databind - 2.15.3 + 2.16.0 From 937cfce7e2eb12f4628ece1b2aed7ed904162748 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 16 Nov 2023 18:50:50 +0000 Subject: [PATCH 016/348] Bump com.fasterxml.jackson.core:jackson-annotations Bumps [com.fasterxml.jackson.core:jackson-annotations](https://github.com/FasterXML/jackson) from 2.15.3 to 2.16.0. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 39768e323..2e6e005bd 100644 --- a/pom.xml +++ b/pom.xml @@ -696,7 +696,7 @@ com.fasterxml.jackson.core jackson-annotations - 2.15.3 + 2.16.0 From 4c18d4d632247f431b9b12a39447bb8fc5546141 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Fri, 17 Nov 2023 15:08:55 +1100 Subject: [PATCH 017/348] add network monitor agent that detects changes in state of the network interfaces and can be used to send update events to other agents in the server --- .../java/io/mapsmessaging/MessageDaemon.java | 32 ++-- .../logging/ServerLogMessages.java | 4 + .../network/monitor/NetworkEvent.java | 22 +++ .../monitor/NetworkInterfaceMonitor.java | 151 ++++++++++++++++++ .../monitor/NetworkInterfaceState.java | 45 ++++++ .../network/monitor/NetworkStateChange.java | 37 +++++ 6 files changed, 276 insertions(+), 15 deletions(-) create mode 100644 src/main/java/io/mapsmessaging/network/monitor/NetworkEvent.java create mode 100644 src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java create mode 100644 src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceState.java create mode 100644 src/main/java/io/mapsmessaging/network/monitor/NetworkStateChange.java diff --git a/src/main/java/io/mapsmessaging/MessageDaemon.java b/src/main/java/io/mapsmessaging/MessageDaemon.java index 6cd7b93fd..69847131f 100644 --- a/src/main/java/io/mapsmessaging/MessageDaemon.java +++ b/src/main/java/io/mapsmessaging/MessageDaemon.java @@ -34,6 +34,7 @@ import io.mapsmessaging.network.NetworkManager; import io.mapsmessaging.network.discovery.DiscoveryManager; import io.mapsmessaging.network.discovery.ServerConnectionManager; +import io.mapsmessaging.network.monitor.NetworkInterfaceMonitor; import io.mapsmessaging.network.protocol.ProtocolImplFactory; import io.mapsmessaging.network.protocol.transformation.TransformationManager; import io.mapsmessaging.rest.RestApiServerManager; @@ -155,21 +156,22 @@ private void createAgentStartStopList(String path) throws IOException { SecurityManager securityManager = new SecurityManager(); DestinationManager destinationManager = new DestinationManager(); - addToMap(5, 110, SchemaManager.getInstance()); - addToMap(10, 90, TransactionManager.getInstance()); - addToMap(30, 10, new DiscoveryManager(uniqueId)); - addToMap(40, 120, securityManager); - addToMap(50, 95, destinationManager); - addToMap(60, 30, new SessionManager(securityManager, destinationManager, path)); - addToMap(70, 15, new NetworkManager(mBean.getTypePath())); - addToMap(80, 5, new SystemTopicManager(destinationManager)); - addToMap(90, 20, new NetworkConnectionManager(mBean.getTypePath())); - addToMap(100, 25, new JolokaManager()); - addToMap(110, 30, new HawtioManager()); - addToMap(120, 40, new RestApiServerManager()); - addToMap(200, 2, new ServerConnectionManager()); - addToMap(210, 0, new RoutingManager()); - addToMap(220, 7, new DeviceManager()); + addToMap(50, 1100, SchemaManager.getInstance()); + addToMap(80, 20, NetworkInterfaceMonitor.getInstance()); + addToMap(100, 900, TransactionManager.getInstance()); + addToMap(300, 100, new DiscoveryManager(uniqueId)); + addToMap(400, 1200, securityManager); + addToMap(500, 950, destinationManager); + addToMap(600, 300, new SessionManager(securityManager, destinationManager, path)); + addToMap(700, 150, new NetworkManager(mBean.getTypePath())); + addToMap(800, 50, new SystemTopicManager(destinationManager)); + addToMap(900, 200, new NetworkConnectionManager(mBean.getTypePath())); + addToMap(1000, 250, new JolokaManager()); + addToMap(1100, 300, new HawtioManager()); + addToMap(1200, 400, new RestApiServerManager()); + addToMap(2000, 30, new ServerConnectionManager()); + addToMap(2100, 10, new RoutingManager()); + addToMap(2200, 70, new DeviceManager()); } private void addToMap(int start, int stop, Agent agent) { diff --git a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java index 8a965d480..557bca8ad 100644 --- a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java +++ b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java @@ -661,7 +661,11 @@ public enum ServerLogMessages implements LogMessage { DEVICE_MANAGER_RESUME_ALL(LEVEL.DEBUG, SERVER_CATEGORY.ENGINE, "Resuming all registered devices"), DEVICE_MANAGER_LOAD_PROPERTIES(LEVEL.DEBUG, SERVER_CATEGORY.ENGINE, "Loading Device Manager Properties"), DEVICE_MANAGER_STARTUP_COMPLETE(LEVEL.DEBUG, SERVER_CATEGORY.ENGINE, "Completed startup Device Manager"), + // + // + NETWORK_MONITOR_STATE_CHANGE(LEVEL.ERROR, SERVER_CATEGORY.NETWORK, "Network interface {} changed state to {}"), + NETWORK_MONITOR_EXCEPTION(LEVEL.INFO, SERVER_CATEGORY.NETWORK, "Network monitor raised exception {}"), // //------------------------------------------------------------------------------------------------------------- diff --git a/src/main/java/io/mapsmessaging/network/monitor/NetworkEvent.java b/src/main/java/io/mapsmessaging/network/monitor/NetworkEvent.java new file mode 100644 index 000000000..123183308 --- /dev/null +++ b/src/main/java/io/mapsmessaging/network/monitor/NetworkEvent.java @@ -0,0 +1,22 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.network.monitor; + +public enum NetworkEvent { + ADDED, REMOVED, UP, DOWN, IP_CHANGED +} diff --git a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java new file mode 100644 index 000000000..c3c101ac0 --- /dev/null +++ b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java @@ -0,0 +1,151 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.network.monitor; + +import io.mapsmessaging.logging.Logger; +import io.mapsmessaging.logging.LoggerFactory; +import io.mapsmessaging.utilities.Agent; +import io.mapsmessaging.utilities.scheduler.SimpleTaskScheduler; +import lombok.Getter; + +import java.net.InetAddress; +import java.net.InterfaceAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.*; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; + +import static io.mapsmessaging.logging.ServerLogMessages.NETWORK_MONITOR_EXCEPTION; +import static io.mapsmessaging.logging.ServerLogMessages.NETWORK_MONITOR_STATE_CHANGE; + +public class NetworkInterfaceMonitor implements Agent { + + @Getter + private static final NetworkInterfaceMonitor instance = new NetworkInterfaceMonitor(); + + private final Logger logger = LoggerFactory.getLogger(NetworkInterfaceMonitor.class); + private final List> listeners = new ArrayList<>(); + + private ScheduledFuture scheduledFuture; + private Map lastInterfaces; + + private NetworkInterfaceMonitor() { + } + + public List getCurrentIpAddresses() { + List addresses = new ArrayList<>(); + getCurrentNetworkInterfaces().forEach((s, networkInterfaceState) -> addresses.addAll(networkInterfaceState.getIpAddresses())); + return addresses; + } + + public void addListener(Consumer listener) { + listeners.add(listener); + } + + private void checkNetworkInterfaces() { + Map currentInterfaces = getCurrentNetworkInterfaces(); + compareInterfaceMaps(lastInterfaces, currentInterfaces); + lastInterfaces = currentInterfaces; + } + + private void compareInterfaceMaps(Map oldMap, Map newMap) { + for (Map.Entry entry : newMap.entrySet()) { + if (!oldMap.containsKey(entry.getKey())) { + notifyListeners(new NetworkStateChange(NetworkEvent.ADDED, entry.getValue())); + } else { + checkInterfaceStateChanges(oldMap.get(entry.getKey()), entry.getValue()); + } + } + for (Map.Entry entry : oldMap.entrySet()) { + if (!newMap.containsKey(entry.getKey())) { + notifyListeners(new NetworkStateChange(NetworkEvent.REMOVED, entry.getValue())); + } + } + } + + private void checkInterfaceStateChanges(NetworkInterfaceState oldInterface, NetworkInterfaceState newInterface) { + // Check for UP/DOWN state change + if (oldInterface.isUp() != newInterface.isUp()) { + NetworkEvent event = newInterface.isUp() ? NetworkEvent.UP : NetworkEvent.DOWN; + notifyListeners(new NetworkStateChange(event, newInterface)); + } + if (newInterface.isUp()) { + List oldAddresses = oldInterface.getIpAddresses(); + List newAddresses = newInterface.getIpAddresses(); + if (oldAddresses.size() != newAddresses.size()) { + notifyListeners(new NetworkStateChange(NetworkEvent.IP_CHANGED, newInterface)); + } else { + for (int i = 0; i < oldAddresses.size(); i++) { + if (!Arrays.equals(oldAddresses.get(i).getAddress(), newAddresses.get(i).getAddress())) { + notifyListeners(new NetworkStateChange(NetworkEvent.IP_CHANGED, newInterface)); + } + } + } + } + } + + private void notifyListeners(NetworkStateChange change) { + logger.log(NETWORK_MONITOR_STATE_CHANGE, change.getNetworkInterface().getName(), change.getEvent().name()); + listeners.forEach(listener -> listener.accept(change)); + } + + private Map getCurrentNetworkInterfaces() { + Map interfacesMap = new HashMap<>(); + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface networkInterface = interfaces.nextElement(); + for (InterfaceAddress address : networkInterface.getInterfaceAddresses()) { + InetAddress inetAddress = address.getAddress(); + if (!inetAddress.isLinkLocalAddress() && !inetAddress.isLoopbackAddress()) { + interfacesMap.put(networkInterface.getName(), new NetworkInterfaceState(networkInterface)); + break; + } + } + } + } catch (SocketException e) { + logger.log(NETWORK_MONITOR_EXCEPTION, e); + } + return interfacesMap; + } + + @Override + public String getName() { + return "Network Interface Monitor"; + } + + @Override + public String getDescription() { + return "Monitors system network interfaces and updates end points dependent on the network state"; + } + + @Override + public void start() { + lastInterfaces = getCurrentNetworkInterfaces(); + scheduledFuture = SimpleTaskScheduler.getInstance().scheduleAtFixedRate(this::checkNetworkInterfaces, 0, 30, TimeUnit.SECONDS); + } + + @Override + public void stop() { + if (scheduledFuture != null) { + scheduledFuture.cancel(true); + } + } +} diff --git a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceState.java b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceState.java new file mode 100644 index 000000000..e37b9c771 --- /dev/null +++ b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceState.java @@ -0,0 +1,45 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.network.monitor; + +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.net.InetAddress; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Collections; +import java.util.List; + +@Data +@EqualsAndHashCode +@ToString +public class NetworkInterfaceState { + private final String name; + private final String displayName; + private final boolean isUp; + private final List ipAddresses; + + public NetworkInterfaceState(NetworkInterface networkInterface) throws SocketException { + this.name = networkInterface.getName(); + this.isUp = networkInterface.isUp(); + this.ipAddresses = Collections.list(networkInterface.getInetAddresses()); + this.displayName = networkInterface.getDisplayName(); + } +} diff --git a/src/main/java/io/mapsmessaging/network/monitor/NetworkStateChange.java b/src/main/java/io/mapsmessaging/network/monitor/NetworkStateChange.java new file mode 100644 index 000000000..e98a83dfa --- /dev/null +++ b/src/main/java/io/mapsmessaging/network/monitor/NetworkStateChange.java @@ -0,0 +1,37 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.network.monitor; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@Getter +@ToString +@EqualsAndHashCode +public class NetworkStateChange { + + private final NetworkEvent event; + private final NetworkInterfaceState networkInterface; + + public NetworkStateChange(NetworkEvent event, NetworkInterfaceState networkInterface) { + this.event = event; + this.networkInterface = networkInterface; + } + +} \ No newline at end of file From fb80631f265c3934dee64457df3f7ae4b92f06b6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 18:22:43 +0000 Subject: [PATCH 018/348] Bump com.amazonaws:aws-java-sdk-cognitoidp from 1.12.589 to 1.12.591 Bumps [com.amazonaws:aws-java-sdk-cognitoidp](https://github.com/aws/aws-sdk-java) from 1.12.589 to 1.12.591. - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.589...1.12.591) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-cognitoidp dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 39768e323..71a08158c 100644 --- a/pom.xml +++ b/pom.xml @@ -865,7 +865,7 @@ com.amazonaws aws-java-sdk-cognitoidp - 1.12.589 + 1.12.591 test From a58f2eb1458066de791266b76fb7c3f7f21317ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 17 Nov 2023 18:23:49 +0000 Subject: [PATCH 019/348] Bump software.amazon.awssdk:bom from 2.21.23 to 2.21.25 Bumps software.amazon.awssdk:bom from 2.21.23 to 2.21.25. --- updated-dependencies: - dependency-name: software.amazon.awssdk:bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 39768e323..bf7468d9c 100644 --- a/pom.xml +++ b/pom.xml @@ -521,7 +521,7 @@ software.amazon.awssdk bom - 2.21.23 + 2.21.25 pom import From 0feb839334b30a835c7233bbd8a2af71c45369d0 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Mon, 20 Nov 2023 10:27:41 +1100 Subject: [PATCH 020/348] prefer ipv6 addresses if available --- src/main/java/io/mapsmessaging/network/NetworkManager.java | 3 +++ src/main/resources/NetworkManager.yaml | 1 + 2 files changed, 4 insertions(+) diff --git a/src/main/java/io/mapsmessaging/network/NetworkManager.java b/src/main/java/io/mapsmessaging/network/NetworkManager.java index 1ca6df2bb..7715e6fe1 100644 --- a/src/main/java/io/mapsmessaging/network/NetworkManager.java +++ b/src/main/java/io/mapsmessaging/network/NetworkManager.java @@ -55,6 +55,9 @@ public NetworkManager(List parent) { logger.log(ServerLogMessages.NETWORK_MANAGER_LOAD_PROPERTIES); endPointServers = ServiceLoader.load(EndPointServerFactory.class); logger.log(ServerLogMessages.NETWORK_MANAGER_STARTUP_COMPLETE); + if (properties.getBooleanProperty("preferIPv6Addresses", true)) { + System.setProperty("java.net.preferIPv6Addresses", "true"); + } bean = new NetworkManagerJMX(parent, this); } diff --git a/src/main/resources/NetworkManager.yaml b/src/main/resources/NetworkManager.yaml index 5f6179635..2bb64879a 100644 --- a/src/main/resources/NetworkManager.yaml +++ b/src/main/resources/NetworkManager.yaml @@ -86,6 +86,7 @@ NetworkManager: # Global configuration # --------------------------------------------------------------------------------------------------------- discoverable: false # If the server registers a mdns entry for the adapter + preferIPv6Addresses: true # If the server should prefer IPv6 addresses over IPv4 addresses data: From 83f2518742d4d4cf27125dc2cd37104a31dc84e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:25:45 +0000 Subject: [PATCH 021/348] Bump com.amazonaws:aws-java-sdk-cognitoidp from 1.12.591 to 1.12.592 Bumps [com.amazonaws:aws-java-sdk-cognitoidp](https://github.com/aws/aws-sdk-java) from 1.12.591 to 1.12.592. - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.591...1.12.592) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-cognitoidp dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0783c21d0..c51be9bb0 100644 --- a/pom.xml +++ b/pom.xml @@ -865,7 +865,7 @@ com.amazonaws aws-java-sdk-cognitoidp - 1.12.591 + 1.12.592 test From 9388fffb062f331f13db8d0eb913489cd434b534 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:25:56 +0000 Subject: [PATCH 022/348] Bump org.codehaus.mojo:exec-maven-plugin from 3.1.0 to 3.1.1 Bumps [org.codehaus.mojo:exec-maven-plugin](https://github.com/mojohaus/exec-maven-plugin) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/mojohaus/exec-maven-plugin/releases) - [Commits](https://github.com/mojohaus/exec-maven-plugin/compare/exec-maven-plugin-3.1.0...3.1.1) --- updated-dependencies: - dependency-name: org.codehaus.mojo:exec-maven-plugin dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0783c21d0..41a3444bf 100644 --- a/pom.xml +++ b/pom.xml @@ -94,7 +94,7 @@ org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.1.1 config-self-signed-certs @@ -421,7 +421,7 @@ org.codehaus.mojo exec-maven-plugin - 3.1.0 + 3.1.1 self-signed-certs From 3d5324dff1ca7122c6af5314356c9253c943166b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:26:28 +0000 Subject: [PATCH 023/348] Bump org.springframework:spring-websocket from 6.0.13 to 6.1.0 Bumps [org.springframework:spring-websocket](https://github.com/spring-projects/spring-framework) from 6.0.13 to 6.1.0. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.0.13...v6.1.0) --- updated-dependencies: - dependency-name: org.springframework:spring-websocket dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0783c21d0..9ab451e19 100644 --- a/pom.xml +++ b/pom.xml @@ -914,7 +914,7 @@ org.springframework spring-websocket - 6.0.13 + 6.1.0 test From 1c3ed29ee4da74accd79a973ffef8963ccc8d624 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:26:36 +0000 Subject: [PATCH 024/348] Bump software.amazon.awssdk:bom from 2.21.25 to 2.21.26 Bumps software.amazon.awssdk:bom from 2.21.25 to 2.21.26. --- updated-dependencies: - dependency-name: software.amazon.awssdk:bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0783c21d0..f9d36491b 100644 --- a/pom.xml +++ b/pom.xml @@ -521,7 +521,7 @@ software.amazon.awssdk bom - 2.21.25 + 2.21.26 pom import From 12ee504609ed3c2cff0ef3cc5a69e55dd4bf18fe Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 20 Nov 2023 18:27:02 +0000 Subject: [PATCH 025/348] Bump com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider Bumps com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider from 2.15.3 to 2.16.0. --- updated-dependencies: - dependency-name: com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 0783c21d0..aaac6a17b 100644 --- a/pom.xml +++ b/pom.xml @@ -702,7 +702,7 @@ com.fasterxml.jackson.jaxrs jackson-jaxrs-json-provider - 2.15.3 + 2.16.0 From b9c681f8ec91208d4215e1e860e3fe6eb1fd061b Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 21 Nov 2023 08:34:58 +1100 Subject: [PATCH 026/348] update for IPv6 support ensure the discovery manager uses the correct IP address so agents can actually connect to the server --- .../network/discovery/DiscoveryManager.java | 16 +++- .../network/monitor/NetworkEvent.java | 6 +- .../monitor/NetworkInterfaceMonitor.java | 73 ++++++++++++------- .../monitor/NetworkInterfaceState.java | 1 + src/main/resources/DiscoveryManager.yaml | 4 +- src/main/resources/NetworkManager.yaml | 23 +++--- 6 files changed, 77 insertions(+), 46 deletions(-) diff --git a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java index 7eb8163d6..0b4769cba 100644 --- a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java +++ b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java @@ -25,6 +25,7 @@ import io.mapsmessaging.logging.ServerLogMessages; import io.mapsmessaging.network.EndPointURL; import io.mapsmessaging.network.io.EndPointServer; +import io.mapsmessaging.network.monitor.NetworkInterfaceMonitor; import io.mapsmessaging.network.protocol.ProtocolFactory; import io.mapsmessaging.network.protocol.ProtocolImplFactory; import io.mapsmessaging.rest.RestApiServerManager; @@ -44,7 +45,7 @@ import static io.mapsmessaging.logging.ServerLogMessages.DISCOVERY_FAILED_TO_REGISTER; public class DiscoveryManager implements Agent { - private static final String ALL_HOSTS = "0.0.0.0"; + private static final String ALL_HOSTS = "::"; private final Logger logger; private final String serverName; @@ -91,10 +92,19 @@ public void start() { if (hostnames != null) { String[] hostnameList = hostnames.split(","); for (String hostname : hostnameList) { - InetAddress address = InetAddress.getByName(hostname.trim()); - boundedNetworks.add(bindInterface(hostname, address, stampMeta)); + List addresses = NetworkInterfaceMonitor.getInstance().getIpAddressByName(hostname.trim()); + for (InetAddress address : addresses) { + String name = address.getHostName(); + boundedNetworks.add(bindInterface(name, address, stampMeta)); + } } } else { + List addresses = NetworkInterfaceMonitor.getInstance().getCurrentIpAddresses(); + for (InetAddress address : addresses) { + String name = address.getHostName(); + boundedNetworks.add(bindInterface(name, address, stampMeta)); + } + InetAddress address = InetAddress.getLocalHost(); boundedNetworks.add(bindInterface(address.getHostName(), address, stampMeta)); } diff --git a/src/main/java/io/mapsmessaging/network/monitor/NetworkEvent.java b/src/main/java/io/mapsmessaging/network/monitor/NetworkEvent.java index 123183308..b869a7ddb 100644 --- a/src/main/java/io/mapsmessaging/network/monitor/NetworkEvent.java +++ b/src/main/java/io/mapsmessaging/network/monitor/NetworkEvent.java @@ -18,5 +18,9 @@ package io.mapsmessaging.network.monitor; public enum NetworkEvent { - ADDED, REMOVED, UP, DOWN, IP_CHANGED + ADDED, + REMOVED, + UP, + DOWN, + IP_CHANGED } diff --git a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java index c3c101ac0..c521df689 100644 --- a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java +++ b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java @@ -23,10 +23,7 @@ import io.mapsmessaging.utilities.scheduler.SimpleTaskScheduler; import lombok.Getter; -import java.net.InetAddress; -import java.net.InterfaceAddress; -import java.net.NetworkInterface; -import java.net.SocketException; +import java.net.*; import java.util.*; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @@ -49,6 +46,47 @@ public class NetworkInterfaceMonitor implements Agent { private NetworkInterfaceMonitor() { } + @Override + public String getName() { + return "Network Interface Monitor"; + } + + @Override + public String getDescription() { + return "Monitors system network interfaces and updates end points dependent on the network state"; + } + + @Override + public void start() { + lastInterfaces = getCurrentNetworkInterfaces(); + scheduledFuture = SimpleTaskScheduler.getInstance().scheduleAtFixedRate(this::checkNetworkInterfaces, 0, 30, TimeUnit.SECONDS); + } + + @Override + public void stop() { + if (scheduledFuture != null) { + scheduledFuture.cancel(true); + } + } + + public List getIpAddressByName(String adapterName) { + List list = new ArrayList<>(); + getCurrentNetworkInterfaces().forEach((s, networkInterfaceState) -> { + if (networkInterfaceState.getName().equals(adapterName)) { + list.addAll(networkInterfaceState.getIpAddresses()); + } else if (adapterName.equals("0.0.0.0")) { + networkInterfaceState.getIpAddresses().forEach((inetAddress) -> { + if (inetAddress instanceof Inet4Address) { + list.add(inetAddress); + } + }); + } else if (adapterName.equals("::")) { + list.addAll(networkInterfaceState.getIpAddresses()); + } + }); + return list; + } + public List getCurrentIpAddresses() { List addresses = new ArrayList<>(); getCurrentNetworkInterfaces().forEach((s, networkInterfaceState) -> addresses.addAll(networkInterfaceState.getIpAddresses())); @@ -59,6 +97,10 @@ public void addListener(Consumer listener) { listeners.add(listener); } + public void removeListener(Consumer listener) { + listeners.remove(listener); + } + private void checkNetworkInterfaces() { Map currentInterfaces = getCurrentNetworkInterfaces(); compareInterfaceMaps(lastInterfaces, currentInterfaces); @@ -125,27 +167,4 @@ private Map getCurrentNetworkInterfaces() { } return interfacesMap; } - - @Override - public String getName() { - return "Network Interface Monitor"; - } - - @Override - public String getDescription() { - return "Monitors system network interfaces and updates end points dependent on the network state"; - } - - @Override - public void start() { - lastInterfaces = getCurrentNetworkInterfaces(); - scheduledFuture = SimpleTaskScheduler.getInstance().scheduleAtFixedRate(this::checkNetworkInterfaces, 0, 30, TimeUnit.SECONDS); - } - - @Override - public void stop() { - if (scheduledFuture != null) { - scheduledFuture.cancel(true); - } - } } diff --git a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceState.java b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceState.java index e37b9c771..db3ee464a 100644 --- a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceState.java +++ b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceState.java @@ -31,6 +31,7 @@ @EqualsAndHashCode @ToString public class NetworkInterfaceState { + private final String name; private final String displayName; private final boolean isUp; diff --git a/src/main/resources/DiscoveryManager.yaml b/src/main/resources/DiscoveryManager.yaml index fff9978e7..b490944cc 100644 --- a/src/main/resources/DiscoveryManager.yaml +++ b/src/main/resources/DiscoveryManager.yaml @@ -17,6 +17,6 @@ --- DiscoveryManager: - enabled: false # If true then the server will start the discovery server else the server will not run the service - hostnames: 10.140.62.189, 100.119.57.114 # Array list of adapters to bind the discovery server to + enabled: true # If true then the server will start the discovery server else the server will not run the service + hostnames: "::" # Array list of adapters to bind the discovery server to addTxtRecords: true diff --git a/src/main/resources/NetworkManager.yaml b/src/main/resources/NetworkManager.yaml index 2bb64879a..d9185910c 100644 --- a/src/main/resources/NetworkManager.yaml +++ b/src/main/resources/NetworkManager.yaml @@ -85,40 +85,38 @@ NetworkManager: # --------------------------------------------------------------------------------------------------------- # Global configuration # --------------------------------------------------------------------------------------------------------- - discoverable: false # If the server registers a mdns entry for the adapter + discoverable: true # If the server registers a mdns entry for the adapter preferIPv6Addresses: true # If the server should prefer IPv6 addresses over IPv4 addresses data: - name: "MQTT Interface" - url: tcp://0.0.0.0:9000/ + url: tcp://:::9000/ protocol : all selectorThreadCount : 5 - name: "MQTT Interface" - url: tcp://0.0.0.0:1883/ + url: tcp://:::1883/ protocol : mqtt - name: "MQTT Interface" - url: "tcp://0.0.0.0:2883/" + url: tcp://:::2883/ protocol : mqtt - name: "Stomp Interface" - url: tcp://0.0.0.0:8675/ + url: tcp://:::8675/ protocol : stomp - - - url: tcp://0.0.0.0:5672/ + - url: tcp://:::5672/ name: "AMQP Interface" protocol : amqp SaslMechanisms : ANONYMOUS, CRAM_MD5, DIGEST-MD5, GSSAPI, NTLM - - - url: udp://0.0.0.0:1884/ + - url: udp://:::1884/ name: "MQTT-SN Interface" protocol: mqtt-sn eventsPerTopicDuringSleep: 5 @@ -130,14 +128,14 @@ NetworkManager: passwordFile: htpasswd - - url: udp://0.0.0.0:5683/ + - url: udp://:::5683/ name: "CoAP Interface" protocol: coap maxBlockSize: 512 idleTimePeriod: 120 - - url: udp://0.0.0.0:2442/ + - url: udp://:::2442/ name: "V2 predefined" protocol: mqtt-sn eventsPerTopicDuringSleep: 5 @@ -153,8 +151,7 @@ NetworkManager: topic: predefined/localhost/topic address: '127.0.0.1' - - - url: udp://0.0.0.0:1700/ + - url: udp://:::1700/ name: "SemTech Gateway" protocol: semtech inbound: /semtech/{gatewayId}/in From f27a55fa155a0c6069fc3829a48a9261e140e4e0 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 21 Nov 2023 12:43:23 +1100 Subject: [PATCH 027/348] Add ability to use the interface name "eth0" etc. Auto bind/close on interface state changes --- .../logging/ServerLogMessages.java | 1 + .../network/discovery/AdapterManager.java | 14 +++- .../network/discovery/DiscoveryManager.java | 75 ++++++++++++++++--- .../monitor/NetworkInterfaceMonitor.java | 29 ++++++- 4 files changed, 100 insertions(+), 19 deletions(-) diff --git a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java index 557bca8ad..99440c416 100644 --- a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java +++ b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java @@ -665,6 +665,7 @@ public enum ServerLogMessages implements LogMessage { // NETWORK_MONITOR_STATE_CHANGE(LEVEL.ERROR, SERVER_CATEGORY.NETWORK, "Network interface {} changed state to {}"), + NETWORK_MONITOR_DISCOVERED_DEVICES(LEVEL.ERROR, SERVER_CATEGORY.NETWORK, "Discovered {} network device as {}"), NETWORK_MONITOR_EXCEPTION(LEVEL.INFO, SERVER_CATEGORY.NETWORK, "Network monitor raised exception {}"), // diff --git a/src/main/java/io/mapsmessaging/network/discovery/AdapterManager.java b/src/main/java/io/mapsmessaging/network/discovery/AdapterManager.java index 2433aedd5..a8bab4655 100644 --- a/src/main/java/io/mapsmessaging/network/discovery/AdapterManager.java +++ b/src/main/java/io/mapsmessaging/network/discovery/AdapterManager.java @@ -24,15 +24,16 @@ import io.mapsmessaging.logging.ServerLogMessages; import io.mapsmessaging.network.EndPointURL; import io.mapsmessaging.network.io.EndPointServer; +import lombok.Getter; + +import javax.jmdns.JmDNS; +import javax.jmdns.ServiceInfo; +import javax.jmdns.ServiceListener; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import javax.jmdns.JmDNS; -import javax.jmdns.ServiceInfo; -import javax.jmdns.ServiceListener; -import lombok.Getter; public class AdapterManager { @@ -54,6 +55,11 @@ public AdapterManager(String adapter, String serverName, JmDNS agent, boolean st endPointList = new LinkedHashMap<>(); } + public void close() throws IOException { + mDNSAgent.close(); + endPointList.clear(); + } + public synchronized void register(EndPointServer endPointServer, String transport, List protocolList){ EndPointURL url = endPointServer.getUrl(); List serviceInfoList = new ArrayList<>(); diff --git a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java index 0b4769cba..ea973377a 100644 --- a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java +++ b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java @@ -25,7 +25,9 @@ import io.mapsmessaging.logging.ServerLogMessages; import io.mapsmessaging.network.EndPointURL; import io.mapsmessaging.network.io.EndPointServer; +import io.mapsmessaging.network.monitor.NetworkEvent; import io.mapsmessaging.network.monitor.NetworkInterfaceMonitor; +import io.mapsmessaging.network.monitor.NetworkStateChange; import io.mapsmessaging.network.protocol.ProtocolFactory; import io.mapsmessaging.network.protocol.ProtocolImplFactory; import io.mapsmessaging.rest.RestApiServerManager; @@ -34,6 +36,7 @@ import io.mapsmessaging.utilities.configuration.ConfigurationProperties; import io.mapsmessaging.utilities.service.Service; import lombok.Getter; +import org.jetbrains.annotations.NotNull; import javax.jmdns.JmDNS; import javax.jmdns.ServiceInfo; @@ -41,16 +44,19 @@ import java.io.IOException; import java.net.InetAddress; import java.util.*; +import java.util.function.Consumer; +import java.util.stream.Collectors; import static io.mapsmessaging.logging.ServerLogMessages.DISCOVERY_FAILED_TO_REGISTER; -public class DiscoveryManager implements Agent { +public class DiscoveryManager implements Agent, Consumer { private static final String ALL_HOSTS = "::"; private final Logger logger; private final String serverName; private final List boundedNetworks; private final ConfigurationProperties properties; + private final boolean stampMeta; @Getter private final boolean enabled; @@ -60,6 +66,7 @@ public DiscoveryManager(String serverName) { boundedNetworks = new ArrayList<>(); properties = ConfigurationManager.getInstance().getProperties("DiscoveryManager"); enabled = properties.getBooleanProperty("enabled", true); + stampMeta = properties.getBooleanProperty("addTxtRecords", false); } public void registerListener(String type, ServiceListener listener){ @@ -86,7 +93,6 @@ public String getDescription() { public void start() { if (enabled) { - boolean stampMeta = properties.getBooleanProperty("addTxtRecords", false); String hostnames = properties.getProperty("hostnames"); try { if (hostnames != null) { @@ -94,23 +100,19 @@ public void start() { for (String hostname : hostnameList) { List addresses = NetworkInterfaceMonitor.getInstance().getIpAddressByName(hostname.trim()); for (InetAddress address : addresses) { - String name = address.getHostName(); - boundedNetworks.add(bindInterface(name, address, stampMeta)); + boundedNetworks.add(bindInterface(address, stampMeta)); } } } else { List addresses = NetworkInterfaceMonitor.getInstance().getCurrentIpAddresses(); for (InetAddress address : addresses) { - String name = address.getHostName(); - boundedNetworks.add(bindInterface(name, address, stampMeta)); + boundedNetworks.add(bindInterface(address, stampMeta)); } - - InetAddress address = InetAddress.getLocalHost(); - boundedNetworks.add(bindInterface(address.getHostName(), address, stampMeta)); } } catch (IOException e) { logger.log(ServerLogMessages.DISCOVERY_FAILED_TO_START, e); } + NetworkInterfaceMonitor.getInstance().addListener(this); } } @@ -119,8 +121,8 @@ public void stop() { t.start(); } - private AdapterManager bindInterface(String hostname, InetAddress homeAddress, boolean stampMeta) throws IOException { - return new AdapterManager(hostname, serverName, JmDNS.create(homeAddress, serverName), stampMeta); + private AdapterManager bindInterface(InetAddress homeAddress, boolean stampMeta) throws IOException { + return new AdapterManager(homeAddress.getHostAddress(), serverName, JmDNS.create(homeAddress, serverName), stampMeta); } public ServiceInfo[] register(RestApiServerManager restApiServerManager) { @@ -229,4 +231,55 @@ public synchronized void deregisterAll() { manager.deregisterAll(); } } + + private boolean addInterface(InetAddress inetAddress) { + String hostnames = properties.getProperty("hostnames"); + if (hostnames != null) { + String[] hostnameList = hostnames.split(","); + for (String hostname : hostnameList) { + if (NetworkInterfaceMonitor.getInstance().ipAddressMatches(hostname.trim(), inetAddress)) { + return true; + } + } + } + return false; + } + + + @Override + public void accept(NetworkStateChange networkStateChange) { + if (networkStateChange.getEvent() == NetworkEvent.IP_CHANGED || networkStateChange.getEvent() == NetworkEvent.ADDED) { + for (InetAddress address : networkStateChange.getNetworkInterface().getIpAddresses()) { + if (addInterface(address)) { + try { + boolean found = boundedNetworks.stream().anyMatch(manager -> manager.getAdapter().equals(address.getHostAddress())); + if (!found) boundedNetworks.add(bindInterface(address, stampMeta)); + } catch (IOException e) { + logger.log(ServerLogMessages.DISCOVERY_FAILED_TO_START, e); + } + } + } + } else if (networkStateChange.getEvent() == NetworkEvent.DOWN || networkStateChange.getEvent() == NetworkEvent.REMOVED) { + for (InetAddress address : networkStateChange.getNetworkInterface().getIpAddresses()) { + String name = address.getHostAddress(); + List toRemove = boundedNetworks.stream().filter(manager -> manager.getAdapter().equals(name)).collect(Collectors.toList()); + for (AdapterManager manager : toRemove) { + boundedNetworks.remove(manager); + try { + manager.close(); + } catch (IOException e) { + // Log It + } + } + } + } else { + System.err.println(networkStateChange.toString()); + } + } + + @NotNull + @Override + public Consumer andThen(@NotNull Consumer after) { + return Consumer.super.andThen(after); + } } diff --git a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java index c521df689..86f0320b4 100644 --- a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java +++ b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java @@ -29,11 +29,13 @@ import java.util.concurrent.TimeUnit; import java.util.function.Consumer; -import static io.mapsmessaging.logging.ServerLogMessages.NETWORK_MONITOR_EXCEPTION; -import static io.mapsmessaging.logging.ServerLogMessages.NETWORK_MONITOR_STATE_CHANGE; +import static io.mapsmessaging.logging.ServerLogMessages.*; public class NetworkInterfaceMonitor implements Agent { + private static final String IPv4_ALL_HOSTS = "0.0.0.0"; + private static final String IPv6_ALL_HOSTS = "::"; + @Getter private static final NetworkInterfaceMonitor instance = new NetworkInterfaceMonitor(); @@ -59,6 +61,17 @@ public String getDescription() { @Override public void start() { lastInterfaces = getCurrentNetworkInterfaces(); + try { + Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); + while (interfaces.hasMoreElements()) { + NetworkInterface networkInterface = interfaces.nextElement(); + if (networkInterface.isUp()) { + logger.log(NETWORK_MONITOR_DISCOVERED_DEVICES, networkInterface.getName(), networkInterface.getDisplayName()); + } + } + } catch (SocketException e) { + // Ignore + } scheduledFuture = SimpleTaskScheduler.getInstance().scheduleAtFixedRate(this::checkNetworkInterfaces, 0, 30, TimeUnit.SECONDS); } @@ -69,18 +82,24 @@ public void stop() { } } + public boolean ipAddressMatches(String source, InetAddress test) { + return (source.equals(test.getHostAddress()) || + test instanceof Inet4Address && source.equals(IPv4_ALL_HOSTS) || + test instanceof Inet6Address && source.equals(IPv6_ALL_HOSTS)); + } + public List getIpAddressByName(String adapterName) { List list = new ArrayList<>(); getCurrentNetworkInterfaces().forEach((s, networkInterfaceState) -> { if (networkInterfaceState.getName().equals(adapterName)) { list.addAll(networkInterfaceState.getIpAddresses()); - } else if (adapterName.equals("0.0.0.0")) { + } else if (adapterName.equals(IPv4_ALL_HOSTS)) { networkInterfaceState.getIpAddresses().forEach((inetAddress) -> { if (inetAddress instanceof Inet4Address) { list.add(inetAddress); } }); - } else if (adapterName.equals("::")) { + } else if (adapterName.equals(IPv6_ALL_HOSTS)) { list.addAll(networkInterfaceState.getIpAddresses()); } }); @@ -132,10 +151,12 @@ private void checkInterfaceStateChanges(NetworkInterfaceState oldInterface, Netw List oldAddresses = oldInterface.getIpAddresses(); List newAddresses = newInterface.getIpAddresses(); if (oldAddresses.size() != newAddresses.size()) { + notifyListeners(new NetworkStateChange(NetworkEvent.DOWN, oldInterface)); notifyListeners(new NetworkStateChange(NetworkEvent.IP_CHANGED, newInterface)); } else { for (int i = 0; i < oldAddresses.size(); i++) { if (!Arrays.equals(oldAddresses.get(i).getAddress(), newAddresses.get(i).getAddress())) { + notifyListeners(new NetworkStateChange(NetworkEvent.DOWN, oldInterface)); notifyListeners(new NetworkStateChange(NetworkEvent.IP_CHANGED, newInterface)); } } From 226885029f17db1ebba3cc112a1f1984f7a9ea08 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 21 Nov 2023 15:47:10 +1100 Subject: [PATCH 028/348] Ensure the json is in fact json now that we validate based on the schema --- .../impl/stomp/StompSelectorTest.java | 50 +++++++++++-------- 1 file changed, 30 insertions(+), 20 deletions(-) diff --git a/src/test/java/io/mapsmessaging/network/protocol/impl/stomp/StompSelectorTest.java b/src/test/java/io/mapsmessaging/network/protocol/impl/stomp/StompSelectorTest.java index bd6b2a563..97aaefed8 100644 --- a/src/test/java/io/mapsmessaging/network/protocol/impl/stomp/StompSelectorTest.java +++ b/src/test/java/io/mapsmessaging/network/protocol/impl/stomp/StompSelectorTest.java @@ -1,18 +1,17 @@ /* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] * - * Copyright [ 2020 - 2022 ] [Matthew Buckton] + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. * */ @@ -21,17 +20,19 @@ import io.mapsmessaging.schemas.config.SchemaConfig; import io.mapsmessaging.schemas.config.impl.JsonSchemaConfig; import io.mapsmessaging.test.WaitForState; +import net.ser1.stomp.Client; +import net.ser1.stomp.Listener; +import org.json.JSONObject; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import javax.security.auth.login.LoginException; import java.io.IOException; import java.util.HashMap; import java.util.Map; import java.util.UUID; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.LongAdder; -import javax.security.auth.login.LoginException; -import net.ser1.stomp.Client; -import net.ser1.stomp.Listener; -import org.junit.jupiter.api.Assertions; -import org.junit.jupiter.api.Test; class StompSelectorTest extends StompBaseTest implements Listener { @@ -52,7 +53,12 @@ void simpleSelectorTest() throws IOException, LoginException, InterruptedExcepti client.send("$schema/"+topicName, config.pack()); client.subscribeW(topicName, this, map); for(int x=0;x(); map.put("receipt","message"+x); client.sendW(topicName, json, map); @@ -69,15 +75,19 @@ void simpleSelectorTest2() throws IOException, LoginException, InterruptedExcept Assertions.assertTrue(client.isConnected()); Map map = new HashMap<>(); map.put("id", "subscribe1"); - map.put("selector", "odd= 0"); + map.put("selector", "odd = 0"); SchemaConfig config = new JsonSchemaConfig(); config.setUniqueId(UUID.randomUUID()); String topicName = getTopicName(); client.send("$schema/"+topicName, config.pack()); client.subscribeW(topicName, this, map); for(int x=0;x(); map.put("receipt","message"); From a797a796c0ef6177df855c49ca0da433ad70a6ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 18:57:28 +0000 Subject: [PATCH 029/348] Bump software.amazon.awssdk:bom from 2.21.26 to 2.21.27 Bumps software.amazon.awssdk:bom from 2.21.26 to 2.21.27. --- updated-dependencies: - dependency-name: software.amazon.awssdk:bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 662963218..193155371 100644 --- a/pom.xml +++ b/pom.xml @@ -521,7 +521,7 @@ software.amazon.awssdk bom - 2.21.26 + 2.21.27 pom import From 6dae48efad78ce342e8cb994facb20a7f9f0cafd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 21 Nov 2023 18:58:05 +0000 Subject: [PATCH 030/348] Bump com.amazonaws:aws-java-sdk-cognitoidp from 1.12.592 to 1.12.593 Bumps [com.amazonaws:aws-java-sdk-cognitoidp](https://github.com/aws/aws-sdk-java) from 1.12.592 to 1.12.593. - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.592...1.12.593) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-cognitoidp dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 662963218..96214e27d 100644 --- a/pom.xml +++ b/pom.xml @@ -865,7 +865,7 @@ com.amazonaws aws-java-sdk-cognitoidp - 1.12.592 + 1.12.593 test From 8558cc0b30b71c651860480dfa3503a04cbc0154 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 22 Nov 2023 12:29:05 +1100 Subject: [PATCH 031/348] Allow lookup of host names. Order is IP Address match All address 0.0.0.0, :: Network Adpater Name, like eth0 etc Network lookup of host name --- .../io/mapsmessaging/logging/ServerLogMessages.java | 2 ++ .../network/monitor/NetworkInterfaceMonitor.java | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java index 99440c416..ac5a8e068 100644 --- a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java +++ b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java @@ -667,6 +667,8 @@ public enum ServerLogMessages implements LogMessage { NETWORK_MONITOR_STATE_CHANGE(LEVEL.ERROR, SERVER_CATEGORY.NETWORK, "Network interface {} changed state to {}"), NETWORK_MONITOR_DISCOVERED_DEVICES(LEVEL.ERROR, SERVER_CATEGORY.NETWORK, "Discovered {} network device as {}"), NETWORK_MONITOR_EXCEPTION(LEVEL.INFO, SERVER_CATEGORY.NETWORK, "Network monitor raised exception {}"), + NETWORK_MONITOR_RESOLVE_ERROR(LEVEL.ERROR, SERVER_CATEGORY.NETWORK, "Failed to resolve host name {} "), + NETWORK_MONITOR_RESOLVE_SUCCESS(LEVEL.INFO, SERVER_CATEGORY.NETWORK, "Successfully resolved host name {} to {}"), // //------------------------------------------------------------------------------------------------------------- diff --git a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java index 86f0320b4..f26f6b3f5 100644 --- a/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java +++ b/src/main/java/io/mapsmessaging/network/monitor/NetworkInterfaceMonitor.java @@ -103,6 +103,19 @@ public List getIpAddressByName(String adapterName) { list.addAll(networkInterfaceState.getIpAddresses()); } }); + if (list.isEmpty()) { + try { + InetAddress inetAddress = InetAddress.getByName(adapterName); + if (inetAddress != null) { + list.add(inetAddress); + logger.log(NETWORK_MONITOR_RESOLVE_SUCCESS, adapterName, inetAddress.getHostAddress()); + } else { + logger.log(NETWORK_MONITOR_RESOLVE_ERROR, adapterName); + } + } catch (UnknownHostException e) { + logger.log(NETWORK_MONITOR_RESOLVE_ERROR, adapterName, e); + } + } return list; } From cb6753bb4c272db0539228063a684167ea3b7942 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 22 Nov 2023 19:39:00 +1100 Subject: [PATCH 032/348] allow the mDNS domain name be added to the configuration --- .../mapsmessaging/network/discovery/AdapterManager.java | 9 +++++++-- src/main/resources/DiscoveryManager.yaml | 5 +++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/src/main/java/io/mapsmessaging/network/discovery/AdapterManager.java b/src/main/java/io/mapsmessaging/network/discovery/AdapterManager.java index a8bab4655..d95bd28d4 100644 --- a/src/main/java/io/mapsmessaging/network/discovery/AdapterManager.java +++ b/src/main/java/io/mapsmessaging/network/discovery/AdapterManager.java @@ -38,6 +38,7 @@ public class AdapterManager { private final Logger logger; + private final String domainName; private final String serverName; private final JmDNS mDNSAgent; private final Map> endPointList; @@ -46,11 +47,15 @@ public class AdapterManager { @Getter private final String adapter; - public AdapterManager(String adapter, String serverName, JmDNS agent, boolean stampMeta) { + public AdapterManager(String adapter, String serverName, JmDNS agent, boolean stampMeta, String domainName) { this.serverName = serverName; this.adapter = adapter; this.mDNSAgent = agent; this.stampMeta = stampMeta; + if (!domainName.startsWith(".")) { + domainName = "." + domainName; + } + this.domainName = domainName; logger = LoggerFactory.getLogger(AdapterManager.class); endPointList = new LinkedHashMap<>(); } @@ -88,7 +93,7 @@ public synchronized void register(EndPointServer endPointServer, String transpor map.put("server name", MessageDaemon.getInstance().getId()); map.put("date", BuildInfo.getBuildDate()); } - String service = "_" + lowerProtocol + "._"+transport+"._local"; + String service = "_" + lowerProtocol + "._" + transport + domainName; ServiceInfo serviceInfo = ServiceInfo.create(service, serverName, url.getPort(), 0, 0, map); serviceInfoList.add(serviceInfo); } diff --git a/src/main/resources/DiscoveryManager.yaml b/src/main/resources/DiscoveryManager.yaml index b490944cc..632ce7744 100644 --- a/src/main/resources/DiscoveryManager.yaml +++ b/src/main/resources/DiscoveryManager.yaml @@ -18,5 +18,6 @@ DiscoveryManager: enabled: true # If true then the server will start the discovery server else the server will not run the service - hostnames: "::" # Array list of adapters to bind the discovery server to - addTxtRecords: true + hostnames: "::" # Array list of adapters to bind the discovery server to + addTxtRecords: true # Add more information to the TXT records + domainName: ".local" # Domain name to use From a9c803ce34ca89522a6d978156ad53c997096a63 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 22 Nov 2023 19:45:55 +1100 Subject: [PATCH 033/348] allow the mDNS domain name be added to the configuration --- src/main/java/io/mapsmessaging/HawtioManager.java | 2 +- .../io/mapsmessaging/network/discovery/DiscoveryManager.java | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/mapsmessaging/HawtioManager.java b/src/main/java/io/mapsmessaging/HawtioManager.java index 4666b6a6c..2bd77b906 100644 --- a/src/main/java/io/mapsmessaging/HawtioManager.java +++ b/src/main/java/io/mapsmessaging/HawtioManager.java @@ -80,7 +80,7 @@ private class Startup implements Runnable { private void register() { if (properties.getBooleanProperty("discoverable", false)) { - String service = "_http._tcp.local."; + String service = "_http._tcp.local"; try { MessageDaemon.getInstance().getDiscoveryManager().register(properties.getProperty("hostname", "0.0.0.0"), service, "hawtio", 8080, "/hawtio/"); } catch (Exception e) { diff --git a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java index ea973377a..6637ddc75 100644 --- a/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java +++ b/src/main/java/io/mapsmessaging/network/discovery/DiscoveryManager.java @@ -57,6 +57,7 @@ public class DiscoveryManager implements Agent, Consumer { private final List boundedNetworks; private final ConfigurationProperties properties; private final boolean stampMeta; + private final String domainName; @Getter private final boolean enabled; @@ -67,6 +68,7 @@ public DiscoveryManager(String serverName) { properties = ConfigurationManager.getInstance().getProperties("DiscoveryManager"); enabled = properties.getBooleanProperty("enabled", true); stampMeta = properties.getBooleanProperty("addTxtRecords", false); + domainName = properties.getProperty("domainName", ".local"); } public void registerListener(String type, ServiceListener listener){ @@ -122,7 +124,7 @@ public void stop() { } private AdapterManager bindInterface(InetAddress homeAddress, boolean stampMeta) throws IOException { - return new AdapterManager(homeAddress.getHostAddress(), serverName, JmDNS.create(homeAddress, serverName), stampMeta); + return new AdapterManager(homeAddress.getHostAddress(), serverName, JmDNS.create(homeAddress, serverName), stampMeta, domainName); } public ServiceInfo[] register(RestApiServerManager restApiServerManager) { From b62d153916720119f56b5e5bc451361a65b06c66 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Nov 2023 18:22:00 +0000 Subject: [PATCH 034/348] Bump com.amazonaws:aws-java-sdk-cognitoidp from 1.12.593 to 1.12.594 Bumps [com.amazonaws:aws-java-sdk-cognitoidp](https://github.com/aws/aws-sdk-java) from 1.12.593 to 1.12.594. - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.593...1.12.594) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-cognitoidp dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 77d46b5c6..4a01a7a39 100644 --- a/pom.xml +++ b/pom.xml @@ -865,7 +865,7 @@ com.amazonaws aws-java-sdk-cognitoidp - 1.12.593 + 1.12.594 test From 2244294fc179bad5a70b790a375f0ba7e28d19a8 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 22 Nov 2023 18:23:03 +0000 Subject: [PATCH 035/348] Bump software.amazon.awssdk:bom from 2.21.27 to 2.21.28 Bumps software.amazon.awssdk:bom from 2.21.27 to 2.21.28. --- updated-dependencies: - dependency-name: software.amazon.awssdk:bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 77d46b5c6..5fc551d1d 100644 --- a/pom.xml +++ b/pom.xml @@ -521,7 +521,7 @@ software.amazon.awssdk bom - 2.21.27 + 2.21.28 pom import From f54c7c7709656982fdd34383f73d339242cbc61f Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Thu, 23 Nov 2023 13:42:50 +1100 Subject: [PATCH 036/348] First pass at starting the auth manager for the server --- .../java/io/mapsmessaging/InstanceConfig.java | 2 +- .../java/io/mapsmessaging/MessageDaemon.java | 2 + .../io/mapsmessaging/auth/AuthManager.java | 89 +++++++++++++++++++ .../auth/InitialStateHelper.java | 83 +++++++++++++++++ .../mapsmessaging/auth/PasswordGenerator.java | 45 ++++++++++ src/main/resources/AuthManager.yaml | 25 ++++++ 6 files changed, 245 insertions(+), 1 deletion(-) create mode 100644 src/main/java/io/mapsmessaging/auth/AuthManager.java create mode 100644 src/main/java/io/mapsmessaging/auth/InitialStateHelper.java create mode 100644 src/main/java/io/mapsmessaging/auth/PasswordGenerator.java create mode 100644 src/main/resources/AuthManager.yaml diff --git a/src/main/java/io/mapsmessaging/InstanceConfig.java b/src/main/java/io/mapsmessaging/InstanceConfig.java index 4950f74aa..010499e72 100644 --- a/src/main/java/io/mapsmessaging/InstanceConfig.java +++ b/src/main/java/io/mapsmessaging/InstanceConfig.java @@ -71,7 +71,7 @@ public void loadState() { serverName = obj.serverName; creationDate = obj.creationDate; } catch (FileNotFoundException e) { -// throw new RuntimeException(e); + // Not a big deal, since it might be the first run } } diff --git a/src/main/java/io/mapsmessaging/MessageDaemon.java b/src/main/java/io/mapsmessaging/MessageDaemon.java index 69847131f..57f9efe7e 100644 --- a/src/main/java/io/mapsmessaging/MessageDaemon.java +++ b/src/main/java/io/mapsmessaging/MessageDaemon.java @@ -19,6 +19,7 @@ import io.mapsmessaging.admin.MessageDaemonJMX; import io.mapsmessaging.api.features.Constants; +import io.mapsmessaging.auth.AuthManager; import io.mapsmessaging.consul.ConsulManagerFactory; import io.mapsmessaging.engine.TransactionManager; import io.mapsmessaging.engine.destination.DestinationManager; @@ -156,6 +157,7 @@ private void createAgentStartStopList(String path) throws IOException { SecurityManager securityManager = new SecurityManager(); DestinationManager destinationManager = new DestinationManager(); + addToMap(10, 2000, AuthManager.getInstance()); addToMap(50, 1100, SchemaManager.getInstance()); addToMap(80, 20, NetworkInterfaceMonitor.getInstance()); addToMap(100, 900, TransactionManager.getInstance()); diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java new file mode 100644 index 000000000..ec7ffcc45 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -0,0 +1,89 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth; + +import io.mapsmessaging.logging.Logger; +import io.mapsmessaging.logging.LoggerFactory; +import io.mapsmessaging.security.identity.IdentityLookup; +import io.mapsmessaging.security.identity.IdentityLookupFactory; +import io.mapsmessaging.utilities.Agent; +import io.mapsmessaging.utilities.configuration.ConfigurationManager; +import io.mapsmessaging.utilities.configuration.ConfigurationProperties; +import lombok.Getter; + +import java.util.Map; + + +public class AuthManager implements Agent { + @Getter + private static final AuthManager instance = new AuthManager(); + + private final Logger logger; + private final ConfigurationProperties properties; + private final boolean authenticationEnabled; + private final boolean authorisationEnabled; + + private final IdentityLookup identityLookup; + + @Override + public String getName() { + return "AuthManager"; + } + + @Override + public String getDescription() { + return "Manages the authentication and authorisation of user connections to the server"; + } + + @Override + public void start() { + + } + + @Override + public void stop() { + + } + + + private AuthManager() { + logger = LoggerFactory.getLogger(AuthManager.class); + properties = ConfigurationManager.getInstance().getProperties("AuthManager"); + authenticationEnabled = properties.getBooleanProperty("authenticationEnabled", false); + authorisationEnabled = properties.getBooleanProperty("authorizationEnabled", false) && authenticationEnabled; + if (authenticationEnabled) { + Map config = ((ConfigurationProperties) properties.get("config")).getMap(); + String authProvider = config.get("identityProvider").toString().trim(); + String password = InitialStateHelper.checkForFirstInstall(properties); + identityLookup = IdentityLookupFactory.getInstance().get(authProvider, config); + if (password != null) { + if (InitialStateHelper.validate("admin", password, identityLookup)) { + // Success!!! + + } else { + // Broke!!!! + } + } + } else { + identityLookup = null; + } + if (identityLookup == null) { + // todo log the fact we have not authentication + } + } +} diff --git a/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java b/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java new file mode 100644 index 000000000..8cf7a6d70 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java @@ -0,0 +1,83 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth; + +import io.mapsmessaging.security.identity.IdentityEntry; +import io.mapsmessaging.security.identity.IdentityLookup; +import io.mapsmessaging.security.identity.parsers.PasswordParser; +import io.mapsmessaging.security.identity.parsers.sha.Sha512PasswordParser; +import io.mapsmessaging.utilities.configuration.ConfigurationProperties; + +import java.io.File; +import java.io.FileOutputStream; +import java.util.Arrays; +import java.util.Map; + +public class InitialStateHelper { + + private InitialStateHelper() { + } + + public static String checkForFirstInstall(ConfigurationProperties properties) { + String password = null; + Map config = ((ConfigurationProperties) properties.get("config")).getMap(); + String authProvider = config.get("identityProvider").toString().trim(); + if (authProvider.equalsIgnoreCase("Apache-Basic-Auth")) { + String directory = (String) config.get("configDirectory"); + if (directory != null) { + File file = new File(directory); + if (!file.exists()) { + file.mkdirs(); + } + File passwordFile = new File(file, ".htpassword"); + File groupFile = new File(file, ".htgroup"); + if (!passwordFile.exists()) { + password = PasswordGenerator.generateRandomPassword(12); + String salt = PasswordGenerator.generateSalt(16); + PasswordParser passwordParser = new Sha512PasswordParser(); + salt = passwordParser.getKey() + salt; + byte[] hash = passwordParser.computeHash(password.getBytes(), salt.getBytes(), passwordParser.getCost()); + try (FileOutputStream fileOutputStream = new FileOutputStream(passwordFile)) { + fileOutputStream.write(("admin" + ":" + new String(hash)).getBytes()); + } catch (Exception e) { + //throw new RuntimeException(e); + } + + } + if (!groupFile.exists()) { + try (FileOutputStream fileOutputStream = new FileOutputStream(groupFile)) { + fileOutputStream.write(("admin:admin").getBytes()); + } catch (Exception e) { + //throw new RuntimeException(e); + } + } + } + } + return password; + } + + public static boolean validate(String username, String password, IdentityLookup identityLookup) { + IdentityEntry identityEntry = identityLookup.findEntry(username); + if (identityEntry != null) { + PasswordParser passwordParser = identityEntry.getPasswordParser(); + byte[] hash = passwordParser.computeHash(password.getBytes(), passwordParser.getSalt(), passwordParser.getCost()); + return Arrays.equals(hash, identityEntry.getPassword().getBytes()); + } + return false; + } +} diff --git a/src/main/java/io/mapsmessaging/auth/PasswordGenerator.java b/src/main/java/io/mapsmessaging/auth/PasswordGenerator.java new file mode 100644 index 000000000..018b6789f --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/PasswordGenerator.java @@ -0,0 +1,45 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth; + +import java.security.SecureRandom; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class PasswordGenerator { + + private static final String CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!@#$%"; + private static final String SALT_CHARACTERS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + public static String generateRandomPassword(int passwordLength) { + return generateRandom(passwordLength, CHARACTERS); + } + + public static String generateSalt(int saltLength) { + return generateRandom(saltLength, SALT_CHARACTERS); + } + + private static String generateRandom(int passwordLength, String chars) { + SecureRandom random = new SecureRandom(); + return IntStream.range(0, passwordLength) + .map(i -> chars.charAt(random.nextInt(chars.length()))) + .mapToObj(c -> String.valueOf((char) c)) + .collect(Collectors.joining()); + } + +} diff --git a/src/main/resources/AuthManager.yaml b/src/main/resources/AuthManager.yaml new file mode 100644 index 000000000..d54a2d2f9 --- /dev/null +++ b/src/main/resources/AuthManager.yaml @@ -0,0 +1,25 @@ +#----------------------------------------------------------------------------- +# +# Copyright [ 2020 - 2023 ] [Matthew Buckton] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +#----------------------------------------------------------------------------- +--- +AuthManager: + authenticationEnabled: true # connections will be authorised according to the config + authorizationEnabled: true # Requestes will be authorised according to the access control list for the resource + config: + defaultMechanism: SHA-512 + identityProvider: "Apache-Basic-Auth" + configDirectory: ./security \ No newline at end of file From cbbe10562606e6de35ada2705986d64af8ca3bbc Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Thu, 23 Nov 2023 15:04:43 +1100 Subject: [PATCH 037/348] First pass at starting the auth manager for the server --- .../auth/InitialStateHelper.java | 10 ++++- src/main/resources/AuthManager.yaml | 4 +- src/main/resources/NetworkManager.yaml | 43 ++----------------- src/main/resources/SecurityManager.yaml | 1 + src/main/resources/jaasAuth.config | 42 +++--------------- 5 files changed, 19 insertions(+), 81 deletions(-) diff --git a/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java b/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java index 8cf7a6d70..472bb8cb7 100644 --- a/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java +++ b/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java @@ -53,7 +53,7 @@ public static String checkForFirstInstall(ConfigurationProperties properties) { salt = passwordParser.getKey() + salt; byte[] hash = passwordParser.computeHash(password.getBytes(), salt.getBytes(), passwordParser.getCost()); try (FileOutputStream fileOutputStream = new FileOutputStream(passwordFile)) { - fileOutputStream.write(("admin" + ":" + new String(hash)).getBytes()); + fileOutputStream.write(("admin" + ":" + new String(hash) + "\n").getBytes()); } catch (Exception e) { //throw new RuntimeException(e); } @@ -61,11 +61,17 @@ public static String checkForFirstInstall(ConfigurationProperties properties) { } if (!groupFile.exists()) { try (FileOutputStream fileOutputStream = new FileOutputStream(groupFile)) { - fileOutputStream.write(("admin:admin").getBytes()); + fileOutputStream.write(("admin:admin\n").getBytes()); } catch (Exception e) { //throw new RuntimeException(e); } } + try { + FileOutputStream fileOutputStream = new FileOutputStream(new File(file, "Site_Password.txt")); + fileOutputStream.write(("Username:admin\nPassword:" + password + "\n").getBytes()); + } catch (Exception e) { + //throw new RuntimeException(e); + } } } return password; diff --git a/src/main/resources/AuthManager.yaml b/src/main/resources/AuthManager.yaml index d54a2d2f9..b5486e1ab 100644 --- a/src/main/resources/AuthManager.yaml +++ b/src/main/resources/AuthManager.yaml @@ -17,8 +17,8 @@ #----------------------------------------------------------------------------- --- AuthManager: - authenticationEnabled: true # connections will be authorised according to the config - authorizationEnabled: true # Requestes will be authorised according to the access control list for the resource + authenticationEnabled: false # connections will be authorised according to the config + authorizationEnabled: false # Requestes will be authorised according to the access control list for the resource config: defaultMechanism: SHA-512 identityProvider: "Apache-Basic-Auth" diff --git a/src/main/resources/NetworkManager.yaml b/src/main/resources/NetworkManager.yaml index d9185910c..8ebe7a55c 100644 --- a/src/main/resources/NetworkManager.yaml +++ b/src/main/resources/NetworkManager.yaml @@ -90,31 +90,12 @@ NetworkManager: data: - - - name: "MQTT Interface" + - name: "Open Interface" url: tcp://:::9000/ protocol : all selectorThreadCount : 5 + auth: default - - - name: "MQTT Interface" - url: tcp://:::1883/ - protocol : mqtt - - - - name: "MQTT Interface" - url: tcp://:::2883/ - protocol : mqtt - - - - name: "Stomp Interface" - url: tcp://:::8675/ - protocol : stomp - - - url: tcp://:::5672/ - name: "AMQP Interface" - protocol : amqp - SaslMechanisms : ANONYMOUS, CRAM_MD5, DIGEST-MD5, GSSAPI, NTLM - url: udp://:::1884/ name: "MQTT-SN Interface" @@ -125,8 +106,7 @@ NetworkManager: sasl: mechanism: SCRAM-SHA-512 identityProvider: htpassword - passwordFile: htpasswd - + passwordFile: ./security/htpassword - url: udp://:::5683/ name: "CoAP Interface" @@ -134,23 +114,6 @@ NetworkManager: maxBlockSize: 512 idleTimePeriod: 120 - - - url: udp://:::2442/ - name: "V2 predefined" - protocol: mqtt-sn - eventsPerTopicDuringSleep: 5 - maxTopicsInSleep: 10 - advertiseGateway: true - preDefinedTopics: - - - id: 1 - topic: predefined/topic - address: '*' - - - id: 1 - topic: predefined/localhost/topic - address: '127.0.0.1' - - url: udp://:::1700/ name: "SemTech Gateway" protocol: semtech diff --git a/src/main/resources/SecurityManager.yaml b/src/main/resources/SecurityManager.yaml index b530f9330..eff753aa9 100644 --- a/src/main/resources/SecurityManager.yaml +++ b/src/main/resources/SecurityManager.yaml @@ -16,3 +16,4 @@ --- SecurityManager: + - default: DefaultLoginAuth diff --git a/src/main/resources/jaasAuth.config b/src/main/resources/jaasAuth.config index 9285f8c36..4f407623d 100644 --- a/src/main/resources/jaasAuth.config +++ b/src/main/resources/jaasAuth.config @@ -1,38 +1,6 @@ -MessagingAuthConfig { - com.sun.security.auth.module.LdapLoginModule Required - userProvider="ldap://10.140.62.27:389" - authIdentity="uid={USERNAME},OU=people,DC=buckton,DC=org" - useSSL=false - debug=false; -}; - - -PrivateAuthConfig { - com.sun.security.auth.module.LdapLoginModule Required - userProvider="ldap://10.140.62.27:389" - authIdentity="uid={USERNAME},OU=people,DC=buckton,DC=org" - useSSL=false - debug=false; -}; - -PublicAuthConfig { - io.mapsmessaging.security.jaas.AnonymousLoginModule Required - debug=true; -}; - -SSLAuthConfig{ - io.mapsmessaging.security.jaas.SSLCertificateLoginModule Required - debug=false; -}; - -JWTAuthConfig{ - io.mapsmessaging.security.jaas.Auth0JwtLoginModule Required - debug=true - auth0Domain=dev-krmpy6-z.au.auth0.com; - -}; - -JaasKrb { - com.sun.security.auth.module.Krb5LoginModule required - debug=true; +DefaultLoginAuth { + io.mapsmessaging.security.jaas.IdentityLoginModule Required + debug=false + identityName="Apache-Basic-Auth" + configDirectory="./security"; }; From 8985b26330d5556c383f0f8546fcb538962e9e65 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Thu, 23 Nov 2023 15:07:45 +1100 Subject: [PATCH 038/348] If the server has disabled auth then override the network configuration as well --- .../io/mapsmessaging/engine/session/SecurityManager.java | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/mapsmessaging/engine/session/SecurityManager.java b/src/main/java/io/mapsmessaging/engine/session/SecurityManager.java index 2fc6e1429..e15ca8e19 100644 --- a/src/main/java/io/mapsmessaging/engine/session/SecurityManager.java +++ b/src/main/java/io/mapsmessaging/engine/session/SecurityManager.java @@ -17,6 +17,7 @@ package io.mapsmessaging.engine.session; +import io.mapsmessaging.auth.AuthManager; import io.mapsmessaging.engine.session.security.AnonymousSecurityContext; import io.mapsmessaging.engine.session.security.JaasSecurityContext; import io.mapsmessaging.engine.session.security.SaslSecurityContext; @@ -65,8 +66,12 @@ public SecurityContext getSecurityContext(SessionContext sessionContext) throws context = new SaslSecurityContext(username, endPointPrincipal); } else if (defined != null) { - LoginContext loginContext = getLoginContext(defined, username, passCode, endPointPrincipal); - context = new JaasSecurityContext(username, loginContext); + if (AuthManager.getInstance().isAuthenticationEnabled()) { + LoginContext loginContext = getLoginContext(defined, username, passCode, endPointPrincipal); + context = new JaasSecurityContext(username, loginContext); + } else { + context = new AnonymousSecurityContext(endPointPrincipal); + } } else { context = new AnonymousSecurityContext(endPointPrincipal); From c390cb244440af705d29e259ba6745c4217742b7 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Thu, 23 Nov 2023 15:10:43 +1100 Subject: [PATCH 039/348] If the server has disabled auth then override the network configuration as well --- src/main/java/io/mapsmessaging/auth/AuthManager.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index ec7ffcc45..3b2e244cf 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -35,7 +35,10 @@ public class AuthManager implements Agent { private final Logger logger; private final ConfigurationProperties properties; + + @Getter private final boolean authenticationEnabled; + @Getter private final boolean authorisationEnabled; private final IdentityLookup identityLookup; From 58be87a3cec4e576c686aca47df03731670bd685 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:19:59 +0000 Subject: [PATCH 040/348] Bump software.amazon.awssdk:bom from 2.21.28 to 2.21.29 Bumps software.amazon.awssdk:bom from 2.21.28 to 2.21.29. --- updated-dependencies: - dependency-name: software.amazon.awssdk:bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2fe1d9747..cea9ff292 100644 --- a/pom.xml +++ b/pom.xml @@ -521,7 +521,7 @@ software.amazon.awssdk bom - 2.21.28 + 2.21.29 pom import From 732703983d6720a59233282896ea847442ded760 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:20:20 +0000 Subject: [PATCH 041/348] Bump org.springframework.boot:spring-boot-starter-websocket Bumps [org.springframework.boot:spring-boot-starter-websocket](https://github.com/spring-projects/spring-boot) from 3.1.5 to 3.2.0. - [Release notes](https://github.com/spring-projects/spring-boot/releases) - [Commits](https://github.com/spring-projects/spring-boot/compare/v3.1.5...v3.2.0) --- updated-dependencies: - dependency-name: org.springframework.boot:spring-boot-starter-websocket dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2fe1d9747..52befb2d3 100644 --- a/pom.xml +++ b/pom.xml @@ -921,7 +921,7 @@ org.springframework.boot spring-boot-starter-websocket - 3.1.5 + 3.2.0 test From 111ee10226c3a7abde68d204e8cd9657cd7d1454 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:20:52 +0000 Subject: [PATCH 042/348] Bump com.amazonaws:aws-java-sdk-cognitoidp from 1.12.594 to 1.12.595 Bumps [com.amazonaws:aws-java-sdk-cognitoidp](https://github.com/aws/aws-sdk-java) from 1.12.594 to 1.12.595. - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.594...1.12.595) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-cognitoidp dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2fe1d9747..379678412 100644 --- a/pom.xml +++ b/pom.xml @@ -865,7 +865,7 @@ com.amazonaws aws-java-sdk-cognitoidp - 1.12.594 + 1.12.595 test From e4608c90e5d8174d56b0f37cf84f08b46b0b2ac9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 23 Nov 2023 18:21:42 +0000 Subject: [PATCH 043/348] Bump org.springframework:spring-websocket from 6.1.0 to 6.1.1 Bumps [org.springframework:spring-websocket](https://github.com/spring-projects/spring-framework) from 6.1.0 to 6.1.1. - [Release notes](https://github.com/spring-projects/spring-framework/releases) - [Commits](https://github.com/spring-projects/spring-framework/compare/v6.1.0...v6.1.1) --- updated-dependencies: - dependency-name: org.springframework:spring-websocket dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2fe1d9747..ffcb6a3dc 100644 --- a/pom.xml +++ b/pom.xml @@ -914,7 +914,7 @@ org.springframework spring-websocket - 6.1.0 + 6.1.1 test From 14d0df87babb05feb5e066433c3129b1cfe92410 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Fri, 24 Nov 2023 16:55:04 +1100 Subject: [PATCH 044/348] Add the user/group to UUID mapping management Add ability to add/mod and delete users and groups Add quota storage, add, mod and delete Update first boot to ensure all files are constructed and sound On log in add the quota principal to the subject --- pom.xml | 8 ++ .../io/mapsmessaging/auth/AuthManager.java | 85 +++++++++++--- .../auth/InitialStateHelper.java | 89 -------------- .../io/mapsmessaging/auth/QuotaPrincipal.java | 42 +++++++ .../auth/registry/AuthenticationStorage.java | 109 ++++++++++++++++++ .../auth/registry/FileManager.java | 68 +++++++++++ .../auth/registry/GroupFileManager.java | 51 ++++++++ .../{ => registry}/PasswordGenerator.java | 2 +- .../mapsmessaging/auth/registry/Quotas.java | 108 +++++++++++++++++ .../auth/registry/UUIDSerializer.java | 40 +++++++ .../auth/registry/UserFileManager.java | 64 ++++++++++ .../auth/registry/UserPermisionManager.java | 67 +++++++++++ .../session/security/JaasSecurityContext.java | 18 ++- src/main/resources/AuthManager.yaml | 3 +- 14 files changed, 642 insertions(+), 112 deletions(-) delete mode 100644 src/main/java/io/mapsmessaging/auth/InitialStateHelper.java create mode 100644 src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/FileManager.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/GroupFileManager.java rename src/main/java/io/mapsmessaging/auth/{ => registry}/PasswordGenerator.java (97%) create mode 100644 src/main/java/io/mapsmessaging/auth/registry/Quotas.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/UUIDSerializer.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/UserFileManager.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java diff --git a/pom.xml b/pom.xml index 2fe1d9747..59c099a59 100644 --- a/pom.xml +++ b/pom.xml @@ -861,6 +861,14 @@ + + + org.mapdb + mapdb + 3.0.10 + + + com.amazonaws diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index 3b2e244cf..d59d0b56b 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -17,6 +17,9 @@ package io.mapsmessaging.auth; +import io.mapsmessaging.auth.registry.AuthenticationStorage; +import io.mapsmessaging.auth.registry.PasswordGenerator; +import io.mapsmessaging.auth.registry.Quotas; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; import io.mapsmessaging.security.identity.IdentityLookup; @@ -26,7 +29,12 @@ import io.mapsmessaging.utilities.configuration.ConfigurationProperties; import lombok.Getter; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; import java.util.Map; +import java.util.UUID; public class AuthManager implements Agent { @@ -35,13 +43,14 @@ public class AuthManager implements Agent { private final Logger logger; private final ConfigurationProperties properties; + private final AuthenticationStorage authenticationStorage; @Getter private final boolean authenticationEnabled; @Getter private final boolean authorisationEnabled; - private final IdentityLookup identityLookup; + private IdentityLookup identityLookup; @Override public String getName() { @@ -55,38 +64,76 @@ public String getDescription() { @Override public void start() { + if (authenticationEnabled) { + Map config = ((ConfigurationProperties) properties.get("config")).getMap(); + String authProvider = config.get("identityProvider").toString().trim(); + String password = null; + if (!authenticationStorage.getUserFile().exists()) { + password = PasswordGenerator.generateRandomPassword(12); + String username = "admin"; + addUser(username, password, Quotas.createAdminQuota(username), new String[]{username}); + String path = properties.getProperty("configDirectory", "./security"); + + try (BufferedWriter bw = new BufferedWriter(new FileWriter(path + File.separator + "admin_password", true))) { + bw.write("admin=" + password); + bw.newLine(); // Add a newline character after each line + } catch (IOException e) { + e.printStackTrace(); + } + } + identityLookup = IdentityLookupFactory.getInstance().get(authProvider, config); + if (password != null) { + if (authenticationStorage.validateUser("admin", password, identityLookup)) { + System.err.println("Successfully added admin"); + } else { + System.err.println("Failed to add admin"); + } + } + + } else { + identityLookup = null; + } + if (identityLookup == null) { + // todo log the fact we have not authentication + } } @Override public void stop() { + try { + authenticationStorage.close(); + } catch (IOException e) { + } } + public boolean addUser(String username, String password, Quotas quotas, String[] groups) { + if (identityLookup == null || identityLookup.findEntry(username) == null) { + if (!quotas.getUsername().equalsIgnoreCase(username)) { + // ToDo we need to check the quotas are valid + } + return authenticationStorage.addUser(username, password, quotas, groups); + } + return false; + } + + public boolean delUser(String username) { + if (identityLookup.findEntry(username) != null) { + return authenticationStorage.delUser(username); + } + return false; + } private AuthManager() { logger = LoggerFactory.getLogger(AuthManager.class); properties = ConfigurationManager.getInstance().getProperties("AuthManager"); authenticationEnabled = properties.getBooleanProperty("authenticationEnabled", false); authorisationEnabled = properties.getBooleanProperty("authorizationEnabled", false) && authenticationEnabled; - if (authenticationEnabled) { - Map config = ((ConfigurationProperties) properties.get("config")).getMap(); - String authProvider = config.get("identityProvider").toString().trim(); - String password = InitialStateHelper.checkForFirstInstall(properties); - identityLookup = IdentityLookupFactory.getInstance().get(authProvider, config); - if (password != null) { - if (InitialStateHelper.validate("admin", password, identityLookup)) { - // Success!!! + authenticationStorage = new AuthenticationStorage(properties.getProperty("configDirectory", "./security")); + } - } else { - // Broke!!!! - } - } - } else { - identityLookup = null; - } - if (identityLookup == null) { - // todo log the fact we have not authentication - } + public Quotas getQuota(UUID userId) { + return authenticationStorage.getQuota(userId); } } diff --git a/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java b/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java deleted file mode 100644 index 472bb8cb7..000000000 --- a/src/main/java/io/mapsmessaging/auth/InitialStateHelper.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright [ 2020 - 2023 ] [Matthew Buckton] - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package io.mapsmessaging.auth; - -import io.mapsmessaging.security.identity.IdentityEntry; -import io.mapsmessaging.security.identity.IdentityLookup; -import io.mapsmessaging.security.identity.parsers.PasswordParser; -import io.mapsmessaging.security.identity.parsers.sha.Sha512PasswordParser; -import io.mapsmessaging.utilities.configuration.ConfigurationProperties; - -import java.io.File; -import java.io.FileOutputStream; -import java.util.Arrays; -import java.util.Map; - -public class InitialStateHelper { - - private InitialStateHelper() { - } - - public static String checkForFirstInstall(ConfigurationProperties properties) { - String password = null; - Map config = ((ConfigurationProperties) properties.get("config")).getMap(); - String authProvider = config.get("identityProvider").toString().trim(); - if (authProvider.equalsIgnoreCase("Apache-Basic-Auth")) { - String directory = (String) config.get("configDirectory"); - if (directory != null) { - File file = new File(directory); - if (!file.exists()) { - file.mkdirs(); - } - File passwordFile = new File(file, ".htpassword"); - File groupFile = new File(file, ".htgroup"); - if (!passwordFile.exists()) { - password = PasswordGenerator.generateRandomPassword(12); - String salt = PasswordGenerator.generateSalt(16); - PasswordParser passwordParser = new Sha512PasswordParser(); - salt = passwordParser.getKey() + salt; - byte[] hash = passwordParser.computeHash(password.getBytes(), salt.getBytes(), passwordParser.getCost()); - try (FileOutputStream fileOutputStream = new FileOutputStream(passwordFile)) { - fileOutputStream.write(("admin" + ":" + new String(hash) + "\n").getBytes()); - } catch (Exception e) { - //throw new RuntimeException(e); - } - - } - if (!groupFile.exists()) { - try (FileOutputStream fileOutputStream = new FileOutputStream(groupFile)) { - fileOutputStream.write(("admin:admin\n").getBytes()); - } catch (Exception e) { - //throw new RuntimeException(e); - } - } - try { - FileOutputStream fileOutputStream = new FileOutputStream(new File(file, "Site_Password.txt")); - fileOutputStream.write(("Username:admin\nPassword:" + password + "\n").getBytes()); - } catch (Exception e) { - //throw new RuntimeException(e); - } - } - } - return password; - } - - public static boolean validate(String username, String password, IdentityLookup identityLookup) { - IdentityEntry identityEntry = identityLookup.findEntry(username); - if (identityEntry != null) { - PasswordParser passwordParser = identityEntry.getPasswordParser(); - byte[] hash = passwordParser.computeHash(password.getBytes(), passwordParser.getSalt(), passwordParser.getCost()); - return Arrays.equals(hash, identityEntry.getPassword().getBytes()); - } - return false; - } -} diff --git a/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java b/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java new file mode 100644 index 000000000..5f10be9d1 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java @@ -0,0 +1,42 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth; + +import io.mapsmessaging.auth.registry.Quotas; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +import java.security.Principal; + +@ToString +@EqualsAndHashCode +public class QuotaPrincipal implements Principal { + + @Getter + private final Quotas quotas; + + public QuotaPrincipal(Quotas quotas) { + this.quotas = quotas; + } + + @Override + public String getName() { + return "QuotaPrincipal"; + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java new file mode 100644 index 000000000..96eed1824 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java @@ -0,0 +1,109 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry; + +import io.mapsmessaging.security.access.mapping.GroupMapManagement; +import io.mapsmessaging.security.access.mapping.UserMapManagement; +import io.mapsmessaging.security.identity.IdentityEntry; +import io.mapsmessaging.security.identity.IdentityLookup; +import io.mapsmessaging.security.identity.parsers.PasswordParser; +import io.mapsmessaging.security.identity.parsers.bcrypt.BCrypt2yPasswordParser; +import lombok.Getter; + +import java.io.Closeable; +import java.io.File; +import java.io.IOException; +import java.util.Arrays; +import java.util.UUID; + +public class AuthenticationStorage implements Closeable { + + @Getter + private final UserFileManager userFile; + @Getter + private final GroupFileManager groupFile; + + private final PasswordParser passwordParser; + private final UserMapManagement userMapManagement; + private final GroupMapManagement groupMapManagement; + private final UserPermisionManager userPermisionManager; + + public AuthenticationStorage(String securityDirectory) { + if (securityDirectory != null) { + File file = new File(securityDirectory); + if (!file.exists()) { + file.mkdirs(); + } + } + userMapManagement = new UserMapManagement(securityDirectory + File.separator + ".userMap"); + groupMapManagement = new GroupMapManagement(securityDirectory + File.separator + ".groupMap"); + UserMapManagement.setGlobalInstance(userMapManagement); + GroupMapManagement.setGlobalInstance(groupMapManagement); + passwordParser = new BCrypt2yPasswordParser(); + this.groupFile = new GroupFileManager(securityDirectory + File.separator + ".htgroup", groupMapManagement); + this.userFile = new UserFileManager(securityDirectory + File.separator + ".htpassword", passwordParser, userMapManagement); + userPermisionManager = new UserPermisionManager(securityDirectory + File.separator + ".userPermissions"); + } + + + public boolean addUser(String username, String password, Quotas quotas, String[] groups) { + try { + UUID uuid = userFile.addUser(username, password); + groupFile.addGroup(username, groups); + quotas.setUuid(uuid); + userPermisionManager.add(quotas); + return true; + } catch (IOException e) { + + } + return false; + } + + public boolean delUser(String username) { + try { + UUID userId = userFile.getUserUUID(username); + userFile.deleteUser(username); + //groupFile.deleteGroup(username); + userPermisionManager.delete(userId); + return true; + } catch (IOException e) { + + } + return false; + } + + + public boolean validateUser(String username, String password, IdentityLookup identityLookup) { + IdentityEntry identityEntry = identityLookup.findEntry(username); + if (identityEntry != null) { + PasswordParser passwordParser = identityEntry.getPasswordParser(); + byte[] hash = passwordParser.computeHash(password.getBytes(), passwordParser.getSalt(), passwordParser.getCost()); + return Arrays.equals(hash, identityEntry.getPassword().getBytes()); + } + return false; + } + + @Override + public void close() throws IOException { + userPermisionManager.close(); + } + + public Quotas getQuota(UUID userId) { + return userPermisionManager.get(userId); + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/FileManager.java b/src/main/java/io/mapsmessaging/auth/registry/FileManager.java new file mode 100644 index 000000000..adf0c454c --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/FileManager.java @@ -0,0 +1,68 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry; + +import java.io.*; + +public abstract class FileManager { + private final File file; + + protected FileManager(String filename) { + file = new File(filename); + } + + public boolean exists() { + return file.exists(); + } + + protected void add(String line) throws IOException { + if (!file.exists()) { + file.createNewFile(); + } + try (BufferedWriter bw = new BufferedWriter(new FileWriter(file, true))) { + bw.write(line); + bw.newLine(); // Add a newline character after each line + } + } + + protected void delete(String name) throws IOException { + File tempFile = new File(file.getAbsolutePath() + ".tmp"); + + try (BufferedReader reader = new BufferedReader(new FileReader(file)); + BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) { + + String lineToRemove = name + ":"; + String currentLine; + + while ((currentLine = reader.readLine()) != null) { + if (!currentLine.startsWith(lineToRemove)) { + writer.write(currentLine + System.lineSeparator()); + } + } + } + + if (!file.delete()) { + throw new IOException("Could not delete original file"); + } + + if (!tempFile.renameTo(file)) { + throw new IOException("Could not rename temporary file"); + } + } + +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/GroupFileManager.java b/src/main/java/io/mapsmessaging/auth/registry/GroupFileManager.java new file mode 100644 index 000000000..f689595b9 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/GroupFileManager.java @@ -0,0 +1,51 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry; + +import io.mapsmessaging.security.access.mapping.GroupIdMap; +import io.mapsmessaging.security.access.mapping.GroupMapManagement; + +import java.io.IOException; +import java.util.UUID; + +public class GroupFileManager extends FileManager { + + private final GroupMapManagement groupMapManagement; + + public GroupFileManager(String filename, GroupMapManagement groupMapManagement) { + super(filename); + this.groupMapManagement = groupMapManagement; + } + + public UUID addGroup(String groupName, String... users) throws IOException { + super.add(groupName + ":" + String.join(",", users)); + GroupIdMap groupIdMap = new GroupIdMap(UUID.randomUUID(), groupName, "apache"); + groupMapManagement.add(groupIdMap); + return groupIdMap.getAuthId(); + } + + public void updateGroup(String groupName, String... users) throws IOException { + deleteGroup(groupName); + addGroup(groupName, users); + } + + public void deleteGroup(String groupName) throws IOException { + super.delete(groupName); + groupMapManagement.delete("apache:" + groupName); + } +} diff --git a/src/main/java/io/mapsmessaging/auth/PasswordGenerator.java b/src/main/java/io/mapsmessaging/auth/registry/PasswordGenerator.java similarity index 97% rename from src/main/java/io/mapsmessaging/auth/PasswordGenerator.java rename to src/main/java/io/mapsmessaging/auth/registry/PasswordGenerator.java index 018b6789f..b8d914460 100644 --- a/src/main/java/io/mapsmessaging/auth/PasswordGenerator.java +++ b/src/main/java/io/mapsmessaging/auth/registry/PasswordGenerator.java @@ -15,7 +15,7 @@ * */ -package io.mapsmessaging.auth; +package io.mapsmessaging.auth.registry; import java.security.SecureRandom; import java.util.stream.Collectors; diff --git a/src/main/java/io/mapsmessaging/auth/registry/Quotas.java b/src/main/java/io/mapsmessaging/auth/registry/Quotas.java new file mode 100644 index 000000000..c6c355d90 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/Quotas.java @@ -0,0 +1,108 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import org.jetbrains.annotations.NotNull; +import org.mapdb.DataInput2; +import org.mapdb.DataOutput2; +import org.mapdb.Serializer; + +import java.io.IOException; +import java.util.UUID; + +@Data +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class Quotas implements Serializer { + + public static Quotas createAdminQuota(String username) { + return new Quotas(username); + } + + private UUID uuid; + private final String username; + private final boolean isAdmin; + private final boolean accessSystemTopics; + private final boolean canPublishRetainedMessages; + + private final int publishPerMinute; + private final int maxPublishSize; + + private final int maxQoS; + private final int maxConcurrentPersistentSessions; + private final int maxConcurrentSubscriptions; + private final int maxConcurrentConnections; + private final long maxSessionTimeout; + + public Quotas() { + this(""); + } + + public Quotas(String username) { + this.username = username; + isAdmin = true; + accessSystemTopics = true; + canPublishRetainedMessages = true; + publishPerMinute = 0; + maxPublishSize = 0; + maxQoS = 0; + maxConcurrentPersistentSessions = 0; + maxConcurrentSubscriptions = 0; + maxConcurrentConnections = 0; + maxSessionTimeout = 0; + } + + @Override + public void serialize(@NotNull DataOutput2 dataOutput2, @NotNull Quotas userDetails) throws IOException { + dataOutput2.writeUTF(userDetails.username); + dataOutput2.writeLong(userDetails.uuid.getMostSignificantBits()); + dataOutput2.writeLong(userDetails.uuid.getLeastSignificantBits()); + dataOutput2.writeBoolean(userDetails.isAdmin); + dataOutput2.writeBoolean(userDetails.accessSystemTopics); + dataOutput2.writeBoolean(userDetails.canPublishRetainedMessages); + dataOutput2.writeInt(userDetails.publishPerMinute); + dataOutput2.writeInt(userDetails.maxPublishSize); + dataOutput2.writeInt(userDetails.maxQoS); + dataOutput2.writeInt(userDetails.maxConcurrentConnections); + dataOutput2.writeInt(userDetails.maxConcurrentSubscriptions); + dataOutput2.writeInt(userDetails.maxConcurrentPersistentSessions); + dataOutput2.writeLong(userDetails.maxSessionTimeout); + } + + @Override + public Quotas deserialize(@NotNull DataInput2 dataInput2, int i) throws IOException { + String user = dataInput2.readUTF(); + java.util.UUID id = new UUID(dataInput2.readLong(), dataInput2.readLong()); + boolean admin = dataInput2.readBoolean(); + boolean system = dataInput2.readBoolean(); + boolean retain = dataInput2.readBoolean(); + int pub = dataInput2.readInt(); + int pubSize = dataInput2.readInt(); + int qos = dataInput2.readInt(); + int persistentSessions = dataInput2.readInt(); + int concurrentSub = dataInput2.readInt(); + int concurrentCon = dataInput2.readInt(); + long timeout = dataInput2.readLong(); + return new Quotas(id, user, admin, system, retain, pub, pubSize, qos, persistentSessions, concurrentSub, concurrentCon, timeout); + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/UUIDSerializer.java b/src/main/java/io/mapsmessaging/auth/registry/UUIDSerializer.java new file mode 100644 index 000000000..7d9dca432 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/UUIDSerializer.java @@ -0,0 +1,40 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry; + +import org.jetbrains.annotations.NotNull; +import org.mapdb.DataInput2; +import org.mapdb.DataOutput2; +import org.mapdb.Serializer; + +import java.io.IOException; +import java.util.UUID; + +public class UUIDSerializer implements Serializer { + + @Override + public void serialize(@NotNull DataOutput2 dataOutput2, @NotNull UUID uuid) throws IOException { + dataOutput2.writeLong(uuid.getMostSignificantBits()); + dataOutput2.writeLong(uuid.getLeastSignificantBits()); + } + + @Override + public UUID deserialize(@NotNull DataInput2 dataInput2, int i) throws IOException { + return new UUID(dataInput2.readLong(), dataInput2.readLong()); + } +} \ No newline at end of file diff --git a/src/main/java/io/mapsmessaging/auth/registry/UserFileManager.java b/src/main/java/io/mapsmessaging/auth/registry/UserFileManager.java new file mode 100644 index 000000000..959628077 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/UserFileManager.java @@ -0,0 +1,64 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry; + +import io.mapsmessaging.security.access.mapping.UserIdMap; +import io.mapsmessaging.security.access.mapping.UserMapManagement; +import io.mapsmessaging.security.identity.parsers.PasswordParser; + +import java.io.IOException; +import java.util.UUID; + +public class UserFileManager extends FileManager { + + private final PasswordParser passwordParser; + private final UserMapManagement userMapManagement; + + public UserFileManager(String filename, PasswordParser passwordParser, UserMapManagement mapManagement) { + super(filename); + this.passwordParser = passwordParser; + this.userMapManagement = mapManagement; + } + + public UUID addUser(String username, String password) throws IOException { + String salt = PasswordGenerator.generateSalt(16); + byte[] hash = passwordParser.computeHash(password.getBytes(), salt.getBytes(), 12); + add(username + ":" + new String(hash)); + UserIdMap userIdMap = new UserIdMap(UUID.randomUUID(), username, "apache", ""); + userMapManagement.add(userIdMap); + return userIdMap.getAuthId(); + } + + public void updateUser(String username, String password) throws IOException { + deleteUser(username); + addUser(username, password); + } + + public void deleteUser(String username) throws IOException { + delete(username); + userMapManagement.delete("apache:" + username); + } + + public UUID getUserUUID(String username) { + UserIdMap map = userMapManagement.get("apache:" + username); + if (map != null) { + return map.getAuthId(); + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java b/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java new file mode 100644 index 000000000..2e5f9e121 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java @@ -0,0 +1,67 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry; + +import org.mapdb.DB; +import org.mapdb.DBMaker; + +import java.io.Closeable; +import java.io.IOException; +import java.util.UUID; +import java.util.concurrent.ConcurrentMap; + +public class UserPermisionManager implements Closeable { + + private final ConcurrentMap store; + private final DB db; + + public UserPermisionManager(String fileName) { + db = DBMaker.fileDB(fileName) + .checksumStoreEnable() + .fileChannelEnable() + .fileMmapEnableIfSupported() + .fileMmapPreclearDisable() + .closeOnJvmShutdown() + .make(); + + db.getStore().fileLoad(); + store = db.hashMap(UserPermisionManager.class.getName(), new UUIDSerializer(), new Quotas()).createOrOpen(); + } + + + public void add(Quotas userDetails) { + store.put(userDetails.getUuid(), userDetails); + } + + public void update(Quotas userDetails) { + store.put(userDetails.getUuid(), userDetails); + } + + public void delete(UUID uuid) { + store.remove(uuid); + } + + @Override + public void close() throws IOException { + db.close(); + } + + public Quotas get(UUID userId) { + return store.get(userId); + } +} diff --git a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java index 10e348b35..41a098573 100644 --- a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java @@ -17,13 +17,19 @@ package io.mapsmessaging.engine.session.security; +import io.mapsmessaging.auth.AuthManager; +import io.mapsmessaging.auth.QuotaPrincipal; +import io.mapsmessaging.auth.registry.Quotas; import io.mapsmessaging.engine.audit.AuditEvent; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; import io.mapsmessaging.logging.ServerLogMessages; -import java.io.IOException; +import io.mapsmessaging.security.identity.principals.UniqueIdentifierPrincipal; + import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; +import java.io.IOException; +import java.util.UUID; public class JaasSecurityContext extends SecurityContext { @@ -41,6 +47,16 @@ public void login() throws IOException { try { loginContext.login(); subject = loginContext.getSubject(); + UUID userId = subject.getPrincipals(UniqueIdentifierPrincipal.class).stream() + .findFirst() + .map(UniqueIdentifierPrincipal::getAuthId) + .orElse(null); + if (userId != null) { + Quotas quotas = AuthManager.getInstance().getQuota(userId); + if (quotas != null) { + subject.getPrincipals().add(new QuotaPrincipal(quotas)); + } + } logger.log(AuditEvent.SUCCESSFUL_LOGIN, subject); isLoggedIn = true; } catch (LoginException e) { diff --git a/src/main/resources/AuthManager.yaml b/src/main/resources/AuthManager.yaml index b5486e1ab..442ae440c 100644 --- a/src/main/resources/AuthManager.yaml +++ b/src/main/resources/AuthManager.yaml @@ -18,8 +18,7 @@ --- AuthManager: authenticationEnabled: false # connections will be authorised according to the config - authorizationEnabled: false # Requestes will be authorised according to the access control list for the resource + authorizationEnabled: true # Requestes will be authorised according to the access control list for the resource config: - defaultMechanism: SHA-512 identityProvider: "Apache-Basic-Auth" configDirectory: ./security \ No newline at end of file From 0e2a8391d4c2cc87e96b122e70801d3b84013246 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Sat, 25 Nov 2023 16:05:43 +1100 Subject: [PATCH 045/348] Use a key/value pair for the privileges so they can be added to without having to break or change the serialisation --- .../api/SessionContextBuilder.java | 1 - .../io/mapsmessaging/auth/AuthManager.java | 8 +- .../io/mapsmessaging/auth/QuotaPrincipal.java | 14 ++- .../auth/registry/AuthenticationStorage.java | 7 +- .../mapsmessaging/auth/registry/Quotas.java | 108 ------------------ .../auth/registry/UserPermisionManager.java | 16 +-- .../registry/priviliges/BooleanPrivilege.java | 18 +++ .../registry/priviliges/LongPrivilege.java | 18 +++ .../auth/registry/priviliges/Privilege.java | 11 ++ .../priviliges/PrivilegeSerializer.java | 52 +++++++++ .../registry/priviliges/StringPrivilege.java | 18 +++ .../priviliges/session/SessionPrivileges.java | 73 ++++++++++++ .../subscription/SubscriptionPrivileges.java | 4 + .../engine/session/SessionContext.java | 2 - .../session/security/JaasSecurityContext.java | 8 +- 15 files changed, 225 insertions(+), 133 deletions(-) delete mode 100644 src/main/java/io/mapsmessaging/auth/registry/Quotas.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/priviliges/BooleanPrivilege.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/priviliges/LongPrivilege.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/priviliges/Privilege.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/priviliges/StringPrivilege.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/priviliges/subscription/SubscriptionPrivileges.java diff --git a/src/main/java/io/mapsmessaging/api/SessionContextBuilder.java b/src/main/java/io/mapsmessaging/api/SessionContextBuilder.java index d09fe3d68..0a2c3a366 100644 --- a/src/main/java/io/mapsmessaging/api/SessionContextBuilder.java +++ b/src/main/java/io/mapsmessaging/api/SessionContextBuilder.java @@ -135,7 +135,6 @@ public SessionContext build() { sc.setWillDelay(willDelay); sc.setExpiry(sessionExpiry); sc.setReceiveMaximum(receiveMaximum); - sc.setDuration(duration); sc.setAuthorized(authorized); return sc; } diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index d59d0b56b..418de1900 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -19,7 +19,7 @@ import io.mapsmessaging.auth.registry.AuthenticationStorage; import io.mapsmessaging.auth.registry.PasswordGenerator; -import io.mapsmessaging.auth.registry.Quotas; +import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; import io.mapsmessaging.security.identity.IdentityLookup; @@ -71,7 +71,7 @@ public void start() { if (!authenticationStorage.getUserFile().exists()) { password = PasswordGenerator.generateRandomPassword(12); String username = "admin"; - addUser(username, password, Quotas.createAdminQuota(username), new String[]{username}); + addUser(username, password, SessionPrivileges.createAdminQuota(username), new String[]{username}); String path = properties.getProperty("configDirectory", "./security"); try (BufferedWriter bw = new BufferedWriter(new FileWriter(path + File.separator + "admin_password", true))) { @@ -108,7 +108,7 @@ public void stop() { } } - public boolean addUser(String username, String password, Quotas quotas, String[] groups) { + public boolean addUser(String username, String password, SessionPrivileges quotas, String[] groups) { if (identityLookup == null || identityLookup.findEntry(username) == null) { if (!quotas.getUsername().equalsIgnoreCase(username)) { // ToDo we need to check the quotas are valid @@ -133,7 +133,7 @@ private AuthManager() { authenticationStorage = new AuthenticationStorage(properties.getProperty("configDirectory", "./security")); } - public Quotas getQuota(UUID userId) { + public SessionPrivileges getQuota(UUID userId) { return authenticationStorage.getQuota(userId); } } diff --git a/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java b/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java index 5f10be9d1..e74641857 100644 --- a/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java +++ b/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java @@ -17,7 +17,8 @@ package io.mapsmessaging.auth; -import io.mapsmessaging.auth.registry.Quotas; +import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; +import io.mapsmessaging.auth.registry.priviliges.subscription.SubscriptionPrivileges; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; @@ -29,10 +30,15 @@ public class QuotaPrincipal implements Principal { @Getter - private final Quotas quotas; + private final SessionPrivileges sessionPrivileges; - public QuotaPrincipal(Quotas quotas) { - this.quotas = quotas; + @Getter + private final SubscriptionPrivileges subscriptionPrivileges; + + + public QuotaPrincipal(SessionPrivileges sessionPrivileges, SubscriptionPrivileges subscriptionPrivileges) { + this.sessionPrivileges = sessionPrivileges; + this.subscriptionPrivileges = subscriptionPrivileges; } @Override diff --git a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java index 96eed1824..5437bd8de 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java +++ b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java @@ -17,6 +17,7 @@ package io.mapsmessaging.auth.registry; +import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; import io.mapsmessaging.security.access.mapping.GroupMapManagement; import io.mapsmessaging.security.access.mapping.UserMapManagement; import io.mapsmessaging.security.identity.IdentityEntry; @@ -61,11 +62,11 @@ public AuthenticationStorage(String securityDirectory) { } - public boolean addUser(String username, String password, Quotas quotas, String[] groups) { + public boolean addUser(String username, String password, SessionPrivileges quotas, String[] groups) { try { UUID uuid = userFile.addUser(username, password); groupFile.addGroup(username, groups); - quotas.setUuid(uuid); + quotas.setUniqueId(uuid); userPermisionManager.add(quotas); return true; } catch (IOException e) { @@ -103,7 +104,7 @@ public void close() throws IOException { userPermisionManager.close(); } - public Quotas getQuota(UUID userId) { + public SessionPrivileges getQuota(UUID userId) { return userPermisionManager.get(userId); } } diff --git a/src/main/java/io/mapsmessaging/auth/registry/Quotas.java b/src/main/java/io/mapsmessaging/auth/registry/Quotas.java deleted file mode 100644 index c6c355d90..000000000 --- a/src/main/java/io/mapsmessaging/auth/registry/Quotas.java +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright [ 2020 - 2023 ] [Matthew Buckton] - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package io.mapsmessaging.auth.registry; - -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; -import org.jetbrains.annotations.NotNull; -import org.mapdb.DataInput2; -import org.mapdb.DataOutput2; -import org.mapdb.Serializer; - -import java.io.IOException; -import java.util.UUID; - -@Data -@AllArgsConstructor -@ToString -@EqualsAndHashCode -public class Quotas implements Serializer { - - public static Quotas createAdminQuota(String username) { - return new Quotas(username); - } - - private UUID uuid; - private final String username; - private final boolean isAdmin; - private final boolean accessSystemTopics; - private final boolean canPublishRetainedMessages; - - private final int publishPerMinute; - private final int maxPublishSize; - - private final int maxQoS; - private final int maxConcurrentPersistentSessions; - private final int maxConcurrentSubscriptions; - private final int maxConcurrentConnections; - private final long maxSessionTimeout; - - public Quotas() { - this(""); - } - - public Quotas(String username) { - this.username = username; - isAdmin = true; - accessSystemTopics = true; - canPublishRetainedMessages = true; - publishPerMinute = 0; - maxPublishSize = 0; - maxQoS = 0; - maxConcurrentPersistentSessions = 0; - maxConcurrentSubscriptions = 0; - maxConcurrentConnections = 0; - maxSessionTimeout = 0; - } - - @Override - public void serialize(@NotNull DataOutput2 dataOutput2, @NotNull Quotas userDetails) throws IOException { - dataOutput2.writeUTF(userDetails.username); - dataOutput2.writeLong(userDetails.uuid.getMostSignificantBits()); - dataOutput2.writeLong(userDetails.uuid.getLeastSignificantBits()); - dataOutput2.writeBoolean(userDetails.isAdmin); - dataOutput2.writeBoolean(userDetails.accessSystemTopics); - dataOutput2.writeBoolean(userDetails.canPublishRetainedMessages); - dataOutput2.writeInt(userDetails.publishPerMinute); - dataOutput2.writeInt(userDetails.maxPublishSize); - dataOutput2.writeInt(userDetails.maxQoS); - dataOutput2.writeInt(userDetails.maxConcurrentConnections); - dataOutput2.writeInt(userDetails.maxConcurrentSubscriptions); - dataOutput2.writeInt(userDetails.maxConcurrentPersistentSessions); - dataOutput2.writeLong(userDetails.maxSessionTimeout); - } - - @Override - public Quotas deserialize(@NotNull DataInput2 dataInput2, int i) throws IOException { - String user = dataInput2.readUTF(); - java.util.UUID id = new UUID(dataInput2.readLong(), dataInput2.readLong()); - boolean admin = dataInput2.readBoolean(); - boolean system = dataInput2.readBoolean(); - boolean retain = dataInput2.readBoolean(); - int pub = dataInput2.readInt(); - int pubSize = dataInput2.readInt(); - int qos = dataInput2.readInt(); - int persistentSessions = dataInput2.readInt(); - int concurrentSub = dataInput2.readInt(); - int concurrentCon = dataInput2.readInt(); - long timeout = dataInput2.readLong(); - return new Quotas(id, user, admin, system, retain, pub, pubSize, qos, persistentSessions, concurrentSub, concurrentCon, timeout); - } -} diff --git a/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java b/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java index 2e5f9e121..132cf6ef6 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java +++ b/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java @@ -17,6 +17,8 @@ package io.mapsmessaging.auth.registry; +import io.mapsmessaging.auth.registry.priviliges.PrivilegeSerializer; +import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; import org.mapdb.DB; import org.mapdb.DBMaker; @@ -27,7 +29,7 @@ public class UserPermisionManager implements Closeable { - private final ConcurrentMap store; + private final ConcurrentMap store; private final DB db; public UserPermisionManager(String fileName) { @@ -40,16 +42,16 @@ public UserPermisionManager(String fileName) { .make(); db.getStore().fileLoad(); - store = db.hashMap(UserPermisionManager.class.getName(), new UUIDSerializer(), new Quotas()).createOrOpen(); + store = db.hashMap(UserPermisionManager.class.getName(), new UUIDSerializer(), new PrivilegeSerializer()).createOrOpen(); } - public void add(Quotas userDetails) { - store.put(userDetails.getUuid(), userDetails); + public void add(SessionPrivileges userDetails) { + store.put(userDetails.getUniqueId(), userDetails); } - public void update(Quotas userDetails) { - store.put(userDetails.getUuid(), userDetails); + public void update(SessionPrivileges userDetails) { + store.put(userDetails.getUniqueId(), userDetails); } public void delete(UUID uuid) { @@ -61,7 +63,7 @@ public void close() throws IOException { db.close(); } - public Quotas get(UUID userId) { + public SessionPrivileges get(UUID userId) { return store.get(userId); } } diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/BooleanPrivilege.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/BooleanPrivilege.java new file mode 100644 index 000000000..7a5f47f61 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/priviliges/BooleanPrivilege.java @@ -0,0 +1,18 @@ +package io.mapsmessaging.auth.registry.priviliges; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@ToString +@Getter +@EqualsAndHashCode(callSuper = true) +public class BooleanPrivilege extends Privilege { + + private final boolean value; + + public BooleanPrivilege(String name, boolean value) { + super(name); + this.value = value; + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/LongPrivilege.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/LongPrivilege.java new file mode 100644 index 000000000..299dc262e --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/priviliges/LongPrivilege.java @@ -0,0 +1,18 @@ +package io.mapsmessaging.auth.registry.priviliges; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@ToString +@Getter +@EqualsAndHashCode(callSuper = true) +public class LongPrivilege extends Privilege { + + private final long value; + + public LongPrivilege(String name, long value) { + super(name); + this.value = value; + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/Privilege.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/Privilege.java new file mode 100644 index 000000000..5bf783a4e --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/priviliges/Privilege.java @@ -0,0 +1,11 @@ +package io.mapsmessaging.auth.registry.priviliges; + +import lombok.*; + +@Data +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class Privilege { + protected final String name; +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java new file mode 100644 index 000000000..5bc002de7 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java @@ -0,0 +1,52 @@ +package io.mapsmessaging.auth.registry.priviliges; + +import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; +import org.jetbrains.annotations.NotNull; +import org.mapdb.DataInput2; +import org.mapdb.DataOutput2; +import org.mapdb.Serializer; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +public class PrivilegeSerializer implements Serializer { + + @Override + public void serialize(@NotNull DataOutput2 dataOutput2, @NotNull SessionPrivileges userDetails) throws IOException { + dataOutput2.writeUTF(userDetails.getUsername()); + dataOutput2.writeLong(userDetails.getUniqueId().getMostSignificantBits()); + dataOutput2.writeLong(userDetails.getUniqueId().getLeastSignificantBits()); + int count = userDetails.getPriviliges().size(); + dataOutput2.writeInt(count); + for (Privilege p : userDetails.getPriviliges()) { + dataOutput2.writeUTF(p.getName()); + if (p instanceof BooleanPrivilege) { + dataOutput2.writeInt(0); + dataOutput2.writeBoolean(((BooleanPrivilege) p).isValue()); + } else if (p instanceof LongPrivilege) { + dataOutput2.writeInt(1); + dataOutput2.writeLong(((LongPrivilege) p).getValue()); + } + } + } + + @Override + public SessionPrivileges deserialize(@NotNull DataInput2 dataInput2, int i) throws IOException { + List list = new ArrayList<>(); + String user = dataInput2.readUTF(); + java.util.UUID id = new UUID(dataInput2.readLong(), dataInput2.readLong()); + int count = dataInput2.readInt(); + for (int x = 0; x < count; x++) { + String name = dataInput2.readUTF(); + int type = dataInput2.readInt(); + if (type == 0) { + list.add(new BooleanPrivilege(name, dataInput2.readBoolean())); + } else { + list.add(new LongPrivilege(name, dataInput2.readLong())); + } + } + return new SessionPrivileges(id, user, list); + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/StringPrivilege.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/StringPrivilege.java new file mode 100644 index 000000000..a1f2d4d26 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/priviliges/StringPrivilege.java @@ -0,0 +1,18 @@ +package io.mapsmessaging.auth.registry.priviliges; + +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.ToString; + +@Getter +@EqualsAndHashCode(callSuper = true) +@ToString +public class StringPrivilege extends Privilege { + + private final String value; + + public StringPrivilege(String name, String value) { + super(name); + this.value = value; + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java new file mode 100644 index 000000000..41998fbf9 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java @@ -0,0 +1,73 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry.priviliges.session; + +import io.mapsmessaging.auth.registry.priviliges.BooleanPrivilege; +import io.mapsmessaging.auth.registry.priviliges.LongPrivilege; +import io.mapsmessaging.auth.registry.priviliges.Privilege; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Data +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class SessionPrivileges { + + public static SessionPrivileges createAdminQuota(String username) { + return new SessionPrivileges(username); + } + + private UUID uniqueId; + private final String username; + private final List priviliges; + + protected SessionPrivileges(String username) { + this.username = username; + priviliges = new ArrayList<>(); + + priviliges.add(new BooleanPrivilege("Admin", false)); + priviliges.add(new BooleanPrivilege("AccessSystemTopics", true)); + priviliges.add(new BooleanPrivilege("PublishRetainedMessages", true)); + priviliges.add(new BooleanPrivilege("ForceReset", false)); + priviliges.add(new BooleanPrivilege("AllowPersistentSession", true)); + + priviliges.add(new LongPrivilege("MaxWillDelay", 86_400_000)); // 1 Day + priviliges.add(new LongPrivilege("MaxSessionExpiry", 86_400_000)); // 1 Day + priviliges.add(new LongPrivilege("MaxMessageSize", 1_048_576)); // 1 MB + priviliges.add(new LongPrivilege("MaxInflightMessages", 10)); // 10 outstanding messages + + priviliges.add(new LongPrivilege("MaxPublishQoS", 0)); + priviliges.add(new LongPrivilege("MaxSubscribeQoS", 0)); + + priviliges.add(new LongPrivilege("PublishPerMinute", 0)); + + priviliges.add(new LongPrivilege("MaxConcurrentPersistentSessions", 0)); + priviliges.add(new LongPrivilege("MaxConcurrentSubscriptions", 0)); + priviliges.add(new LongPrivilege("MaxConcurrentConnections", 0)); + priviliges.add(new LongPrivilege("MaxConcurrentPublishes", 0)); + + } + +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/subscription/SubscriptionPrivileges.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/subscription/SubscriptionPrivileges.java new file mode 100644 index 000000000..e92f874f9 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/priviliges/subscription/SubscriptionPrivileges.java @@ -0,0 +1,4 @@ +package io.mapsmessaging.auth.registry.priviliges.subscription; + +public class SubscriptionPrivileges { +} diff --git a/src/main/java/io/mapsmessaging/engine/session/SessionContext.java b/src/main/java/io/mapsmessaging/engine/session/SessionContext.java index 0f8573080..e73e19da4 100644 --- a/src/main/java/io/mapsmessaging/engine/session/SessionContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/SessionContext.java @@ -43,7 +43,6 @@ public class SessionContext { private String username; private char[] password; private int receiveMaximum; - private int duration; private boolean isRestored; private boolean resetState; private boolean persistentSession; @@ -55,7 +54,6 @@ public SessionContext(String id, ClientConnection clientConnection) { expiry = -1; receiveMaximum = (1 << 16) - 1; isRestored = false; - duration = -1; uniqueId = UUID.randomUUID().toString(); } } diff --git a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java index 41a098573..32cddad12 100644 --- a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java @@ -19,7 +19,7 @@ import io.mapsmessaging.auth.AuthManager; import io.mapsmessaging.auth.QuotaPrincipal; -import io.mapsmessaging.auth.registry.Quotas; +import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; import io.mapsmessaging.engine.audit.AuditEvent; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; @@ -52,9 +52,9 @@ public void login() throws IOException { .map(UniqueIdentifierPrincipal::getAuthId) .orElse(null); if (userId != null) { - Quotas quotas = AuthManager.getInstance().getQuota(userId); - if (quotas != null) { - subject.getPrincipals().add(new QuotaPrincipal(quotas)); + SessionPrivileges session = AuthManager.getInstance().getQuota(userId); + if (session != null) { + subject.getPrincipals().add(new QuotaPrincipal(session, null)); } } logger.log(AuditEvent.SUCCESSFUL_LOGIN, subject); From b7ae42c81eb157449e80efa8517916c12862cb48 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Sat, 25 Nov 2023 16:07:13 +1100 Subject: [PATCH 046/348] include strings --- .../auth/registry/priviliges/PrivilegeSerializer.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java index 5bc002de7..42552f3f0 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java +++ b/src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java @@ -28,6 +28,9 @@ public void serialize(@NotNull DataOutput2 dataOutput2, @NotNull SessionPrivileg } else if (p instanceof LongPrivilege) { dataOutput2.writeInt(1); dataOutput2.writeLong(((LongPrivilege) p).getValue()); + } else if (p instanceof StringPrivilege) { + dataOutput2.writeInt(2); + dataOutput2.writeUTF(((StringPrivilege) p).getValue()); } } } @@ -43,8 +46,10 @@ public SessionPrivileges deserialize(@NotNull DataInput2 dataInput2, int i) thro int type = dataInput2.readInt(); if (type == 0) { list.add(new BooleanPrivilege(name, dataInput2.readBoolean())); - } else { + } else if (type == 1) { list.add(new LongPrivilege(name, dataInput2.readLong())); + } else if (type == 2) { + list.add(new StringPrivilege(name, dataInput2.readUTF())); } } return new SessionPrivileges(id, user, list); From 1d7b78580727fe8aa2d6a5ed1cc328d47a2cf496 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 28 Nov 2023 10:53:57 +1100 Subject: [PATCH 047/348] Use the single db for the user/group mappings and the permissions for a user. This will NOT be the acl store, they will be tied to resources --- .../io/mapsmessaging/auth/AuthManager.java | 34 ++------ .../auth/registry/AuthenticationStorage.java | 80 ++++++++++++------- .../auth/registry/FileManager.java | 68 ---------------- .../auth/registry/GroupFileManager.java | 51 ------------ .../auth/registry/UserFileManager.java | 64 --------------- .../auth/registry/UserPermisionManager.java | 30 ++----- .../registry/mapping/GroupIdSerializer.java | 46 +++++++++++ .../auth/registry/mapping/IdDbStore.java | 48 +++++++++++ .../registry/mapping/UserIdSerializer.java | 46 +++++++++++ 9 files changed, 202 insertions(+), 265 deletions(-) delete mode 100644 src/main/java/io/mapsmessaging/auth/registry/FileManager.java delete mode 100644 src/main/java/io/mapsmessaging/auth/registry/GroupFileManager.java delete mode 100644 src/main/java/io/mapsmessaging/auth/registry/UserFileManager.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/mapping/GroupIdSerializer.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/mapping/IdDbStore.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/mapping/UserIdSerializer.java diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index 418de1900..fcee917be 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -22,8 +22,6 @@ import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; -import io.mapsmessaging.security.identity.IdentityLookup; -import io.mapsmessaging.security.identity.IdentityLookupFactory; import io.mapsmessaging.utilities.Agent; import io.mapsmessaging.utilities.configuration.ConfigurationManager; import io.mapsmessaging.utilities.configuration.ConfigurationProperties; @@ -50,8 +48,6 @@ public class AuthManager implements Agent { @Getter private final boolean authorisationEnabled; - private IdentityLookup identityLookup; - @Override public String getName() { return "AuthManager"; @@ -66,13 +62,12 @@ public String getDescription() { public void start() { if (authenticationEnabled) { Map config = ((ConfigurationProperties) properties.get("config")).getMap(); - String authProvider = config.get("identityProvider").toString().trim(); String password = null; - if (!authenticationStorage.getUserFile().exists()) { + if (!authenticationStorage.isExisted()) { password = PasswordGenerator.generateRandomPassword(12); String username = "admin"; addUser(username, password, SessionPrivileges.createAdminQuota(username), new String[]{username}); - String path = properties.getProperty("configDirectory", "./security"); + String path = config.get("configDirectory").toString(); try (BufferedWriter bw = new BufferedWriter(new FileWriter(path + File.separator + "admin_password", true))) { bw.write("admin=" + password); @@ -81,20 +76,13 @@ public void start() { e.printStackTrace(); } } - identityLookup = IdentityLookupFactory.getInstance().get(authProvider, config); if (password != null) { - if (authenticationStorage.validateUser("admin", password, identityLookup)) { + if (authenticationStorage.validateUser("admin", password)) { System.err.println("Successfully added admin"); } else { System.err.println("Failed to add admin"); } } - - } else { - identityLookup = null; - } - if (identityLookup == null) { - // todo log the fact we have not authentication } } @@ -109,20 +97,11 @@ public void stop() { } public boolean addUser(String username, String password, SessionPrivileges quotas, String[] groups) { - if (identityLookup == null || identityLookup.findEntry(username) == null) { - if (!quotas.getUsername().equalsIgnoreCase(username)) { - // ToDo we need to check the quotas are valid - } - return authenticationStorage.addUser(username, password, quotas, groups); - } - return false; + return authenticationStorage.addUser(username, password, quotas, groups); } public boolean delUser(String username) { - if (identityLookup.findEntry(username) != null) { - return authenticationStorage.delUser(username); - } - return false; + return authenticationStorage.delUser(username); } private AuthManager() { @@ -130,7 +109,8 @@ private AuthManager() { properties = ConfigurationManager.getInstance().getProperties("AuthManager"); authenticationEnabled = properties.getBooleanProperty("authenticationEnabled", false); authorisationEnabled = properties.getBooleanProperty("authorizationEnabled", false) && authenticationEnabled; - authenticationStorage = new AuthenticationStorage(properties.getProperty("configDirectory", "./security")); + ConfigurationProperties config = (ConfigurationProperties) properties.get("config"); + authenticationStorage = new AuthenticationStorage(config); } public SessionPrivileges getQuota(UUID userId) { diff --git a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java index 5437bd8de..379fe551f 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java +++ b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java @@ -17,55 +17,74 @@ package io.mapsmessaging.auth.registry; +import io.mapsmessaging.auth.registry.mapping.GroupIdSerializer; +import io.mapsmessaging.auth.registry.mapping.IdDbStore; +import io.mapsmessaging.auth.registry.mapping.UserIdSerializer; +import io.mapsmessaging.auth.registry.priviliges.PrivilegeSerializer; import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; -import io.mapsmessaging.security.access.mapping.GroupMapManagement; -import io.mapsmessaging.security.access.mapping.UserMapManagement; +import io.mapsmessaging.security.access.IdentityAccessManager; +import io.mapsmessaging.security.access.mapping.GroupIdMap; +import io.mapsmessaging.security.access.mapping.UserIdMap; import io.mapsmessaging.security.identity.IdentityEntry; -import io.mapsmessaging.security.identity.IdentityLookup; import io.mapsmessaging.security.identity.parsers.PasswordParser; import io.mapsmessaging.security.identity.parsers.bcrypt.BCrypt2yPasswordParser; +import io.mapsmessaging.utilities.configuration.ConfigurationProperties; import lombok.Getter; +import org.mapdb.DB; +import org.mapdb.DBMaker; import java.io.Closeable; import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.Map; import java.util.UUID; public class AuthenticationStorage implements Closeable { - @Getter - private final UserFileManager userFile; - @Getter - private final GroupFileManager groupFile; - - private final PasswordParser passwordParser; - private final UserMapManagement userMapManagement; - private final GroupMapManagement groupMapManagement; + private final IdentityAccessManager identityAccessManager; + private final PasswordParser globalPasswordParser; private final UserPermisionManager userPermisionManager; + private final DB db; + @Getter + private final boolean existed; - public AuthenticationStorage(String securityDirectory) { + public AuthenticationStorage(ConfigurationProperties config) { + String securityDirectory = config.getProperty("configDirectory", "./.security"); if (securityDirectory != null) { File file = new File(securityDirectory); if (!file.exists()) { file.mkdirs(); } } - userMapManagement = new UserMapManagement(securityDirectory + File.separator + ".userMap"); - groupMapManagement = new GroupMapManagement(securityDirectory + File.separator + ".groupMap"); - UserMapManagement.setGlobalInstance(userMapManagement); - GroupMapManagement.setGlobalInstance(groupMapManagement); - passwordParser = new BCrypt2yPasswordParser(); - this.groupFile = new GroupFileManager(securityDirectory + File.separator + ".htgroup", groupMapManagement); - this.userFile = new UserFileManager(securityDirectory + File.separator + ".htpassword", passwordParser, userMapManagement); - userPermisionManager = new UserPermisionManager(securityDirectory + File.separator + ".userPermissions"); - } + existed = new File(securityDirectory + File.separator + ".auth.db").exists(); + db = DBMaker.fileDB(securityDirectory + File.separator + ".auth.db") + .checksumStoreEnable() + .fileChannelEnable() + .fileMmapEnableIfSupported() + .fileMmapPreclearDisable() + .closeOnJvmShutdown() + .make(); + db.getStore().fileLoad(); + Map userMapSet = db.hashMap("userIdMap", new UUIDSerializer(), new UserIdSerializer()).createOrOpen(); + Map groupMapSet = db.hashMap("groupIdMap", new UUIDSerializer(), new GroupIdSerializer()).createOrOpen(); + Map sessionPrivilegesMap = db.hashMap(UserPermisionManager.class.getName(), new UUIDSerializer(), new PrivilegeSerializer()).createOrOpen(); + String authProvider = config.getProperty("identityProvider", "Apache-Basic-Auth"); + + identityAccessManager = new IdentityAccessManager(authProvider, Map.of("configDirectory", securityDirectory), new IdDbStore(userMapSet), new IdDbStore(groupMapSet)); + globalPasswordParser = new BCrypt2yPasswordParser(); + userPermisionManager = new UserPermisionManager(sessionPrivilegesMap); + } public boolean addUser(String username, String password, SessionPrivileges quotas, String[] groups) { try { - UUID uuid = userFile.addUser(username, password); - groupFile.addGroup(username, groups); + UserIdMap userIdMap = identityAccessManager.createUser(username, password, globalPasswordParser); + UUID uuid = userIdMap.getAuthId(); + for (String group : groups) { + identityAccessManager.createGroup(group); + identityAccessManager.addUserToGroup(username, group); + } quotas.setUniqueId(uuid); userPermisionManager.add(quotas); return true; @@ -77,10 +96,11 @@ public boolean addUser(String username, String password, SessionPrivileges quota public boolean delUser(String username) { try { - UUID userId = userFile.getUserUUID(username); - userFile.deleteUser(username); - //groupFile.deleteGroup(username); - userPermisionManager.delete(userId); + UserIdMap userIdMap = identityAccessManager.getUser(username); + if (userIdMap != null) { + identityAccessManager.deleteUser(username); + userPermisionManager.delete(userIdMap.getAuthId()); + } return true; } catch (IOException e) { @@ -89,8 +109,8 @@ public boolean delUser(String username) { } - public boolean validateUser(String username, String password, IdentityLookup identityLookup) { - IdentityEntry identityEntry = identityLookup.findEntry(username); + public boolean validateUser(String username, String password) { + IdentityEntry identityEntry = identityAccessManager.getUserIdentity(username); if (identityEntry != null) { PasswordParser passwordParser = identityEntry.getPasswordParser(); byte[] hash = passwordParser.computeHash(password.getBytes(), passwordParser.getSalt(), passwordParser.getCost()); @@ -101,7 +121,7 @@ public boolean validateUser(String username, String password, IdentityLookup ide @Override public void close() throws IOException { - userPermisionManager.close(); + db.close(); } public SessionPrivileges getQuota(UUID userId) { diff --git a/src/main/java/io/mapsmessaging/auth/registry/FileManager.java b/src/main/java/io/mapsmessaging/auth/registry/FileManager.java deleted file mode 100644 index adf0c454c..000000000 --- a/src/main/java/io/mapsmessaging/auth/registry/FileManager.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright [ 2020 - 2023 ] [Matthew Buckton] - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package io.mapsmessaging.auth.registry; - -import java.io.*; - -public abstract class FileManager { - private final File file; - - protected FileManager(String filename) { - file = new File(filename); - } - - public boolean exists() { - return file.exists(); - } - - protected void add(String line) throws IOException { - if (!file.exists()) { - file.createNewFile(); - } - try (BufferedWriter bw = new BufferedWriter(new FileWriter(file, true))) { - bw.write(line); - bw.newLine(); // Add a newline character after each line - } - } - - protected void delete(String name) throws IOException { - File tempFile = new File(file.getAbsolutePath() + ".tmp"); - - try (BufferedReader reader = new BufferedReader(new FileReader(file)); - BufferedWriter writer = new BufferedWriter(new FileWriter(tempFile))) { - - String lineToRemove = name + ":"; - String currentLine; - - while ((currentLine = reader.readLine()) != null) { - if (!currentLine.startsWith(lineToRemove)) { - writer.write(currentLine + System.lineSeparator()); - } - } - } - - if (!file.delete()) { - throw new IOException("Could not delete original file"); - } - - if (!tempFile.renameTo(file)) { - throw new IOException("Could not rename temporary file"); - } - } - -} diff --git a/src/main/java/io/mapsmessaging/auth/registry/GroupFileManager.java b/src/main/java/io/mapsmessaging/auth/registry/GroupFileManager.java deleted file mode 100644 index f689595b9..000000000 --- a/src/main/java/io/mapsmessaging/auth/registry/GroupFileManager.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright [ 2020 - 2023 ] [Matthew Buckton] - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package io.mapsmessaging.auth.registry; - -import io.mapsmessaging.security.access.mapping.GroupIdMap; -import io.mapsmessaging.security.access.mapping.GroupMapManagement; - -import java.io.IOException; -import java.util.UUID; - -public class GroupFileManager extends FileManager { - - private final GroupMapManagement groupMapManagement; - - public GroupFileManager(String filename, GroupMapManagement groupMapManagement) { - super(filename); - this.groupMapManagement = groupMapManagement; - } - - public UUID addGroup(String groupName, String... users) throws IOException { - super.add(groupName + ":" + String.join(",", users)); - GroupIdMap groupIdMap = new GroupIdMap(UUID.randomUUID(), groupName, "apache"); - groupMapManagement.add(groupIdMap); - return groupIdMap.getAuthId(); - } - - public void updateGroup(String groupName, String... users) throws IOException { - deleteGroup(groupName); - addGroup(groupName, users); - } - - public void deleteGroup(String groupName) throws IOException { - super.delete(groupName); - groupMapManagement.delete("apache:" + groupName); - } -} diff --git a/src/main/java/io/mapsmessaging/auth/registry/UserFileManager.java b/src/main/java/io/mapsmessaging/auth/registry/UserFileManager.java deleted file mode 100644 index 959628077..000000000 --- a/src/main/java/io/mapsmessaging/auth/registry/UserFileManager.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright [ 2020 - 2023 ] [Matthew Buckton] - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package io.mapsmessaging.auth.registry; - -import io.mapsmessaging.security.access.mapping.UserIdMap; -import io.mapsmessaging.security.access.mapping.UserMapManagement; -import io.mapsmessaging.security.identity.parsers.PasswordParser; - -import java.io.IOException; -import java.util.UUID; - -public class UserFileManager extends FileManager { - - private final PasswordParser passwordParser; - private final UserMapManagement userMapManagement; - - public UserFileManager(String filename, PasswordParser passwordParser, UserMapManagement mapManagement) { - super(filename); - this.passwordParser = passwordParser; - this.userMapManagement = mapManagement; - } - - public UUID addUser(String username, String password) throws IOException { - String salt = PasswordGenerator.generateSalt(16); - byte[] hash = passwordParser.computeHash(password.getBytes(), salt.getBytes(), 12); - add(username + ":" + new String(hash)); - UserIdMap userIdMap = new UserIdMap(UUID.randomUUID(), username, "apache", ""); - userMapManagement.add(userIdMap); - return userIdMap.getAuthId(); - } - - public void updateUser(String username, String password) throws IOException { - deleteUser(username); - addUser(username, password); - } - - public void deleteUser(String username) throws IOException { - delete(username); - userMapManagement.delete("apache:" + username); - } - - public UUID getUserUUID(String username) { - UserIdMap map = userMapManagement.get("apache:" + username); - if (map != null) { - return map.getAuthId(); - } - return null; - } -} \ No newline at end of file diff --git a/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java b/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java index 132cf6ef6..861d92616 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java +++ b/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java @@ -17,32 +17,17 @@ package io.mapsmessaging.auth.registry; -import io.mapsmessaging.auth.registry.priviliges.PrivilegeSerializer; import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; -import org.mapdb.DB; -import org.mapdb.DBMaker; -import java.io.Closeable; -import java.io.IOException; +import java.util.Map; import java.util.UUID; -import java.util.concurrent.ConcurrentMap; -public class UserPermisionManager implements Closeable { +public class UserPermisionManager { - private final ConcurrentMap store; - private final DB db; + private final Map store; - public UserPermisionManager(String fileName) { - db = DBMaker.fileDB(fileName) - .checksumStoreEnable() - .fileChannelEnable() - .fileMmapEnableIfSupported() - .fileMmapPreclearDisable() - .closeOnJvmShutdown() - .make(); - - db.getStore().fileLoad(); - store = db.hashMap(UserPermisionManager.class.getName(), new UUIDSerializer(), new PrivilegeSerializer()).createOrOpen(); + public UserPermisionManager(Map map) { + store = map; } @@ -58,11 +43,6 @@ public void delete(UUID uuid) { store.remove(uuid); } - @Override - public void close() throws IOException { - db.close(); - } - public SessionPrivileges get(UUID userId) { return store.get(userId); } diff --git a/src/main/java/io/mapsmessaging/auth/registry/mapping/GroupIdSerializer.java b/src/main/java/io/mapsmessaging/auth/registry/mapping/GroupIdSerializer.java new file mode 100644 index 000000000..89c64edd6 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/mapping/GroupIdSerializer.java @@ -0,0 +1,46 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry.mapping; + +import io.mapsmessaging.security.access.mapping.GroupIdMap; +import org.jetbrains.annotations.NotNull; +import org.mapdb.DataInput2; +import org.mapdb.DataOutput2; +import org.mapdb.Serializer; + +import java.io.IOException; +import java.util.UUID; + +public class GroupIdSerializer implements Serializer { + + @Override + public void serialize(@NotNull DataOutput2 dataOutput2, @NotNull GroupIdMap groupId) throws IOException { + dataOutput2.writeLong(groupId.getAuthId().getMostSignificantBits()); + dataOutput2.writeLong(groupId.getAuthId().getLeastSignificantBits()); + dataOutput2.writeUTF(groupId.getAuthDomain()); + dataOutput2.writeUTF(groupId.getGroupName()); + } + + @Override + public GroupIdMap deserialize(@NotNull DataInput2 dataInput2, int i) throws IOException { + java.util.UUID id = new UUID(dataInput2.readLong(), dataInput2.readLong()); + String auth = dataInput2.readUTF(); + String group = dataInput2.readUTF(); + return new GroupIdMap(id, auth, group); + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/mapping/IdDbStore.java b/src/main/java/io/mapsmessaging/auth/registry/mapping/IdDbStore.java new file mode 100644 index 000000000..b0b2454e7 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/mapping/IdDbStore.java @@ -0,0 +1,48 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry.mapping; + +import io.mapsmessaging.security.access.mapping.IdMap; +import io.mapsmessaging.security.access.mapping.MapParser; +import io.mapsmessaging.security.access.mapping.store.MapStore; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +public class IdDbStore implements MapStore { + + private final Map store; + + public IdDbStore(Map store) { + this.store = store; + } + + @Override + public List load(MapParser parser) { + return new ArrayList<>(store.values()); + } + + @Override + public void save(List entries, MapParser parser) { + store.clear(); + for (T entry : entries) + store.put(entry.getAuthId(), entry); + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/mapping/UserIdSerializer.java b/src/main/java/io/mapsmessaging/auth/registry/mapping/UserIdSerializer.java new file mode 100644 index 000000000..2b3d6b58a --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/mapping/UserIdSerializer.java @@ -0,0 +1,46 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry.mapping; + +import io.mapsmessaging.security.access.mapping.UserIdMap; +import org.jetbrains.annotations.NotNull; +import org.mapdb.DataInput2; +import org.mapdb.DataOutput2; +import org.mapdb.Serializer; + +import java.io.IOException; +import java.util.UUID; + +public class UserIdSerializer implements Serializer { + + @Override + public void serialize(@NotNull DataOutput2 dataOutput2, @NotNull UserIdMap userId) throws IOException { + dataOutput2.writeLong(userId.getAuthId().getMostSignificantBits()); + dataOutput2.writeLong(userId.getAuthId().getLeastSignificantBits()); + dataOutput2.writeUTF(userId.getAuthDomain()); + dataOutput2.writeUTF(userId.getUsername()); + } + + @Override + public UserIdMap deserialize(@NotNull DataInput2 dataInput2, int i) throws IOException { + java.util.UUID id = new UUID(dataInput2.readLong(), dataInput2.readLong()); + String auth = dataInput2.readUTF(); + String group = dataInput2.readUTF(); + return new UserIdMap(id, auth, group); + } +} From 2dc40e6c12f4f2f65deaa26960eaeadb6d774a72 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 28 Nov 2023 14:28:06 +1100 Subject: [PATCH 048/348] Look up the session privilege for the user and add it to the subject as well as the groups and user UUID --- .../io/mapsmessaging/auth/AuthManager.java | 30 ++++++++++++---- .../auth/registry/AuthenticationStorage.java | 19 +++++++++- .../principal/SessionPrivilegePrincipal.java | 36 +++++++++++++++++++ .../priviliges/session/SessionPrivileges.java | 22 ++++++------ .../engine/session/SessionContext.java | 5 +++ .../session/security/JaasSecurityContext.java | 1 + .../session/security/SecurityContext.java | 3 +- 7 files changed, 97 insertions(+), 19 deletions(-) create mode 100644 src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index fcee917be..4c1785c72 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -27,11 +27,11 @@ import io.mapsmessaging.utilities.configuration.ConfigurationProperties; import lombok.Getter; +import javax.security.auth.Subject; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.util.Map; import java.util.UUID; @@ -41,7 +41,7 @@ public class AuthManager implements Agent { private final Logger logger; private final ConfigurationProperties properties; - private final AuthenticationStorage authenticationStorage; + private AuthenticationStorage authenticationStorage; @Getter private final boolean authenticationEnabled; @@ -61,17 +61,28 @@ public String getDescription() { @Override public void start() { if (authenticationEnabled) { - Map config = ((ConfigurationProperties) properties.get("config")).getMap(); + ConfigurationProperties config = (ConfigurationProperties) properties.get("config"); String password = null; + String userpassword = null; + authenticationStorage = new AuthenticationStorage(config); + if (!authenticationStorage.isExisted()) { password = PasswordGenerator.generateRandomPassword(12); String username = "admin"; - addUser(username, password, SessionPrivileges.createAdminQuota(username), new String[]{username}); + addUser(username, password, SessionPrivileges.create(username), new String[]{username, "everyone"}); + + userpassword = PasswordGenerator.generateRandomPassword(12); + username = "user"; + addUser(username, userpassword, SessionPrivileges.create(username), new String[]{"everyone"}); + String path = config.get("configDirectory").toString(); try (BufferedWriter bw = new BufferedWriter(new FileWriter(path + File.separator + "admin_password", true))) { bw.write("admin=" + password); bw.newLine(); // Add a newline character after each line + bw.write("user=" + userpassword); + bw.newLine(); // Add a newline character after each line + } catch (IOException e) { e.printStackTrace(); } @@ -82,6 +93,11 @@ public void start() { } else { System.err.println("Failed to add admin"); } + if (authenticationStorage.validateUser("user", userpassword)) { + System.err.println("Successfully added user"); + } else { + System.err.println("Failed to add user"); + } } } @@ -104,13 +120,15 @@ public boolean delUser(String username) { return authenticationStorage.delUser(username); } + public Subject update(Subject subject) { + return authenticationStorage.update(subject); + } + private AuthManager() { logger = LoggerFactory.getLogger(AuthManager.class); properties = ConfigurationManager.getInstance().getProperties("AuthManager"); authenticationEnabled = properties.getBooleanProperty("authenticationEnabled", false); authorisationEnabled = properties.getBooleanProperty("authorizationEnabled", false) && authenticationEnabled; - ConfigurationProperties config = (ConfigurationProperties) properties.get("config"); - authenticationStorage = new AuthenticationStorage(config); } public SessionPrivileges getQuota(UUID userId) { diff --git a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java index 379fe551f..fd95c205e 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java +++ b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java @@ -20,8 +20,10 @@ import io.mapsmessaging.auth.registry.mapping.GroupIdSerializer; import io.mapsmessaging.auth.registry.mapping.IdDbStore; import io.mapsmessaging.auth.registry.mapping.UserIdSerializer; +import io.mapsmessaging.auth.registry.principal.SessionPrivilegePrincipal; import io.mapsmessaging.auth.registry.priviliges.PrivilegeSerializer; import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; +import io.mapsmessaging.security.SubjectHelper; import io.mapsmessaging.security.access.IdentityAccessManager; import io.mapsmessaging.security.access.mapping.GroupIdMap; import io.mapsmessaging.security.access.mapping.UserIdMap; @@ -33,6 +35,7 @@ import org.mapdb.DB; import org.mapdb.DBMaker; +import javax.security.auth.Subject; import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -82,7 +85,9 @@ public boolean addUser(String username, String password, SessionPrivileges quota UserIdMap userIdMap = identityAccessManager.createUser(username, password, globalPasswordParser); UUID uuid = userIdMap.getAuthId(); for (String group : groups) { - identityAccessManager.createGroup(group); + if (identityAccessManager.getGroup(group) == null) { + identityAccessManager.createGroup(group); + } identityAccessManager.addUserToGroup(username, group); } quotas.setUniqueId(uuid); @@ -127,4 +132,16 @@ public void close() throws IOException { public SessionPrivileges getQuota(UUID userId) { return userPermisionManager.get(userId); } + + public Subject update(Subject subject) { + Subject subject1 = identityAccessManager.updateSubject(subject); + UUID userId = SubjectHelper.getUniqueId(subject1); + if (userId != null) { + SessionPrivileges sessionPrivileges = userPermisionManager.get(userId); + if (sessionPrivileges != null) { + subject1.getPrincipals().add(new SessionPrivilegePrincipal(sessionPrivileges)); + } + } + return subject1; + } } diff --git a/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java b/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java new file mode 100644 index 000000000..aa533e811 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java @@ -0,0 +1,36 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry.principal; + +import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; + +import java.security.Principal; + +public class SessionPrivilegePrincipal implements Principal { + + private final SessionPrivileges privileges; + + public SessionPrivilegePrincipal(SessionPrivileges privileges) { + this.privileges = privileges; + } + + @Override + public String getName() { + return "SessionPrivilegePrincipal"; + } +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java index 41998fbf9..70245afc0 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java +++ b/src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java @@ -17,6 +17,7 @@ package io.mapsmessaging.auth.registry.priviliges.session; +import io.mapsmessaging.api.features.QualityOfService; import io.mapsmessaging.auth.registry.priviliges.BooleanPrivilege; import io.mapsmessaging.auth.registry.priviliges.LongPrivilege; import io.mapsmessaging.auth.registry.priviliges.Privilege; @@ -35,7 +36,7 @@ @EqualsAndHashCode public class SessionPrivileges { - public static SessionPrivileges createAdminQuota(String username) { + public static SessionPrivileges create(String username) { return new SessionPrivileges(username); } @@ -46,28 +47,27 @@ public static SessionPrivileges createAdminQuota(String username) { protected SessionPrivileges(String username) { this.username = username; priviliges = new ArrayList<>(); - priviliges.add(new BooleanPrivilege("Admin", false)); priviliges.add(new BooleanPrivilege("AccessSystemTopics", true)); priviliges.add(new BooleanPrivilege("PublishRetainedMessages", true)); priviliges.add(new BooleanPrivilege("ForceReset", false)); priviliges.add(new BooleanPrivilege("AllowPersistentSession", true)); + priviliges.add(new LongPrivilege("WillDelay", 0)); // 1 Day priviliges.add(new LongPrivilege("MaxWillDelay", 86_400_000)); // 1 Day priviliges.add(new LongPrivilege("MaxSessionExpiry", 86_400_000)); // 1 Day priviliges.add(new LongPrivilege("MaxMessageSize", 1_048_576)); // 1 MB - priviliges.add(new LongPrivilege("MaxInflightMessages", 10)); // 10 outstanding messages + priviliges.add(new LongPrivilege("MaxInflightMessages", 1 << 16 - 1)); // 10 outstanding messages - priviliges.add(new LongPrivilege("MaxPublishQoS", 0)); - priviliges.add(new LongPrivilege("MaxSubscribeQoS", 0)); + priviliges.add(new LongPrivilege("MaxPublishQoS", QualityOfService.EXACTLY_ONCE.getLevel())); + priviliges.add(new LongPrivilege("MaxSubscribeQoS", QualityOfService.EXACTLY_ONCE.getLevel())); - priviliges.add(new LongPrivilege("PublishPerMinute", 0)); + priviliges.add(new LongPrivilege("PublishPerMinute", Integer.MAX_VALUE)); - priviliges.add(new LongPrivilege("MaxConcurrentPersistentSessions", 0)); - priviliges.add(new LongPrivilege("MaxConcurrentSubscriptions", 0)); - priviliges.add(new LongPrivilege("MaxConcurrentConnections", 0)); - priviliges.add(new LongPrivilege("MaxConcurrentPublishes", 0)); + priviliges.add(new LongPrivilege("MaxConcurrentPersistentSessions", Short.MAX_VALUE)); + priviliges.add(new LongPrivilege("MaxConcurrentSubscriptions", Short.MAX_VALUE)); + priviliges.add(new LongPrivilege("MaxConcurrentConnections", Short.MAX_VALUE)); + priviliges.add(new LongPrivilege("MaxConcurrentPublishes", Short.MAX_VALUE)); } - } diff --git a/src/main/java/io/mapsmessaging/engine/session/SessionContext.java b/src/main/java/io/mapsmessaging/engine/session/SessionContext.java index e73e19da4..df2367a57 100644 --- a/src/main/java/io/mapsmessaging/engine/session/SessionContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/SessionContext.java @@ -18,6 +18,7 @@ package io.mapsmessaging.engine.session; import io.mapsmessaging.api.message.Message; +import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; import lombok.Data; import lombok.ToString; @@ -56,4 +57,8 @@ public SessionContext(String id, ClientConnection clientConnection) { isRestored = false; uniqueId = UUID.randomUUID().toString(); } + + public void update(SessionPrivileges sessionPrivileges) { + + } } diff --git a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java index 32cddad12..8db08fea2 100644 --- a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java @@ -59,6 +59,7 @@ public void login() throws IOException { } logger.log(AuditEvent.SUCCESSFUL_LOGIN, subject); isLoggedIn = true; + subject = AuthManager.getInstance().update(subject); } catch (LoginException e) { logger.log(ServerLogMessages.SECURITY_MANAGER_FAILED_LOG_IN, username, e.getMessage()); IOException ioException = new IOException(e.getMessage()); diff --git a/src/main/java/io/mapsmessaging/engine/session/security/SecurityContext.java b/src/main/java/io/mapsmessaging/engine/session/security/SecurityContext.java index c29ce438e..b45e60689 100644 --- a/src/main/java/io/mapsmessaging/engine/session/security/SecurityContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/security/SecurityContext.java @@ -18,11 +18,12 @@ package io.mapsmessaging.engine.session.security; import com.sun.security.auth.UserPrincipal; + +import javax.security.auth.Subject; import java.io.IOException; import java.security.Principal; import java.util.HashSet; import java.util.Set; -import javax.security.auth.Subject; public abstract class SecurityContext { From 052925bbb1465eed189e6c498b7b1a1b9e48085d Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 28 Nov 2023 15:02:41 +1100 Subject: [PATCH 049/348] Configure the protocols on the correct port for Non Docker instances Configure docker instance to not request username/password --- .../logging/ServerLogMessages.java | 4 +- src/main/resources/NetworkManager.yaml | 51 ++++++++++++++++--- src/main/resources/NetworkManagerDocker.yaml | 1 + src/main/resources/SecurityManager.yaml | 4 +- src/main/resources/jaasAuth.config | 8 ++- src/main/resources/logback.xml | 2 +- 6 files changed, 56 insertions(+), 14 deletions(-) diff --git a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java index ac5a8e068..be6d7c04f 100644 --- a/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java +++ b/src/main/java/io/mapsmessaging/logging/ServerLogMessages.java @@ -626,8 +626,8 @@ public enum ServerLogMessages implements LogMessage { DISCOVERY_DEREGISTERED_SERVICE(LEVEL.INFO, SERVER_CATEGORY.DISCOVERY, "Deregistered mDNS service {}"), DISCOVERY_DEREGISTERED_ALL(LEVEL.INFO, SERVER_CATEGORY.DISCOVERY, "Removed all registered mDNS services"), - DISCOVERY_RESOLVED_REMOTE_SERVER(LEVEL.INFO, SERVER_CATEGORY.DISCOVERY, "Discovered remote server {} on {} using {}"), - DISCOVERY_REMOVED_REMOTE_SERVER(LEVEL.INFO, SERVER_CATEGORY.DISCOVERY, "Removed remote server {} on {} using {}"), + DISCOVERY_RESOLVED_REMOTE_SERVER(LEVEL.DEBUG, SERVER_CATEGORY.DISCOVERY, "Discovered remote server {} on {} using {}"), + DISCOVERY_REMOVED_REMOTE_SERVER(LEVEL.DEBUG, SERVER_CATEGORY.DISCOVERY, "Removed remote server {} on {} using {}"), // // diff --git a/src/main/resources/NetworkManager.yaml b/src/main/resources/NetworkManager.yaml index 8ebe7a55c..e5981cb1f 100644 --- a/src/main/resources/NetworkManager.yaml +++ b/src/main/resources/NetworkManager.yaml @@ -47,7 +47,7 @@ NetworkManager: # --------------------------------------------------------------------------------------------------------- serverReadBufferSize : 10K serverWriteBufferSize : 10K - selectorThreadCount : 1 + selectorThreadCount: 2 # --------------------------------------------------------------------------------------------------------- # MQTT Protocol configuration @@ -90,14 +90,32 @@ NetworkManager: data: - - name: "Open Interface" - url: tcp://:::9000/ - protocol : all - selectorThreadCount : 5 - auth: default + - name: "AMQP Interface" + url: tcp://:::5672/ + protocol: amqp + auth: usernamePassword + - name: "AMQPs Interface" + url: ssl://:::5671/ + protocol: amqp + auth: usernamePassword - - url: udp://:::1884/ + - name: "MQTT Interface" + url: tcp://:::1883/ + protocol: mqtt + auth: usernamePassword + + - name: "Stomp Interface" + url: tcp://:::61613/ + protocol: stomp + auth: usernamePassword + + - name: "Stomp Interface" + url: ssl://:::61614/ + protocol: stomp + auth: usernamePassword + + - url: udp://:::1883/ name: "MQTT-SN Interface" protocol: mqtt-sn eventsPerTopicDuringSleep: 5 @@ -106,7 +124,18 @@ NetworkManager: sasl: mechanism: SCRAM-SHA-512 identityProvider: htpassword - passwordFile: ./security/htpassword + passwordFile: ./.security/htpassword + + - url: dtls://:::8883/ + name: "MQTT-SN Interface" + protocol: mqtt-sn + eventsPerTopicDuringSleep: 5 + maxTopicsInSleep: 10 + advertiseGateway: true + sasl: + mechanism: SCRAM-SHA-512 + identityProvider: htpassword + passwordFile: ./.security/htpassword - url: udp://:::5683/ name: "CoAP Interface" @@ -114,6 +143,12 @@ NetworkManager: maxBlockSize: 512 idleTimePeriod: 120 + - url: dtls://:::5684/ + name: "CoAP Interface" + protocol: coap + maxBlockSize: 512 + idleTimePeriod: 120 + - url: udp://:::1700/ name: "SemTech Gateway" protocol: semtech diff --git a/src/main/resources/NetworkManagerDocker.yaml b/src/main/resources/NetworkManagerDocker.yaml index a5313d226..18ed644a3 100644 --- a/src/main/resources/NetworkManagerDocker.yaml +++ b/src/main/resources/NetworkManagerDocker.yaml @@ -74,6 +74,7 @@ NetworkManager: url: tcp://0.0.0.0:9000/ protocol : all selectorThreadCount : 5 + auth: default - url: udp://0.0.0.0:1884/ diff --git a/src/main/resources/SecurityManager.yaml b/src/main/resources/SecurityManager.yaml index eff753aa9..2593a503a 100644 --- a/src/main/resources/SecurityManager.yaml +++ b/src/main/resources/SecurityManager.yaml @@ -16,4 +16,6 @@ --- SecurityManager: - - default: DefaultLoginAuth + + default: PublicAuthConfig + usernamePassword: UsernamePasswordLoginModule diff --git a/src/main/resources/jaasAuth.config b/src/main/resources/jaasAuth.config index 4f407623d..368f9bd35 100644 --- a/src/main/resources/jaasAuth.config +++ b/src/main/resources/jaasAuth.config @@ -1,6 +1,10 @@ -DefaultLoginAuth { +UsernamePasswordLoginModule{ io.mapsmessaging.security.jaas.IdentityLoginModule Required debug=false identityName="Apache-Basic-Auth" - configDirectory="./security"; + configDirectory="./.security"; }; + +PublicAuthConfig { + io.mapsmessaging.security.jaas.AnonymousLoginModule Required debug=true; +}; \ No newline at end of file diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index ca4f5b0c0..f17a1a42d 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -31,7 +31,7 @@ - + \ No newline at end of file From d55ea8a992a9b9387de8cbc5c115ba48ac2b38db Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 28 Nov 2023 17:12:02 +1100 Subject: [PATCH 050/348] Adjust the login entry for the subject ensure the group is serialised correctly --- .../auth/registry/mapping/GroupIdSerializer.java | 2 +- .../auth/registry/principal/SessionPrivilegePrincipal.java | 6 ++++++ .../engine/session/security/JaasSecurityContext.java | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/mapsmessaging/auth/registry/mapping/GroupIdSerializer.java b/src/main/java/io/mapsmessaging/auth/registry/mapping/GroupIdSerializer.java index 89c64edd6..5141d9bb2 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/mapping/GroupIdSerializer.java +++ b/src/main/java/io/mapsmessaging/auth/registry/mapping/GroupIdSerializer.java @@ -41,6 +41,6 @@ public GroupIdMap deserialize(@NotNull DataInput2 dataInput2, int i) throws IOEx java.util.UUID id = new UUID(dataInput2.readLong(), dataInput2.readLong()); String auth = dataInput2.readUTF(); String group = dataInput2.readUTF(); - return new GroupIdMap(id, auth, group); + return new GroupIdMap(id, group, auth); } } diff --git a/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java b/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java index aa533e811..884336109 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java +++ b/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java @@ -33,4 +33,10 @@ public SessionPrivilegePrincipal(SessionPrivileges privileges) { public String getName() { return "SessionPrivilegePrincipal"; } + + @Override + public String toString() { + return "Session Privileges : " + privileges.toString(); + } + } diff --git a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java index 8db08fea2..bdf3685b3 100644 --- a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java @@ -57,9 +57,9 @@ public void login() throws IOException { subject.getPrincipals().add(new QuotaPrincipal(session, null)); } } - logger.log(AuditEvent.SUCCESSFUL_LOGIN, subject); isLoggedIn = true; subject = AuthManager.getInstance().update(subject); + logger.log(AuditEvent.SUCCESSFUL_LOGIN, subject); } catch (LoginException e) { logger.log(ServerLogMessages.SECURITY_MANAGER_FAILED_LOG_IN, username, e.getMessage()); IOException ioException = new IOException(e.getMessage()); From f2240aa0e459901ba8db43f497bf313eaab5af95 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 28 Nov 2023 20:50:23 +1100 Subject: [PATCH 051/348] build up a list of UUIDs to use for ACL tests --- .../session/security/JaasSecurityContext.java | 1 + .../session/security/SecurityContext.java | 40 +++++++++++-------- src/main/resources/AuthManager.yaml | 2 +- 3 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java index bdf3685b3..a9a2f0651 100644 --- a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java @@ -59,6 +59,7 @@ public void login() throws IOException { } isLoggedIn = true; subject = AuthManager.getInstance().update(subject); + buildAccessIds(); logger.log(AuditEvent.SUCCESSFUL_LOGIN, subject); } catch (LoginException e) { logger.log(ServerLogMessages.SECURITY_MANAGER_FAILED_LOG_IN, username, e.getMessage()); diff --git a/src/main/java/io/mapsmessaging/engine/session/security/SecurityContext.java b/src/main/java/io/mapsmessaging/engine/session/security/SecurityContext.java index b45e60689..d6330bde3 100644 --- a/src/main/java/io/mapsmessaging/engine/session/security/SecurityContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/security/SecurityContext.java @@ -18,40 +18,35 @@ package io.mapsmessaging.engine.session.security; import com.sun.security.auth.UserPrincipal; +import io.mapsmessaging.security.SubjectHelper; +import io.mapsmessaging.security.access.mapping.GroupIdMap; +import io.mapsmessaging.security.identity.principals.GroupIdPrincipal; +import io.mapsmessaging.security.identity.principals.UniqueIdentifierPrincipal; +import lombok.Getter; import javax.security.auth.Subject; import java.io.IOException; import java.security.Principal; -import java.util.HashSet; -import java.util.Set; +import java.util.*; +@Getter public abstract class SecurityContext { + protected boolean isLoggedIn; protected final String username; protected Subject subject; - protected boolean isLoggedIn; + + private List accessIds; protected SecurityContext(String username){ this.username = username; } - public String getUsername(){ - return username; - } - - public Subject getSubject(){ - return subject; - } - - public boolean isLoggedIn(){ - return isLoggedIn; - } - public abstract void login() throws IOException; public abstract void logout(); - protected Subject buildSubject(String user, Principal endPointPrincipal){ + static protected Subject buildSubject(String user, Principal endPointPrincipal) { Set principalSet = new HashSet<>(); Set credentials = new HashSet<>(); Set privileges = new HashSet<>(); @@ -60,8 +55,21 @@ protected Subject buildSubject(String user, Principal endPointPrincipal){ return new Subject(true, principalSet, credentials, privileges); } + public void buildAccessIds() { + if (accessIds == null) { + accessIds = new ArrayList<>(); + accessIds.add(SubjectHelper.getUniqueId(subject)); + for (GroupIdPrincipal groupIdPrincipal : subject.getPrincipals(GroupIdPrincipal.class)) { + for (GroupIdMap g : groupIdPrincipal.getGroupIds()) { + accessIds.add(g.getAuthId()); + } + } + } + } + @Override public String toString(){ return "Username:"+username+"/tSubject:"+subject; } + } diff --git a/src/main/resources/AuthManager.yaml b/src/main/resources/AuthManager.yaml index 442ae440c..1eee24b8e 100644 --- a/src/main/resources/AuthManager.yaml +++ b/src/main/resources/AuthManager.yaml @@ -21,4 +21,4 @@ AuthManager: authorizationEnabled: true # Requestes will be authorised according to the access control list for the resource config: identityProvider: "Apache-Basic-Auth" - configDirectory: ./security \ No newline at end of file + configDirectory: ./.security \ No newline at end of file From bb7bc43006a262b1b4ae497bd07172de61bcc20c Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 28 Nov 2023 22:52:26 +1100 Subject: [PATCH 052/348] start wiring in the acl logic for server access resource access interface access --- .../auth/acl/InterfaceAccessControl.java | 36 +++++++ .../auth/acl/ResourceAccessControl.java | 38 +++++++ .../auth/acl/ResourceAccessControlList.java | 98 +++++++++++++++++++ .../auth/acl/ServerAccessControl.java | 37 +++++++ 4 files changed, 209 insertions(+) create mode 100644 src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControl.java create mode 100644 src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControl.java create mode 100644 src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java create mode 100644 src/main/java/io/mapsmessaging/auth/acl/ServerAccessControl.java diff --git a/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControl.java b/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControl.java new file mode 100644 index 000000000..e4b3e7d84 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControl.java @@ -0,0 +1,36 @@ +package io.mapsmessaging.auth.acl; + +import io.mapsmessaging.security.access.AccessControlMapping; + +public enum InterfaceAccessControl implements AccessControlMapping { + CONNECT, + MANAGE; + + private final long value; + + InterfaceAccessControl() { + this.value = 1L << this.ordinal(); // Shift 1 left by 'ordinal' positions + } + + @Override + public Long getAccessValue(String accessControl) { + if (accessControl == null) { + return 0L; + } + try { + return valueOf(accessControl.toUpperCase()).value; + } catch (IllegalArgumentException e) { + return 0L; + } + } + + @Override + public String getAccessName(long value) { + for (InterfaceAccessControl ac : values()) { + if (ac.value == value) { + return ac.name().toLowerCase(); + } + } + return null; + } +} \ No newline at end of file diff --git a/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControl.java b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControl.java new file mode 100644 index 000000000..5d87a7f42 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControl.java @@ -0,0 +1,38 @@ +package io.mapsmessaging.auth.acl; + +import io.mapsmessaging.security.access.AccessControlMapping; + +public enum ResourceAccessControl implements AccessControlMapping { + SUBSCRIBE, // ordinal 0, 2^0 = 1 + PUBLISH, // ordinal 1, 2^1 = 2 + GET_SCHEMA, // ordinal 2, 2^2 = 4 + UPDATE_SCHEMA; // ordinal 3, 2^3 = 8 + + private final long value; + + ResourceAccessControl() { + this.value = 1L << this.ordinal(); // Shift 1 left by 'ordinal' positions + } + + @Override + public Long getAccessValue(String accessControl) { + if (accessControl == null) { + return 0L; + } + try { + return valueOf(accessControl.toUpperCase()).value; + } catch (IllegalArgumentException e) { + return 0L; + } + } + + @Override + public String getAccessName(long value) { + for (ResourceAccessControl ac : values()) { + if (ac.value == value) { + return ac.name().toLowerCase(); + } + } + return null; + } +} diff --git a/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java new file mode 100644 index 000000000..c70423347 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java @@ -0,0 +1,98 @@ +package io.mapsmessaging.auth.acl; + +import io.mapsmessaging.security.SubjectHelper; +import io.mapsmessaging.security.access.AccessControlList; +import io.mapsmessaging.security.access.AccessControlListParser; +import io.mapsmessaging.security.access.AccessControlMapping; +import io.mapsmessaging.security.access.AclEntry; +import io.mapsmessaging.security.access.mapping.GroupIdMap; +import io.mapsmessaging.security.identity.principals.GroupIdPrincipal; + +import javax.security.auth.Subject; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public class ResourceAccessControlList implements AccessControlList { + + + private final List aclEntries; + + public ResourceAccessControlList() { + aclEntries = new ArrayList<>(); + } + + public ResourceAccessControlList(List aclEntries) { + this.aclEntries = new ArrayList<>(aclEntries); + } + + @Override + public String getName() { + return "ResourceAccessControlList"; + } + + @Override + public AccessControlList create(AccessControlMapping accessControlMapping, List config) { + AccessControlListParser parser = new AccessControlListParser(); + return new ResourceAccessControlList(parser.createList(accessControlMapping, config)); + } + + public long getSubjectAccess(Subject subject) { + long mask = 0; + if (subject != null) { + long time = System.currentTimeMillis(); + UUID authId = SubjectHelper.getUniqueId(subject); + for (AclEntry aclEntry : aclEntries) { + if (!aclEntry.getExpiryPolicy().hasExpired(time) && + aclEntry.matches(authId)) { + mask = mask | aclEntry.getPermissions(); + } + } + + // Scan the groups for access + Set groups = subject.getPrincipals(GroupIdPrincipal.class); + for (GroupIdPrincipal group : groups) { + for (GroupIdMap groupIdMap : group.getGroupIds()) { + for (AclEntry aclEntry : aclEntries) { + if (!aclEntry.getExpiryPolicy().hasExpired(time) + && aclEntry.matches(groupIdMap.getAuthId())) { + mask = mask | aclEntry.getPermissions(); + } + } + } + } + } + return mask; + } + + public boolean canAccess(Subject subject, long requestedAccess) { + if (subject == null || requestedAccess == 0) { + return false; + } + UUID authId = SubjectHelper.getUniqueId(subject); + + // Scan for authId for access + for (AclEntry aclEntry : aclEntries) { + if ((aclEntry.getPermissions() & requestedAccess) == requestedAccess + && aclEntry.matches(authId)) { + return true; + } + } + + // Scan the groups for access + Set groups = subject.getPrincipals(GroupIdPrincipal.class); + for (GroupIdPrincipal group : groups) { + for (GroupIdMap groupIdMap : group.getGroupIds()) { + for (AclEntry aclEntry : aclEntries) { + if ((aclEntry.getPermissions() & requestedAccess) == requestedAccess + && aclEntry.matches(groupIdMap.getAuthId())) { + return true; + } + } + } + } + // This means neither user nor group has access + return false; + } +} diff --git a/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControl.java b/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControl.java new file mode 100644 index 000000000..639c3f928 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControl.java @@ -0,0 +1,37 @@ +package io.mapsmessaging.auth.acl; + +import io.mapsmessaging.security.access.AccessControlMapping; + +public enum ServerAccessControl implements AccessControlMapping { + CONNECT, + MANAGE; + + + private final long value; + + ServerAccessControl() { + this.value = 1L << this.ordinal(); // Shift 1 left by 'ordinal' positions + } + + @Override + public Long getAccessValue(String accessControl) { + if (accessControl == null) { + return 0L; + } + try { + return valueOf(accessControl.toUpperCase()).value; + } catch (IllegalArgumentException e) { + return 0L; + } + } + + @Override + public String getAccessName(long value) { + for (ServerAccessControl ac : values()) { + if (ac.value == value) { + return ac.name().toLowerCase(); + } + } + return null; + } +} \ No newline at end of file From 0f44a2137d2a3f716c8f01bd1464a526fd29eb74 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Tue, 28 Nov 2023 23:00:25 +1100 Subject: [PATCH 053/348] rework the package --- .../io/mapsmessaging/auth/AuthManager.java | 2 +- .../io/mapsmessaging/auth/QuotaPrincipal.java | 4 +-- .../priviliges/BooleanPrivilege.java | 2 +- .../priviliges/LongPrivilege.java | 2 +- .../{registry => }/priviliges/Privilege.java | 2 +- .../priviliges/PrivilegeSerializer.java | 3 +-- .../auth/priviliges/PublishPrivileges.java | 14 ++++++++++ .../SessionPrivileges.java | 26 ++++++++++--------- .../priviliges/StringPrivilege.java | 2 +- .../priviliges/SubscriptionPrivileges.java | 8 ++++++ .../subscription/SubscriptionPrivileges.java | 4 +++ .../auth/registry/AuthenticationStorage.java | 4 +-- .../auth/registry/UserPermisionManager.java | 2 +- .../principal/SessionPrivilegePrincipal.java | 2 +- .../subscription/SubscriptionPrivileges.java | 4 --- .../engine/session/SessionContext.java | 2 +- .../session/security/JaasSecurityContext.java | 2 +- 17 files changed, 54 insertions(+), 31 deletions(-) rename src/main/java/io/mapsmessaging/auth/{registry => }/priviliges/BooleanPrivilege.java (86%) rename src/main/java/io/mapsmessaging/auth/{registry => }/priviliges/LongPrivilege.java (85%) rename src/main/java/io/mapsmessaging/auth/{registry => }/priviliges/Privilege.java (72%) rename src/main/java/io/mapsmessaging/auth/{registry => }/priviliges/PrivilegeSerializer.java (94%) create mode 100644 src/main/java/io/mapsmessaging/auth/priviliges/PublishPrivileges.java rename src/main/java/io/mapsmessaging/auth/{registry/priviliges/session => priviliges}/SessionPrivileges.java (84%) rename src/main/java/io/mapsmessaging/auth/{registry => }/priviliges/StringPrivilege.java (86%) create mode 100644 src/main/java/io/mapsmessaging/auth/priviliges/SubscriptionPrivileges.java create mode 100644 src/main/java/io/mapsmessaging/auth/priviliges/subscription/SubscriptionPrivileges.java delete mode 100644 src/main/java/io/mapsmessaging/auth/registry/priviliges/subscription/SubscriptionPrivileges.java diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index 4c1785c72..13926d24e 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -19,7 +19,7 @@ import io.mapsmessaging.auth.registry.AuthenticationStorage; import io.mapsmessaging.auth.registry.PasswordGenerator; -import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; +import io.mapsmessaging.auth.priviliges.SessionPrivileges; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; import io.mapsmessaging.utilities.Agent; diff --git a/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java b/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java index e74641857..6816936e5 100644 --- a/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java +++ b/src/main/java/io/mapsmessaging/auth/QuotaPrincipal.java @@ -17,8 +17,8 @@ package io.mapsmessaging.auth; -import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; -import io.mapsmessaging.auth.registry.priviliges.subscription.SubscriptionPrivileges; +import io.mapsmessaging.auth.priviliges.SessionPrivileges; +import io.mapsmessaging.auth.priviliges.subscription.SubscriptionPrivileges; import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.ToString; diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/BooleanPrivilege.java b/src/main/java/io/mapsmessaging/auth/priviliges/BooleanPrivilege.java similarity index 86% rename from src/main/java/io/mapsmessaging/auth/registry/priviliges/BooleanPrivilege.java rename to src/main/java/io/mapsmessaging/auth/priviliges/BooleanPrivilege.java index 7a5f47f61..f6ab93ce9 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/priviliges/BooleanPrivilege.java +++ b/src/main/java/io/mapsmessaging/auth/priviliges/BooleanPrivilege.java @@ -1,4 +1,4 @@ -package io.mapsmessaging.auth.registry.priviliges; +package io.mapsmessaging.auth.priviliges; import lombok.EqualsAndHashCode; import lombok.Getter; diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/LongPrivilege.java b/src/main/java/io/mapsmessaging/auth/priviliges/LongPrivilege.java similarity index 85% rename from src/main/java/io/mapsmessaging/auth/registry/priviliges/LongPrivilege.java rename to src/main/java/io/mapsmessaging/auth/priviliges/LongPrivilege.java index 299dc262e..936c1c047 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/priviliges/LongPrivilege.java +++ b/src/main/java/io/mapsmessaging/auth/priviliges/LongPrivilege.java @@ -1,4 +1,4 @@ -package io.mapsmessaging.auth.registry.priviliges; +package io.mapsmessaging.auth.priviliges; import lombok.EqualsAndHashCode; import lombok.Getter; diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/Privilege.java b/src/main/java/io/mapsmessaging/auth/priviliges/Privilege.java similarity index 72% rename from src/main/java/io/mapsmessaging/auth/registry/priviliges/Privilege.java rename to src/main/java/io/mapsmessaging/auth/priviliges/Privilege.java index 5bf783a4e..8ed5cdefd 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/priviliges/Privilege.java +++ b/src/main/java/io/mapsmessaging/auth/priviliges/Privilege.java @@ -1,4 +1,4 @@ -package io.mapsmessaging.auth.registry.priviliges; +package io.mapsmessaging.auth.priviliges; import lombok.*; diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java b/src/main/java/io/mapsmessaging/auth/priviliges/PrivilegeSerializer.java similarity index 94% rename from src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java rename to src/main/java/io/mapsmessaging/auth/priviliges/PrivilegeSerializer.java index 42552f3f0..93bf36de0 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/priviliges/PrivilegeSerializer.java +++ b/src/main/java/io/mapsmessaging/auth/priviliges/PrivilegeSerializer.java @@ -1,6 +1,5 @@ -package io.mapsmessaging.auth.registry.priviliges; +package io.mapsmessaging.auth.priviliges; -import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; import org.jetbrains.annotations.NotNull; import org.mapdb.DataInput2; import org.mapdb.DataOutput2; diff --git a/src/main/java/io/mapsmessaging/auth/priviliges/PublishPrivileges.java b/src/main/java/io/mapsmessaging/auth/priviliges/PublishPrivileges.java new file mode 100644 index 000000000..09ce19306 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/priviliges/PublishPrivileges.java @@ -0,0 +1,14 @@ +package io.mapsmessaging.auth.priviliges; + +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@ToString +@EqualsAndHashCode +public class PublishPrivileges extends Privilege { + + public PublishPrivileges() { + super("publish"); + } + +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java b/src/main/java/io/mapsmessaging/auth/priviliges/SessionPrivileges.java similarity index 84% rename from src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java rename to src/main/java/io/mapsmessaging/auth/priviliges/SessionPrivileges.java index 70245afc0..37bc45c17 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/priviliges/session/SessionPrivileges.java +++ b/src/main/java/io/mapsmessaging/auth/priviliges/SessionPrivileges.java @@ -15,26 +15,20 @@ * */ -package io.mapsmessaging.auth.registry.priviliges.session; +package io.mapsmessaging.auth.priviliges; import io.mapsmessaging.api.features.QualityOfService; -import io.mapsmessaging.auth.registry.priviliges.BooleanPrivilege; -import io.mapsmessaging.auth.registry.priviliges.LongPrivilege; -import io.mapsmessaging.auth.registry.priviliges.Privilege; -import lombok.AllArgsConstructor; -import lombok.Data; -import lombok.EqualsAndHashCode; -import lombok.ToString; +import lombok.*; import java.util.ArrayList; import java.util.List; import java.util.UUID; -@Data -@AllArgsConstructor @ToString -@EqualsAndHashCode -public class SessionPrivileges { +@EqualsAndHashCode(callSuper = false) +@Getter +@Setter +public class SessionPrivileges extends Privilege { public static SessionPrivileges create(String username) { return new SessionPrivileges(username); @@ -44,7 +38,15 @@ public static SessionPrivileges create(String username) { private final String username; private final List priviliges; + public SessionPrivileges(UUID id, String username, List priviliges) { + super("session"); + this.uniqueId = id; + this.username = username; + this.priviliges = priviliges; + } + protected SessionPrivileges(String username) { + super("session"); this.username = username; priviliges = new ArrayList<>(); priviliges.add(new BooleanPrivilege("Admin", false)); diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/StringPrivilege.java b/src/main/java/io/mapsmessaging/auth/priviliges/StringPrivilege.java similarity index 86% rename from src/main/java/io/mapsmessaging/auth/registry/priviliges/StringPrivilege.java rename to src/main/java/io/mapsmessaging/auth/priviliges/StringPrivilege.java index a1f2d4d26..39b0c1bbe 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/priviliges/StringPrivilege.java +++ b/src/main/java/io/mapsmessaging/auth/priviliges/StringPrivilege.java @@ -1,4 +1,4 @@ -package io.mapsmessaging.auth.registry.priviliges; +package io.mapsmessaging.auth.priviliges; import lombok.EqualsAndHashCode; import lombok.Getter; diff --git a/src/main/java/io/mapsmessaging/auth/priviliges/SubscriptionPrivileges.java b/src/main/java/io/mapsmessaging/auth/priviliges/SubscriptionPrivileges.java new file mode 100644 index 000000000..ec9a25451 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/priviliges/SubscriptionPrivileges.java @@ -0,0 +1,8 @@ +package io.mapsmessaging.auth.priviliges; + +public class SubscriptionPrivileges extends Privilege { + + public SubscriptionPrivileges() { + super("subscriptionPrivileges"); + } +} diff --git a/src/main/java/io/mapsmessaging/auth/priviliges/subscription/SubscriptionPrivileges.java b/src/main/java/io/mapsmessaging/auth/priviliges/subscription/SubscriptionPrivileges.java new file mode 100644 index 000000000..2f923dbae --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/priviliges/subscription/SubscriptionPrivileges.java @@ -0,0 +1,4 @@ +package io.mapsmessaging.auth.priviliges.subscription; + +public class SubscriptionPrivileges { +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java index fd95c205e..72bd505fc 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java +++ b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java @@ -21,8 +21,8 @@ import io.mapsmessaging.auth.registry.mapping.IdDbStore; import io.mapsmessaging.auth.registry.mapping.UserIdSerializer; import io.mapsmessaging.auth.registry.principal.SessionPrivilegePrincipal; -import io.mapsmessaging.auth.registry.priviliges.PrivilegeSerializer; -import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; +import io.mapsmessaging.auth.priviliges.PrivilegeSerializer; +import io.mapsmessaging.auth.priviliges.SessionPrivileges; import io.mapsmessaging.security.SubjectHelper; import io.mapsmessaging.security.access.IdentityAccessManager; import io.mapsmessaging.security.access.mapping.GroupIdMap; diff --git a/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java b/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java index 861d92616..64c9b3811 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java +++ b/src/main/java/io/mapsmessaging/auth/registry/UserPermisionManager.java @@ -17,7 +17,7 @@ package io.mapsmessaging.auth.registry; -import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; +import io.mapsmessaging.auth.priviliges.SessionPrivileges; import java.util.Map; import java.util.UUID; diff --git a/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java b/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java index 884336109..540ce864d 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java +++ b/src/main/java/io/mapsmessaging/auth/registry/principal/SessionPrivilegePrincipal.java @@ -17,7 +17,7 @@ package io.mapsmessaging.auth.registry.principal; -import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; +import io.mapsmessaging.auth.priviliges.SessionPrivileges; import java.security.Principal; diff --git a/src/main/java/io/mapsmessaging/auth/registry/priviliges/subscription/SubscriptionPrivileges.java b/src/main/java/io/mapsmessaging/auth/registry/priviliges/subscription/SubscriptionPrivileges.java deleted file mode 100644 index e92f874f9..000000000 --- a/src/main/java/io/mapsmessaging/auth/registry/priviliges/subscription/SubscriptionPrivileges.java +++ /dev/null @@ -1,4 +0,0 @@ -package io.mapsmessaging.auth.registry.priviliges.subscription; - -public class SubscriptionPrivileges { -} diff --git a/src/main/java/io/mapsmessaging/engine/session/SessionContext.java b/src/main/java/io/mapsmessaging/engine/session/SessionContext.java index df2367a57..8965d720d 100644 --- a/src/main/java/io/mapsmessaging/engine/session/SessionContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/SessionContext.java @@ -18,7 +18,7 @@ package io.mapsmessaging.engine.session; import io.mapsmessaging.api.message.Message; -import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; +import io.mapsmessaging.auth.priviliges.SessionPrivileges; import lombok.Data; import lombok.ToString; diff --git a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java index a9a2f0651..f973b4f77 100644 --- a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java @@ -19,7 +19,7 @@ import io.mapsmessaging.auth.AuthManager; import io.mapsmessaging.auth.QuotaPrincipal; -import io.mapsmessaging.auth.registry.priviliges.session.SessionPrivileges; +import io.mapsmessaging.auth.priviliges.SessionPrivileges; import io.mapsmessaging.engine.audit.AuditEvent; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; From 552d0464061c5de6b2dcb66ef93e4f88c1a71ed9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 18:33:15 +0000 Subject: [PATCH 054/348] Bump logback.version from 1.4.11 to 1.4.13 Bumps `logback.version` from 1.4.11 to 1.4.13. Updates `ch.qos.logback:logback-core` from 1.4.11 to 1.4.13 - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.11...v_1.4.13) Updates `ch.qos.logback:logback-classic` from 1.4.11 to 1.4.13 - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.11...v_1.4.13) Updates `ch.qos.logback:logback-access` from 1.4.11 to 1.4.13 - [Commits](https://github.com/qos-ch/logback/compare/v_1.4.11...v_1.4.13) --- updated-dependencies: - dependency-name: ch.qos.logback:logback-core dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: ch.qos.logback:logback-classic dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: ch.qos.logback:logback-access dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2e0c280fb..82cba565e 100644 --- a/pom.xml +++ b/pom.xml @@ -478,7 +478,7 @@ - 1.4.11 + 1.4.13 UTF-8 src/main 2.4.0 From 466e46ed76fb256676ddc7ca66513f6bcf2a4fc9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 18:33:49 +0000 Subject: [PATCH 055/348] Bump software.amazon.awssdk:bom from 2.21.29 to 2.21.32 Bumps software.amazon.awssdk:bom from 2.21.29 to 2.21.32. --- updated-dependencies: - dependency-name: software.amazon.awssdk:bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2e0c280fb..492267669 100644 --- a/pom.xml +++ b/pom.xml @@ -521,7 +521,7 @@ software.amazon.awssdk bom - 2.21.29 + 2.21.32 pom import From bcc2fa71260c4025b31ce92387056972154f216a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 28 Nov 2023 18:34:27 +0000 Subject: [PATCH 056/348] Bump com.amazonaws:aws-java-sdk-cognitoidp from 1.12.595 to 1.12.598 Bumps [com.amazonaws:aws-java-sdk-cognitoidp](https://github.com/aws/aws-sdk-java) from 1.12.595 to 1.12.598. - [Changelog](https://github.com/aws/aws-sdk-java/blob/master/CHANGELOG.md) - [Commits](https://github.com/aws/aws-sdk-java/compare/1.12.595...1.12.598) --- updated-dependencies: - dependency-name: com.amazonaws:aws-java-sdk-cognitoidp dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 2e0c280fb..b2877b1b7 100644 --- a/pom.xml +++ b/pom.xml @@ -873,7 +873,7 @@ com.amazonaws aws-java-sdk-cognitoidp - 1.12.595 + 1.12.598 test From 97d8cffa3d65cbc4a708cc0091f677e1e79bae4c Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 29 Nov 2023 10:01:23 +1100 Subject: [PATCH 057/348] Add list of uuids to the subject use the list, if present to determine access to the required resource add support for resource (topic/queue), interfaces and server --- .../auth/acl/BaseAccessControlList.java | 163 ++++++++++++++++++ .../auth/acl/InterfaceAccessControlList.java | 47 +++++ .../auth/acl/ResourceAccessControl.java | 22 ++- .../auth/acl/ResourceAccessControlList.java | 89 ++-------- .../auth/acl/ServerAccessControl.java | 18 ++ .../auth/acl/ServerAccessControlList.java | 47 +++++ .../auth/priviliges/SessionPrivileges.java | 7 +- .../registry/principal/AccessIdPrincipal.java | 38 ++++ .../session/security/JaasSecurityContext.java | 2 + 9 files changed, 358 insertions(+), 75 deletions(-) create mode 100644 src/main/java/io/mapsmessaging/auth/acl/BaseAccessControlList.java create mode 100644 src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControlList.java create mode 100644 src/main/java/io/mapsmessaging/auth/acl/ServerAccessControlList.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/principal/AccessIdPrincipal.java diff --git a/src/main/java/io/mapsmessaging/auth/acl/BaseAccessControlList.java b/src/main/java/io/mapsmessaging/auth/acl/BaseAccessControlList.java new file mode 100644 index 000000000..7b8460ee5 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/acl/BaseAccessControlList.java @@ -0,0 +1,163 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.acl; + +import io.mapsmessaging.auth.registry.principal.AccessIdPrincipal; +import io.mapsmessaging.security.SubjectHelper; +import io.mapsmessaging.security.access.AccessControlList; +import io.mapsmessaging.security.access.AclEntry; +import io.mapsmessaging.security.access.mapping.GroupIdMap; +import io.mapsmessaging.security.identity.principals.GroupIdPrincipal; + +import javax.security.auth.Subject; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; + +public abstract class BaseAccessControlList implements AccessControlList { + + protected final List aclEntries; + + protected BaseAccessControlList() { + aclEntries = new ArrayList<>(); + } + + protected BaseAccessControlList(List aclEntries) { + this.aclEntries = new ArrayList<>(aclEntries); + } + + + public long getSubjectAccess(Subject subject) { + long mask = 0; + if (subject != null) { + long time = System.currentTimeMillis(); + Set accessIdPrincipals = subject.getPrincipals(AccessIdPrincipal.class); + if (!accessIdPrincipals.isEmpty()) { // If we have a prebuilt list of UUIDs then lets scan it rather than look up individually + mask = parseUUIDList(accessIdPrincipals, time); + } else { + // Scan the user + mask = parseUserUUID(SubjectHelper.getUniqueId(subject), time); + // Scan the groups for access + mask = parseGroupUUID(subject.getPrincipals(GroupIdPrincipal.class), mask, time); + } + } + return mask; + } + + + public boolean canAccess(Subject subject, long requestedAccess) { + if (subject == null || requestedAccess == 0) { + return false; + } + Set accessIdPrincipals = subject.getPrincipals(AccessIdPrincipal.class); + if (!accessIdPrincipals.isEmpty()) { // If we have a prebuilt list of UUIDs then lets scan it rather than look up individually + return listHas(accessIdPrincipals, System.currentTimeMillis(), requestedAccess); + } else { + UUID authId = SubjectHelper.getUniqueId(subject); + if (userHas(authId, System.currentTimeMillis(), requestedAccess)) return true; + + // Scan the groups for access + Set groups = subject.getPrincipals(GroupIdPrincipal.class); + return groupHas(groups, System.currentTimeMillis(), requestedAccess); + } + } + + private long parseUserUUID(UUID authId, long time) { + long mask = 0; + for (AclEntry aclEntry : aclEntries) { + if (!aclEntry.getExpiryPolicy().hasExpired(time) && + aclEntry.matches(authId)) { + mask = mask | aclEntry.getPermissions(); + } + } + return mask; + } + + + private boolean userHas(UUID authId, long time, long requestedAccess) { + for (AclEntry aclEntry : aclEntries) { + if (!aclEntry.getExpiryPolicy().hasExpired(time) && + (aclEntry.getPermissions() & requestedAccess) == requestedAccess + && aclEntry.matches(authId)) { + return true; + } + } + return false; + } + + + private long parseGroupUUID(Set groups, long mask, long time) { + for (GroupIdPrincipal group : groups) { + for (GroupIdMap groupIdMap : group.getGroupIds()) { + for (AclEntry aclEntry : aclEntries) { + if (!aclEntry.getExpiryPolicy().hasExpired(time) + && aclEntry.matches(groupIdMap.getAuthId())) { + mask = mask | aclEntry.getPermissions(); + } + } + } + } + return mask; + } + + private boolean groupHas(Set groups, long time, long requestedAccess) { + for (GroupIdPrincipal group : groups) { + for (GroupIdMap groupIdMap : group.getGroupIds()) { + for (AclEntry aclEntry : aclEntries) { + if (!aclEntry.getExpiryPolicy().hasExpired(time) && + (aclEntry.getPermissions() & requestedAccess) == requestedAccess + && aclEntry.matches(groupIdMap.getAuthId())) { + return true; + } + } + } + } + return false; + } + + private long parseUUIDList(Set accessIdPrincipals, long time) { + long mask = 0; + for (AccessIdPrincipal accessIdPrincipal : accessIdPrincipals) { + for (UUID uuid : accessIdPrincipal.getAccessIds()) { + for (AclEntry aclEntry : aclEntries) { + if (!aclEntry.getExpiryPolicy().hasExpired(time) && aclEntry.matches(uuid)) + mask = mask | aclEntry.getPermissions(); + } + } + } + return mask; + } + + + private boolean listHas(Set accessIdPrincipals, long timeMillis, long requestedAccess) { + for (AccessIdPrincipal accessIdPrincipal : accessIdPrincipals) { + for (UUID uuid : accessIdPrincipal.getAccessIds()) { + for (AclEntry aclEntry : aclEntries) { + if (!aclEntry.getExpiryPolicy().hasExpired(timeMillis) && + (aclEntry.getPermissions() & requestedAccess) == requestedAccess + && aclEntry.matches(uuid)) { + return true; + } + } + } + } + return false; + } + +} diff --git a/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControlList.java b/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControlList.java new file mode 100644 index 000000000..1bcbcb245 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControlList.java @@ -0,0 +1,47 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.acl; + +import io.mapsmessaging.security.access.AccessControlList; +import io.mapsmessaging.security.access.AccessControlListParser; +import io.mapsmessaging.security.access.AccessControlMapping; +import io.mapsmessaging.security.access.AclEntry; + +import java.util.List; + +public class InterfaceAccessControlList extends BaseAccessControlList { + + public InterfaceAccessControlList() { + } + + public InterfaceAccessControlList(List aclEntries) { + super(aclEntries); + } + + @Override + public String getName() { + return "InterfaceAccessControlList"; + } + + @Override + public AccessControlList create(AccessControlMapping accessControlMapping, List config) { + AccessControlListParser parser = new AccessControlListParser(); + return new InterfaceAccessControlList(parser.createList(accessControlMapping, config)); + } + +} diff --git a/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControl.java b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControl.java index 5d87a7f42..7fd75cc48 100644 --- a/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControl.java +++ b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControl.java @@ -1,3 +1,20 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package io.mapsmessaging.auth.acl; import io.mapsmessaging.security.access.AccessControlMapping; @@ -5,8 +22,9 @@ public enum ResourceAccessControl implements AccessControlMapping { SUBSCRIBE, // ordinal 0, 2^0 = 1 PUBLISH, // ordinal 1, 2^1 = 2 - GET_SCHEMA, // ordinal 2, 2^2 = 4 - UPDATE_SCHEMA; // ordinal 3, 2^3 = 8 + PUBLISH_RETAINED, // ordinal 2, 2^2 = 4 + GET_SCHEMA, // ordinal 2, 2^3 = 8 + UPDATE_SCHEMA; // ordinal 3, 2^4 = 16 private final long value; diff --git a/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java index c70423347..62e602caf 100644 --- a/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java +++ b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java @@ -1,30 +1,36 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package io.mapsmessaging.auth.acl; -import io.mapsmessaging.security.SubjectHelper; import io.mapsmessaging.security.access.AccessControlList; import io.mapsmessaging.security.access.AccessControlListParser; import io.mapsmessaging.security.access.AccessControlMapping; import io.mapsmessaging.security.access.AclEntry; -import io.mapsmessaging.security.access.mapping.GroupIdMap; -import io.mapsmessaging.security.identity.principals.GroupIdPrincipal; -import javax.security.auth.Subject; -import java.util.ArrayList; import java.util.List; -import java.util.Set; -import java.util.UUID; - -public class ResourceAccessControlList implements AccessControlList { - - private final List aclEntries; +public class ResourceAccessControlList extends BaseAccessControlList { public ResourceAccessControlList() { - aclEntries = new ArrayList<>(); } public ResourceAccessControlList(List aclEntries) { - this.aclEntries = new ArrayList<>(aclEntries); + super(aclEntries); } @Override @@ -38,61 +44,4 @@ public AccessControlList create(AccessControlMapping accessControlMapping, List< return new ResourceAccessControlList(parser.createList(accessControlMapping, config)); } - public long getSubjectAccess(Subject subject) { - long mask = 0; - if (subject != null) { - long time = System.currentTimeMillis(); - UUID authId = SubjectHelper.getUniqueId(subject); - for (AclEntry aclEntry : aclEntries) { - if (!aclEntry.getExpiryPolicy().hasExpired(time) && - aclEntry.matches(authId)) { - mask = mask | aclEntry.getPermissions(); - } - } - - // Scan the groups for access - Set groups = subject.getPrincipals(GroupIdPrincipal.class); - for (GroupIdPrincipal group : groups) { - for (GroupIdMap groupIdMap : group.getGroupIds()) { - for (AclEntry aclEntry : aclEntries) { - if (!aclEntry.getExpiryPolicy().hasExpired(time) - && aclEntry.matches(groupIdMap.getAuthId())) { - mask = mask | aclEntry.getPermissions(); - } - } - } - } - } - return mask; - } - - public boolean canAccess(Subject subject, long requestedAccess) { - if (subject == null || requestedAccess == 0) { - return false; - } - UUID authId = SubjectHelper.getUniqueId(subject); - - // Scan for authId for access - for (AclEntry aclEntry : aclEntries) { - if ((aclEntry.getPermissions() & requestedAccess) == requestedAccess - && aclEntry.matches(authId)) { - return true; - } - } - - // Scan the groups for access - Set groups = subject.getPrincipals(GroupIdPrincipal.class); - for (GroupIdPrincipal group : groups) { - for (GroupIdMap groupIdMap : group.getGroupIds()) { - for (AclEntry aclEntry : aclEntries) { - if ((aclEntry.getPermissions() & requestedAccess) == requestedAccess - && aclEntry.matches(groupIdMap.getAuthId())) { - return true; - } - } - } - } - // This means neither user nor group has access - return false; - } } diff --git a/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControl.java b/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControl.java index 639c3f928..1c4b7806b 100644 --- a/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControl.java +++ b/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControl.java @@ -1,9 +1,27 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + package io.mapsmessaging.auth.acl; import io.mapsmessaging.security.access.AccessControlMapping; public enum ServerAccessControl implements AccessControlMapping { CONNECT, + ADMIN, MANAGE; diff --git a/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControlList.java b/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControlList.java new file mode 100644 index 000000000..bb62eba69 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControlList.java @@ -0,0 +1,47 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.acl; + +import io.mapsmessaging.security.access.AccessControlList; +import io.mapsmessaging.security.access.AccessControlListParser; +import io.mapsmessaging.security.access.AccessControlMapping; +import io.mapsmessaging.security.access.AclEntry; + +import java.util.List; + +public class ServerAccessControlList extends BaseAccessControlList { + + public ServerAccessControlList() { + } + + public ServerAccessControlList(List aclEntries) { + super(aclEntries); + } + + @Override + public String getName() { + return "ServerAccessControlList"; + } + + @Override + public AccessControlList create(AccessControlMapping accessControlMapping, List config) { + AccessControlListParser parser = new AccessControlListParser(); + return new ServerAccessControlList(parser.createList(accessControlMapping, config)); + } + +} diff --git a/src/main/java/io/mapsmessaging/auth/priviliges/SessionPrivileges.java b/src/main/java/io/mapsmessaging/auth/priviliges/SessionPrivileges.java index 37bc45c17..121eedc58 100644 --- a/src/main/java/io/mapsmessaging/auth/priviliges/SessionPrivileges.java +++ b/src/main/java/io/mapsmessaging/auth/priviliges/SessionPrivileges.java @@ -18,7 +18,10 @@ package io.mapsmessaging.auth.priviliges; import io.mapsmessaging.api.features.QualityOfService; -import lombok.*; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; import java.util.ArrayList; import java.util.List; @@ -49,9 +52,7 @@ protected SessionPrivileges(String username) { super("session"); this.username = username; priviliges = new ArrayList<>(); - priviliges.add(new BooleanPrivilege("Admin", false)); priviliges.add(new BooleanPrivilege("AccessSystemTopics", true)); - priviliges.add(new BooleanPrivilege("PublishRetainedMessages", true)); priviliges.add(new BooleanPrivilege("ForceReset", false)); priviliges.add(new BooleanPrivilege("AllowPersistentSession", true)); diff --git a/src/main/java/io/mapsmessaging/auth/registry/principal/AccessIdPrincipal.java b/src/main/java/io/mapsmessaging/auth/registry/principal/AccessIdPrincipal.java new file mode 100644 index 000000000..ecf743d76 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/principal/AccessIdPrincipal.java @@ -0,0 +1,38 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry.principal; + +import lombok.Getter; + +import java.security.Principal; +import java.util.List; +import java.util.UUID; + +public class AccessIdPrincipal implements Principal { + + @Getter + private final List accessIds; + + public AccessIdPrincipal(List accessIds) { + this.accessIds = accessIds; + } + + public String getName() { + return "AccessIdPrinicpal"; + } +} diff --git a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java index f973b4f77..84471b0ad 100644 --- a/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java +++ b/src/main/java/io/mapsmessaging/engine/session/security/JaasSecurityContext.java @@ -20,6 +20,7 @@ import io.mapsmessaging.auth.AuthManager; import io.mapsmessaging.auth.QuotaPrincipal; import io.mapsmessaging.auth.priviliges.SessionPrivileges; +import io.mapsmessaging.auth.registry.principal.AccessIdPrincipal; import io.mapsmessaging.engine.audit.AuditEvent; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; @@ -59,6 +60,7 @@ public void login() throws IOException { } isLoggedIn = true; subject = AuthManager.getInstance().update(subject); + subject.getPrincipals().add(new AccessIdPrincipal(getAccessIds())); buildAccessIds(); logger.log(AuditEvent.SUCCESSFUL_LOGIN, subject); } catch (LoginException e) { From fe62d980f29717d905d284d41a85e00f44239d6e Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 29 Nov 2023 13:00:05 +1100 Subject: [PATCH 058/348] Add auth to the rest api and integrate it into the server auth --- .../io/mapsmessaging/auth/AuthManager.java | 88 +++++++++++-------- .../auth/acl/InterfaceAccessControlList.java | 2 +- .../auth/acl/ResourceAccessControlList.java | 2 +- .../auth/acl/ServerAccessControlList.java | 2 +- .../auth/registry/AuthenticationStorage.java | 8 +- .../rest/AuthenticationFilter.java | 60 +++++++++++++ .../rest/RestApiServerManager.java | 5 ++ ...essaging.security.access.AccessControlList | 20 +++++ 8 files changed, 142 insertions(+), 45 deletions(-) create mode 100644 src/main/java/io/mapsmessaging/rest/AuthenticationFilter.java create mode 100644 src/main/resources/META-INF/services/io.mapsmessaging.security.access.AccessControlList diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index 13926d24e..ac90808fb 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -17,9 +17,9 @@ package io.mapsmessaging.auth; +import io.mapsmessaging.auth.priviliges.SessionPrivileges; import io.mapsmessaging.auth.registry.AuthenticationStorage; import io.mapsmessaging.auth.registry.PasswordGenerator; -import io.mapsmessaging.auth.priviliges.SessionPrivileges; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; import io.mapsmessaging.utilities.Agent; @@ -36,6 +36,12 @@ public class AuthManager implements Agent { + private static final String ADMIN_USER = "admin"; + private static final String USER = "user"; + + private static final String ADMIN_GROUP = "admin"; + private static final String EVERYONE = "everyone"; + @Getter private static final AuthManager instance = new AuthManager(); @@ -62,45 +68,22 @@ public String getDescription() { public void start() { if (authenticationEnabled) { ConfigurationProperties config = (ConfigurationProperties) properties.get("config"); - String password = null; - String userpassword = null; authenticationStorage = new AuthenticationStorage(config); - - if (!authenticationStorage.isExisted()) { - password = PasswordGenerator.generateRandomPassword(12); - String username = "admin"; - addUser(username, password, SessionPrivileges.create(username), new String[]{username, "everyone"}); - - userpassword = PasswordGenerator.generateRandomPassword(12); - username = "user"; - addUser(username, userpassword, SessionPrivileges.create(username), new String[]{"everyone"}); - - String path = config.get("configDirectory").toString(); - - try (BufferedWriter bw = new BufferedWriter(new FileWriter(path + File.separator + "admin_password", true))) { - bw.write("admin=" + password); - bw.newLine(); // Add a newline character after each line - bw.write("user=" + userpassword); - bw.newLine(); // Add a newline character after each line - - } catch (IOException e) { - e.printStackTrace(); - } - } - if (password != null) { - if (authenticationStorage.validateUser("admin", password)) { - System.err.println("Successfully added admin"); - } else { - System.err.println("Failed to add admin"); - } - if (authenticationStorage.validateUser("user", userpassword)) { - System.err.println("Successfully added user"); - } else { - System.err.println("Failed to add user"); - } + if (!authenticationStorage.isFirstBoot()) { + createInitialUsers(config.get("configDirectory").toString()); } } + } + private void saveInitialUserDetails(String path, String[][] details) { + try (BufferedWriter bw = new BufferedWriter(new FileWriter(path + File.separator + "admin_password", true))) { + for (String[] detail : details) { + bw.write(detail[0] + "=" + detail[1]); + bw.newLine(); // Add a newline character after each line + } + } catch (IOException e) { + e.printStackTrace(); + } } @Override @@ -124,6 +107,10 @@ public Subject update(Subject subject) { return authenticationStorage.update(subject); } + public SessionPrivileges getQuota(UUID userId) { + return authenticationStorage.getQuota(userId); + } + private AuthManager() { logger = LoggerFactory.getLogger(AuthManager.class); properties = ConfigurationManager.getInstance().getProperties("AuthManager"); @@ -131,7 +118,32 @@ private AuthManager() { authorisationEnabled = properties.getBooleanProperty("authorizationEnabled", false) && authenticationEnabled; } - public SessionPrivileges getQuota(UUID userId) { - return authenticationStorage.getQuota(userId); + private void createInitialUsers(String path) { + String password = PasswordGenerator.generateRandomPassword(12); + if (!addUser(ADMIN_USER, password, SessionPrivileges.create(ADMIN_USER), new String[]{ADMIN_GROUP, EVERYONE})) { + // ToDo : log + } + + String userpassword = PasswordGenerator.generateRandomPassword(12); + if (addUser(USER, userpassword, SessionPrivileges.create(USER), new String[]{EVERYONE})) { + // ToDo : log + + } + + saveInitialUserDetails(path, new String[][]{{ADMIN_USER, password}, {USER, userpassword}}); + if (authenticationStorage.validateUser(ADMIN_USER, password)) { + // To Do : log + } else { + // To Do : log + } + if (authenticationStorage.validateUser(USER, userpassword)) { + // To Do : log + } else { + // To Do : log + } + } + + public boolean validate(String username, String password) { + return authenticationStorage.validateUser(username, password); } } diff --git a/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControlList.java b/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControlList.java index 1bcbcb245..a1b48f202 100644 --- a/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControlList.java +++ b/src/main/java/io/mapsmessaging/auth/acl/InterfaceAccessControlList.java @@ -35,7 +35,7 @@ public InterfaceAccessControlList(List aclEntries) { @Override public String getName() { - return "InterfaceAccessControlList"; + return "InterfaceACL"; } @Override diff --git a/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java index 62e602caf..f6cd7b4b7 100644 --- a/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java +++ b/src/main/java/io/mapsmessaging/auth/acl/ResourceAccessControlList.java @@ -35,7 +35,7 @@ public ResourceAccessControlList(List aclEntries) { @Override public String getName() { - return "ResourceAccessControlList"; + return "ResourceACL"; } @Override diff --git a/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControlList.java b/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControlList.java index bb62eba69..9ae6dfc39 100644 --- a/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControlList.java +++ b/src/main/java/io/mapsmessaging/auth/acl/ServerAccessControlList.java @@ -35,7 +35,7 @@ public ServerAccessControlList(List aclEntries) { @Override public String getName() { - return "ServerAccessControlList"; + return "ServerACL"; } @Override diff --git a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java index 72bd505fc..9bed6eecc 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java +++ b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java @@ -17,12 +17,12 @@ package io.mapsmessaging.auth.registry; +import io.mapsmessaging.auth.priviliges.PrivilegeSerializer; +import io.mapsmessaging.auth.priviliges.SessionPrivileges; import io.mapsmessaging.auth.registry.mapping.GroupIdSerializer; import io.mapsmessaging.auth.registry.mapping.IdDbStore; import io.mapsmessaging.auth.registry.mapping.UserIdSerializer; import io.mapsmessaging.auth.registry.principal.SessionPrivilegePrincipal; -import io.mapsmessaging.auth.priviliges.PrivilegeSerializer; -import io.mapsmessaging.auth.priviliges.SessionPrivileges; import io.mapsmessaging.security.SubjectHelper; import io.mapsmessaging.security.access.IdentityAccessManager; import io.mapsmessaging.security.access.mapping.GroupIdMap; @@ -50,7 +50,7 @@ public class AuthenticationStorage implements Closeable { private final UserPermisionManager userPermisionManager; private final DB db; @Getter - private final boolean existed; + private final boolean firstBoot; public AuthenticationStorage(ConfigurationProperties config) { String securityDirectory = config.getProperty("configDirectory", "./.security"); @@ -61,7 +61,7 @@ public AuthenticationStorage(ConfigurationProperties config) { } } - existed = new File(securityDirectory + File.separator + ".auth.db").exists(); + firstBoot = new File(securityDirectory + File.separator + ".auth.db").exists(); db = DBMaker.fileDB(securityDirectory + File.separator + ".auth.db") .checksumStoreEnable() .fileChannelEnable() diff --git a/src/main/java/io/mapsmessaging/rest/AuthenticationFilter.java b/src/main/java/io/mapsmessaging/rest/AuthenticationFilter.java new file mode 100644 index 000000000..77fd62393 --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/AuthenticationFilter.java @@ -0,0 +1,60 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest; + +import com.sun.jersey.core.util.Base64; +import com.sun.jersey.core.util.Priority; +import io.mapsmessaging.auth.AuthManager; +import jakarta.ws.rs.WebApplicationException; +import jakarta.ws.rs.container.ContainerRequestContext; +import jakarta.ws.rs.container.ContainerRequestFilter; +import jakarta.ws.rs.core.HttpHeaders; +import jakarta.ws.rs.core.Response; +import jakarta.ws.rs.ext.Provider; + +import java.io.IOException; + +@Provider +@Priority(1) +public class AuthenticationFilter implements ContainerRequestFilter { + + // Exception thrown if user is unauthorized. + private static final WebApplicationException unauthorized = + new WebApplicationException( + Response.status(Response.Status.UNAUTHORIZED) + .header(HttpHeaders.WWW_AUTHENTICATE, "Basic realm=\"realm\"") + .entity("Page requires login.").build()); + + @Override + public void filter(ContainerRequestContext containerRequest) throws IOException { + + // Get the authentication passed in HTTP headers parameters + String auth = containerRequest.getHeaderString("authorization"); + if (auth == null) + throw unauthorized; + + auth = auth.replaceFirst("[Bb]asic ", ""); + String userColonPass = Base64.base64Decode(auth); + String[] split = userColonPass.split(":"); + String username = split[0]; + String password = split[1]; + if (AuthManager.getInstance().isAuthenticationEnabled() && !AuthManager.getInstance().validate(username, password)) { + throw unauthorized; + } + } +} diff --git a/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java b/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java index 2babacc26..2f4014cbf 100644 --- a/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java +++ b/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java @@ -18,6 +18,7 @@ package io.mapsmessaging.rest; import io.mapsmessaging.MessageDaemon; +import io.mapsmessaging.auth.AuthManager; import io.mapsmessaging.rest.translation.DebugMapper; import io.mapsmessaging.utilities.Agent; import io.mapsmessaging.utilities.configuration.ConfigurationManager; @@ -142,6 +143,10 @@ public void startServer() { // config.register(io.swagger.jaxrs.listing.ApiListingResource.class); // config.register(io.swagger.jaxrs.listing.SwaggerSerializers.class); } + boolean enableAuth = map.getBooleanProperty("enableAuthentication", false); + if (enableAuth && AuthManager.getInstance().isAuthenticationEnabled()) { + config.register(new AuthenticationFilter()); + } config.register(DebugMapper.class); ServletContainer sc = new ServletContainer(config); diff --git a/src/main/resources/META-INF/services/io.mapsmessaging.security.access.AccessControlList b/src/main/resources/META-INF/services/io.mapsmessaging.security.access.AccessControlList new file mode 100644 index 000000000..6d4ad0baf --- /dev/null +++ b/src/main/resources/META-INF/services/io.mapsmessaging.security.access.AccessControlList @@ -0,0 +1,20 @@ +# +# Copyright [ 2020 - 2023 ] [Matthew Buckton] +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +io.mapsmessaging.auth.acl.InterfaceAccessControlList +io.mapsmessaging.auth.acl.ServerAccessControlList +io.mapsmessaging.auth.acl.ResourceAccessControlList \ No newline at end of file From 04bd461b3c209645b5ad3549678fca96b8c83206 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 29 Nov 2023 13:54:23 +1100 Subject: [PATCH 059/348] Add auth to the rest api, it still is dependent on the auth manager being enabled --- .../io/mapsmessaging/auth/AuthManager.java | 17 ++++++ .../auth/acl/RestAccessControl.java | 54 ++++++++++++++++++ .../auth/acl/RestAccessControlList.java | 47 +++++++++++++++ .../auth/registry/AuthenticationStorage.java | 4 ++ .../rest/RestApiServerManager.java | 1 + .../rest/auth/AuthenticatedUserPrincipal.java | 40 +++++++++++++ .../rest/{ => auth}/AuthenticationFilter.java | 34 ++++++++++- .../rest/auth/UserSecurityContext.java | 57 +++++++++++++++++++ ...essaging.security.access.AccessControlList | 3 +- src/main/resources/RestApi.yaml | 6 ++ src/main/resources/logback.xml | 2 +- 11 files changed, 262 insertions(+), 3 deletions(-) create mode 100644 src/main/java/io/mapsmessaging/auth/acl/RestAccessControl.java create mode 100644 src/main/java/io/mapsmessaging/auth/acl/RestAccessControlList.java create mode 100644 src/main/java/io/mapsmessaging/rest/auth/AuthenticatedUserPrincipal.java rename src/main/java/io/mapsmessaging/rest/{ => auth}/AuthenticationFilter.java (70%) create mode 100644 src/main/java/io/mapsmessaging/rest/auth/UserSecurityContext.java diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index ac90808fb..e18bc0e78 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -17,11 +17,14 @@ package io.mapsmessaging.auth; +import com.sun.security.auth.UserPrincipal; import io.mapsmessaging.auth.priviliges.SessionPrivileges; import io.mapsmessaging.auth.registry.AuthenticationStorage; import io.mapsmessaging.auth.registry.PasswordGenerator; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; +import io.mapsmessaging.security.access.mapping.UserIdMap; +import io.mapsmessaging.security.identity.principals.UniqueIdentifierPrincipal; import io.mapsmessaging.utilities.Agent; import io.mapsmessaging.utilities.configuration.ConfigurationManager; import io.mapsmessaging.utilities.configuration.ConfigurationProperties; @@ -32,6 +35,8 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.security.Principal; +import java.util.Set; import java.util.UUID; @@ -146,4 +151,16 @@ private void createInitialUsers(String path) { public boolean validate(String username, String password) { return authenticationStorage.validateUser(username, password); } + + public Subject getUser(String username) { + Subject subject = new Subject(); + Set principalList = subject.getPrincipals(); + UserIdMap map = authenticationStorage.findUser(username); + if (map != null) { + principalList.add(new UniqueIdentifierPrincipal(map.getAuthId())); + principalList.add(new UserPrincipal(username)); + authenticationStorage.update(subject); + } + return subject; + } } diff --git a/src/main/java/io/mapsmessaging/auth/acl/RestAccessControl.java b/src/main/java/io/mapsmessaging/auth/acl/RestAccessControl.java new file mode 100644 index 000000000..b69fbb95a --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/acl/RestAccessControl.java @@ -0,0 +1,54 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.acl; + +import io.mapsmessaging.security.access.AccessControlMapping; + +public enum RestAccessControl implements AccessControlMapping { + READ_ONLY, + WRITE; + + private final long value; + + RestAccessControl() { + this.value = 1L << this.ordinal(); // Shift 1 left by 'ordinal' positions + } + + @Override + public Long getAccessValue(String accessControl) { + if (accessControl == null) { + return 0L; + } + try { + return valueOf(accessControl.toUpperCase()).value; + } catch (IllegalArgumentException e) { + return 0L; + } + } + + @Override + public String getAccessName(long value) { + for (RestAccessControl ac : values()) { + if (ac.value == value) { + return ac.name().toLowerCase(); + } + } + return null; + } +} + diff --git a/src/main/java/io/mapsmessaging/auth/acl/RestAccessControlList.java b/src/main/java/io/mapsmessaging/auth/acl/RestAccessControlList.java new file mode 100644 index 000000000..6080f5e29 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/acl/RestAccessControlList.java @@ -0,0 +1,47 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.acl; + +import io.mapsmessaging.security.access.AccessControlList; +import io.mapsmessaging.security.access.AccessControlListParser; +import io.mapsmessaging.security.access.AccessControlMapping; +import io.mapsmessaging.security.access.AclEntry; + +import java.util.List; + +public class RestAccessControlList extends BaseAccessControlList { + + public RestAccessControlList() { + } + + public RestAccessControlList(List aclEntries) { + super(aclEntries); + } + + @Override + public String getName() { + return "RestACL"; + } + + @Override + public AccessControlList create(AccessControlMapping accessControlMapping, List config) { + AccessControlListParser parser = new AccessControlListParser(); + return new RestAccessControlList(parser.createList(accessControlMapping, config)); + } + +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java index 9bed6eecc..170ea3ad6 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java +++ b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java @@ -144,4 +144,8 @@ public Subject update(Subject subject) { } return subject1; } + + public UserIdMap findUser(String username) { + return identityAccessManager.getUser(username); + } } diff --git a/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java b/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java index 2f4014cbf..54129f224 100644 --- a/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java +++ b/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java @@ -19,6 +19,7 @@ import io.mapsmessaging.MessageDaemon; import io.mapsmessaging.auth.AuthManager; +import io.mapsmessaging.rest.auth.AuthenticationFilter; import io.mapsmessaging.rest.translation.DebugMapper; import io.mapsmessaging.utilities.Agent; import io.mapsmessaging.utilities.configuration.ConfigurationManager; diff --git a/src/main/java/io/mapsmessaging/rest/auth/AuthenticatedUserPrincipal.java b/src/main/java/io/mapsmessaging/rest/auth/AuthenticatedUserPrincipal.java new file mode 100644 index 000000000..7be560da8 --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/auth/AuthenticatedUserPrincipal.java @@ -0,0 +1,40 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.auth; + +import java.security.Principal; + +public class AuthenticatedUserPrincipal implements Principal { + + private final String username; + + public AuthenticatedUserPrincipal(String username) { + this.username = username; + } + + @Override + public String getName() { + return username; + } + + @Override + public String toString() { + return "Authenticated User: " + getName(); + } + +} diff --git a/src/main/java/io/mapsmessaging/rest/AuthenticationFilter.java b/src/main/java/io/mapsmessaging/rest/auth/AuthenticationFilter.java similarity index 70% rename from src/main/java/io/mapsmessaging/rest/AuthenticationFilter.java rename to src/main/java/io/mapsmessaging/rest/auth/AuthenticationFilter.java index 77fd62393..0d12e6989 100644 --- a/src/main/java/io/mapsmessaging/rest/AuthenticationFilter.java +++ b/src/main/java/io/mapsmessaging/rest/auth/AuthenticationFilter.java @@ -15,7 +15,7 @@ * */ -package io.mapsmessaging.rest; +package io.mapsmessaging.rest.auth; import com.sun.jersey.core.util.Base64; import com.sun.jersey.core.util.Priority; @@ -27,6 +27,7 @@ import jakarta.ws.rs.core.Response; import jakarta.ws.rs.ext.Provider; +import javax.security.auth.Subject; import java.io.IOException; @Provider @@ -48,13 +49,44 @@ public void filter(ContainerRequestContext containerRequest) throws IOException if (auth == null) throw unauthorized; + auth = auth.replaceFirst("[Bb]asic ", ""); String userColonPass = Base64.base64Decode(auth); String[] split = userColonPass.split(":"); String username = split[0]; String password = split[1]; + if (AuthManager.getInstance().isAuthenticationEnabled() && !AuthManager.getInstance().validate(username, password)) { throw unauthorized; } + Subject subject = AuthManager.getInstance().getUser(username); + if (subject == null) { + throw unauthorized; + } + boolean isWrite = false; + switch (containerRequest.getMethod()) { + case "GET": + case "HEAD": + case "OPTIONS": + break; + + case "PUT": + case "POST": + case "DELETE": + isWrite = true; + break; + + default: + throw unauthorized; + } + /* + if(!isWrite && AuthManager.getInstance().isAuthorisationEnabled() && !AuthManager.getInstance().isAuthorised(subject, RestAccessControl.READ_ONLY)){ + throw unauthorized; + } + if(isWrite && AuthManager.getInstance().isAuthorisationEnabled() && !AuthManager.getInstance().isAuthorised(subject, RestAccessControl.WRITE)){ + throw unauthorized; + } + + */ } } diff --git a/src/main/java/io/mapsmessaging/rest/auth/UserSecurityContext.java b/src/main/java/io/mapsmessaging/rest/auth/UserSecurityContext.java new file mode 100644 index 000000000..f9fc2a2cb --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/auth/UserSecurityContext.java @@ -0,0 +1,57 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.auth; + +import io.mapsmessaging.auth.AuthManager; +import jakarta.ws.rs.core.SecurityContext; +import lombok.Getter; + +import javax.security.auth.Subject; +import java.security.Principal; + +public class UserSecurityContext implements SecurityContext { + + private final AuthenticatedUserPrincipal userPrincipal; + @Getter + private final Subject subject; + + public UserSecurityContext(String username) { + userPrincipal = new AuthenticatedUserPrincipal(username); + subject = AuthManager.getInstance().getUser(username); + } + + @Override + public Principal getUserPrincipal() { + return userPrincipal; + } + + @Override + public boolean isUserInRole(String role) { + return false; + } + + @Override + public boolean isSecure() { + return false; + } + + @Override + public String getAuthenticationScheme() { + return SecurityContext.BASIC_AUTH; + } +} \ No newline at end of file diff --git a/src/main/resources/META-INF/services/io.mapsmessaging.security.access.AccessControlList b/src/main/resources/META-INF/services/io.mapsmessaging.security.access.AccessControlList index 6d4ad0baf..7c1eee71e 100644 --- a/src/main/resources/META-INF/services/io.mapsmessaging.security.access.AccessControlList +++ b/src/main/resources/META-INF/services/io.mapsmessaging.security.access.AccessControlList @@ -17,4 +17,5 @@ io.mapsmessaging.auth.acl.InterfaceAccessControlList io.mapsmessaging.auth.acl.ServerAccessControlList -io.mapsmessaging.auth.acl.ResourceAccessControlList \ No newline at end of file +io.mapsmessaging.auth.acl.ResourceAccessControlList +io.mapsmessaging.auth.acl.RestAccessControlList \ No newline at end of file diff --git a/src/main/resources/RestApi.yaml b/src/main/resources/RestApi.yaml index 3ee7ef4fa..28812f6c8 100644 --- a/src/main/resources/RestApi.yaml +++ b/src/main/resources/RestApi.yaml @@ -17,11 +17,17 @@ --- RestApi: enabled: true + enableAuthentication: true hostnames: 0.0.0.0 port: 8082 enableSwagger: true enableSwaggerUI: true + # ssl_keyStoreFile: my-keystore.jks + # ssl_keyStorePassphrase: password + # ssl_trustStoreFile: my-keystore.jks + # ssl_trustStorePassphrase: password + static: enabled: true path: src/main/resources/html/ diff --git a/src/main/resources/logback.xml b/src/main/resources/logback.xml index f17a1a42d..6d7d8c96e 100644 --- a/src/main/resources/logback.xml +++ b/src/main/resources/logback.xml @@ -31,7 +31,7 @@ - + \ No newline at end of file From 3a7ce6677931c9b6921d6561d0cc2a3b712a340b Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 29 Nov 2023 13:56:37 +1100 Subject: [PATCH 060/348] Cache subject creations to speed things up --- .../io/mapsmessaging/auth/AuthManager.java | 21 ++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index e18bc0e78..0367e9dd4 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -36,8 +36,10 @@ import java.io.FileWriter; import java.io.IOException; import java.security.Principal; +import java.util.Map; import java.util.Set; import java.util.UUID; +import java.util.WeakHashMap; public class AuthManager implements Agent { @@ -53,6 +55,7 @@ public class AuthManager implements Agent { private final Logger logger; private final ConfigurationProperties properties; private AuthenticationStorage authenticationStorage; + private final Map subjectMap = new WeakHashMap<>(); @Getter private final boolean authenticationEnabled; @@ -153,13 +156,17 @@ public boolean validate(String username, String password) { } public Subject getUser(String username) { - Subject subject = new Subject(); - Set principalList = subject.getPrincipals(); - UserIdMap map = authenticationStorage.findUser(username); - if (map != null) { - principalList.add(new UniqueIdentifierPrincipal(map.getAuthId())); - principalList.add(new UserPrincipal(username)); - authenticationStorage.update(subject); + Subject subject = subjectMap.get(username); + if (subject == null) { + subject = new Subject(); + Set principalList = subject.getPrincipals(); + UserIdMap map = authenticationStorage.findUser(username); + if (map != null) { + principalList.add(new UniqueIdentifierPrincipal(map.getAuthId())); + principalList.add(new UserPrincipal(username)); + authenticationStorage.update(subject); + } + subjectMap.put(username, subject); } return subject; } From acf930e2ea74d4420cf290c0beccab0a39ef6d9d Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 29 Nov 2023 15:03:15 +1100 Subject: [PATCH 061/348] Cleanup hawtio Parallel out the interface startup --- src/main/java/io/mapsmessaging/HawtioManager.java | 10 +++++++--- .../java/io/mapsmessaging/network/NetworkManager.java | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/mapsmessaging/HawtioManager.java b/src/main/java/io/mapsmessaging/HawtioManager.java index 2bd77b906..c60bd044f 100644 --- a/src/main/java/io/mapsmessaging/HawtioManager.java +++ b/src/main/java/io/mapsmessaging/HawtioManager.java @@ -40,7 +40,8 @@ public class HawtioManager implements Agent { public HawtioManager() { properties = ConfigurationManager.getInstance().getProperties("hawtio"); - System.setProperty("hawtio.authenticationEnabled", properties.getProperty("authenticationEnabled", "false")); + System.setProperty("hawtio.authenticationEnabled", "" + properties.getBooleanProperty("authenticationEnabled", false)); + String checkFile = properties.getProperty("warFileLocation", ""); enabled = properties.getProperty("enable", "true").equalsIgnoreCase("true"); if (enabled) { @@ -73,9 +74,12 @@ public void start() { } } + @Override public void stop() { + // nothing to stop } + private class Startup implements Runnable { private void register() { @@ -90,9 +94,9 @@ private void register() { } public void run() { - if (properties.getProperty("enable").equalsIgnoreCase("true")) { + if (properties.getBooleanProperty("enable", false)) { logger.log(HAWTIO_STARTUP); - if (warFile.length() > 0) { + if (!warFile.isEmpty()) { try { Class hawtioMain = Class.forName("io.hawt.embedded.Main"); Object main = hawtioMain.getConstructor().newInstance(); diff --git a/src/main/java/io/mapsmessaging/network/NetworkManager.java b/src/main/java/io/mapsmessaging/network/NetworkManager.java index 7715e6fe1..8428715a2 100644 --- a/src/main/java/io/mapsmessaging/network/NetworkManager.java +++ b/src/main/java/io/mapsmessaging/network/NetworkManager.java @@ -121,7 +121,7 @@ public List getAll(){ public void startAll() { logger.log(ServerLogMessages.NETWORK_MANAGER_START_ALL); - for (Map.Entry entry : endPointManagers.entrySet()) { + endPointManagers.entrySet().parallelStream().forEach(entry -> { try { EndPointManager endPointManager = entry.getValue(); if (endPointManager.getState() == STATE.STOPPED) { @@ -130,7 +130,7 @@ public void startAll() { } catch (IOException e) { logger.log(ServerLogMessages.NETWORK_MANAGER_START_FAILED, e, entry.getKey()); } - } + }); } public void stopAll() { From 67526d81eafe7a030f102d86862dfb2ed991042b Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 29 Nov 2023 15:15:23 +1100 Subject: [PATCH 062/348] cleanup --- .../java/io/mapsmessaging/network/NetworkManager.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/io/mapsmessaging/network/NetworkManager.java b/src/main/java/io/mapsmessaging/network/NetworkManager.java index 8428715a2..f7a50fb80 100644 --- a/src/main/java/io/mapsmessaging/network/NetworkManager.java +++ b/src/main/java/io/mapsmessaging/network/NetworkManager.java @@ -99,10 +99,8 @@ private void initialiseInstance(EndPointURL endPointURL, NetworkConfig networkCo try { EndPointManager endPointManager = new EndPointManager(endPointURL, endPointServerFactory, networkConfig, bean); endPointManagers.put(endPointURL.toString(), endPointManager); - } catch (IOException iox) { + } catch (IOException | RuntimeException iox) { logger.log(ServerLogMessages.NETWORK_MANAGER_START_FAILURE, iox, endPointURL.toString()); - } catch (RuntimeException runtimeException) { - logger.log(ServerLogMessages.NETWORK_MANAGER_START_FAILURE, runtimeException, endPointURL.toString()); } } else { logger.log(ServerLogMessages.NETWORK_MANAGER_DEVICE_NOT_LOADED, endPointServerFactory.getName()); @@ -135,7 +133,7 @@ public void startAll() { public void stopAll() { logger.log(ServerLogMessages.NETWORK_MANAGER_STOP_ALL); - for (Map.Entry entry : endPointManagers.entrySet()) { + endPointManagers.entrySet().parallelStream().forEach(entry -> { try { EndPointManager endPointManager = entry.getValue(); if (endPointManager.getState() != STATE.STOPPED) { @@ -144,7 +142,7 @@ public void stopAll() { } catch (IOException e) { logger.log(ServerLogMessages.NETWORK_MANAGER_STOP_FAILED, e, entry.getKey()); } - } + }); } public void pauseAll() { From 52b734a63dc523f2f67b0e3cbffa58fbaa5933f9 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Wed, 29 Nov 2023 22:25:20 +1100 Subject: [PATCH 063/348] first build with swagger working again. Need to work on swagger-ui next --- pom.xml | 10 +------ .../rest/RestApiServerManager.java | 11 +++++--- .../rest/api/impl/ConsulHealth.java | 6 ++--- .../api/impl/DestinationManagementApi.java | 9 +++---- .../rest/api/impl/DestinationStatusApi.java | 9 +++---- .../rest/api/impl/InterfaceInstanceApi.java | 15 +++++------ .../rest/api/impl/InterfaceManagementApi.java | 15 +++++------ .../rest/api/impl/MapsRestServerApi.java | 27 +++++++++++-------- .../rest/api/impl/SchemaQueryApi.java | 25 +++++++++-------- .../rest/data/InterfaceInfo.java | 11 ++++---- .../responses/InterfaceDetailResponse.java | 6 ++--- 11 files changed, 68 insertions(+), 76 deletions(-) diff --git a/pom.xml b/pom.xml index cf784db70..aa6819bf9 100644 --- a/pom.xml +++ b/pom.xml @@ -511,7 +511,6 @@ - 3.1.3 - 2.0.2 3.17.0 @@ -655,24 +654,17 @@ ${jersey.version} - io.swagger.core.v3 swagger-jaxrs2-jakarta 2.2.19 - io.swagger.core.v3 - swagger-annotations + swagger-jaxrs2-servlet-initializer-v2-jakarta 2.2.19 - - io.swagger - swagger-annotations - 1.6.12 - org.glassfish.jersey.inject diff --git a/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java b/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java index 54129f224..a2a7e7319 100644 --- a/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java +++ b/src/main/java/io/mapsmessaging/rest/RestApiServerManager.java @@ -137,12 +137,15 @@ private void loadStatic(){ public void startServer() { try { - final ResourceConfig config = new ResourceConfig(); - config.packages(true, "io.mapsmessaging.rest.api.impl", "io.mapsmessaging.rest.api", "io.mapsmessaging.rest.translation"); + config.packages(true, + "io.swagger.v3.jaxrs2.integration.resources", + "io.swagger.v3.jaxrs2.integration.resources.AcceptHeaderOpenApiResource", + "io.mapsmessaging.rest.api.impl", + "io.mapsmessaging.rest.api", + "io.mapsmessaging.rest.translation" + ); if(map.getBooleanProperty("enableSwagger", false)) { -// config.register(io.swagger.jaxrs.listing.ApiListingResource.class); -// config.register(io.swagger.jaxrs.listing.SwaggerSerializers.class); } boolean enableAuth = map.getBooleanProperty("enableAuthentication", false); if (enableAuth && AuthManager.getInstance().isAuthenticationEnabled()) { diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/ConsulHealth.java b/src/main/java/io/mapsmessaging/rest/api/impl/ConsulHealth.java index 584456f50..fc15c3696 100644 --- a/src/main/java/io/mapsmessaging/rest/api/impl/ConsulHealth.java +++ b/src/main/java/io/mapsmessaging/rest/api/impl/ConsulHealth.java @@ -18,21 +18,19 @@ package io.mapsmessaging.rest.api.impl; import io.mapsmessaging.rest.api.BaseRestApi; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; import jakarta.ws.rs.core.MediaType; -@Api(value = "/health") +//@Api(value = "/health") @Path("/health") public class ConsulHealth extends BaseRestApi { @GET @Produces({MediaType.TEXT_PLAIN}) - @ApiOperation(value = "Simple request to test if the server is running") +// @ApiOperation(value = "Simple request to test if the server is running") public String getPing() { return "Ok"; } diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/DestinationManagementApi.java b/src/main/java/io/mapsmessaging/rest/api/impl/DestinationManagementApi.java index 2c31d45ac..88a8ca400 100644 --- a/src/main/java/io/mapsmessaging/rest/api/impl/DestinationManagementApi.java +++ b/src/main/java/io/mapsmessaging/rest/api/impl/DestinationManagementApi.java @@ -22,8 +22,7 @@ import io.mapsmessaging.engine.destination.DestinationImpl; import io.mapsmessaging.rest.data.Destination; import io.mapsmessaging.rest.responses.DestinationResponse; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; + import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; @@ -38,14 +37,14 @@ import static io.mapsmessaging.rest.api.Constants.URI_PATH; -@Api(value = URI_PATH + "/server/destination", tags="Destination Management") +//@Api(value = URI_PATH + "/server/destination", tags="Destination Management") @Path(URI_PATH) public class DestinationManagementApi extends BaseDestinationApi { @GET @Path("/server/destination/{destination}") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get the specific destination details") + //@ApiOperation(value = "Get the specific destination details") public DestinationResponse getDestination(@PathParam("destination") String destinationName) throws ExecutionException, InterruptedException, TimeoutException, IOException { Destination destination = lookupDestination(destinationName); return new DestinationResponse(request, destination); @@ -54,7 +53,7 @@ public DestinationResponse getDestination(@PathParam("destination") String desti @GET @Path("/server/destination") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get all the destination configuration") + //@ApiOperation(value = "Get all the destination configuration") public DestinationResponse getAllDestinations() throws IOException, ExecutionException, InterruptedException, TimeoutException { List destinations = MessageDaemon.getInstance().getDestinationManager().getAll(); List results = new ArrayList<>(); diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/DestinationStatusApi.java b/src/main/java/io/mapsmessaging/rest/api/impl/DestinationStatusApi.java index 22c7fc5f1..75e230471 100644 --- a/src/main/java/io/mapsmessaging/rest/api/impl/DestinationStatusApi.java +++ b/src/main/java/io/mapsmessaging/rest/api/impl/DestinationStatusApi.java @@ -21,8 +21,7 @@ import io.mapsmessaging.engine.destination.DestinationImpl; import io.mapsmessaging.rest.data.DestinationStatus; import io.mapsmessaging.rest.responses.DestinationStatusResponse; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; + import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.PathParam; @@ -37,14 +36,14 @@ import static io.mapsmessaging.rest.api.Constants.URI_PATH; -@Api(value = URI_PATH + "/server/destination/status", tags="Destination Status Management") +//@Api(value = URI_PATH + "/server/destination/status", tags="Destination Status Management") @Path(URI_PATH) public class DestinationStatusApi extends BaseDestinationApi { @GET @Path("/server/destination/status/{destination}") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get the specific destination details") + //@ApiOperation(value = "Get the specific destination details") public DestinationStatusResponse getDestination(@PathParam("destination") String destinationName) throws ExecutionException, InterruptedException, TimeoutException { DestinationStatus destination = lookupDestination(destinationName); return new DestinationStatusResponse(request, destination); @@ -53,7 +52,7 @@ public DestinationStatusResponse getDestination(@PathParam("destination") String @GET @Path("/server/destination/status") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get all the destination configuration") + //@ApiOperation(value = "Get all the destination configuration") public DestinationStatusResponse getAllDestinations() throws ExecutionException, InterruptedException, TimeoutException { List destinations = MessageDaemon.getInstance().getDestinationManager().getAll(); List results = new ArrayList<>(); diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/InterfaceInstanceApi.java b/src/main/java/io/mapsmessaging/rest/api/impl/InterfaceInstanceApi.java index 0b56519d0..eeb1161d1 100644 --- a/src/main/java/io/mapsmessaging/rest/api/impl/InterfaceInstanceApi.java +++ b/src/main/java/io/mapsmessaging/rest/api/impl/InterfaceInstanceApi.java @@ -22,8 +22,7 @@ import io.mapsmessaging.network.EndPointManager.STATE; import io.mapsmessaging.rest.api.BaseRestApi; import io.mapsmessaging.rest.data.InterfaceInfo; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; + import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import jakarta.ws.rs.core.Response; @@ -33,14 +32,14 @@ import static io.mapsmessaging.rest.api.Constants.URI_PATH; -@Api(value = URI_PATH + "/server/interface", tags="Server Interface Management") +//@Api(value = URI_PATH + "/server/interface", tags="Server Interface Management") @Path(URI_PATH) public class InterfaceInstanceApi extends BaseRestApi { @GET @Path("/server/interface/{endpoint}") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get the endpoint current status and configuration") + //@ApiOperation(value = "Get the endpoint current status and configuration") public InterfaceInfo getInterface(@PathParam("endpoint") String endpointName) { List endPointManagers = MessageDaemon.getInstance().getNetworkManager().getAll(); for (EndPointManager endPointManager : endPointManagers) { @@ -54,7 +53,7 @@ public InterfaceInfo getInterface(@PathParam("endpoint") String endpointName) { @PUT @Path("/server/interface/{endpoint}/stop") - @ApiOperation(value = "Stops the specified endpoint and closes existing connections") + //@ApiOperation(value = "Stops the specified endpoint and closes existing connections") public Response stopInterface(@PathParam("endpoint") String endpointName) { List endPointManagers = MessageDaemon.getInstance().getNetworkManager().getAll(); for (EndPointManager endPointManager : endPointManagers) { @@ -68,7 +67,7 @@ public Response stopInterface(@PathParam("endpoint") String endpointName) { @PUT @Path("/server/interface/{endpoint}/start") - @ApiOperation(value = "Starts the specified endpoint") + //@ApiOperation(value = "Starts the specified endpoint") public Response startInterface(@PathParam("endpoint") String endpointName) { List endPointManagers = MessageDaemon.getInstance().getNetworkManager().getAll(); for (EndPointManager endPointManager : endPointManagers) { @@ -83,7 +82,7 @@ public Response startInterface(@PathParam("endpoint") String endpointName) { @PUT @Path("/server/interface/{endpoint}/resume") - @ApiOperation(value = "Resumes the specified endpoint if the endpoint had been paused") + //@ApiOperation(value = "Resumes the specified endpoint if the endpoint had been paused") public Response resumeInterface(@PathParam("endpoint") String endpointName) { List endPointManagers = MessageDaemon.getInstance().getNetworkManager().getAll(); for (EndPointManager endPointManager : endPointManagers) { @@ -97,7 +96,7 @@ public Response resumeInterface(@PathParam("endpoint") String endpointName) { @PUT @Path("/server/interface/{endpoint}/pause") - @ApiOperation(value = "Pauses the specified endpoint, existing connections are maintained but no new connections can be made") + //@ApiOperation(value = "Pauses the specified endpoint, existing connections are maintained but no new connections can be made") public Response pauseInterface(@PathParam("endpoint") String endpointName) { List endPointManagers = MessageDaemon.getInstance().getNetworkManager().getAll(); for (EndPointManager endPointManager : endPointManagers) { diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/InterfaceManagementApi.java b/src/main/java/io/mapsmessaging/rest/api/impl/InterfaceManagementApi.java index 5a6abbe76..7ec7a2721 100644 --- a/src/main/java/io/mapsmessaging/rest/api/impl/InterfaceManagementApi.java +++ b/src/main/java/io/mapsmessaging/rest/api/impl/InterfaceManagementApi.java @@ -24,8 +24,7 @@ import io.mapsmessaging.rest.data.InterfaceInfo; import io.mapsmessaging.rest.responses.InterfaceDetailResponse; import io.mapsmessaging.utilities.configuration.ConfigurationProperties; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; + import jakarta.ws.rs.GET; import jakarta.ws.rs.PUT; import jakarta.ws.rs.Path; @@ -38,14 +37,14 @@ import static io.mapsmessaging.rest.api.Constants.URI_PATH; -@Api(value = URI_PATH + "/server/interfaces", tags="Interface Management") +//@Api(value = URI_PATH + "/server/interfaces", tags="Interface Management") @Path(URI_PATH) public class InterfaceManagementApi extends BaseRestApi { @GET @Path("/server/interfaces") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Retrieve a list of all configured interfaces") + //@ApiOperation(value = "Retrieve a list of all configured interfaces") public InterfaceDetailResponse getAllInterfaces() { List endPointManagers = MessageDaemon.getInstance().getNetworkManager().getAll(); List protocols = new ArrayList<>(); @@ -63,7 +62,7 @@ public InterfaceDetailResponse getAllInterfaces() { @PUT @Path("/server/interfaces/stopAll") - @ApiOperation(value = "Stops all all configured interfaces") + //@ApiOperation(value = "Stops all all configured interfaces") public Response stopAllInterfaces() { MessageDaemon.getInstance().getNetworkManager().stopAll(); return Response.ok().build(); @@ -71,7 +70,7 @@ public Response stopAllInterfaces() { @PUT @Path("/server/interfaces/startAll") - @ApiOperation(value = "Starts all all configured interfaces") + //@ApiOperation(value = "Starts all all configured interfaces") public Response startAllInterfaces() { MessageDaemon.getInstance().getNetworkManager().startAll(); return Response.ok().build(); @@ -79,7 +78,7 @@ public Response startAllInterfaces() { @PUT @Path("/server/interfaces/pauseAll") - @ApiOperation(value = "Pauses all all configured interfaces") + //@ApiOperation(value = "Pauses all all configured interfaces") public Response pauseAllInterfaces() { MessageDaemon.getInstance().getNetworkManager().pauseAll(); return Response.ok().build(); @@ -88,7 +87,7 @@ public Response pauseAllInterfaces() { @PUT @Path("/server/interfaces/resumeAll") - @ApiOperation(value = "Resumes all all configured interfaces") + //@ApiOperation(value = "Resumes all all configured interfaces") public Response resumeAllInterfaces() { MessageDaemon.getInstance().getNetworkManager().resumeAll(); return Response.ok().build(); diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/MapsRestServerApi.java b/src/main/java/io/mapsmessaging/rest/api/impl/MapsRestServerApi.java index 7aed41123..58d7610dd 100644 --- a/src/main/java/io/mapsmessaging/rest/api/impl/MapsRestServerApi.java +++ b/src/main/java/io/mapsmessaging/rest/api/impl/MapsRestServerApi.java @@ -23,16 +23,22 @@ import io.mapsmessaging.rest.responses.ServerStatisticsResponse; import io.mapsmessaging.rest.responses.StringResponse; import io.mapsmessaging.rest.responses.UpdateCheckResponse; -import io.swagger.annotations.*; +import io.swagger.v3.oas.annotations.ExternalDocumentation; +import io.swagger.v3.oas.annotations.OpenAPIDefinition; +import io.swagger.v3.oas.annotations.info.Contact; +import io.swagger.v3.oas.annotations.info.Info; +import io.swagger.v3.oas.annotations.info.License; +import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.Application; import jakarta.ws.rs.core.MediaType; import static io.mapsmessaging.BuildInfo.buildVersion; import static io.mapsmessaging.rest.api.Constants.URI_PATH; -@SwaggerDefinition( +@OpenAPIDefinition( info = @Info( description = "Maps Messaging Server Rest API, provides simple Rest API to manage the server", version = buildVersion, @@ -47,9 +53,7 @@ url = "http://www.apache.org/licenses/LICENSE-2.0" ) ), - consumes = {"application/json", "application/xml"}, - produces = {"application/json", "application/xml"}, - schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS}, + //schemes = {SwaggerDefinition.Scheme.HTTP, SwaggerDefinition.Scheme.HTTPS}, tags = { @Tag(name = "Server Interface Management", description = "Used to manage the servers network interfaces"), @Tag(name = "Destination Management", description = "Used to manage the destinations (topic/queues) and the subscriptions"), @@ -59,16 +63,17 @@ @Tag(name = "Messaging Server API", description = "Global APIs to manage and query the server"), }, - externalDocs = @ExternalDocs(value = "Maps Messaging", url = "https://www.mapsmessaging.io/") + externalDocs = @ExternalDocumentation(description = "Maps Messaging", url = "https://www.mapsmessaging.io/") ) -@Api(value = URI_PATH, tags="Messaging Server API") +//@Api(value = URI_PATH, tags="Messaging Server API") + @Path(URI_PATH) public class MapsRestServerApi extends BaseRestApi { @GET @Path("/ping") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Simple request to test if the server is running") + //@ApiOperation(value = "Simple request to test if the server is running") public StringResponse getPing() { return new StringResponse(request, "ok"); } @@ -76,7 +81,7 @@ public StringResponse getPing() { @GET @Path("/name") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Returns the servers unique name") + // @ApiOperation(value = "Returns the servers unique name") public StringResponse getName() { return new StringResponse(request, MessageDaemon.getInstance().getId()); } @@ -84,7 +89,7 @@ public StringResponse getName() { @GET @Path("/stats") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Retrieve the server statistics") +// @ApiOperation(value = "Retrieve the server statistics") public ServerStatisticsResponse getStats() { return new ServerStatisticsResponse(request); } @@ -92,7 +97,7 @@ public ServerStatisticsResponse getStats() { @GET @Path("/updates") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Check for changes to the configuration update counts") + // @ApiOperation(value = "Check for changes to the configuration update counts") public UpdateCheckResponse checkForUpdates() { long schema = SchemaManager.getInstance().getUpdateCount(); return new UpdateCheckResponse(schema, 0, 0); diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/SchemaQueryApi.java b/src/main/java/io/mapsmessaging/rest/api/impl/SchemaQueryApi.java index 2d8cda051..fdb5c7f41 100644 --- a/src/main/java/io/mapsmessaging/rest/api/impl/SchemaQueryApi.java +++ b/src/main/java/io/mapsmessaging/rest/api/impl/SchemaQueryApi.java @@ -25,8 +25,7 @@ import io.mapsmessaging.rest.responses.StringListResponse; import io.mapsmessaging.schemas.config.SchemaConfig; import io.mapsmessaging.schemas.config.SchemaConfigFactory; -import io.swagger.annotations.Api; -import io.swagger.annotations.ApiOperation; + import jakarta.ws.rs.*; import jakarta.ws.rs.core.MediaType; import lombok.Getter; @@ -41,14 +40,14 @@ import static io.mapsmessaging.rest.api.Constants.URI_PATH; -@Api(value = URI_PATH + "/server/schema", tags = "Schema Management") +//@Api(value = URI_PATH + "/server/schema", tags = "Schema Management") @Path(URI_PATH) public class SchemaQueryApi extends BaseRestApi { @DELETE @Path("/server/schema/{schemaId}") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Delete the schema configuration by unique id") + //@ApiOperation(value = "Delete the schema configuration by unique id") public BaseResponse deleteSchemaById(@PathParam("schemaId") String schemaId) { SchemaConfig config = SchemaManager.getInstance().getSchema(schemaId); if (config != null) { @@ -61,13 +60,13 @@ public BaseResponse deleteSchemaById(@PathParam("schemaId") String schemaId) { @DELETE @Path("/server/schema") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Delete all schema configuration in the repository") + //@ApiOperation(value = "Delete all schema configuration in the repository") public BaseResponse deleteAllSchemas() { SchemaManager.getInstance().removeAllSchemas(); return new BaseResponse(request); } - @ApiOperation(value = "Add a new schema configuration to the repository") + //@ApiOperation(value = "Add a new schema configuration to the repository") @Path("/server/schema") @POST @Consumes({MediaType.APPLICATION_JSON}) @@ -80,7 +79,7 @@ public BaseResponse addSchema(SchemaPostData jsonString) throws IOException { @GET @Path("/server/schema/{schemaId}") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get the schema configuration by unique id") + //@ApiOperation(value = "Get the schema configuration by unique id") public SchemaResponse getSchemaById(@PathParam("schemaId") String schemaId) throws IOException { SchemaConfig config = SchemaManager.getInstance().getSchema(schemaId); if (config != null) { @@ -92,7 +91,7 @@ public SchemaResponse getSchemaById(@PathParam("schemaId") String schemaId) thro @GET @Path("/server/schema/context/{context}") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get the schema configuration by context name") + //@ApiOperation(value = "Get the schema configuration by context name") public SchemaResponse getSchemaByContext(@PathParam("context") String context) throws IOException { List config = SchemaManager.getInstance().getSchemaByContext(context); if (config != null) { @@ -104,7 +103,7 @@ public SchemaResponse getSchemaByContext(@PathParam("context") String context) t @GET @Path("/server/schema/type/{type}") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get the schema configuration by schema type") + //@ApiOperation(value = "Get the schema configuration by schema type") public SchemaResponse getSchemaByType(@PathParam("type") String type) throws IOException { List config = SchemaManager.getInstance().getSchemas(type); if (config != null) { @@ -116,7 +115,7 @@ public SchemaResponse getSchemaByType(@PathParam("type") String type) throws IOE @GET @Path("/server/schema") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get all the schema configuration") + //@ApiOperation(value = "Get all the schema configuration") public SchemaResponse getAllSchemas() throws IOException { return new SchemaResponse(request, convert(SchemaManager.getInstance().getAll())); } @@ -124,7 +123,7 @@ public SchemaResponse getAllSchemas() throws IOException { @GET @Path("/server/schema/map") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get all the schema configuration") + //@ApiOperation(value = "Get all the schema configuration") public SchemaMapResponse getSchemaMapping() throws IOException { Map> map = SchemaManager.getInstance().getMappedSchemas(); Map> responseMap = new LinkedHashMap<>(); @@ -137,7 +136,7 @@ public SchemaMapResponse getSchemaMapping() throws IOException { @GET @Path("/server/schema/formats") @Produces({MediaType.APPLICATION_JSON}) - @ApiOperation(value = "Get all known formats currently supported by the schema") + //@ApiOperation(value = "Get all known formats currently supported by the schema") public StringListResponse getKnownFormats() { return new StringListResponse(request, SchemaManager.getInstance().getMessageFormats()); } @@ -145,7 +144,7 @@ public StringListResponse getKnownFormats() { @GET @Path("/server/schema/link-format") @Produces({MediaType.TEXT_PLAIN}) - @ApiOperation(value = "Get link format string") + //@ApiOperation(value = "Get link format string") public String getLinkFormat() { return SchemaManager.getInstance().buildLinkFormatResponse(); } diff --git a/src/main/java/io/mapsmessaging/rest/data/InterfaceInfo.java b/src/main/java/io/mapsmessaging/rest/data/InterfaceInfo.java index edb75a595..7f8c3622e 100644 --- a/src/main/java/io/mapsmessaging/rest/data/InterfaceInfo.java +++ b/src/main/java/io/mapsmessaging/rest/data/InterfaceInfo.java @@ -18,7 +18,6 @@ package io.mapsmessaging.rest.data; import io.mapsmessaging.network.EndPointManager; -import io.swagger.annotations.ApiModelProperty; import lombok.Getter; import lombok.ToString; @@ -29,23 +28,23 @@ public class InterfaceInfo implements Serializable { @Getter - @ApiModelProperty(value = "Unique name of the interface") +// @ApiModelProperty(value = "Unique name of the interface") private final String name; @Getter - @ApiModelProperty(value = "Port that the interface is bound to") +// @ApiModelProperty(value = "Port that the interface is bound to") private final int port; @Getter - @ApiModelProperty(value="Host that the interface is bound to") +// @ApiModelProperty(value="Host that the interface is bound to") private final String host; @Getter - @ApiModelProperty(value="Current state of the interface") + // @ApiModelProperty(value="Current state of the interface") private final String state; @Getter - @ApiModelProperty(value="Configuration for the interface") + // @ApiModelProperty(value="Configuration for the interface") private final Map config; public InterfaceInfo(EndPointManager endPointManager){ diff --git a/src/main/java/io/mapsmessaging/rest/responses/InterfaceDetailResponse.java b/src/main/java/io/mapsmessaging/rest/responses/InterfaceDetailResponse.java index f0fa8de9e..d21c67995 100644 --- a/src/main/java/io/mapsmessaging/rest/responses/InterfaceDetailResponse.java +++ b/src/main/java/io/mapsmessaging/rest/responses/InterfaceDetailResponse.java @@ -19,7 +19,7 @@ import io.mapsmessaging.rest.data.InterfaceInfo; import io.mapsmessaging.utilities.configuration.ConfigurationProperties; -import io.swagger.annotations.ApiModelProperty; +import io.swagger.v3.oas.annotations.*; import lombok.Getter; import javax.ws.rs.core.Request; @@ -29,11 +29,11 @@ public class InterfaceDetailResponse extends BaseResponse { @Getter - @ApiModelProperty(value="List of interfaces") +// @ApiModelProperty(value="List of interfaces") private final List data; @Getter - @ApiModelProperty(value="Default values for all interfaces used unless overridden by the specific config") + //@ApiModelProperty(value="Default values for all interfaces used unless overridden by the specific config") private final Map globalConfig; From 1e044659c56d69e0409f13f107627a80665d5d25 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Thu, 30 Nov 2023 11:35:21 +1100 Subject: [PATCH 064/348] add initial user management to the rest api GetUsers and getGroups --- .../io/mapsmessaging/auth/AuthManager.java | 27 +++++-- .../auth/registry/AuthenticationStorage.java | 51 ++++++++++++- .../auth/registry/GroupDetails.java | 35 +++++++++ .../auth/registry/UserDetails.java | 38 ++++++++++ .../rest/api/impl/MapsRestServerApi.java | 1 - .../rest/api/impl/UserManagementApi.java | 75 +++++++++++++++++++ .../rest/auth/AuthenticationFilter.java | 2 +- .../rest/auth/UserSecurityContext.java | 2 +- .../mapsmessaging/rest/responses/Group.java | 30 ++++++++ .../rest/responses/GroupListResponse.java | 35 +++++++++ .../io/mapsmessaging/rest/responses/User.java | 30 ++++++++ .../rest/responses/UserListResponse.java | 35 +++++++++ 12 files changed, 350 insertions(+), 11 deletions(-) create mode 100644 src/main/java/io/mapsmessaging/auth/registry/GroupDetails.java create mode 100644 src/main/java/io/mapsmessaging/auth/registry/UserDetails.java create mode 100644 src/main/java/io/mapsmessaging/rest/api/impl/UserManagementApi.java create mode 100644 src/main/java/io/mapsmessaging/rest/responses/Group.java create mode 100644 src/main/java/io/mapsmessaging/rest/responses/GroupListResponse.java create mode 100644 src/main/java/io/mapsmessaging/rest/responses/User.java create mode 100644 src/main/java/io/mapsmessaging/rest/responses/UserListResponse.java diff --git a/src/main/java/io/mapsmessaging/auth/AuthManager.java b/src/main/java/io/mapsmessaging/auth/AuthManager.java index 0367e9dd4..936c6daac 100644 --- a/src/main/java/io/mapsmessaging/auth/AuthManager.java +++ b/src/main/java/io/mapsmessaging/auth/AuthManager.java @@ -20,7 +20,9 @@ import com.sun.security.auth.UserPrincipal; import io.mapsmessaging.auth.priviliges.SessionPrivileges; import io.mapsmessaging.auth.registry.AuthenticationStorage; +import io.mapsmessaging.auth.registry.GroupDetails; import io.mapsmessaging.auth.registry.PasswordGenerator; +import io.mapsmessaging.auth.registry.UserDetails; import io.mapsmessaging.logging.Logger; import io.mapsmessaging.logging.LoggerFactory; import io.mapsmessaging.security.access.mapping.UserIdMap; @@ -36,10 +38,7 @@ import java.io.FileWriter; import java.io.IOException; import java.security.Principal; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.WeakHashMap; +import java.util.*; public class AuthManager implements Agent { @@ -155,7 +154,11 @@ public boolean validate(String username, String password) { return authenticationStorage.validateUser(username, password); } - public Subject getUser(String username) { + public UserIdMap getUserIdentity(String username) { + return authenticationStorage.findUser(username); + } + + public Subject getUserSubject(String username) { Subject subject = subjectMap.get(username); if (subject == null) { subject = new Subject(); @@ -170,4 +173,18 @@ public Subject getUser(String username) { } return subject; } + + public List getUsers() { + if (authenticationStorage != null) { + return authenticationStorage.getUsers(); + } + return new ArrayList<>(); + } + + public List getGroups() { + if (authenticationStorage != null) { + return authenticationStorage.getGroups(); + } + return new ArrayList<>(); + } } diff --git a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java index 170ea3ad6..086d98d4e 100644 --- a/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java +++ b/src/main/java/io/mapsmessaging/auth/registry/AuthenticationStorage.java @@ -27,6 +27,7 @@ import io.mapsmessaging.security.access.IdentityAccessManager; import io.mapsmessaging.security.access.mapping.GroupIdMap; import io.mapsmessaging.security.access.mapping.UserIdMap; +import io.mapsmessaging.security.identity.GroupEntry; import io.mapsmessaging.security.identity.IdentityEntry; import io.mapsmessaging.security.identity.parsers.PasswordParser; import io.mapsmessaging.security.identity.parsers.bcrypt.BCrypt2yPasswordParser; @@ -39,9 +40,7 @@ import java.io.Closeable; import java.io.File; import java.io.IOException; -import java.util.Arrays; -import java.util.Map; -import java.util.UUID; +import java.util.*; public class AuthenticationStorage implements Closeable { @@ -148,4 +147,50 @@ public Subject update(Subject subject) { public UserIdMap findUser(String username) { return identityAccessManager.getUser(username); } + + public List getUsers() { + List userIdMaps = identityAccessManager.getAllUsers(); + List users = new ArrayList<>(); + for (UserIdMap userIdMap : userIdMaps) { + IdentityEntry entry = identityAccessManager.getUserIdentity(userIdMap.getUsername()); + List groupIds = new ArrayList<>(); + List groupEntries = entry.getGroups(); + for (GroupEntry groupEntry : groupEntries) { + GroupIdMap groupIdMap = identityAccessManager.getGroup(groupEntry.getName()); + if (groupIdMap != null) { + groupIds.add(groupIdMap.getAuthId()); + } + } + UserDetails details = new UserDetails( + userIdMap, + entry, + groupIds + ); + users.add(details); + } + return users; + } + + public List getGroups() { + List groupIdMaps = identityAccessManager.getAllGroups(); + List groups = new ArrayList<>(); + for (GroupIdMap groupIdMap : groupIdMaps) { + GroupEntry entry = identityAccessManager.getGroupDetails(groupIdMap.getGroupName()); + List userIds = new ArrayList<>(); + Set userList = entry.getUsers(); + for (String user : userList) { + UserIdMap userIdMap = identityAccessManager.getUser(user); + if (userIdMap != null) { + userIds.add(userIdMap.getAuthId()); + } + } + GroupDetails details = new GroupDetails( + groupIdMap.getGroupName(), + groupIdMap.getAuthId(), + userIds + ); + groups.add(details); + } + return groups; + } } diff --git a/src/main/java/io/mapsmessaging/auth/registry/GroupDetails.java b/src/main/java/io/mapsmessaging/auth/registry/GroupDetails.java new file mode 100644 index 000000000..b91e8c574 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/GroupDetails.java @@ -0,0 +1,35 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.ToString; + +import java.util.List; +import java.util.UUID; + +@Data +@ToString +@AllArgsConstructor +public class GroupDetails { + + private final String name; + private final UUID groupId; + private final List users; +} diff --git a/src/main/java/io/mapsmessaging/auth/registry/UserDetails.java b/src/main/java/io/mapsmessaging/auth/registry/UserDetails.java new file mode 100644 index 000000000..2709f4d83 --- /dev/null +++ b/src/main/java/io/mapsmessaging/auth/registry/UserDetails.java @@ -0,0 +1,38 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.auth.registry; + +import io.mapsmessaging.security.access.mapping.UserIdMap; +import io.mapsmessaging.security.identity.IdentityEntry; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.ToString; + +import java.util.List; +import java.util.UUID; + +@Data +@ToString +@AllArgsConstructor +public class UserDetails { + + private final UserIdMap userIdMap; + private final IdentityEntry identityEntry; + private final List groups; + +} diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/MapsRestServerApi.java b/src/main/java/io/mapsmessaging/rest/api/impl/MapsRestServerApi.java index 58d7610dd..b215ce4f3 100644 --- a/src/main/java/io/mapsmessaging/rest/api/impl/MapsRestServerApi.java +++ b/src/main/java/io/mapsmessaging/rest/api/impl/MapsRestServerApi.java @@ -32,7 +32,6 @@ import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.ws.rs.Produces; -import jakarta.ws.rs.core.Application; import jakarta.ws.rs.core.MediaType; import static io.mapsmessaging.BuildInfo.buildVersion; diff --git a/src/main/java/io/mapsmessaging/rest/api/impl/UserManagementApi.java b/src/main/java/io/mapsmessaging/rest/api/impl/UserManagementApi.java new file mode 100644 index 000000000..bbecb8504 --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/api/impl/UserManagementApi.java @@ -0,0 +1,75 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.api.impl; + +import io.mapsmessaging.auth.AuthManager; +import io.mapsmessaging.auth.registry.GroupDetails; +import io.mapsmessaging.auth.registry.UserDetails; +import io.mapsmessaging.rest.responses.Group; +import io.mapsmessaging.rest.responses.GroupListResponse; +import io.mapsmessaging.rest.responses.User; +import io.mapsmessaging.rest.responses.UserListResponse; +import jakarta.ws.rs.GET; +import jakarta.ws.rs.Path; +import jakarta.ws.rs.Produces; +import jakarta.ws.rs.core.MediaType; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static io.mapsmessaging.rest.api.Constants.URI_PATH; + +@Path(URI_PATH) +public class UserManagementApi extends BaseDestinationApi { + + @GET + @Path("/auth/users") + @Produces({MediaType.APPLICATION_JSON}) + public UserListResponse getUsers() { + AuthManager authManager = AuthManager.getInstance(); + List users = authManager.getUsers(); + List results = new ArrayList<>(); + for (UserDetails user : users) { + String username = user.getUserIdMap().getUsername(); + UUID userId = user.getUserIdMap().getAuthId(); + + results.add(new User(username, userId, user.getGroups())); + } + return new UserListResponse(request, results); + } + + @GET + @Path("/auth/groups") + @Produces({MediaType.APPLICATION_JSON}) + //@ApiOperation(value = "Get all the destination configuration") + public GroupListResponse getGroups() { + AuthManager authManager = AuthManager.getInstance(); + List groups = authManager.getGroups(); + List results = new ArrayList<>(); + for (GroupDetails group : groups) { + String groupName = group.getName(); + UUID groupId = group.getGroupId(); + + results.add(new Group(groupName, groupId, group.getUsers())); + } + return new GroupListResponse(request, results); + } + + +} \ No newline at end of file diff --git a/src/main/java/io/mapsmessaging/rest/auth/AuthenticationFilter.java b/src/main/java/io/mapsmessaging/rest/auth/AuthenticationFilter.java index 0d12e6989..1a6222f74 100644 --- a/src/main/java/io/mapsmessaging/rest/auth/AuthenticationFilter.java +++ b/src/main/java/io/mapsmessaging/rest/auth/AuthenticationFilter.java @@ -59,7 +59,7 @@ public void filter(ContainerRequestContext containerRequest) throws IOException if (AuthManager.getInstance().isAuthenticationEnabled() && !AuthManager.getInstance().validate(username, password)) { throw unauthorized; } - Subject subject = AuthManager.getInstance().getUser(username); + Subject subject = AuthManager.getInstance().getUserSubject(username); if (subject == null) { throw unauthorized; } diff --git a/src/main/java/io/mapsmessaging/rest/auth/UserSecurityContext.java b/src/main/java/io/mapsmessaging/rest/auth/UserSecurityContext.java index f9fc2a2cb..6bce1d117 100644 --- a/src/main/java/io/mapsmessaging/rest/auth/UserSecurityContext.java +++ b/src/main/java/io/mapsmessaging/rest/auth/UserSecurityContext.java @@ -32,7 +32,7 @@ public class UserSecurityContext implements SecurityContext { public UserSecurityContext(String username) { userPrincipal = new AuthenticatedUserPrincipal(username); - subject = AuthManager.getInstance().getUser(username); + subject = AuthManager.getInstance().getUserSubject(username); } @Override diff --git a/src/main/java/io/mapsmessaging/rest/responses/Group.java b/src/main/java/io/mapsmessaging/rest/responses/Group.java new file mode 100644 index 000000000..367f83bae --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/responses/Group.java @@ -0,0 +1,30 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.responses; + +import lombok.Data; + +import java.util.List; +import java.util.UUID; + +@Data +public class Group { + private final String name; + private final UUID uniqueId; + private final List usersList; +} diff --git a/src/main/java/io/mapsmessaging/rest/responses/GroupListResponse.java b/src/main/java/io/mapsmessaging/rest/responses/GroupListResponse.java new file mode 100644 index 000000000..c474cec1c --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/responses/GroupListResponse.java @@ -0,0 +1,35 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.responses; + +import lombok.Getter; + +import javax.ws.rs.core.Request; +import java.util.List; + +public class GroupListResponse extends BaseResponse { + + @Getter + private final List data; + + + public GroupListResponse(Request request, List data) { + super(request); + this.data = data; + } +} diff --git a/src/main/java/io/mapsmessaging/rest/responses/User.java b/src/main/java/io/mapsmessaging/rest/responses/User.java new file mode 100644 index 000000000..5d6d813b8 --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/responses/User.java @@ -0,0 +1,30 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.responses; + +import lombok.Data; + +import java.util.List; +import java.util.UUID; + +@Data +public class User { + private final String username; + private final UUID uniqueId; + private final List groupList; +} diff --git a/src/main/java/io/mapsmessaging/rest/responses/UserListResponse.java b/src/main/java/io/mapsmessaging/rest/responses/UserListResponse.java new file mode 100644 index 000000000..69a87002e --- /dev/null +++ b/src/main/java/io/mapsmessaging/rest/responses/UserListResponse.java @@ -0,0 +1,35 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package io.mapsmessaging.rest.responses; + +import lombok.Getter; + +import javax.ws.rs.core.Request; +import java.util.List; + +public class UserListResponse extends BaseResponse { + + @Getter + private final List data; + + + public UserListResponse(Request request, List data) { + super(request); + this.data = data; + } +} From 9956cc7b788d630e0db1e3f9738a1abcdaa66865 Mon Sep 17 00:00:00 2001 From: Matthew Buckton Date: Thu, 30 Nov 2023 12:44:15 +1100 Subject: [PATCH 065/348] add swagger-ui --- .../html/swagger-ui/favicon-16x16.png | Bin 0 -> 665 bytes .../html/swagger-ui/favicon-32x32.png | Bin 0 -> 628 bytes src/main/resources/html/swagger-ui/index.css | 33 + src/main/resources/html/swagger-ui/index.html | 36 + .../html/swagger-ui/oauth2-redirect.html | 99 + .../html/swagger-ui/swagger-initializer.js | 37 + .../html/swagger-ui/swagger-ui-bundle.js | 20 + .../html/swagger-ui/swagger-ui-bundle.js.map | 1 + .../swagger-ui/swagger-ui-es-bundle-core.js | 20 + .../swagger-ui-es-bundle-core.js.map | 1 + .../html/swagger-ui/swagger-ui-es-bundle.js | 20 + .../swagger-ui/swagger-ui-es-bundle.js.map | 1 + .../swagger-ui-standalone-preset.js | 20 + .../swagger-ui-standalone-preset.js.map | 1 + .../resources/html/swagger-ui/swagger-ui.css | 11505 ++++++++++++++++ .../html/swagger-ui/swagger-ui.css.map | 1 + .../resources/html/swagger-ui/swagger-ui.js | 19 + .../html/swagger-ui/swagger-ui.js.map | 1 + 18 files changed, 11815 insertions(+) create mode 100644 src/main/resources/html/swagger-ui/favicon-16x16.png create mode 100644 src/main/resources/html/swagger-ui/favicon-32x32.png create mode 100644 src/main/resources/html/swagger-ui/index.css create mode 100644 src/main/resources/html/swagger-ui/index.html create mode 100644 src/main/resources/html/swagger-ui/oauth2-redirect.html create mode 100644 src/main/resources/html/swagger-ui/swagger-initializer.js create mode 100644 src/main/resources/html/swagger-ui/swagger-ui-bundle.js create mode 100644 src/main/resources/html/swagger-ui/swagger-ui-bundle.js.map create mode 100644 src/main/resources/html/swagger-ui/swagger-ui-es-bundle-core.js create mode 100644 src/main/resources/html/swagger-ui/swagger-ui-es-bundle-core.js.map create mode 100644 src/main/resources/html/swagger-ui/swagger-ui-es-bundle.js create mode 100644 src/main/resources/html/swagger-ui/swagger-ui-es-bundle.js.map create mode 100644 src/main/resources/html/swagger-ui/swagger-ui-standalone-preset.js create mode 100644 src/main/resources/html/swagger-ui/swagger-ui-standalone-preset.js.map create mode 100644 src/main/resources/html/swagger-ui/swagger-ui.css create mode 100644 src/main/resources/html/swagger-ui/swagger-ui.css.map create mode 100644 src/main/resources/html/swagger-ui/swagger-ui.js create mode 100644 src/main/resources/html/swagger-ui/swagger-ui.js.map diff --git a/src/main/resources/html/swagger-ui/favicon-16x16.png b/src/main/resources/html/swagger-ui/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..8b194e617af1c135e6b37939591d24ac3a5efa18 GIT binary patch literal 665 zcmV;K0%rY*P)}JKSduyL>)s!A4EhTMMEM%Q;aL6%l#xiZiF>S;#Y{N2Zz%pvTGHJduXuC6Lx-)0EGfRy*N{Tv4i8@4oJ41gw zKzThrcRe|7J~(YYIBq{SYCkn-KQm=N8$CrEK1CcqMI1dv9z#VRL_{D)L|`QmF8}}l zJ9JV`Q}p!p_4f7m_U`WQ@apR4;o;!mnU<7}iG_qr zF(e)x9~BG-3IzcG2M4an0002kNkl41`ZiN1i62V%{PM@Ry|IS_+Yc7{bb`MM~xm(7p4|kMHP&!VGuDW4kFixat zXw43VmgwEvB$hXt_u=vZ>+v4i7E}n~eG6;n4Z=zF1n?T*yg<;W6kOfxpC6nao>VR% z?fpr=asSJ&`L*wu^rLJ5Peq*PB0;alL#XazZCBxJLd&giTfw@!hW167F^`7kobi;( ze<<>qNlP|xy7S1zl@lZNIBR7#o9ybJsptO#%}P0hz~sBp00000NkvXXu0mjfUsDF? literal 0 HcmV?d00001 diff --git a/src/main/resources/html/swagger-ui/favicon-32x32.png b/src/main/resources/html/swagger-ui/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..249737fe44558e679f0b67134e274461d988fa98 GIT binary patch literal 628 zcmV-)0*n2LP)Ma*GM0}OV<074bNCP7P7GVd{iMr*I6y~TMLss@FjvgL~HxU z%Vvj33AwpD(Z4*$Mfx=HaU16axM zt2xG_rloN<$iy9j9I5 + + + + + + + Swagger UI + + + + + + + +
+ + + + + diff --git a/src/main/resources/html/swagger-ui/oauth2-redirect.html b/src/main/resources/html/swagger-ui/oauth2-redirect.html new file mode 100644 index 000000000..8b44479d4 --- /dev/null +++ b/src/main/resources/html/swagger-ui/oauth2-redirect.html @@ -0,0 +1,99 @@ + + + + + + Swagger UI: OAuth2 Redirect + + + + + diff --git a/src/main/resources/html/swagger-ui/swagger-initializer.js b/src/main/resources/html/swagger-ui/swagger-initializer.js new file mode 100644 index 000000000..aa4b4ac2b --- /dev/null +++ b/src/main/resources/html/swagger-ui/swagger-initializer.js @@ -0,0 +1,37 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +window.onload = function () { + // + + // the following lines will be replaced by docker/configurator, when it runs in a docker-container + window.ui = SwaggerUIBundle({ + url: "https://petstore.swagger.io/v2/swagger.json", + dom_id: '#swagger-ui', + deepLinking: true, + presets: [ + SwaggerUIBundle.presets.apis, + SwaggerUIStandalonePreset + ], + plugins: [ + SwaggerUIBundle.plugins.DownloadUrl + ], + layout: "StandaloneLayout" + }); + + // +}; diff --git a/src/main/resources/html/swagger-ui/swagger-ui-bundle.js b/src/main/resources/html/swagger-ui/swagger-ui-bundle.js new file mode 100644 index 000000000..c6f944d75 --- /dev/null +++ b/src/main/resources/html/swagger-ui/swagger-ui-bundle.js @@ -0,0 +1,20 @@ +/* + * Copyright [ 2020 - 2023 ] [Matthew Buckton] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */ +!function webpackUniversalModuleDefinition(i,s){"object"==typeof exports&&"object"==typeof module?module.exports=s():"function"==typeof define&&define.amd?define([],s):"object"==typeof exports?exports.SwaggerUIBundle=s():i.SwaggerUIBundle=s()}(this,(()=>(()=>{var i={17967:(i,s)=>{"use strict";s.Nm=s.Rq=void 0;var u=/^([^\w]*)(javascript|data|vbscript)/im,m=/&#(\w+)(^\w|;)?/g,v=/&(newline|tab);/gi,_=/[\u0000-\u001F\u007F-\u009F\u2000-\u200D\uFEFF]/gim,j=/^.+(:|:)/gim,M=[".","/"];s.Rq="about:blank",s.Nm=function sanitizeUrl(i){if(!i)return s.Rq;var $=function decodeHtmlCharacters(i){return i.replace(_,"").replace(m,(function(i,s){return String.fromCharCode(s)}))}(i).replace(v,"").replace(_,"").trim();if(!$)return s.Rq;if(function isRelativeUrlWithoutProtocol(i){return M.indexOf(i[0])>-1}($))return $;var W=$.match(j);if(!W)return $;var X=W[0];return u.test(X)?s.Rq:$}},79742:(i,s)=>{"use strict";s.byteLength=function byteLength(i){var s=getLens(i),u=s[0],m=s[1];return 3*(u+m)/4-m},s.toByteArray=function toByteArray(i){var s,u,_=getLens(i),j=_[0],M=_[1],$=new v(function _byteLength(i,s,u){return 3*(s+u)/4-u}(0,j,M)),W=0,X=M>0?j-4:j;for(u=0;u>16&255,$[W++]=s>>8&255,$[W++]=255&s;2===M&&(s=m[i.charCodeAt(u)]<<2|m[i.charCodeAt(u+1)]>>4,$[W++]=255&s);1===M&&(s=m[i.charCodeAt(u)]<<10|m[i.charCodeAt(u+1)]<<4|m[i.charCodeAt(u+2)]>>2,$[W++]=s>>8&255,$[W++]=255&s);return $},s.fromByteArray=function fromByteArray(i){for(var s,m=i.length,v=m%3,_=[],j=16383,M=0,$=m-v;M<$;M+=j)_.push(encodeChunk(i,M,M+j>$?$:M+j));1===v?(s=i[m-1],_.push(u[s>>2]+u[s<<4&63]+"==")):2===v&&(s=(i[m-2]<<8)+i[m-1],_.push(u[s>>10]+u[s>>4&63]+u[s<<2&63]+"="));return _.join("")};for(var u=[],m=[],v="undefined"!=typeof Uint8Array?Uint8Array:Array,_="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",j=0;j<64;++j)u[j]=_[j],m[_.charCodeAt(j)]=j;function getLens(i){var s=i.length;if(s%4>0)throw new Error("Invalid string. Length must be a multiple of 4");var u=i.indexOf("=");return-1===u&&(u=s),[u,u===s?0:4-u%4]}function encodeChunk(i,s,m){for(var v,_,j=[],M=s;M>18&63]+u[_>>12&63]+u[_>>6&63]+u[63&_]);return j.join("")}m["-".charCodeAt(0)]=62,m["_".charCodeAt(0)]=63},48764:(i,s,u)=>{"use strict";const m=u(79742),v=u(80645),_="function"==typeof Symbol&&"function"==typeof Symbol.for?Symbol.for("nodejs.util.inspect.custom"):null;s.Buffer=Buffer,s.SlowBuffer=function SlowBuffer(i){+i!=i&&(i=0);return Buffer.alloc(+i)},s.INSPECT_MAX_BYTES=50;const j=2147483647;function createBuffer(i){if(i>j)throw new RangeError('The value "'+i+'" is invalid for option "size"');const s=new Uint8Array(i);return Object.setPrototypeOf(s,Buffer.prototype),s}function Buffer(i,s,u){if("number"==typeof i){if("string"==typeof s)throw new TypeError('The "string" argument must be of type string. Received type number');return allocUnsafe(i)}return from(i,s,u)}function from(i,s,u){if("string"==typeof i)return function fromString(i,s){"string"==typeof s&&""!==s||(s="utf8");if(!Buffer.isEncoding(s))throw new TypeError("Unknown encoding: "+s);const u=0|byteLength(i,s);let m=createBuffer(u);const v=m.write(i,s);v!==u&&(m=m.slice(0,v));return m}(i,s);if(ArrayBuffer.isView(i))return function fromArrayView(i){if(isInstance(i,Uint8Array)){const s=new Uint8Array(i);return fromArrayBuffer(s.buffer,s.byteOffset,s.byteLength)}return fromArrayLike(i)}(i);if(null==i)throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof i);if(isInstance(i,ArrayBuffer)||i&&isInstance(i.buffer,ArrayBuffer))return fromArrayBuffer(i,s,u);if("undefined"!=typeof SharedArrayBuffer&&(isInstance(i,SharedArrayBuffer)||i&&isInstance(i.buffer,SharedArrayBuffer)))return fromArrayBuffer(i,s,u);if("number"==typeof i)throw new TypeError('The "value" argument must not be of type number. Received type number');const m=i.valueOf&&i.valueOf();if(null!=m&&m!==i)return Buffer.from(m,s,u);const v=function fromObject(i){if(Buffer.isBuffer(i)){const s=0|checked(i.length),u=createBuffer(s);return 0===u.length||i.copy(u,0,0,s),u}if(void 0!==i.length)return"number"!=typeof i.length||numberIsNaN(i.length)?createBuffer(0):fromArrayLike(i);if("Buffer"===i.type&&Array.isArray(i.data))return fromArrayLike(i.data)}(i);if(v)return v;if("undefined"!=typeof Symbol&&null!=Symbol.toPrimitive&&"function"==typeof i[Symbol.toPrimitive])return Buffer.from(i[Symbol.toPrimitive]("string"),s,u);throw new TypeError("The first argument must be one of type string, Buffer, ArrayBuffer, Array, or Array-like Object. Received type "+typeof i)}function assertSize(i){if("number"!=typeof i)throw new TypeError('"size" argument must be of type number');if(i<0)throw new RangeError('The value "'+i+'" is invalid for option "size"')}function allocUnsafe(i){return assertSize(i),createBuffer(i<0?0:0|checked(i))}function fromArrayLike(i){const s=i.length<0?0:0|checked(i.length),u=createBuffer(s);for(let m=0;m=j)throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+j.toString(16)+" bytes");return 0|i}function byteLength(i,s){if(Buffer.isBuffer(i))return i.length;if(ArrayBuffer.isView(i)||isInstance(i,ArrayBuffer))return i.byteLength;if("string"!=typeof i)throw new TypeError('The "string" argument must be one of type string, Buffer, or ArrayBuffer. Received type '+typeof i);const u=i.length,m=arguments.length>2&&!0===arguments[2];if(!m&&0===u)return 0;let v=!1;for(;;)switch(s){case"ascii":case"latin1":case"binary":return u;case"utf8":case"utf-8":return utf8ToBytes(i).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*u;case"hex":return u>>>1;case"base64":return base64ToBytes(i).length;default:if(v)return m?-1:utf8ToBytes(i).length;s=(""+s).toLowerCase(),v=!0}}function slowToString(i,s,u){let m=!1;if((void 0===s||s<0)&&(s=0),s>this.length)return"";if((void 0===u||u>this.length)&&(u=this.length),u<=0)return"";if((u>>>=0)<=(s>>>=0))return"";for(i||(i="utf8");;)switch(i){case"hex":return hexSlice(this,s,u);case"utf8":case"utf-8":return utf8Slice(this,s,u);case"ascii":return asciiSlice(this,s,u);case"latin1":case"binary":return latin1Slice(this,s,u);case"base64":return base64Slice(this,s,u);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return utf16leSlice(this,s,u);default:if(m)throw new TypeError("Unknown encoding: "+i);i=(i+"").toLowerCase(),m=!0}}function swap(i,s,u){const m=i[s];i[s]=i[u],i[u]=m}function bidirectionalIndexOf(i,s,u,m,v){if(0===i.length)return-1;if("string"==typeof u?(m=u,u=0):u>2147483647?u=2147483647:u<-2147483648&&(u=-2147483648),numberIsNaN(u=+u)&&(u=v?0:i.length-1),u<0&&(u=i.length+u),u>=i.length){if(v)return-1;u=i.length-1}else if(u<0){if(!v)return-1;u=0}if("string"==typeof s&&(s=Buffer.from(s,m)),Buffer.isBuffer(s))return 0===s.length?-1:arrayIndexOf(i,s,u,m,v);if("number"==typeof s)return s&=255,"function"==typeof Uint8Array.prototype.indexOf?v?Uint8Array.prototype.indexOf.call(i,s,u):Uint8Array.prototype.lastIndexOf.call(i,s,u):arrayIndexOf(i,[s],u,m,v);throw new TypeError("val must be string, number or Buffer")}function arrayIndexOf(i,s,u,m,v){let _,j=1,M=i.length,$=s.length;if(void 0!==m&&("ucs2"===(m=String(m).toLowerCase())||"ucs-2"===m||"utf16le"===m||"utf-16le"===m)){if(i.length<2||s.length<2)return-1;j=2,M/=2,$/=2,u/=2}function read(i,s){return 1===j?i[s]:i.readUInt16BE(s*j)}if(v){let m=-1;for(_=u;_M&&(u=M-$),_=u;_>=0;_--){let u=!0;for(let m=0;m<$;m++)if(read(i,_+m)!==read(s,m)){u=!1;break}if(u)return _}return-1}function hexWrite(i,s,u,m){u=Number(u)||0;const v=i.length-u;m?(m=Number(m))>v&&(m=v):m=v;const _=s.length;let j;for(m>_/2&&(m=_/2),j=0;j>8,v=u%256,_.push(v),_.push(m);return _}(s,i.length-u),i,u,m)}function base64Slice(i,s,u){return 0===s&&u===i.length?m.fromByteArray(i):m.fromByteArray(i.slice(s,u))}function utf8Slice(i,s,u){u=Math.min(i.length,u);const m=[];let v=s;for(;v239?4:s>223?3:s>191?2:1;if(v+j<=u){let u,m,M,$;switch(j){case 1:s<128&&(_=s);break;case 2:u=i[v+1],128==(192&u)&&($=(31&s)<<6|63&u,$>127&&(_=$));break;case 3:u=i[v+1],m=i[v+2],128==(192&u)&&128==(192&m)&&($=(15&s)<<12|(63&u)<<6|63&m,$>2047&&($<55296||$>57343)&&(_=$));break;case 4:u=i[v+1],m=i[v+2],M=i[v+3],128==(192&u)&&128==(192&m)&&128==(192&M)&&($=(15&s)<<18|(63&u)<<12|(63&m)<<6|63&M,$>65535&&$<1114112&&(_=$))}}null===_?(_=65533,j=1):_>65535&&(_-=65536,m.push(_>>>10&1023|55296),_=56320|1023&_),m.push(_),v+=j}return function decodeCodePointsArray(i){const s=i.length;if(s<=M)return String.fromCharCode.apply(String,i);let u="",m=0;for(;mm.length?(Buffer.isBuffer(s)||(s=Buffer.from(s)),s.copy(m,v)):Uint8Array.prototype.set.call(m,s,v);else{if(!Buffer.isBuffer(s))throw new TypeError('"list" argument must be an Array of Buffers');s.copy(m,v)}v+=s.length}return m},Buffer.byteLength=byteLength,Buffer.prototype._isBuffer=!0,Buffer.prototype.swap16=function swap16(){const i=this.length;if(i%2!=0)throw new RangeError("Buffer size must be a multiple of 16-bits");for(let s=0;su&&(i+=" ... "),""},_&&(Buffer.prototype[_]=Buffer.prototype.inspect),Buffer.prototype.compare=function compare(i,s,u,m,v){if(isInstance(i,Uint8Array)&&(i=Buffer.from(i,i.offset,i.byteLength)),!Buffer.isBuffer(i))throw new TypeError('The "target" argument must be one of type Buffer or Uint8Array. Received type '+typeof i);if(void 0===s&&(s=0),void 0===u&&(u=i?i.length:0),void 0===m&&(m=0),void 0===v&&(v=this.length),s<0||u>i.length||m<0||v>this.length)throw new RangeError("out of range index");if(m>=v&&s>=u)return 0;if(m>=v)return-1;if(s>=u)return 1;if(this===i)return 0;let _=(v>>>=0)-(m>>>=0),j=(u>>>=0)-(s>>>=0);const M=Math.min(_,j),$=this.slice(m,v),W=i.slice(s,u);for(let i=0;i>>=0,isFinite(u)?(u>>>=0,void 0===m&&(m="utf8")):(m=u,u=void 0)}const v=this.length-s;if((void 0===u||u>v)&&(u=v),i.length>0&&(u<0||s<0)||s>this.length)throw new RangeError("Attempt to write outside buffer bounds");m||(m="utf8");let _=!1;for(;;)switch(m){case"hex":return hexWrite(this,i,s,u);case"utf8":case"utf-8":return utf8Write(this,i,s,u);case"ascii":case"latin1":case"binary":return asciiWrite(this,i,s,u);case"base64":return base64Write(this,i,s,u);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return ucs2Write(this,i,s,u);default:if(_)throw new TypeError("Unknown encoding: "+m);m=(""+m).toLowerCase(),_=!0}},Buffer.prototype.toJSON=function toJSON(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};const M=4096;function asciiSlice(i,s,u){let m="";u=Math.min(i.length,u);for(let v=s;vm)&&(u=m);let v="";for(let m=s;mu)throw new RangeError("Trying to access beyond buffer length")}function checkInt(i,s,u,m,v,_){if(!Buffer.isBuffer(i))throw new TypeError('"buffer" argument must be a Buffer instance');if(s>v||s<_)throw new RangeError('"value" argument is out of bounds');if(u+m>i.length)throw new RangeError("Index out of range")}function wrtBigUInt64LE(i,s,u,m,v){checkIntBI(s,m,v,i,u,7);let _=Number(s&BigInt(4294967295));i[u++]=_,_>>=8,i[u++]=_,_>>=8,i[u++]=_,_>>=8,i[u++]=_;let j=Number(s>>BigInt(32)&BigInt(4294967295));return i[u++]=j,j>>=8,i[u++]=j,j>>=8,i[u++]=j,j>>=8,i[u++]=j,u}function wrtBigUInt64BE(i,s,u,m,v){checkIntBI(s,m,v,i,u,7);let _=Number(s&BigInt(4294967295));i[u+7]=_,_>>=8,i[u+6]=_,_>>=8,i[u+5]=_,_>>=8,i[u+4]=_;let j=Number(s>>BigInt(32)&BigInt(4294967295));return i[u+3]=j,j>>=8,i[u+2]=j,j>>=8,i[u+1]=j,j>>=8,i[u]=j,u+8}function checkIEEE754(i,s,u,m,v,_){if(u+m>i.length)throw new RangeError("Index out of range");if(u<0)throw new RangeError("Index out of range")}function writeFloat(i,s,u,m,_){return s=+s,u>>>=0,_||checkIEEE754(i,0,u,4),v.write(i,s,u,m,23,4),u+4}function writeDouble(i,s,u,m,_){return s=+s,u>>>=0,_||checkIEEE754(i,0,u,8),v.write(i,s,u,m,52,8),u+8}Buffer.prototype.slice=function slice(i,s){const u=this.length;(i=~~i)<0?(i+=u)<0&&(i=0):i>u&&(i=u),(s=void 0===s?u:~~s)<0?(s+=u)<0&&(s=0):s>u&&(s=u),s>>=0,s>>>=0,u||checkOffset(i,s,this.length);let m=this[i],v=1,_=0;for(;++_>>=0,s>>>=0,u||checkOffset(i,s,this.length);let m=this[i+--s],v=1;for(;s>0&&(v*=256);)m+=this[i+--s]*v;return m},Buffer.prototype.readUint8=Buffer.prototype.readUInt8=function readUInt8(i,s){return i>>>=0,s||checkOffset(i,1,this.length),this[i]},Buffer.prototype.readUint16LE=Buffer.prototype.readUInt16LE=function readUInt16LE(i,s){return i>>>=0,s||checkOffset(i,2,this.length),this[i]|this[i+1]<<8},Buffer.prototype.readUint16BE=Buffer.prototype.readUInt16BE=function readUInt16BE(i,s){return i>>>=0,s||checkOffset(i,2,this.length),this[i]<<8|this[i+1]},Buffer.prototype.readUint32LE=Buffer.prototype.readUInt32LE=function readUInt32LE(i,s){return i>>>=0,s||checkOffset(i,4,this.length),(this[i]|this[i+1]<<8|this[i+2]<<16)+16777216*this[i+3]},Buffer.prototype.readUint32BE=Buffer.prototype.readUInt32BE=function readUInt32BE(i,s){return i>>>=0,s||checkOffset(i,4,this.length),16777216*this[i]+(this[i+1]<<16|this[i+2]<<8|this[i+3])},Buffer.prototype.readBigUInt64LE=defineBigIntMethod((function readBigUInt64LE(i){validateNumber(i>>>=0,"offset");const s=this[i],u=this[i+7];void 0!==s&&void 0!==u||boundsError(i,this.length-8);const m=s+256*this[++i]+65536*this[++i]+this[++i]*2**24,v=this[++i]+256*this[++i]+65536*this[++i]+u*2**24;return BigInt(m)+(BigInt(v)<>>=0,"offset");const s=this[i],u=this[i+7];void 0!==s&&void 0!==u||boundsError(i,this.length-8);const m=s*2**24+65536*this[++i]+256*this[++i]+this[++i],v=this[++i]*2**24+65536*this[++i]+256*this[++i]+u;return(BigInt(m)<>>=0,s>>>=0,u||checkOffset(i,s,this.length);let m=this[i],v=1,_=0;for(;++_=v&&(m-=Math.pow(2,8*s)),m},Buffer.prototype.readIntBE=function readIntBE(i,s,u){i>>>=0,s>>>=0,u||checkOffset(i,s,this.length);let m=s,v=1,_=this[i+--m];for(;m>0&&(v*=256);)_+=this[i+--m]*v;return v*=128,_>=v&&(_-=Math.pow(2,8*s)),_},Buffer.prototype.readInt8=function readInt8(i,s){return i>>>=0,s||checkOffset(i,1,this.length),128&this[i]?-1*(255-this[i]+1):this[i]},Buffer.prototype.readInt16LE=function readInt16LE(i,s){i>>>=0,s||checkOffset(i,2,this.length);const u=this[i]|this[i+1]<<8;return 32768&u?4294901760|u:u},Buffer.prototype.readInt16BE=function readInt16BE(i,s){i>>>=0,s||checkOffset(i,2,this.length);const u=this[i+1]|this[i]<<8;return 32768&u?4294901760|u:u},Buffer.prototype.readInt32LE=function readInt32LE(i,s){return i>>>=0,s||checkOffset(i,4,this.length),this[i]|this[i+1]<<8|this[i+2]<<16|this[i+3]<<24},Buffer.prototype.readInt32BE=function readInt32BE(i,s){return i>>>=0,s||checkOffset(i,4,this.length),this[i]<<24|this[i+1]<<16|this[i+2]<<8|this[i+3]},Buffer.prototype.readBigInt64LE=defineBigIntMethod((function readBigInt64LE(i){validateNumber(i>>>=0,"offset");const s=this[i],u=this[i+7];void 0!==s&&void 0!==u||boundsError(i,this.length-8);const m=this[i+4]+256*this[i+5]+65536*this[i+6]+(u<<24);return(BigInt(m)<>>=0,"offset");const s=this[i],u=this[i+7];void 0!==s&&void 0!==u||boundsError(i,this.length-8);const m=(s<<24)+65536*this[++i]+256*this[++i]+this[++i];return(BigInt(m)<>>=0,s||checkOffset(i,4,this.length),v.read(this,i,!0,23,4)},Buffer.prototype.readFloatBE=function readFloatBE(i,s){return i>>>=0,s||checkOffset(i,4,this.length),v.read(this,i,!1,23,4)},Buffer.prototype.readDoubleLE=function readDoubleLE(i,s){return i>>>=0,s||checkOffset(i,8,this.length),v.read(this,i,!0,52,8)},Buffer.prototype.readDoubleBE=function readDoubleBE(i,s){return i>>>=0,s||checkOffset(i,8,this.length),v.read(this,i,!1,52,8)},Buffer.prototype.writeUintLE=Buffer.prototype.writeUIntLE=function writeUIntLE(i,s,u,m){if(i=+i,s>>>=0,u>>>=0,!m){checkInt(this,i,s,u,Math.pow(2,8*u)-1,0)}let v=1,_=0;for(this[s]=255&i;++_>>=0,u>>>=0,!m){checkInt(this,i,s,u,Math.pow(2,8*u)-1,0)}let v=u-1,_=1;for(this[s+v]=255&i;--v>=0&&(_*=256);)this[s+v]=i/_&255;return s+u},Buffer.prototype.writeUint8=Buffer.prototype.writeUInt8=function writeUInt8(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,1,255,0),this[s]=255&i,s+1},Buffer.prototype.writeUint16LE=Buffer.prototype.writeUInt16LE=function writeUInt16LE(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,2,65535,0),this[s]=255&i,this[s+1]=i>>>8,s+2},Buffer.prototype.writeUint16BE=Buffer.prototype.writeUInt16BE=function writeUInt16BE(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,2,65535,0),this[s]=i>>>8,this[s+1]=255&i,s+2},Buffer.prototype.writeUint32LE=Buffer.prototype.writeUInt32LE=function writeUInt32LE(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,4,4294967295,0),this[s+3]=i>>>24,this[s+2]=i>>>16,this[s+1]=i>>>8,this[s]=255&i,s+4},Buffer.prototype.writeUint32BE=Buffer.prototype.writeUInt32BE=function writeUInt32BE(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,4,4294967295,0),this[s]=i>>>24,this[s+1]=i>>>16,this[s+2]=i>>>8,this[s+3]=255&i,s+4},Buffer.prototype.writeBigUInt64LE=defineBigIntMethod((function writeBigUInt64LE(i,s=0){return wrtBigUInt64LE(this,i,s,BigInt(0),BigInt("0xffffffffffffffff"))})),Buffer.prototype.writeBigUInt64BE=defineBigIntMethod((function writeBigUInt64BE(i,s=0){return wrtBigUInt64BE(this,i,s,BigInt(0),BigInt("0xffffffffffffffff"))})),Buffer.prototype.writeIntLE=function writeIntLE(i,s,u,m){if(i=+i,s>>>=0,!m){const m=Math.pow(2,8*u-1);checkInt(this,i,s,u,m-1,-m)}let v=0,_=1,j=0;for(this[s]=255&i;++v>0)-j&255;return s+u},Buffer.prototype.writeIntBE=function writeIntBE(i,s,u,m){if(i=+i,s>>>=0,!m){const m=Math.pow(2,8*u-1);checkInt(this,i,s,u,m-1,-m)}let v=u-1,_=1,j=0;for(this[s+v]=255&i;--v>=0&&(_*=256);)i<0&&0===j&&0!==this[s+v+1]&&(j=1),this[s+v]=(i/_>>0)-j&255;return s+u},Buffer.prototype.writeInt8=function writeInt8(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,1,127,-128),i<0&&(i=255+i+1),this[s]=255&i,s+1},Buffer.prototype.writeInt16LE=function writeInt16LE(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,2,32767,-32768),this[s]=255&i,this[s+1]=i>>>8,s+2},Buffer.prototype.writeInt16BE=function writeInt16BE(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,2,32767,-32768),this[s]=i>>>8,this[s+1]=255&i,s+2},Buffer.prototype.writeInt32LE=function writeInt32LE(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,4,2147483647,-2147483648),this[s]=255&i,this[s+1]=i>>>8,this[s+2]=i>>>16,this[s+3]=i>>>24,s+4},Buffer.prototype.writeInt32BE=function writeInt32BE(i,s,u){return i=+i,s>>>=0,u||checkInt(this,i,s,4,2147483647,-2147483648),i<0&&(i=4294967295+i+1),this[s]=i>>>24,this[s+1]=i>>>16,this[s+2]=i>>>8,this[s+3]=255&i,s+4},Buffer.prototype.writeBigInt64LE=defineBigIntMethod((function writeBigInt64LE(i,s=0){return wrtBigUInt64LE(this,i,s,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),Buffer.prototype.writeBigInt64BE=defineBigIntMethod((function writeBigInt64BE(i,s=0){return wrtBigUInt64BE(this,i,s,-BigInt("0x8000000000000000"),BigInt("0x7fffffffffffffff"))})),Buffer.prototype.writeFloatLE=function writeFloatLE(i,s,u){return writeFloat(this,i,s,!0,u)},Buffer.prototype.writeFloatBE=function writeFloatBE(i,s,u){return writeFloat(this,i,s,!1,u)},Buffer.prototype.writeDoubleLE=function writeDoubleLE(i,s,u){return writeDouble(this,i,s,!0,u)},Buffer.prototype.writeDoubleBE=function writeDoubleBE(i,s,u){return writeDouble(this,i,s,!1,u)},Buffer.prototype.copy=function copy(i,s,u,m){if(!Buffer.isBuffer(i))throw new TypeError("argument should be a Buffer");if(u||(u=0),m||0===m||(m=this.length),s>=i.length&&(s=i.length),s||(s=0),m>0&&m=this.length)throw new RangeError("Index out of range");if(m<0)throw new RangeError("sourceEnd out of bounds");m>this.length&&(m=this.length),i.length-s>>=0,u=void 0===u?this.length:u>>>0,i||(i=0),"number"==typeof i)for(v=s;v=m+4;u-=3)s=`_${i.slice(u-3,u)}${s}`;return`${i.slice(0,u)}${s}`}function checkIntBI(i,s,u,m,v,_){if(i>u||i3?0===s||s===BigInt(0)?`>= 0${m} and < 2${m} ** ${8*(_+1)}${m}`:`>= -(2${m} ** ${8*(_+1)-1}${m}) and < 2 ** ${8*(_+1)-1}${m}`:`>= ${s}${m} and <= ${u}${m}`,new $.ERR_OUT_OF_RANGE("value",v,i)}!function checkBounds(i,s,u){validateNumber(s,"offset"),void 0!==i[s]&&void 0!==i[s+u]||boundsError(s,i.length-(u+1))}(m,v,_)}function validateNumber(i,s){if("number"!=typeof i)throw new $.ERR_INVALID_ARG_TYPE(s,"number",i)}function boundsError(i,s,u){if(Math.floor(i)!==i)throw validateNumber(i,u),new $.ERR_OUT_OF_RANGE(u||"offset","an integer",i);if(s<0)throw new $.ERR_BUFFER_OUT_OF_BOUNDS;throw new $.ERR_OUT_OF_RANGE(u||"offset",`>= ${u?1:0} and <= ${s}`,i)}E("ERR_BUFFER_OUT_OF_BOUNDS",(function(i){return i?`${i} is outside of buffer bounds`:"Attempt to access memory outside buffer bounds"}),RangeError),E("ERR_INVALID_ARG_TYPE",(function(i,s){return`The "${i}" argument must be of type number. Received type ${typeof s}`}),TypeError),E("ERR_OUT_OF_RANGE",(function(i,s,u){let m=`The value of "${i}" is out of range.`,v=u;return Number.isInteger(u)&&Math.abs(u)>2**32?v=addNumericalSeparator(String(u)):"bigint"==typeof u&&(v=String(u),(u>BigInt(2)**BigInt(32)||u<-(BigInt(2)**BigInt(32)))&&(v=addNumericalSeparator(v)),v+="n"),m+=` It must be ${s}. Received ${v}`,m}),RangeError);const W=/[^+/0-9A-Za-z-_]/g;function utf8ToBytes(i,s){let u;s=s||1/0;const m=i.length;let v=null;const _=[];for(let j=0;j55295&&u<57344){if(!v){if(u>56319){(s-=3)>-1&&_.push(239,191,189);continue}if(j+1===m){(s-=3)>-1&&_.push(239,191,189);continue}v=u;continue}if(u<56320){(s-=3)>-1&&_.push(239,191,189),v=u;continue}u=65536+(v-55296<<10|u-56320)}else v&&(s-=3)>-1&&_.push(239,191,189);if(v=null,u<128){if((s-=1)<0)break;_.push(u)}else if(u<2048){if((s-=2)<0)break;_.push(u>>6|192,63&u|128)}else if(u<65536){if((s-=3)<0)break;_.push(u>>12|224,u>>6&63|128,63&u|128)}else{if(!(u<1114112))throw new Error("Invalid code point");if((s-=4)<0)break;_.push(u>>18|240,u>>12&63|128,u>>6&63|128,63&u|128)}}return _}function base64ToBytes(i){return m.toByteArray(function base64clean(i){if((i=(i=i.split("=")[0]).trim().replace(W,"")).length<2)return"";for(;i.length%4!=0;)i+="=";return i}(i))}function blitBuffer(i,s,u,m){let v;for(v=0;v=s.length||v>=i.length);++v)s[v+u]=i[v];return v}function isInstance(i,s){return i instanceof s||null!=i&&null!=i.constructor&&null!=i.constructor.name&&i.constructor.name===s.name}function numberIsNaN(i){return i!=i}const X=function(){const i="0123456789abcdef",s=new Array(256);for(let u=0;u<16;++u){const m=16*u;for(let v=0;v<16;++v)s[m+v]=i[u]+i[v]}return s}();function defineBigIntMethod(i){return"undefined"==typeof BigInt?BufferBigIntNotDefined:i}function BufferBigIntNotDefined(){throw new Error("BigInt not supported")}},21924:(i,s,u)=>{"use strict";var m=u(40210),v=u(55559),_=v(m("String.prototype.indexOf"));i.exports=function callBoundIntrinsic(i,s){var u=m(i,!!s);return"function"==typeof u&&_(i,".prototype.")>-1?v(u):u}},55559:(i,s,u)=>{"use strict";var m=u(58612),v=u(40210),_=v("%Function.prototype.apply%"),j=v("%Function.prototype.call%"),M=v("%Reflect.apply%",!0)||m.call(j,_),$=v("%Object.getOwnPropertyDescriptor%",!0),W=v("%Object.defineProperty%",!0),X=v("%Math.max%");if(W)try{W({},"a",{value:1})}catch(i){W=null}i.exports=function callBind(i){var s=M(m,j,arguments);$&&W&&($(s,"length").configurable&&W(s,"length",{value:1+X(0,i.length-(arguments.length-1))}));return s};var Y=function applyBind(){return M(m,_,arguments)};W?W(i.exports,"apply",{value:Y}):i.exports.apply=Y},94184:(i,s)=>{var u;!function(){"use strict";var m={}.hasOwnProperty;function classNames(){for(var i=[],s=0;s{"use strict";s.parse=function parse(i,s){if("string"!=typeof i)throw new TypeError("argument str must be a string");var u={},m=(s||{}).decode||decode,v=0;for(;v{"use strict";var m=u(11742),v={"text/plain":"Text","text/html":"Url",default:"Text"};i.exports=function copy(i,s){var u,_,j,M,$,W,X=!1;s||(s={}),u=s.debug||!1;try{if(j=m(),M=document.createRange(),$=document.getSelection(),(W=document.createElement("span")).textContent=i,W.ariaHidden="true",W.style.all="unset",W.style.position="fixed",W.style.top=0,W.style.clip="rect(0, 0, 0, 0)",W.style.whiteSpace="pre",W.style.webkitUserSelect="text",W.style.MozUserSelect="text",W.style.msUserSelect="text",W.style.userSelect="text",W.addEventListener("copy",(function(m){if(m.stopPropagation(),s.format)if(m.preventDefault(),void 0===m.clipboardData){u&&console.warn("unable to use e.clipboardData"),u&&console.warn("trying IE specific stuff"),window.clipboardData.clearData();var _=v[s.format]||v.default;window.clipboardData.setData(_,i)}else m.clipboardData.clearData(),m.clipboardData.setData(s.format,i);s.onCopy&&(m.preventDefault(),s.onCopy(m.clipboardData))})),document.body.appendChild(W),M.selectNodeContents(W),$.addRange(M),!document.execCommand("copy"))throw new Error("copy command was unsuccessful");X=!0}catch(m){u&&console.error("unable to copy using execCommand: ",m),u&&console.warn("trying IE specific stuff");try{window.clipboardData.setData(s.format||"text",i),s.onCopy&&s.onCopy(window.clipboardData),X=!0}catch(m){u&&console.error("unable to copy using clipboardData: ",m),u&&console.error("falling back to prompt"),_=function format(i){var s=(/mac os x/i.test(navigator.userAgent)?"⌘":"Ctrl")+"+C";return i.replace(/#{\s*key\s*}/g,s)}("message"in s?s.message:"Copy to clipboard: #{key}, Enter"),window.prompt(_,i)}}finally{$&&("function"==typeof $.removeRange?$.removeRange(M):$.removeAllRanges()),W&&document.body.removeChild(W),j()}return X}},44101:(i,s,u)=>{var m=u(18957);i.exports=m},90093:(i,s,u)=>{var m=u(28196);i.exports=m},65362:(i,s,u)=>{var m=u(63383);i.exports=m},50415:(i,s,u)=>{u(61181),u(47627),u(24415),u(66274),u(77971);var m=u(54058);i.exports=m.AggregateError},27700:(i,s,u)=>{u(73381);var m=u(35703);i.exports=m("Function").bind},16246:(i,s,u)=>{var m=u(7046),v=u(27700),_=Function.prototype;i.exports=function(i){var s=i.bind;return i===_||m(_,i)&&s===_.bind?v:s}},45999:(i,s,u)=>{u(49221);var m=u(54058);i.exports=m.Object.assign},16121:(i,s,u)=>{i.exports=u(38644)},14122:(i,s,u)=>{i.exports=u(89097)},60269:(i,s,u)=>{i.exports=u(76936)},38644:(i,s,u)=>{u(89731);var m=u(44101);i.exports=m},89097:(i,s,u)=>{var m=u(90093);i.exports=m},76936:(i,s,u)=>{var m=u(65362);i.exports=m},24883:(i,s,u)=>{var m=u(57475),v=u(69826),_=TypeError;i.exports=function(i){if(m(i))return i;throw _(v(i)+" is not a function")}},11851:(i,s,u)=>{var m=u(57475),v=String,_=TypeError;i.exports=function(i){if("object"==typeof i||m(i))return i;throw _("Can't set "+v(i)+" as a prototype")}},18479:i=>{i.exports=function(){}},96059:(i,s,u)=>{var m=u(10941),v=String,_=TypeError;i.exports=function(i){if(m(i))return i;throw _(v(i)+" is not an object")}},31692:(i,s,u)=>{var m=u(74529),v=u(59413),_=u(10623),createMethod=function(i){return function(s,u,j){var M,$=m(s),W=_($),X=v(j,W);if(i&&u!=u){for(;W>X;)if((M=$[X++])!=M)return!0}else for(;W>X;X++)if((i||X in $)&&$[X]===u)return i||X||0;return!i&&-1}};i.exports={includes:createMethod(!0),indexOf:createMethod(!1)}},93765:(i,s,u)=>{var m=u(95329);i.exports=m([].slice)},82532:(i,s,u)=>{var m=u(95329),v=m({}.toString),_=m("".slice);i.exports=function(i){return _(v(i),8,-1)}},9697:(i,s,u)=>{var m=u(22885),v=u(57475),_=u(82532),j=u(99813)("toStringTag"),M=Object,$="Arguments"==_(function(){return arguments}());i.exports=m?_:function(i){var s,u,m;return void 0===i?"Undefined":null===i?"Null":"string"==typeof(u=function(i,s){try{return i[s]}catch(i){}}(s=M(i),j))?u:$?_(s):"Object"==(m=_(s))&&v(s.callee)?"Arguments":m}},23489:(i,s,u)=>{var m=u(90953),v=u(31136),_=u(49677),j=u(65988);i.exports=function(i,s,u){for(var M=v(s),$=j.f,W=_.f,X=0;X{var m=u(95981);i.exports=!m((function(){function F(){}return F.prototype.constructor=null,Object.getPrototypeOf(new F)!==F.prototype}))},23538:i=>{i.exports=function(i,s){return{value:i,done:s}}},32029:(i,s,u)=>{var m=u(55746),v=u(65988),_=u(31887);i.exports=m?function(i,s,u){return v.f(i,s,_(1,u))}:function(i,s,u){return i[s]=u,i}},31887:i=>{i.exports=function(i,s){return{enumerable:!(1&i),configurable:!(2&i),writable:!(4&i),value:s}}},95929:(i,s,u)=>{var m=u(32029);i.exports=function(i,s,u,v){return v&&v.enumerable?i[s]=u:m(i,s,u),i}},75609:(i,s,u)=>{var m=u(21899),v=Object.defineProperty;i.exports=function(i,s){try{v(m,i,{value:s,configurable:!0,writable:!0})}catch(u){m[i]=s}return s}},55746:(i,s,u)=>{var m=u(95981);i.exports=!m((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},76616:i=>{var s="object"==typeof document&&document.all,u=void 0===s&&void 0!==s;i.exports={all:s,IS_HTMLDDA:u}},61333:(i,s,u)=>{var m=u(21899),v=u(10941),_=m.document,j=v(_)&&v(_.createElement);i.exports=function(i){return j?_.createElement(i):{}}},63281:i=>{i.exports={CSSRuleList:0,CSSStyleDeclaration:0,CSSValueList:0,ClientRectList:0,DOMRectList:0,DOMStringList:0,DOMTokenList:1,DataTransferItemList:0,FileList:0,HTMLAllCollection:0,HTMLCollection:0,HTMLFormElement:0,HTMLSelectElement:0,MediaList:0,MimeTypeArray:0,NamedNodeMap:0,NodeList:1,PaintRequestList:0,Plugin:0,PluginArray:0,SVGLengthList:0,SVGNumberList:0,SVGPathSegList:0,SVGPointList:0,SVGStringList:0,SVGTransformList:0,SourceBufferList:0,StyleSheetList:0,TextTrackCueList:0,TextTrackList:0,TouchList:0}},2861:i=>{i.exports="undefined"!=typeof navigator&&String(navigator.userAgent)||""},53385:(i,s,u)=>{var m,v,_=u(21899),j=u(2861),M=_.process,$=_.Deno,W=M&&M.versions||$&&$.version,X=W&&W.v8;X&&(v=(m=X.split("."))[0]>0&&m[0]<4?1:+(m[0]+m[1])),!v&&j&&(!(m=j.match(/Edge\/(\d+)/))||m[1]>=74)&&(m=j.match(/Chrome\/(\d+)/))&&(v=+m[1]),i.exports=v},35703:(i,s,u)=>{var m=u(54058);i.exports=function(i){return m[i+"Prototype"]}},56759:i=>{i.exports=["constructor","hasOwnProperty","isPrototypeOf","propertyIsEnumerable","toLocaleString","toString","valueOf"]},53995:(i,s,u)=>{var m=u(95329),v=Error,_=m("".replace),j=String(v("zxcasd").stack),M=/\n\s*at [^:]*:[^\n]*/,$=M.test(j);i.exports=function(i,s){if($&&"string"==typeof i&&!v.prepareStackTrace)for(;s--;)i=_(i,M,"");return i}},79585:(i,s,u)=>{var m=u(32029),v=u(53995),_=u(18780),j=Error.captureStackTrace;i.exports=function(i,s,u,M){_&&(j?j(i,s):m(i,"stack",v(u,M)))}},18780:(i,s,u)=>{var m=u(95981),v=u(31887);i.exports=!m((function(){var i=Error("a");return!("stack"in i)||(Object.defineProperty(i,"stack",v(1,7)),7!==i.stack)}))},76887:(i,s,u)=>{"use strict";var m=u(21899),v=u(79730),_=u(97484),j=u(57475),M=u(49677).f,$=u(37252),W=u(54058),X=u(86843),Y=u(32029),Z=u(90953),wrapConstructor=function(i){var Wrapper=function(s,u,m){if(this instanceof Wrapper){switch(arguments.length){case 0:return new i;case 1:return new i(s);case 2:return new i(s,u)}return new i(s,u,m)}return v(i,this,arguments)};return Wrapper.prototype=i.prototype,Wrapper};i.exports=function(i,s){var u,v,ee,ie,ae,le,ce,pe,de,fe=i.target,ye=i.global,be=i.stat,_e=i.proto,we=ye?m:be?m[fe]:(m[fe]||{}).prototype,Se=ye?W:W[fe]||Y(W,fe,{})[fe],xe=Se.prototype;for(ie in s)v=!(u=$(ye?ie:fe+(be?".":"#")+ie,i.forced))&&we&&Z(we,ie),le=Se[ie],v&&(ce=i.dontCallGetSet?(de=M(we,ie))&&de.value:we[ie]),ae=v&&ce?ce:s[ie],v&&typeof le==typeof ae||(pe=i.bind&&v?X(ae,m):i.wrap&&v?wrapConstructor(ae):_e&&j(ae)?_(ae):ae,(i.sham||ae&&ae.sham||le&&le.sham)&&Y(pe,"sham",!0),Y(Se,ie,pe),_e&&(Z(W,ee=fe+"Prototype")||Y(W,ee,{}),Y(W[ee],ie,ae),i.real&&xe&&(u||!xe[ie])&&Y(xe,ie,ae)))}},95981:i=>{i.exports=function(i){try{return!!i()}catch(i){return!0}}},79730:(i,s,u)=>{var m=u(18285),v=Function.prototype,_=v.apply,j=v.call;i.exports="object"==typeof Reflect&&Reflect.apply||(m?j.bind(_):function(){return j.apply(_,arguments)})},86843:(i,s,u)=>{var m=u(97484),v=u(24883),_=u(18285),j=m(m.bind);i.exports=function(i,s){return v(i),void 0===s?i:_?j(i,s):function(){return i.apply(s,arguments)}}},18285:(i,s,u)=>{var m=u(95981);i.exports=!m((function(){var i=function(){}.bind();return"function"!=typeof i||i.hasOwnProperty("prototype")}))},98308:(i,s,u)=>{"use strict";var m=u(95329),v=u(24883),_=u(10941),j=u(90953),M=u(93765),$=u(18285),W=Function,X=m([].concat),Y=m([].join),Z={};i.exports=$?W.bind:function bind(i){var s=v(this),u=s.prototype,m=M(arguments,1),$=function bound(){var u=X(m,M(arguments));return this instanceof $?function(i,s,u){if(!j(Z,s)){for(var m=[],v=0;v{var m=u(18285),v=Function.prototype.call;i.exports=m?v.bind(v):function(){return v.apply(v,arguments)}},79417:(i,s,u)=>{var m=u(55746),v=u(90953),_=Function.prototype,j=m&&Object.getOwnPropertyDescriptor,M=v(_,"name"),$=M&&"something"===function something(){}.name,W=M&&(!m||m&&j(_,"name").configurable);i.exports={EXISTS:M,PROPER:$,CONFIGURABLE:W}},45526:(i,s,u)=>{var m=u(95329),v=u(24883);i.exports=function(i,s,u){try{return m(v(Object.getOwnPropertyDescriptor(i,s)[u]))}catch(i){}}},97484:(i,s,u)=>{var m=u(82532),v=u(95329);i.exports=function(i){if("Function"===m(i))return v(i)}},95329:(i,s,u)=>{var m=u(18285),v=Function.prototype,_=v.call,j=m&&v.bind.bind(_,_);i.exports=m?j:function(i){return function(){return _.apply(i,arguments)}}},626:(i,s,u)=>{var m=u(54058),v=u(21899),_=u(57475),aFunction=function(i){return _(i)?i:void 0};i.exports=function(i,s){return arguments.length<2?aFunction(m[i])||aFunction(v[i]):m[i]&&m[i][s]||v[i]&&v[i][s]}},22902:(i,s,u)=>{var m=u(9697),v=u(14229),_=u(82119),j=u(12077),M=u(99813)("iterator");i.exports=function(i){if(!_(i))return v(i,M)||v(i,"@@iterator")||j[m(i)]}},53476:(i,s,u)=>{var m=u(78834),v=u(24883),_=u(96059),j=u(69826),M=u(22902),$=TypeError;i.exports=function(i,s){var u=arguments.length<2?M(i):s;if(v(u))return _(m(u,i));throw $(j(i)+" is not iterable")}},14229:(i,s,u)=>{var m=u(24883),v=u(82119);i.exports=function(i,s){var u=i[s];return v(u)?void 0:m(u)}},21899:function(i,s,u){var check=function(i){return i&&i.Math==Math&&i};i.exports=check("object"==typeof globalThis&&globalThis)||check("object"==typeof window&&window)||check("object"==typeof self&&self)||check("object"==typeof u.g&&u.g)||function(){return this}()||this||Function("return this")()},90953:(i,s,u)=>{var m=u(95329),v=u(89678),_=m({}.hasOwnProperty);i.exports=Object.hasOwn||function hasOwn(i,s){return _(v(i),s)}},27748:i=>{i.exports={}},15463:(i,s,u)=>{var m=u(626);i.exports=m("document","documentElement")},2840:(i,s,u)=>{var m=u(55746),v=u(95981),_=u(61333);i.exports=!m&&!v((function(){return 7!=Object.defineProperty(_("div"),"a",{get:function(){return 7}}).a}))},37026:(i,s,u)=>{var m=u(95329),v=u(95981),_=u(82532),j=Object,M=m("".split);i.exports=v((function(){return!j("z").propertyIsEnumerable(0)}))?function(i){return"String"==_(i)?M(i,""):j(i)}:j},70926:(i,s,u)=>{var m=u(57475),v=u(10941),_=u(88929);i.exports=function(i,s,u){var j,M;return _&&m(j=s.constructor)&&j!==u&&v(M=j.prototype)&&M!==u.prototype&&_(i,M),i}},53794:(i,s,u)=>{var m=u(10941),v=u(32029);i.exports=function(i,s){m(s)&&"cause"in s&&v(i,"cause",s.cause)}},45402:(i,s,u)=>{var m,v,_,j=u(47093),M=u(21899),$=u(10941),W=u(32029),X=u(90953),Y=u(63030),Z=u(44262),ee=u(27748),ie="Object already initialized",ae=M.TypeError,le=M.WeakMap;if(j||Y.state){var ce=Y.state||(Y.state=new le);ce.get=ce.get,ce.has=ce.has,ce.set=ce.set,m=function(i,s){if(ce.has(i))throw ae(ie);return s.facade=i,ce.set(i,s),s},v=function(i){return ce.get(i)||{}},_=function(i){return ce.has(i)}}else{var pe=Z("state");ee[pe]=!0,m=function(i,s){if(X(i,pe))throw ae(ie);return s.facade=i,W(i,pe,s),s},v=function(i){return X(i,pe)?i[pe]:{}},_=function(i){return X(i,pe)}}i.exports={set:m,get:v,has:_,enforce:function(i){return _(i)?v(i):m(i,{})},getterFor:function(i){return function(s){var u;if(!$(s)||(u=v(s)).type!==i)throw ae("Incompatible receiver, "+i+" required");return u}}}},6782:(i,s,u)=>{var m=u(99813),v=u(12077),_=m("iterator"),j=Array.prototype;i.exports=function(i){return void 0!==i&&(v.Array===i||j[_]===i)}},57475:(i,s,u)=>{var m=u(76616),v=m.all;i.exports=m.IS_HTMLDDA?function(i){return"function"==typeof i||i===v}:function(i){return"function"==typeof i}},37252:(i,s,u)=>{var m=u(95981),v=u(57475),_=/#|\.prototype\./,isForced=function(i,s){var u=M[j(i)];return u==W||u!=$&&(v(s)?m(s):!!s)},j=isForced.normalize=function(i){return String(i).replace(_,".").toLowerCase()},M=isForced.data={},$=isForced.NATIVE="N",W=isForced.POLYFILL="P";i.exports=isForced},82119:i=>{i.exports=function(i){return null==i}},10941:(i,s,u)=>{var m=u(57475),v=u(76616),_=v.all;i.exports=v.IS_HTMLDDA?function(i){return"object"==typeof i?null!==i:m(i)||i===_}:function(i){return"object"==typeof i?null!==i:m(i)}},82529:i=>{i.exports=!0},56664:(i,s,u)=>{var m=u(626),v=u(57475),_=u(7046),j=u(32302),M=Object;i.exports=j?function(i){return"symbol"==typeof i}:function(i){var s=m("Symbol");return v(s)&&_(s.prototype,M(i))}},93091:(i,s,u)=>{var m=u(86843),v=u(78834),_=u(96059),j=u(69826),M=u(6782),$=u(10623),W=u(7046),X=u(53476),Y=u(22902),Z=u(7609),ee=TypeError,Result=function(i,s){this.stopped=i,this.result=s},ie=Result.prototype;i.exports=function(i,s,u){var ae,le,ce,pe,de,fe,ye,be=u&&u.that,_e=!(!u||!u.AS_ENTRIES),we=!(!u||!u.IS_RECORD),Se=!(!u||!u.IS_ITERATOR),xe=!(!u||!u.INTERRUPTED),Ie=m(s,be),stop=function(i){return ae&&Z(ae,"normal",i),new Result(!0,i)},callFn=function(i){return _e?(_(i),xe?Ie(i[0],i[1],stop):Ie(i[0],i[1])):xe?Ie(i,stop):Ie(i)};if(we)ae=i.iterator;else if(Se)ae=i;else{if(!(le=Y(i)))throw ee(j(i)+" is not iterable");if(M(le)){for(ce=0,pe=$(i);pe>ce;ce++)if((de=callFn(i[ce]))&&W(ie,de))return de;return new Result(!1)}ae=X(i,le)}for(fe=we?i.next:ae.next;!(ye=v(fe,ae)).done;){try{de=callFn(ye.value)}catch(i){Z(ae,"throw",i)}if("object"==typeof de&&de&&W(ie,de))return de}return new Result(!1)}},7609:(i,s,u)=>{var m=u(78834),v=u(96059),_=u(14229);i.exports=function(i,s,u){var j,M;v(i);try{if(!(j=_(i,"return"))){if("throw"===s)throw u;return u}j=m(j,i)}catch(i){M=!0,j=i}if("throw"===s)throw u;if(M)throw j;return v(j),u}},53847:(i,s,u)=>{"use strict";var m=u(35143).IteratorPrototype,v=u(29290),_=u(31887),j=u(90904),M=u(12077),returnThis=function(){return this};i.exports=function(i,s,u,$){var W=s+" Iterator";return i.prototype=v(m,{next:_(+!$,u)}),j(i,W,!1,!0),M[W]=returnThis,i}},75105:(i,s,u)=>{"use strict";var m=u(76887),v=u(78834),_=u(82529),j=u(79417),M=u(57475),$=u(53847),W=u(249),X=u(88929),Y=u(90904),Z=u(32029),ee=u(95929),ie=u(99813),ae=u(12077),le=u(35143),ce=j.PROPER,pe=j.CONFIGURABLE,de=le.IteratorPrototype,fe=le.BUGGY_SAFARI_ITERATORS,ye=ie("iterator"),be="keys",_e="values",we="entries",returnThis=function(){return this};i.exports=function(i,s,u,j,ie,le,Se){$(u,s,j);var xe,Ie,Pe,getIterationMethod=function(i){if(i===ie&&Ve)return Ve;if(!fe&&i in qe)return qe[i];switch(i){case be:return function keys(){return new u(this,i)};case _e:return function values(){return new u(this,i)};case we:return function entries(){return new u(this,i)}}return function(){return new u(this)}},Te=s+" Iterator",Re=!1,qe=i.prototype,ze=qe[ye]||qe["@@iterator"]||ie&&qe[ie],Ve=!fe&&ze||getIterationMethod(ie),We="Array"==s&&qe.entries||ze;if(We&&(xe=W(We.call(new i)))!==Object.prototype&&xe.next&&(_||W(xe)===de||(X?X(xe,de):M(xe[ye])||ee(xe,ye,returnThis)),Y(xe,Te,!0,!0),_&&(ae[Te]=returnThis)),ce&&ie==_e&&ze&&ze.name!==_e&&(!_&&pe?Z(qe,"name",_e):(Re=!0,Ve=function values(){return v(ze,this)})),ie)if(Ie={values:getIterationMethod(_e),keys:le?Ve:getIterationMethod(be),entries:getIterationMethod(we)},Se)for(Pe in Ie)(fe||Re||!(Pe in qe))&&ee(qe,Pe,Ie[Pe]);else m({target:s,proto:!0,forced:fe||Re},Ie);return _&&!Se||qe[ye]===Ve||ee(qe,ye,Ve,{name:ie}),ae[s]=Ve,Ie}},35143:(i,s,u)=>{"use strict";var m,v,_,j=u(95981),M=u(57475),$=u(10941),W=u(29290),X=u(249),Y=u(95929),Z=u(99813),ee=u(82529),ie=Z("iterator"),ae=!1;[].keys&&("next"in(_=[].keys())?(v=X(X(_)))!==Object.prototype&&(m=v):ae=!0),!$(m)||j((function(){var i={};return m[ie].call(i)!==i}))?m={}:ee&&(m=W(m)),M(m[ie])||Y(m,ie,(function(){return this})),i.exports={IteratorPrototype:m,BUGGY_SAFARI_ITERATORS:ae}},12077:i=>{i.exports={}},10623:(i,s,u)=>{var m=u(43057);i.exports=function(i){return m(i.length)}},35331:i=>{var s=Math.ceil,u=Math.floor;i.exports=Math.trunc||function trunc(i){var m=+i;return(m>0?u:s)(m)}},14649:(i,s,u)=>{var m=u(85803);i.exports=function(i,s){return void 0===i?arguments.length<2?"":s:m(i)}},24420:(i,s,u)=>{"use strict";var m=u(55746),v=u(95329),_=u(78834),j=u(95981),M=u(14771),$=u(87857),W=u(36760),X=u(89678),Y=u(37026),Z=Object.assign,ee=Object.defineProperty,ie=v([].concat);i.exports=!Z||j((function(){if(m&&1!==Z({b:1},Z(ee({},"a",{enumerable:!0,get:function(){ee(this,"b",{value:3,enumerable:!1})}}),{b:2})).b)return!0;var i={},s={},u=Symbol(),v="abcdefghijklmnopqrst";return i[u]=7,v.split("").forEach((function(i){s[i]=i})),7!=Z({},i)[u]||M(Z({},s)).join("")!=v}))?function assign(i,s){for(var u=X(i),v=arguments.length,j=1,Z=$.f,ee=W.f;v>j;)for(var ae,le=Y(arguments[j++]),ce=Z?ie(M(le),Z(le)):M(le),pe=ce.length,de=0;pe>de;)ae=ce[de++],m&&!_(ee,le,ae)||(u[ae]=le[ae]);return u}:Z},29290:(i,s,u)=>{var m,v=u(96059),_=u(59938),j=u(56759),M=u(27748),$=u(15463),W=u(61333),X=u(44262),Y="prototype",Z="script",ee=X("IE_PROTO"),EmptyConstructor=function(){},scriptTag=function(i){return"<"+Z+">"+i+""},NullProtoObjectViaActiveX=function(i){i.write(scriptTag("")),i.close();var s=i.parentWindow.Object;return i=null,s},NullProtoObject=function(){try{m=new ActiveXObject("htmlfile")}catch(i){}var i,s,u;NullProtoObject="undefined"!=typeof document?document.domain&&m?NullProtoObjectViaActiveX(m):(s=W("iframe"),u="java"+Z+":",s.style.display="none",$.appendChild(s),s.src=String(u),(i=s.contentWindow.document).open(),i.write(scriptTag("document.F=Object")),i.close(),i.F):NullProtoObjectViaActiveX(m);for(var v=j.length;v--;)delete NullProtoObject[Y][j[v]];return NullProtoObject()};M[ee]=!0,i.exports=Object.create||function create(i,s){var u;return null!==i?(EmptyConstructor[Y]=v(i),u=new EmptyConstructor,EmptyConstructor[Y]=null,u[ee]=i):u=NullProtoObject(),void 0===s?u:_.f(u,s)}},59938:(i,s,u)=>{var m=u(55746),v=u(83937),_=u(65988),j=u(96059),M=u(74529),$=u(14771);s.f=m&&!v?Object.defineProperties:function defineProperties(i,s){j(i);for(var u,m=M(s),v=$(s),W=v.length,X=0;W>X;)_.f(i,u=v[X++],m[u]);return i}},65988:(i,s,u)=>{var m=u(55746),v=u(2840),_=u(83937),j=u(96059),M=u(83894),$=TypeError,W=Object.defineProperty,X=Object.getOwnPropertyDescriptor,Y="enumerable",Z="configurable",ee="writable";s.f=m?_?function defineProperty(i,s,u){if(j(i),s=M(s),j(u),"function"==typeof i&&"prototype"===s&&"value"in u&&ee in u&&!u[ee]){var m=X(i,s);m&&m[ee]&&(i[s]=u.value,u={configurable:Z in u?u[Z]:m[Z],enumerable:Y in u?u[Y]:m[Y],writable:!1})}return W(i,s,u)}:W:function defineProperty(i,s,u){if(j(i),s=M(s),j(u),v)try{return W(i,s,u)}catch(i){}if("get"in u||"set"in u)throw $("Accessors not supported");return"value"in u&&(i[s]=u.value),i}},49677:(i,s,u)=>{var m=u(55746),v=u(78834),_=u(36760),j=u(31887),M=u(74529),$=u(83894),W=u(90953),X=u(2840),Y=Object.getOwnPropertyDescriptor;s.f=m?Y:function getOwnPropertyDescriptor(i,s){if(i=M(i),s=$(s),X)try{return Y(i,s)}catch(i){}if(W(i,s))return j(!v(_.f,i,s),i[s])}},10946:(i,s,u)=>{var m=u(55629),v=u(56759).concat("length","prototype");s.f=Object.getOwnPropertyNames||function getOwnPropertyNames(i){return m(i,v)}},87857:(i,s)=>{s.f=Object.getOwnPropertySymbols},249:(i,s,u)=>{var m=u(90953),v=u(57475),_=u(89678),j=u(44262),M=u(91310),$=j("IE_PROTO"),W=Object,X=W.prototype;i.exports=M?W.getPrototypeOf:function(i){var s=_(i);if(m(s,$))return s[$];var u=s.constructor;return v(u)&&s instanceof u?u.prototype:s instanceof W?X:null}},7046:(i,s,u)=>{var m=u(95329);i.exports=m({}.isPrototypeOf)},55629:(i,s,u)=>{var m=u(95329),v=u(90953),_=u(74529),j=u(31692).indexOf,M=u(27748),$=m([].push);i.exports=function(i,s){var u,m=_(i),W=0,X=[];for(u in m)!v(M,u)&&v(m,u)&&$(X,u);for(;s.length>W;)v(m,u=s[W++])&&(~j(X,u)||$(X,u));return X}},14771:(i,s,u)=>{var m=u(55629),v=u(56759);i.exports=Object.keys||function keys(i){return m(i,v)}},36760:(i,s)=>{"use strict";var u={}.propertyIsEnumerable,m=Object.getOwnPropertyDescriptor,v=m&&!u.call({1:2},1);s.f=v?function propertyIsEnumerable(i){var s=m(this,i);return!!s&&s.enumerable}:u},88929:(i,s,u)=>{var m=u(45526),v=u(96059),_=u(11851);i.exports=Object.setPrototypeOf||("__proto__"in{}?function(){var i,s=!1,u={};try{(i=m(Object.prototype,"__proto__","set"))(u,[]),s=u instanceof Array}catch(i){}return function setPrototypeOf(u,m){return v(u),_(m),s?i(u,m):u.__proto__=m,u}}():void 0)},95623:(i,s,u)=>{"use strict";var m=u(22885),v=u(9697);i.exports=m?{}.toString:function toString(){return"[object "+v(this)+"]"}},39811:(i,s,u)=>{var m=u(78834),v=u(57475),_=u(10941),j=TypeError;i.exports=function(i,s){var u,M;if("string"===s&&v(u=i.toString)&&!_(M=m(u,i)))return M;if(v(u=i.valueOf)&&!_(M=m(u,i)))return M;if("string"!==s&&v(u=i.toString)&&!_(M=m(u,i)))return M;throw j("Can't convert object to primitive value")}},31136:(i,s,u)=>{var m=u(626),v=u(95329),_=u(10946),j=u(87857),M=u(96059),$=v([].concat);i.exports=m("Reflect","ownKeys")||function ownKeys(i){var s=_.f(M(i)),u=j.f;return u?$(s,u(i)):s}},54058:i=>{i.exports={}},9056:(i,s,u)=>{var m=u(65988).f;i.exports=function(i,s,u){u in i||m(i,u,{configurable:!0,get:function(){return s[u]},set:function(i){s[u]=i}})}},48219:(i,s,u)=>{var m=u(82119),v=TypeError;i.exports=function(i){if(m(i))throw v("Can't call method on "+i);return i}},90904:(i,s,u)=>{var m=u(22885),v=u(65988).f,_=u(32029),j=u(90953),M=u(95623),$=u(99813)("toStringTag");i.exports=function(i,s,u,W){if(i){var X=u?i:i.prototype;j(X,$)||v(X,$,{configurable:!0,value:s}),W&&!m&&_(X,"toString",M)}}},44262:(i,s,u)=>{var m=u(68726),v=u(99418),_=m("keys");i.exports=function(i){return _[i]||(_[i]=v(i))}},63030:(i,s,u)=>{var m=u(21899),v=u(75609),_="__core-js_shared__",j=m[_]||v(_,{});i.exports=j},68726:(i,s,u)=>{var m=u(82529),v=u(63030);(i.exports=function(i,s){return v[i]||(v[i]=void 0!==s?s:{})})("versions",[]).push({version:"3.31.1",mode:m?"pure":"global",copyright:"© 2014-2023 Denis Pushkarev (zloirock.ru)",license:"https://github.com/zloirock/core-js/blob/v3.31.1/LICENSE",source:"https://github.com/zloirock/core-js"})},64620:(i,s,u)=>{var m=u(95329),v=u(62435),_=u(85803),j=u(48219),M=m("".charAt),$=m("".charCodeAt),W=m("".slice),createMethod=function(i){return function(s,u){var m,X,Y=_(j(s)),Z=v(u),ee=Y.length;return Z<0||Z>=ee?i?"":void 0:(m=$(Y,Z))<55296||m>56319||Z+1===ee||(X=$(Y,Z+1))<56320||X>57343?i?M(Y,Z):m:i?W(Y,Z,Z+2):X-56320+(m-55296<<10)+65536}};i.exports={codeAt:createMethod(!1),charAt:createMethod(!0)}},63405:(i,s,u)=>{var m=u(53385),v=u(95981),_=u(21899).String;i.exports=!!Object.getOwnPropertySymbols&&!v((function(){var i=Symbol();return!_(i)||!(Object(i)instanceof Symbol)||!Symbol.sham&&m&&m<41}))},59413:(i,s,u)=>{var m=u(62435),v=Math.max,_=Math.min;i.exports=function(i,s){var u=m(i);return u<0?v(u+s,0):_(u,s)}},74529:(i,s,u)=>{var m=u(37026),v=u(48219);i.exports=function(i){return m(v(i))}},62435:(i,s,u)=>{var m=u(35331);i.exports=function(i){var s=+i;return s!=s||0===s?0:m(s)}},43057:(i,s,u)=>{var m=u(62435),v=Math.min;i.exports=function(i){return i>0?v(m(i),9007199254740991):0}},89678:(i,s,u)=>{var m=u(48219),v=Object;i.exports=function(i){return v(m(i))}},46935:(i,s,u)=>{var m=u(78834),v=u(10941),_=u(56664),j=u(14229),M=u(39811),$=u(99813),W=TypeError,X=$("toPrimitive");i.exports=function(i,s){if(!v(i)||_(i))return i;var u,$=j(i,X);if($){if(void 0===s&&(s="default"),u=m($,i,s),!v(u)||_(u))return u;throw W("Can't convert object to primitive value")}return void 0===s&&(s="number"),M(i,s)}},83894:(i,s,u)=>{var m=u(46935),v=u(56664);i.exports=function(i){var s=m(i,"string");return v(s)?s:s+""}},22885:(i,s,u)=>{var m={};m[u(99813)("toStringTag")]="z",i.exports="[object z]"===String(m)},85803:(i,s,u)=>{var m=u(9697),v=String;i.exports=function(i){if("Symbol"===m(i))throw TypeError("Cannot convert a Symbol value to a string");return v(i)}},69826:i=>{var s=String;i.exports=function(i){try{return s(i)}catch(i){return"Object"}}},99418:(i,s,u)=>{var m=u(95329),v=0,_=Math.random(),j=m(1..toString);i.exports=function(i){return"Symbol("+(void 0===i?"":i)+")_"+j(++v+_,36)}},32302:(i,s,u)=>{var m=u(63405);i.exports=m&&!Symbol.sham&&"symbol"==typeof Symbol.iterator},83937:(i,s,u)=>{var m=u(55746),v=u(95981);i.exports=m&&v((function(){return 42!=Object.defineProperty((function(){}),"prototype",{value:42,writable:!1}).prototype}))},47093:(i,s,u)=>{var m=u(21899),v=u(57475),_=m.WeakMap;i.exports=v(_)&&/native code/.test(String(_))},99813:(i,s,u)=>{var m=u(21899),v=u(68726),_=u(90953),j=u(99418),M=u(63405),$=u(32302),W=m.Symbol,X=v("wks"),Y=$?W.for||W:W&&W.withoutSetter||j;i.exports=function(i){return _(X,i)||(X[i]=M&&_(W,i)?W[i]:Y("Symbol."+i)),X[i]}},62864:(i,s,u)=>{"use strict";var m=u(626),v=u(90953),_=u(32029),j=u(7046),M=u(88929),$=u(23489),W=u(9056),X=u(70926),Y=u(14649),Z=u(53794),ee=u(79585),ie=u(55746),ae=u(82529);i.exports=function(i,s,u,le){var ce="stackTraceLimit",pe=le?2:1,de=i.split("."),fe=de[de.length-1],ye=m.apply(null,de);if(ye){var be=ye.prototype;if(!ae&&v(be,"cause")&&delete be.cause,!u)return ye;var _e=m("Error"),we=s((function(i,s){var u=Y(le?s:i,void 0),m=le?new ye(i):new ye;return void 0!==u&&_(m,"message",u),ee(m,we,m.stack,2),this&&j(be,this)&&X(m,this,we),arguments.length>pe&&Z(m,arguments[pe]),m}));if(we.prototype=be,"Error"!==fe?M?M(we,_e):$(we,_e,{name:!0}):ie&&ce in ye&&(W(we,ye,ce),W(we,ye,"prepareStackTrace")),$(we,ye),!ae)try{be.name!==fe&&_(be,"name",fe),be.constructor=we}catch(i){}return we}}},24415:(i,s,u)=>{var m=u(76887),v=u(626),_=u(79730),j=u(95981),M=u(62864),$="AggregateError",W=v($),X=!j((function(){return 1!==W([1]).errors[0]}))&&j((function(){return 7!==W([1],$,{cause:7}).cause}));m({global:!0,constructor:!0,arity:2,forced:X},{AggregateError:M($,(function(i){return function AggregateError(s,u){return _(i,this,arguments)}}),X,!0)})},49812:(i,s,u)=>{"use strict";var m=u(76887),v=u(7046),_=u(249),j=u(88929),M=u(23489),$=u(29290),W=u(32029),X=u(31887),Y=u(53794),Z=u(79585),ee=u(93091),ie=u(14649),ae=u(99813)("toStringTag"),le=Error,ce=[].push,pe=function AggregateError(i,s){var u,m=v(de,this);j?u=j(le(),m?_(this):de):(u=m?this:$(de),W(u,ae,"Error")),void 0!==s&&W(u,"message",ie(s)),Z(u,pe,u.stack,1),arguments.length>2&&Y(u,arguments[2]);var M=[];return ee(i,ce,{that:M}),W(u,"errors",M),u};j?j(pe,le):M(pe,le,{name:!0});var de=pe.prototype=$(le.prototype,{constructor:X(1,pe),message:X(1,""),name:X(1,"AggregateError")});m({global:!0,constructor:!0,arity:2},{AggregateError:pe})},47627:(i,s,u)=>{u(49812)},66274:(i,s,u)=>{"use strict";var m=u(74529),v=u(18479),_=u(12077),j=u(45402),M=u(65988).f,$=u(75105),W=u(23538),X=u(82529),Y=u(55746),Z="Array Iterator",ee=j.set,ie=j.getterFor(Z);i.exports=$(Array,"Array",(function(i,s){ee(this,{type:Z,target:m(i),index:0,kind:s})}),(function(){var i=ie(this),s=i.target,u=i.kind,m=i.index++;return!s||m>=s.length?(i.target=void 0,W(void 0,!0)):W("keys"==u?m:"values"==u?s[m]:[m,s[m]],!1)}),"values");var ae=_.Arguments=_.Array;if(v("keys"),v("values"),v("entries"),!X&&Y&&"values"!==ae.name)try{M(ae,"name",{value:"values"})}catch(i){}},61181:(i,s,u)=>{var m=u(76887),v=u(21899),_=u(79730),j=u(62864),M="WebAssembly",$=v[M],W=7!==Error("e",{cause:7}).cause,exportGlobalErrorCauseWrapper=function(i,s){var u={};u[i]=j(i,s,W),m({global:!0,constructor:!0,arity:1,forced:W},u)},exportWebAssemblyErrorCauseWrapper=function(i,s){if($&&$[i]){var u={};u[i]=j(M+"."+i,s,W),m({target:M,stat:!0,constructor:!0,arity:1,forced:W},u)}};exportGlobalErrorCauseWrapper("Error",(function(i){return function Error(s){return _(i,this,arguments)}})),exportGlobalErrorCauseWrapper("EvalError",(function(i){return function EvalError(s){return _(i,this,arguments)}})),exportGlobalErrorCauseWrapper("RangeError",(function(i){return function RangeError(s){return _(i,this,arguments)}})),exportGlobalErrorCauseWrapper("ReferenceError",(function(i){return function ReferenceError(s){return _(i,this,arguments)}})),exportGlobalErrorCauseWrapper("SyntaxError",(function(i){return function SyntaxError(s){return _(i,this,arguments)}})),exportGlobalErrorCauseWrapper("TypeError",(function(i){return function TypeError(s){return _(i,this,arguments)}})),exportGlobalErrorCauseWrapper("URIError",(function(i){return function URIError(s){return _(i,this,arguments)}})),exportWebAssemblyErrorCauseWrapper("CompileError",(function(i){return function CompileError(s){return _(i,this,arguments)}})),exportWebAssemblyErrorCauseWrapper("LinkError",(function(i){return function LinkError(s){return _(i,this,arguments)}})),exportWebAssemblyErrorCauseWrapper("RuntimeError",(function(i){return function RuntimeError(s){return _(i,this,arguments)}}))},73381:(i,s,u)=>{var m=u(76887),v=u(98308);m({target:"Function",proto:!0,forced:Function.bind!==v},{bind:v})},49221:(i,s,u)=>{var m=u(76887),v=u(24420);m({target:"Object",stat:!0,arity:2,forced:Object.assign!==v},{assign:v})},77971:(i,s,u)=>{"use strict";var m=u(64620).charAt,v=u(85803),_=u(45402),j=u(75105),M=u(23538),$="String Iterator",W=_.set,X=_.getterFor($);j(String,"String",(function(i){W(this,{type:$,string:v(i),index:0})}),(function next(){var i,s=X(this),u=s.string,v=s.index;return v>=u.length?M(void 0,!0):(i=m(u,v),s.index+=i.length,M(i,!1))}))},89731:(i,s,u)=>{u(47627)},7634:(i,s,u)=>{u(66274);var m=u(63281),v=u(21899),_=u(9697),j=u(32029),M=u(12077),$=u(99813)("toStringTag");for(var W in m){var X=v[W],Y=X&&X.prototype;Y&&_(Y)!==$&&j(Y,$,W),M[W]=M.Array}},18957:(i,s,u)=>{u(89731);var m=u(50415);u(7634),i.exports=m},28196:(i,s,u)=>{var m=u(16246);i.exports=m},63383:(i,s,u)=>{var m=u(45999);i.exports=m},8269:function(i,s,u){var m;m=void 0!==u.g?u.g:this,i.exports=function(i){if(i.CSS&&i.CSS.escape)return i.CSS.escape;var cssEscape=function(i){if(0==arguments.length)throw new TypeError("`CSS.escape` requires an argument.");for(var s,u=String(i),m=u.length,v=-1,_="",j=u.charCodeAt(0);++v=1&&s<=31||127==s||0==v&&s>=48&&s<=57||1==v&&s>=48&&s<=57&&45==j?"\\"+s.toString(16)+" ":0==v&&1==m&&45==s||!(s>=128||45==s||95==s||s>=48&&s<=57||s>=65&&s<=90||s>=97&&s<=122)?"\\"+u.charAt(v):u.charAt(v):_+="�";return _};return i.CSS||(i.CSS={}),i.CSS.escape=cssEscape,cssEscape}(m)},27698:(i,s,u)=>{"use strict";var m=u(48764).Buffer;function isSpecificValue(i){return i instanceof m||i instanceof Date||i instanceof RegExp}function cloneSpecificValue(i){if(i instanceof m){var s=m.alloc?m.alloc(i.length):new m(i.length);return i.copy(s),s}if(i instanceof Date)return new Date(i.getTime());if(i instanceof RegExp)return new RegExp(i);throw new Error("Unexpected situation")}function deepCloneArray(i){var s=[];return i.forEach((function(i,u){"object"==typeof i&&null!==i?Array.isArray(i)?s[u]=deepCloneArray(i):isSpecificValue(i)?s[u]=cloneSpecificValue(i):s[u]=v({},i):s[u]=i})),s}function safeGetProperty(i,s){return"__proto__"===s?void 0:i[s]}var v=i.exports=function(){if(arguments.length<1||"object"!=typeof arguments[0])return!1;if(arguments.length<2)return arguments[0];var i,s,u=arguments[0];return Array.prototype.slice.call(arguments,1).forEach((function(m){"object"!=typeof m||null===m||Array.isArray(m)||Object.keys(m).forEach((function(_){return s=safeGetProperty(u,_),(i=safeGetProperty(m,_))===u?void 0:"object"!=typeof i||null===i?void(u[_]=i):Array.isArray(i)?void(u[_]=deepCloneArray(i)):isSpecificValue(i)?void(u[_]=cloneSpecificValue(i)):"object"!=typeof s||null===s||Array.isArray(s)?void(u[_]=v({},i)):void(u[_]=v(s,i))}))})),u}},9996:i=>{"use strict";var s=function isMergeableObject(i){return function isNonNullObject(i){return!!i&&"object"==typeof i}(i)&&!function isSpecial(i){var s=Object.prototype.toString.call(i);return"[object RegExp]"===s||"[object Date]"===s||function isReactElement(i){return i.$$typeof===u}(i)}(i)};var u="function"==typeof Symbol&&Symbol.for?Symbol.for("react.element"):60103;function cloneUnlessOtherwiseSpecified(i,s){return!1!==s.clone&&s.isMergeableObject(i)?deepmerge(function emptyTarget(i){return Array.isArray(i)?[]:{}}(i),i,s):i}function defaultArrayMerge(i,s,u){return i.concat(s).map((function(i){return cloneUnlessOtherwiseSpecified(i,u)}))}function getKeys(i){return Object.keys(i).concat(function getEnumerableOwnPropertySymbols(i){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(i).filter((function(s){return Object.propertyIsEnumerable.call(i,s)})):[]}(i))}function propertyIsOnObject(i,s){try{return s in i}catch(i){return!1}}function mergeObject(i,s,u){var m={};return u.isMergeableObject(i)&&getKeys(i).forEach((function(s){m[s]=cloneUnlessOtherwiseSpecified(i[s],u)})),getKeys(s).forEach((function(v){(function propertyIsUnsafe(i,s){return propertyIsOnObject(i,s)&&!(Object.hasOwnProperty.call(i,s)&&Object.propertyIsEnumerable.call(i,s))})(i,v)||(propertyIsOnObject(i,v)&&u.isMergeableObject(s[v])?m[v]=function getMergeFunction(i,s){if(!s.customMerge)return deepmerge;var u=s.customMerge(i);return"function"==typeof u?u:deepmerge}(v,u)(i[v],s[v],u):m[v]=cloneUnlessOtherwiseSpecified(s[v],u))})),m}function deepmerge(i,u,m){(m=m||{}).arrayMerge=m.arrayMerge||defaultArrayMerge,m.isMergeableObject=m.isMergeableObject||s,m.cloneUnlessOtherwiseSpecified=cloneUnlessOtherwiseSpecified;var v=Array.isArray(u);return v===Array.isArray(i)?v?m.arrayMerge(i,u,m):mergeObject(i,u,m):cloneUnlessOtherwiseSpecified(u,m)}deepmerge.all=function deepmergeAll(i,s){if(!Array.isArray(i))throw new Error("first argument should be an array");return i.reduce((function(i,u){return deepmerge(i,u,s)}),{})};var m=deepmerge;i.exports=m},27856:function(i){i.exports=function(){"use strict";const{entries:i,setPrototypeOf:s,isFrozen:u,getPrototypeOf:m,getOwnPropertyDescriptor:v}=Object;let{freeze:_,seal:j,create:M}=Object,{apply:$,construct:W}="undefined"!=typeof Reflect&&Reflect;_||(_=function freeze(i){return i}),j||(j=function seal(i){return i}),$||($=function apply(i,s,u){return i.apply(s,u)}),W||(W=function construct(i,s){return new i(...s)});const X=unapply(Array.prototype.forEach),Y=unapply(Array.prototype.pop),Z=unapply(Array.prototype.push),ee=unapply(String.prototype.toLowerCase),ie=unapply(String.prototype.toString),ae=unapply(String.prototype.match),le=unapply(String.prototype.replace),ce=unapply(String.prototype.indexOf),pe=unapply(String.prototype.trim),de=unapply(RegExp.prototype.test),fe=unconstruct(TypeError);function unapply(i){return function(s){for(var u=arguments.length,m=new Array(u>1?u-1:0),v=1;v2&&void 0!==arguments[2]?arguments[2]:ee;s&&s(i,null);let _=m.length;for(;_--;){let s=m[_];if("string"==typeof s){const i=v(s);i!==s&&(u(m)||(m[_]=i),s=i)}i[s]=!0}return i}function clone(s){const u=M(null);for(const[m,_]of i(s))void 0!==v(s,m)&&(u[m]=_);return u}function lookupGetter(i,s){for(;null!==i;){const u=v(i,s);if(u){if(u.get)return unapply(u.get);if("function"==typeof u.value)return unapply(u.value)}i=m(i)}function fallbackValue(i){return console.warn("fallback value for",i),null}return fallbackValue}const ye=_(["a","abbr","acronym","address","area","article","aside","audio","b","bdi","bdo","big","blink","blockquote","body","br","button","canvas","caption","center","cite","code","col","colgroup","content","data","datalist","dd","decorator","del","details","dfn","dialog","dir","div","dl","dt","element","em","fieldset","figcaption","figure","font","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","img","input","ins","kbd","label","legend","li","main","map","mark","marquee","menu","menuitem","meter","nav","nobr","ol","optgroup","option","output","p","picture","pre","progress","q","rp","rt","ruby","s","samp","section","select","shadow","small","source","spacer","span","strike","strong","style","sub","summary","sup","table","tbody","td","template","textarea","tfoot","th","thead","time","tr","track","tt","u","ul","var","video","wbr"]),be=_(["svg","a","altglyph","altglyphdef","altglyphitem","animatecolor","animatemotion","animatetransform","circle","clippath","defs","desc","ellipse","filter","font","g","glyph","glyphref","hkern","image","line","lineargradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialgradient","rect","stop","style","switch","symbol","text","textpath","title","tref","tspan","view","vkern"]),_e=_(["feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence"]),we=_(["animate","color-profile","cursor","discard","font-face","font-face-format","font-face-name","font-face-src","font-face-uri","foreignobject","hatch","hatchpath","mesh","meshgradient","meshpatch","meshrow","missing-glyph","script","set","solidcolor","unknown","use"]),Se=_(["math","menclose","merror","mfenced","mfrac","mglyph","mi","mlabeledtr","mmultiscripts","mn","mo","mover","mpadded","mphantom","mroot","mrow","ms","mspace","msqrt","mstyle","msub","msup","msubsup","mtable","mtd","mtext","mtr","munder","munderover","mprescripts"]),xe=_(["maction","maligngroup","malignmark","mlongdiv","mscarries","mscarry","msgroup","mstack","msline","msrow","semantics","annotation","annotation-xml","mprescripts","none"]),Ie=_(["#text"]),Pe=_(["accept","action","align","alt","autocapitalize","autocomplete","autopictureinpicture","autoplay","background","bgcolor","border","capture","cellpadding","cellspacing","checked","cite","class","clear","color","cols","colspan","controls","controlslist","coords","crossorigin","datetime","decoding","default","dir","disabled","disablepictureinpicture","disableremoteplayback","download","draggable","enctype","enterkeyhint","face","for","headers","height","hidden","high","href","hreflang","id","inputmode","integrity","ismap","kind","label","lang","list","loading","loop","low","max","maxlength","media","method","min","minlength","multiple","muted","name","nonce","noshade","novalidate","nowrap","open","optimum","pattern","placeholder","playsinline","poster","preload","pubdate","radiogroup","readonly","rel","required","rev","reversed","role","rows","rowspan","spellcheck","scope","selected","shape","size","sizes","span","srclang","start","src","srcset","step","style","summary","tabindex","title","translate","type","usemap","valign","value","width","xmlns","slot"]),Te=_(["accent-height","accumulate","additive","alignment-baseline","ascent","attributename","attributetype","azimuth","basefrequency","baseline-shift","begin","bias","by","class","clip","clippathunits","clip-path","clip-rule","color","color-interpolation","color-interpolation-filters","color-profile","color-rendering","cx","cy","d","dx","dy","diffuseconstant","direction","display","divisor","dur","edgemode","elevation","end","fill","fill-opacity","fill-rule","filter","filterunits","flood-color","flood-opacity","font-family","font-size","font-size-adjust","font-stretch","font-style","font-variant","font-weight","fx","fy","g1","g2","glyph-name","glyphref","gradientunits","gradienttransform","height","href","id","image-rendering","in","in2","k","k1","k2","k3","k4","kerning","keypoints","keysplines","keytimes","lang","lengthadjust","letter-spacing","kernelmatrix","kernelunitlength","lighting-color","local","marker-end","marker-mid","marker-start","markerheight","markerunits","markerwidth","maskcontentunits","maskunits","max","mask","media","method","mode","min","name","numoctaves","offset","operator","opacity","order","orient","orientation","origin","overflow","paint-order","path","pathlength","patterncontentunits","patterntransform","patternunits","points","preservealpha","preserveaspectratio","primitiveunits","r","rx","ry","radius","refx","refy","repeatcount","repeatdur","restart","result","rotate","scale","seed","shape-rendering","specularconstant","specularexponent","spreadmethod","startoffset","stddeviation","stitchtiles","stop-color","stop-opacity","stroke-dasharray","stroke-dashoffset","stroke-linecap","stroke-linejoin","stroke-miterlimit","stroke-opacity","stroke","stroke-width","style","surfacescale","systemlanguage","tabindex","targetx","targety","transform","transform-origin","text-anchor","text-decoration","text-rendering","textlength","type","u1","u2","unicode","values","viewbox","visibility","version","vert-adv-y","vert-origin-x","vert-origin-y","width","word-spacing","wrap","writing-mode","xchannelselector","ychannelselector","x","x1","x2","xmlns","y","y1","y2","z","zoomandpan"]),Re=_(["accent","accentunder","align","bevelled","close","columnsalign","columnlines","columnspan","denomalign","depth","dir","display","displaystyle","encoding","fence","frame","height","href","id","largeop","length","linethickness","lspace","lquote","mathbackground","mathcolor","mathsize","mathvariant","maxsize","minsize","movablelimits","notation","numalign","open","rowalign","rowlines","rowspacing","rowspan","rspace","rquote","scriptlevel","scriptminsize","scriptsizemultiplier","selection","separator","separators","stretchy","subscriptshift","supscriptshift","symmetric","voffset","width","xmlns"]),qe=_(["xlink:href","xml:id","xlink:title","xml:space","xmlns:xlink"]),ze=j(/\{\{[\w\W]*|[\w\W]*\}\}/gm),Ve=j(/<%[\w\W]*|[\w\W]*%>/gm),We=j(/\${[\w\W]*}/gm),He=j(/^data-[\-\w.\u00B7-\uFFFF]/),Xe=j(/^aria-[\-\w]+$/),Ye=j(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|sms|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Qe=j(/^(?:\w+script|data):/i),et=j(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),tt=j(/^html$/i);var rt=Object.freeze({__proto__:null,MUSTACHE_EXPR:ze,ERB_EXPR:Ve,TMPLIT_EXPR:We,DATA_ATTR:He,ARIA_ATTR:Xe,IS_ALLOWED_URI:Ye,IS_SCRIPT_OR_DATA:Qe,ATTR_WHITESPACE:et,DOCTYPE_NAME:tt});const nt=function getGlobal(){return"undefined"==typeof window?null:window},ot=function _createTrustedTypesPolicy(i,s){if("object"!=typeof i||"function"!=typeof i.createPolicy)return null;let u=null;const m="data-tt-policy-suffix";s&&s.hasAttribute(m)&&(u=s.getAttribute(m));const v="dompurify"+(u?"#"+u:"");try{return i.createPolicy(v,{createHTML:i=>i,createScriptURL:i=>i})}catch(i){return console.warn("TrustedTypes policy "+v+" could not be created."),null}};function createDOMPurify(){let s=arguments.length>0&&void 0!==arguments[0]?arguments[0]:nt();const DOMPurify=i=>createDOMPurify(i);if(DOMPurify.version="3.0.6",DOMPurify.removed=[],!s||!s.document||9!==s.document.nodeType)return DOMPurify.isSupported=!1,DOMPurify;let{document:u}=s;const m=u,v=m.currentScript,{DocumentFragment:j,HTMLTemplateElement:$,Node:W,Element:ze,NodeFilter:Ve,NamedNodeMap:We=s.NamedNodeMap||s.MozNamedAttrMap,HTMLFormElement:He,DOMParser:Xe,trustedTypes:Qe}=s,et=ze.prototype,it=lookupGetter(et,"cloneNode"),at=lookupGetter(et,"nextSibling"),st=lookupGetter(et,"childNodes"),lt=lookupGetter(et,"parentNode");if("function"==typeof $){const i=u.createElement("template");i.content&&i.content.ownerDocument&&(u=i.content.ownerDocument)}let ct,ut="";const{implementation:pt,createNodeIterator:ht,createDocumentFragment:dt,getElementsByTagName:mt}=u,{importNode:gt}=m;let yt={};DOMPurify.isSupported="function"==typeof i&&"function"==typeof lt&&pt&&void 0!==pt.createHTMLDocument;const{MUSTACHE_EXPR:vt,ERB_EXPR:bt,TMPLIT_EXPR:_t,DATA_ATTR:wt,ARIA_ATTR:Et,IS_SCRIPT_OR_DATA:St,ATTR_WHITESPACE:xt}=rt;let{IS_ALLOWED_URI:kt}=rt,Ot=null;const At=addToSet({},[...ye,...be,..._e,...Se,...Ie]);let Ct=null;const jt=addToSet({},[...Pe,...Te,...Re,...qe]);let It=Object.seal(M(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Pt=null,Nt=null,Tt=!0,Mt=!0,Rt=!1,Dt=!0,Bt=!1,Lt=!1,Ft=!1,qt=!1,$t=!1,Ut=!1,zt=!1,Vt=!0,Wt=!1;const Kt="user-content-";let Ht=!0,Jt=!1,Gt={},Xt=null;const Yt=addToSet({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]);let Qt=null;const Zt=addToSet({},["audio","video","img","source","image","track"]);let er=null;const tr=addToSet({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),rr="http://www.w3.org/1998/Math/MathML",nr="http://www.w3.org/2000/svg",ir="http://www.w3.org/1999/xhtml";let ar=ir,sr=!1,lr=null;const cr=addToSet({},[rr,nr,ir],ie);let ur=null;const pr=["application/xhtml+xml","text/html"],dr="text/html";let fr=null,mr=null;const gr=u.createElement("form"),yr=function isRegexOrFunction(i){return i instanceof RegExp||i instanceof Function},vr=function _parseConfig(){let i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};if(!mr||mr!==i){if(i&&"object"==typeof i||(i={}),i=clone(i),ur=ur=-1===pr.indexOf(i.PARSER_MEDIA_TYPE)?dr:i.PARSER_MEDIA_TYPE,fr="application/xhtml+xml"===ur?ie:ee,Ot="ALLOWED_TAGS"in i?addToSet({},i.ALLOWED_TAGS,fr):At,Ct="ALLOWED_ATTR"in i?addToSet({},i.ALLOWED_ATTR,fr):jt,lr="ALLOWED_NAMESPACES"in i?addToSet({},i.ALLOWED_NAMESPACES,ie):cr,er="ADD_URI_SAFE_ATTR"in i?addToSet(clone(tr),i.ADD_URI_SAFE_ATTR,fr):tr,Qt="ADD_DATA_URI_TAGS"in i?addToSet(clone(Zt),i.ADD_DATA_URI_TAGS,fr):Zt,Xt="FORBID_CONTENTS"in i?addToSet({},i.FORBID_CONTENTS,fr):Yt,Pt="FORBID_TAGS"in i?addToSet({},i.FORBID_TAGS,fr):{},Nt="FORBID_ATTR"in i?addToSet({},i.FORBID_ATTR,fr):{},Gt="USE_PROFILES"in i&&i.USE_PROFILES,Tt=!1!==i.ALLOW_ARIA_ATTR,Mt=!1!==i.ALLOW_DATA_ATTR,Rt=i.ALLOW_UNKNOWN_PROTOCOLS||!1,Dt=!1!==i.ALLOW_SELF_CLOSE_IN_ATTR,Bt=i.SAFE_FOR_TEMPLATES||!1,Lt=i.WHOLE_DOCUMENT||!1,$t=i.RETURN_DOM||!1,Ut=i.RETURN_DOM_FRAGMENT||!1,zt=i.RETURN_TRUSTED_TYPE||!1,qt=i.FORCE_BODY||!1,Vt=!1!==i.SANITIZE_DOM,Wt=i.SANITIZE_NAMED_PROPS||!1,Ht=!1!==i.KEEP_CONTENT,Jt=i.IN_PLACE||!1,kt=i.ALLOWED_URI_REGEXP||Ye,ar=i.NAMESPACE||ir,It=i.CUSTOM_ELEMENT_HANDLING||{},i.CUSTOM_ELEMENT_HANDLING&&yr(i.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(It.tagNameCheck=i.CUSTOM_ELEMENT_HANDLING.tagNameCheck),i.CUSTOM_ELEMENT_HANDLING&&yr(i.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(It.attributeNameCheck=i.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),i.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof i.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(It.allowCustomizedBuiltInElements=i.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),Bt&&(Mt=!1),Ut&&($t=!0),Gt&&(Ot=addToSet({},[...Ie]),Ct=[],!0===Gt.html&&(addToSet(Ot,ye),addToSet(Ct,Pe)),!0===Gt.svg&&(addToSet(Ot,be),addToSet(Ct,Te),addToSet(Ct,qe)),!0===Gt.svgFilters&&(addToSet(Ot,_e),addToSet(Ct,Te),addToSet(Ct,qe)),!0===Gt.mathMl&&(addToSet(Ot,Se),addToSet(Ct,Re),addToSet(Ct,qe))),i.ADD_TAGS&&(Ot===At&&(Ot=clone(Ot)),addToSet(Ot,i.ADD_TAGS,fr)),i.ADD_ATTR&&(Ct===jt&&(Ct=clone(Ct)),addToSet(Ct,i.ADD_ATTR,fr)),i.ADD_URI_SAFE_ATTR&&addToSet(er,i.ADD_URI_SAFE_ATTR,fr),i.FORBID_CONTENTS&&(Xt===Yt&&(Xt=clone(Xt)),addToSet(Xt,i.FORBID_CONTENTS,fr)),Ht&&(Ot["#text"]=!0),Lt&&addToSet(Ot,["html","head","body"]),Ot.table&&(addToSet(Ot,["tbody"]),delete Pt.tbody),i.TRUSTED_TYPES_POLICY){if("function"!=typeof i.TRUSTED_TYPES_POLICY.createHTML)throw fe('TRUSTED_TYPES_POLICY configuration option must provide a "createHTML" hook.');if("function"!=typeof i.TRUSTED_TYPES_POLICY.createScriptURL)throw fe('TRUSTED_TYPES_POLICY configuration option must provide a "createScriptURL" hook.');ct=i.TRUSTED_TYPES_POLICY,ut=ct.createHTML("")}else void 0===ct&&(ct=ot(Qe,v)),null!==ct&&"string"==typeof ut&&(ut=ct.createHTML(""));_&&_(i),mr=i}},br=addToSet({},["mi","mo","mn","ms","mtext"]),_r=addToSet({},["foreignobject","desc","title","annotation-xml"]),wr=addToSet({},["title","style","font","a","script"]),Er=addToSet({},be);addToSet(Er,_e),addToSet(Er,we);const Sr=addToSet({},Se);addToSet(Sr,xe);const xr=function _checkValidNamespace(i){let s=lt(i);s&&s.tagName||(s={namespaceURI:ar,tagName:"template"});const u=ee(i.tagName),m=ee(s.tagName);return!!lr[i.namespaceURI]&&(i.namespaceURI===nr?s.namespaceURI===ir?"svg"===u:s.namespaceURI===rr?"svg"===u&&("annotation-xml"===m||br[m]):Boolean(Er[u]):i.namespaceURI===rr?s.namespaceURI===ir?"math"===u:s.namespaceURI===nr?"math"===u&&_r[m]:Boolean(Sr[u]):i.namespaceURI===ir?!(s.namespaceURI===nr&&!_r[m])&&!(s.namespaceURI===rr&&!br[m])&&!Sr[u]&&(wr[u]||!Er[u]):!("application/xhtml+xml"!==ur||!lr[i.namespaceURI]))},kr=function _forceRemove(i){Z(DOMPurify.removed,{element:i});try{i.parentNode.removeChild(i)}catch(s){i.remove()}},Or=function _removeAttribute(i,s){try{Z(DOMPurify.removed,{attribute:s.getAttributeNode(i),from:s})}catch(i){Z(DOMPurify.removed,{attribute:null,from:s})}if(s.removeAttribute(i),"is"===i&&!Ct[i])if($t||Ut)try{kr(s)}catch(i){}else try{s.setAttribute(i,"")}catch(i){}},Ar=function _initDocument(i){let s=null,m=null;if(qt)i=""+i;else{const s=ae(i,/^[\r\n\t ]+/);m=s&&s[0]}"application/xhtml+xml"===ur&&ar===ir&&(i=''+i+"");const v=ct?ct.createHTML(i):i;if(ar===ir)try{s=(new Xe).parseFromString(v,ur)}catch(i){}if(!s||!s.documentElement){s=pt.createDocument(ar,"template",null);try{s.documentElement.innerHTML=sr?ut:v}catch(i){}}const _=s.body||s.documentElement;return i&&m&&_.insertBefore(u.createTextNode(m),_.childNodes[0]||null),ar===ir?mt.call(s,Lt?"html":"body")[0]:Lt?s.documentElement:_},Cr=function _createNodeIterator(i){return ht.call(i.ownerDocument||i,i,Ve.SHOW_ELEMENT|Ve.SHOW_COMMENT|Ve.SHOW_TEXT,null)},jr=function _isClobbered(i){return i instanceof He&&("string"!=typeof i.nodeName||"string"!=typeof i.textContent||"function"!=typeof i.removeChild||!(i.attributes instanceof We)||"function"!=typeof i.removeAttribute||"function"!=typeof i.setAttribute||"string"!=typeof i.namespaceURI||"function"!=typeof i.insertBefore||"function"!=typeof i.hasChildNodes)},Ir=function _isNode(i){return"function"==typeof W&&i instanceof W},Pr=function _executeHook(i,s,u){yt[i]&&X(yt[i],(i=>{i.call(DOMPurify,s,u,mr)}))},Nr=function _sanitizeElements(i){let s=null;if(Pr("beforeSanitizeElements",i,null),jr(i))return kr(i),!0;const u=fr(i.nodeName);if(Pr("uponSanitizeElement",i,{tagName:u,allowedTags:Ot}),i.hasChildNodes()&&!Ir(i.firstElementChild)&&de(/<[/\w]/g,i.innerHTML)&&de(/<[/\w]/g,i.textContent))return kr(i),!0;if(!Ot[u]||Pt[u]){if(!Pt[u]&&Mr(u)){if(It.tagNameCheck instanceof RegExp&&de(It.tagNameCheck,u))return!1;if(It.tagNameCheck instanceof Function&&It.tagNameCheck(u))return!1}if(Ht&&!Xt[u]){const s=lt(i)||i.parentNode,u=st(i)||i.childNodes;if(u&&s)for(let m=u.length-1;m>=0;--m)s.insertBefore(it(u[m],!0),at(i))}return kr(i),!0}return i instanceof ze&&!xr(i)?(kr(i),!0):"noscript"!==u&&"noembed"!==u&&"noframes"!==u||!de(/<\/no(script|embed|frames)/i,i.innerHTML)?(Bt&&3===i.nodeType&&(s=i.textContent,X([vt,bt,_t],(i=>{s=le(s,i," ")})),i.textContent!==s&&(Z(DOMPurify.removed,{element:i.cloneNode()}),i.textContent=s)),Pr("afterSanitizeElements",i,null),!1):(kr(i),!0)},Tr=function _isValidAttribute(i,s,m){if(Vt&&("id"===s||"name"===s)&&(m in u||m in gr))return!1;if(Mt&&!Nt[s]&&de(wt,s));else if(Tt&&de(Et,s));else if(!Ct[s]||Nt[s]){if(!(Mr(i)&&(It.tagNameCheck instanceof RegExp&&de(It.tagNameCheck,i)||It.tagNameCheck instanceof Function&&It.tagNameCheck(i))&&(It.attributeNameCheck instanceof RegExp&&de(It.attributeNameCheck,s)||It.attributeNameCheck instanceof Function&&It.attributeNameCheck(s))||"is"===s&&It.allowCustomizedBuiltInElements&&(It.tagNameCheck instanceof RegExp&&de(It.tagNameCheck,m)||It.tagNameCheck instanceof Function&&It.tagNameCheck(m))))return!1}else if(er[s]);else if(de(kt,le(m,xt,"")));else if("src"!==s&&"xlink:href"!==s&&"href"!==s||"script"===i||0!==ce(m,"data:")||!Qt[i])if(Rt&&!de(St,le(m,xt,"")));else if(m)return!1;return!0},Mr=function _isBasicCustomElement(i){return i.indexOf("-")>0},Rr=function _sanitizeAttributes(i){Pr("beforeSanitizeAttributes",i,null);const{attributes:s}=i;if(!s)return;const u={attrName:"",attrValue:"",keepAttr:!0,allowedAttributes:Ct};let m=s.length;for(;m--;){const v=s[m],{name:_,namespaceURI:j,value:M}=v,$=fr(_);let W="value"===_?M:pe(M);if(u.attrName=$,u.attrValue=W,u.keepAttr=!0,u.forceKeepAttr=void 0,Pr("uponSanitizeAttribute",i,u),W=u.attrValue,u.forceKeepAttr)continue;if(Or(_,i),!u.keepAttr)continue;if(!Dt&&de(/\/>/i,W)){Or(_,i);continue}Bt&&X([vt,bt,_t],(i=>{W=le(W,i," ")}));const Z=fr(i.nodeName);if(Tr(Z,$,W)){if(!Wt||"id"!==$&&"name"!==$||(Or(_,i),W=Kt+W),ct&&"object"==typeof Qe&&"function"==typeof Qe.getAttributeType)if(j);else switch(Qe.getAttributeType(Z,$)){case"TrustedHTML":W=ct.createHTML(W);break;case"TrustedScriptURL":W=ct.createScriptURL(W)}try{j?i.setAttributeNS(j,_,W):i.setAttribute(_,W),Y(DOMPurify.removed)}catch(i){}}}Pr("afterSanitizeAttributes",i,null)},Dr=function _sanitizeShadowDOM(i){let s=null;const u=Cr(i);for(Pr("beforeSanitizeShadowDOM",i,null);s=u.nextNode();)Pr("uponSanitizeShadowNode",s,null),Nr(s)||(s.content instanceof j&&_sanitizeShadowDOM(s.content),Rr(s));Pr("afterSanitizeShadowDOM",i,null)};return DOMPurify.sanitize=function(i){let s=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},u=null,v=null,_=null,M=null;if(sr=!i,sr&&(i="\x3c!--\x3e"),"string"!=typeof i&&!Ir(i)){if("function"!=typeof i.toString)throw fe("toString is not a function");if("string"!=typeof(i=i.toString()))throw fe("dirty is not a string, aborting")}if(!DOMPurify.isSupported)return i;if(Ft||vr(s),DOMPurify.removed=[],"string"==typeof i&&(Jt=!1),Jt){if(i.nodeName){const s=fr(i.nodeName);if(!Ot[s]||Pt[s])throw fe("root node is forbidden and cannot be sanitized in-place")}}else if(i instanceof W)u=Ar("\x3c!----\x3e"),v=u.ownerDocument.importNode(i,!0),1===v.nodeType&&"BODY"===v.nodeName||"HTML"===v.nodeName?u=v:u.appendChild(v);else{if(!$t&&!Bt&&!Lt&&-1===i.indexOf("<"))return ct&&zt?ct.createHTML(i):i;if(u=Ar(i),!u)return $t?null:zt?ut:""}u&&qt&&kr(u.firstChild);const $=Cr(Jt?i:u);for(;_=$.nextNode();)Nr(_)||(_.content instanceof j&&Dr(_.content),Rr(_));if(Jt)return i;if($t){if(Ut)for(M=dt.call(u.ownerDocument);u.firstChild;)M.appendChild(u.firstChild);else M=u;return(Ct.shadowroot||Ct.shadowrootmode)&&(M=gt.call(m,M,!0)),M}let Y=Lt?u.outerHTML:u.innerHTML;return Lt&&Ot["!doctype"]&&u.ownerDocument&&u.ownerDocument.doctype&&u.ownerDocument.doctype.name&&de(tt,u.ownerDocument.doctype.name)&&(Y="\n"+Y),Bt&&X([vt,bt,_t],(i=>{Y=le(Y,i," ")})),ct&&zt?ct.createHTML(Y):Y},DOMPurify.setConfig=function(){vr(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}),Ft=!0},DOMPurify.clearConfig=function(){mr=null,Ft=!1},DOMPurify.isValidAttribute=function(i,s,u){mr||vr({});const m=fr(i),v=fr(s);return Tr(m,v,u)},DOMPurify.addHook=function(i,s){"function"==typeof s&&(yt[i]=yt[i]||[],Z(yt[i],s))},DOMPurify.removeHook=function(i){if(yt[i])return Y(yt[i])},DOMPurify.removeHooks=function(i){yt[i]&&(yt[i]=[])},DOMPurify.removeAllHooks=function(){yt={}},DOMPurify}return createDOMPurify()}()},69450:i=>{"use strict";class SubRange{constructor(i,s){this.low=i,this.high=s,this.length=1+s-i}overlaps(i){return!(this.highi.high)}touches(i){return!(this.high+1i.high)}add(i){return new SubRange(Math.min(this.low,i.low),Math.max(this.high,i.high))}subtract(i){return i.low<=this.low&&i.high>=this.high?[]:i.low>this.low&&i.highi+s.length),0)}add(i,s){var _add=i=>{for(var s=0;s{for(var s=0;s{for(var s=0;s{for(var u=s.low;u<=s.high;)i.push(u),u++;return i}),[])}subranges(){return this.ranges.map((i=>({low:i.low,high:i.high,length:1+i.high-i.low})))}}i.exports=DRange},17187:i=>{"use strict";var s,u="object"==typeof Reflect?Reflect:null,m=u&&"function"==typeof u.apply?u.apply:function ReflectApply(i,s,u){return Function.prototype.apply.call(i,s,u)};s=u&&"function"==typeof u.ownKeys?u.ownKeys:Object.getOwnPropertySymbols?function ReflectOwnKeys(i){return Object.getOwnPropertyNames(i).concat(Object.getOwnPropertySymbols(i))}:function ReflectOwnKeys(i){return Object.getOwnPropertyNames(i)};var v=Number.isNaN||function NumberIsNaN(i){return i!=i};function EventEmitter(){EventEmitter.init.call(this)}i.exports=EventEmitter,i.exports.once=function once(i,s){return new Promise((function(u,m){function errorListener(u){i.removeListener(s,resolver),m(u)}function resolver(){"function"==typeof i.removeListener&&i.removeListener("error",errorListener),u([].slice.call(arguments))}eventTargetAgnosticAddListener(i,s,resolver,{once:!0}),"error"!==s&&function addErrorHandlerIfEventEmitter(i,s,u){"function"==typeof i.on&&eventTargetAgnosticAddListener(i,"error",s,u)}(i,errorListener,{once:!0})}))},EventEmitter.EventEmitter=EventEmitter,EventEmitter.prototype._events=void 0,EventEmitter.prototype._eventsCount=0,EventEmitter.prototype._maxListeners=void 0;var _=10;function checkListener(i){if("function"!=typeof i)throw new TypeError('The "listener" argument must be of type Function. Received type '+typeof i)}function _getMaxListeners(i){return void 0===i._maxListeners?EventEmitter.defaultMaxListeners:i._maxListeners}function _addListener(i,s,u,m){var v,_,j;if(checkListener(u),void 0===(_=i._events)?(_=i._events=Object.create(null),i._eventsCount=0):(void 0!==_.newListener&&(i.emit("newListener",s,u.listener?u.listener:u),_=i._events),j=_[s]),void 0===j)j=_[s]=u,++i._eventsCount;else if("function"==typeof j?j=_[s]=m?[u,j]:[j,u]:m?j.unshift(u):j.push(u),(v=_getMaxListeners(i))>0&&j.length>v&&!j.warned){j.warned=!0;var M=new Error("Possible EventEmitter memory leak detected. "+j.length+" "+String(s)+" listeners added. Use emitter.setMaxListeners() to increase limit");M.name="MaxListenersExceededWarning",M.emitter=i,M.type=s,M.count=j.length,function ProcessEmitWarning(i){console&&console.warn&&console.warn(i)}(M)}return i}function onceWrapper(){if(!this.fired)return this.target.removeListener(this.type,this.wrapFn),this.fired=!0,0===arguments.length?this.listener.call(this.target):this.listener.apply(this.target,arguments)}function _onceWrap(i,s,u){var m={fired:!1,wrapFn:void 0,target:i,type:s,listener:u},v=onceWrapper.bind(m);return v.listener=u,m.wrapFn=v,v}function _listeners(i,s,u){var m=i._events;if(void 0===m)return[];var v=m[s];return void 0===v?[]:"function"==typeof v?u?[v.listener||v]:[v]:u?function unwrapListeners(i){for(var s=new Array(i.length),u=0;u0&&(j=s[0]),j instanceof Error)throw j;var M=new Error("Unhandled error."+(j?" ("+j.message+")":""));throw M.context=j,M}var $=_[i];if(void 0===$)return!1;if("function"==typeof $)m($,this,s);else{var W=$.length,X=arrayClone($,W);for(u=0;u=0;_--)if(u[_]===s||u[_].listener===s){j=u[_].listener,v=_;break}if(v<0)return this;0===v?u.shift():function spliceOne(i,s){for(;s+1=0;m--)this.removeListener(i,s[m]);return this},EventEmitter.prototype.listeners=function listeners(i){return _listeners(this,i,!0)},EventEmitter.prototype.rawListeners=function rawListeners(i){return _listeners(this,i,!1)},EventEmitter.listenerCount=function(i,s){return"function"==typeof i.listenerCount?i.listenerCount(s):listenerCount.call(i,s)},EventEmitter.prototype.listenerCount=listenerCount,EventEmitter.prototype.eventNames=function eventNames(){return this._eventsCount>0?s(this._events):[]}},21102:(i,s,u)=>{"use strict";var m=u(46291),v=create(Error);function create(i){return FormattedError.displayName=i.displayName||i.name,FormattedError;function FormattedError(s){return s&&(s=m.apply(null,arguments)),new i(s)}}i.exports=v,v.eval=create(EvalError),v.range=create(RangeError),v.reference=create(ReferenceError),v.syntax=create(SyntaxError),v.type=create(TypeError),v.uri=create(URIError),v.create=create},46291:i=>{!function(){var s;function format(i){for(var s,u,m,v,_=1,j=[].slice.call(arguments),M=0,$=i.length,W="",X=!1,Y=!1,nextArg=function(){return j[_++]},slurpNumber=function(){for(var u="";/\d/.test(i[M]);)u+=i[M++],s=i[M];return u.length>0?parseInt(u):null};M<$;++M)if(s=i[M],X)switch(X=!1,"."==s?(Y=!1,s=i[++M]):"0"==s&&"."==i[M+1]?(Y=!0,s=i[M+=2]):Y=!0,v=slurpNumber(),s){case"b":W+=parseInt(nextArg(),10).toString(2);break;case"c":W+="string"==typeof(u=nextArg())||u instanceof String?u:String.fromCharCode(parseInt(u,10));break;case"d":W+=parseInt(nextArg(),10);break;case"f":m=String(parseFloat(nextArg()).toFixed(v||6)),W+=Y?m:m.replace(/^0/,"");break;case"j":W+=JSON.stringify(nextArg());break;case"o":W+="0"+parseInt(nextArg(),10).toString(8);break;case"s":W+=nextArg();break;case"x":W+="0x"+parseInt(nextArg(),10).toString(16);break;case"X":W+="0x"+parseInt(nextArg(),10).toString(16).toUpperCase();break;default:W+=s}else"%"===s?X=!0:W+=s;return W}(s=i.exports=format).format=format,s.vsprintf=function vsprintf(i,s){return format.apply(null,[i].concat(s))},"undefined"!=typeof console&&"function"==typeof console.log&&(s.printf=function printf(){console.log(format.apply(null,arguments))})}()},17648:i=>{"use strict";var s=Object.prototype.toString,u=Math.max,m=function concatty(i,s){for(var u=[],m=0;m{"use strict";var m=u(17648);i.exports=Function.prototype.bind||m},40210:(i,s,u)=>{"use strict";var m,v=SyntaxError,_=Function,j=TypeError,getEvalledConstructor=function(i){try{return _('"use strict"; return ('+i+").constructor;")()}catch(i){}},M=Object.getOwnPropertyDescriptor;if(M)try{M({},"")}catch(i){M=null}var throwTypeError=function(){throw new j},$=M?function(){try{return throwTypeError}catch(i){try{return M(arguments,"callee").get}catch(i){return throwTypeError}}}():throwTypeError,W=u(41405)(),X=u(28185)(),Y=Object.getPrototypeOf||(X?function(i){return i.__proto__}:null),Z={},ee="undefined"!=typeof Uint8Array&&Y?Y(Uint8Array):m,ie={"%AggregateError%":"undefined"==typeof AggregateError?m:AggregateError,"%Array%":Array,"%ArrayBuffer%":"undefined"==typeof ArrayBuffer?m:ArrayBuffer,"%ArrayIteratorPrototype%":W&&Y?Y([][Symbol.iterator]()):m,"%AsyncFromSyncIteratorPrototype%":m,"%AsyncFunction%":Z,"%AsyncGenerator%":Z,"%AsyncGeneratorFunction%":Z,"%AsyncIteratorPrototype%":Z,"%Atomics%":"undefined"==typeof Atomics?m:Atomics,"%BigInt%":"undefined"==typeof BigInt?m:BigInt,"%BigInt64Array%":"undefined"==typeof BigInt64Array?m:BigInt64Array,"%BigUint64Array%":"undefined"==typeof BigUint64Array?m:BigUint64Array,"%Boolean%":Boolean,"%DataView%":"undefined"==typeof DataView?m:DataView,"%Date%":Date,"%decodeURI%":decodeURI,"%decodeURIComponent%":decodeURIComponent,"%encodeURI%":encodeURI,"%encodeURIComponent%":encodeURIComponent,"%Error%":Error,"%eval%":eval,"%EvalError%":EvalError,"%Float32Array%":"undefined"==typeof Float32Array?m:Float32Array,"%Float64Array%":"undefined"==typeof Float64Array?m:Float64Array,"%FinalizationRegistry%":"undefined"==typeof FinalizationRegistry?m:FinalizationRegistry,"%Function%":_,"%GeneratorFunction%":Z,"%Int8Array%":"undefined"==typeof Int8Array?m:Int8Array,"%Int16Array%":"undefined"==typeof Int16Array?m:Int16Array,"%Int32Array%":"undefined"==typeof Int32Array?m:Int32Array,"%isFinite%":isFinite,"%isNaN%":isNaN,"%IteratorPrototype%":W&&Y?Y(Y([][Symbol.iterator]())):m,"%JSON%":"object"==typeof JSON?JSON:m,"%Map%":"undefined"==typeof Map?m:Map,"%MapIteratorPrototype%":"undefined"!=typeof Map&&W&&Y?Y((new Map)[Symbol.iterator]()):m,"%Math%":Math,"%Number%":Number,"%Object%":Object,"%parseFloat%":parseFloat,"%parseInt%":parseInt,"%Promise%":"undefined"==typeof Promise?m:Promise,"%Proxy%":"undefined"==typeof Proxy?m:Proxy,"%RangeError%":RangeError,"%ReferenceError%":ReferenceError,"%Reflect%":"undefined"==typeof Reflect?m:Reflect,"%RegExp%":RegExp,"%Set%":"undefined"==typeof Set?m:Set,"%SetIteratorPrototype%":"undefined"!=typeof Set&&W&&Y?Y((new Set)[Symbol.iterator]()):m,"%SharedArrayBuffer%":"undefined"==typeof SharedArrayBuffer?m:SharedArrayBuffer,"%String%":String,"%StringIteratorPrototype%":W&&Y?Y(""[Symbol.iterator]()):m,"%Symbol%":W?Symbol:m,"%SyntaxError%":v,"%ThrowTypeError%":$,"%TypedArray%":ee,"%TypeError%":j,"%Uint8Array%":"undefined"==typeof Uint8Array?m:Uint8Array,"%Uint8ClampedArray%":"undefined"==typeof Uint8ClampedArray?m:Uint8ClampedArray,"%Uint16Array%":"undefined"==typeof Uint16Array?m:Uint16Array,"%Uint32Array%":"undefined"==typeof Uint32Array?m:Uint32Array,"%URIError%":URIError,"%WeakMap%":"undefined"==typeof WeakMap?m:WeakMap,"%WeakRef%":"undefined"==typeof WeakRef?m:WeakRef,"%WeakSet%":"undefined"==typeof WeakSet?m:WeakSet};if(Y)try{null.error}catch(i){var ae=Y(Y(i));ie["%Error.prototype%"]=ae}var le=function doEval(i){var s;if("%AsyncFunction%"===i)s=getEvalledConstructor("async function () {}");else if("%GeneratorFunction%"===i)s=getEvalledConstructor("function* () {}");else if("%AsyncGeneratorFunction%"===i)s=getEvalledConstructor("async function* () {}");else if("%AsyncGenerator%"===i){var u=doEval("%AsyncGeneratorFunction%");u&&(s=u.prototype)}else if("%AsyncIteratorPrototype%"===i){var m=doEval("%AsyncGenerator%");m&&Y&&(s=Y(m.prototype))}return ie[i]=s,s},ce={"%ArrayBufferPrototype%":["ArrayBuffer","prototype"],"%ArrayPrototype%":["Array","prototype"],"%ArrayProto_entries%":["Array","prototype","entries"],"%ArrayProto_forEach%":["Array","prototype","forEach"],"%ArrayProto_keys%":["Array","prototype","keys"],"%ArrayProto_values%":["Array","prototype","values"],"%AsyncFunctionPrototype%":["AsyncFunction","prototype"],"%AsyncGenerator%":["AsyncGeneratorFunction","prototype"],"%AsyncGeneratorPrototype%":["AsyncGeneratorFunction","prototype","prototype"],"%BooleanPrototype%":["Boolean","prototype"],"%DataViewPrototype%":["DataView","prototype"],"%DatePrototype%":["Date","prototype"],"%ErrorPrototype%":["Error","prototype"],"%EvalErrorPrototype%":["EvalError","prototype"],"%Float32ArrayPrototype%":["Float32Array","prototype"],"%Float64ArrayPrototype%":["Float64Array","prototype"],"%FunctionPrototype%":["Function","prototype"],"%Generator%":["GeneratorFunction","prototype"],"%GeneratorPrototype%":["GeneratorFunction","prototype","prototype"],"%Int8ArrayPrototype%":["Int8Array","prototype"],"%Int16ArrayPrototype%":["Int16Array","prototype"],"%Int32ArrayPrototype%":["Int32Array","prototype"],"%JSONParse%":["JSON","parse"],"%JSONStringify%":["JSON","stringify"],"%MapPrototype%":["Map","prototype"],"%NumberPrototype%":["Number","prototype"],"%ObjectPrototype%":["Object","prototype"],"%ObjProto_toString%":["Object","prototype","toString"],"%ObjProto_valueOf%":["Object","prototype","valueOf"],"%PromisePrototype%":["Promise","prototype"],"%PromiseProto_then%":["Promise","prototype","then"],"%Promise_all%":["Promise","all"],"%Promise_reject%":["Promise","reject"],"%Promise_resolve%":["Promise","resolve"],"%RangeErrorPrototype%":["RangeError","prototype"],"%ReferenceErrorPrototype%":["ReferenceError","prototype"],"%RegExpPrototype%":["RegExp","prototype"],"%SetPrototype%":["Set","prototype"],"%SharedArrayBufferPrototype%":["SharedArrayBuffer","prototype"],"%StringPrototype%":["String","prototype"],"%SymbolPrototype%":["Symbol","prototype"],"%SyntaxErrorPrototype%":["SyntaxError","prototype"],"%TypedArrayPrototype%":["TypedArray","prototype"],"%TypeErrorPrototype%":["TypeError","prototype"],"%Uint8ArrayPrototype%":["Uint8Array","prototype"],"%Uint8ClampedArrayPrototype%":["Uint8ClampedArray","prototype"],"%Uint16ArrayPrototype%":["Uint16Array","prototype"],"%Uint32ArrayPrototype%":["Uint32Array","prototype"],"%URIErrorPrototype%":["URIError","prototype"],"%WeakMapPrototype%":["WeakMap","prototype"],"%WeakSetPrototype%":["WeakSet","prototype"]},pe=u(58612),de=u(17642),fe=pe.call(Function.call,Array.prototype.concat),ye=pe.call(Function.apply,Array.prototype.splice),be=pe.call(Function.call,String.prototype.replace),_e=pe.call(Function.call,String.prototype.slice),we=pe.call(Function.call,RegExp.prototype.exec),Se=/[^%.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|%$))/g,xe=/\\(\\)?/g,Ie=function getBaseIntrinsic(i,s){var u,m=i;if(de(ce,m)&&(m="%"+(u=ce[m])[0]+"%"),de(ie,m)){var _=ie[m];if(_===Z&&(_=le(m)),void 0===_&&!s)throw new j("intrinsic "+i+" exists, but is not available. Please file an issue!");return{alias:u,name:m,value:_}}throw new v("intrinsic "+i+" does not exist!")};i.exports=function GetIntrinsic(i,s){if("string"!=typeof i||0===i.length)throw new j("intrinsic name must be a non-empty string");if(arguments.length>1&&"boolean"!=typeof s)throw new j('"allowMissing" argument must be a boolean');if(null===we(/^%?[^%]*%?$/,i))throw new v("`%` may not be present anywhere but at the beginning and end of the intrinsic name");var u=function stringToPath(i){var s=_e(i,0,1),u=_e(i,-1);if("%"===s&&"%"!==u)throw new v("invalid intrinsic syntax, expected closing `%`");if("%"===u&&"%"!==s)throw new v("invalid intrinsic syntax, expected opening `%`");var m=[];return be(i,Se,(function(i,s,u,v){m[m.length]=u?be(v,xe,"$1"):s||i})),m}(i),m=u.length>0?u[0]:"",_=Ie("%"+m+"%",s),$=_.name,W=_.value,X=!1,Y=_.alias;Y&&(m=Y[0],ye(u,fe([0,1],Y)));for(var Z=1,ee=!0;Z=u.length){var pe=M(W,ae);W=(ee=!!pe)&&"get"in pe&&!("originalValue"in pe.get)?pe.get:W[ae]}else ee=de(W,ae),W=W[ae];ee&&!X&&(ie[$]=W)}}return W}},28185:i=>{"use strict";var s={foo:{}},u=Object;i.exports=function hasProto(){return{__proto__:s}.foo===s.foo&&!({__proto__:null}instanceof u)}},41405:(i,s,u)=>{"use strict";var m="undefined"!=typeof Symbol&&Symbol,v=u(55419);i.exports=function hasNativeSymbols(){return"function"==typeof m&&("function"==typeof Symbol&&("symbol"==typeof m("foo")&&("symbol"==typeof Symbol("bar")&&v())))}},55419:i=>{"use strict";i.exports=function hasSymbols(){if("function"!=typeof Symbol||"function"!=typeof Object.getOwnPropertySymbols)return!1;if("symbol"==typeof Symbol.iterator)return!0;var i={},s=Symbol("test"),u=Object(s);if("string"==typeof s)return!1;if("[object Symbol]"!==Object.prototype.toString.call(s))return!1;if("[object Symbol]"!==Object.prototype.toString.call(u))return!1;for(s in i[s]=42,i)return!1;if("function"==typeof Object.keys&&0!==Object.keys(i).length)return!1;if("function"==typeof Object.getOwnPropertyNames&&0!==Object.getOwnPropertyNames(i).length)return!1;var m=Object.getOwnPropertySymbols(i);if(1!==m.length||m[0]!==s)return!1;if(!Object.prototype.propertyIsEnumerable.call(i,s))return!1;if("function"==typeof Object.getOwnPropertyDescriptor){var v=Object.getOwnPropertyDescriptor(i,s);if(42!==v.value||!0!==v.enumerable)return!1}return!0}},17642:(i,s,u)=>{"use strict";var m=u(58612);i.exports=m.call(Function.call,Object.prototype.hasOwnProperty)},47802:i=>{function deepFreeze(i){return i instanceof Map?i.clear=i.delete=i.set=function(){throw new Error("map is read-only")}:i instanceof Set&&(i.add=i.clear=i.delete=function(){throw new Error("set is read-only")}),Object.freeze(i),Object.getOwnPropertyNames(i).forEach((function(s){var u=i[s];"object"!=typeof u||Object.isFrozen(u)||deepFreeze(u)})),i}var s=deepFreeze,u=deepFreeze;s.default=u;class Response{constructor(i){void 0===i.data&&(i.data={}),this.data=i.data,this.isMatchIgnored=!1}ignoreMatch(){this.isMatchIgnored=!0}}function escapeHTML(i){return i.replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/'/g,"'")}function inherit(i,...s){const u=Object.create(null);for(const s in i)u[s]=i[s];return s.forEach((function(i){for(const s in i)u[s]=i[s]})),u}const emitsWrappingTags=i=>!!i.kind;class HTMLRenderer{constructor(i,s){this.buffer="",this.classPrefix=s.classPrefix,i.walk(this)}addText(i){this.buffer+=escapeHTML(i)}openNode(i){if(!emitsWrappingTags(i))return;let s=i.kind;i.sublanguage||(s=`${this.classPrefix}${s}`),this.span(s)}closeNode(i){emitsWrappingTags(i)&&(this.buffer+="")}value(){return this.buffer}span(i){this.buffer+=``}}class TokenTree{constructor(){this.rootNode={children:[]},this.stack=[this.rootNode]}get top(){return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(i){this.top.children.push(i)}openNode(i){const s={kind:i,children:[]};this.add(s),this.stack.push(s)}closeNode(){if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)}walk(i){return this.constructor._walk(i,this.rootNode)}static _walk(i,s){return"string"==typeof s?i.addText(s):s.children&&(i.openNode(s),s.children.forEach((s=>this._walk(i,s))),i.closeNode(s)),i}static _collapse(i){"string"!=typeof i&&i.children&&(i.children.every((i=>"string"==typeof i))?i.children=[i.children.join("")]:i.children.forEach((i=>{TokenTree._collapse(i)})))}}class TokenTreeEmitter extends TokenTree{constructor(i){super(),this.options=i}addKeyword(i,s){""!==i&&(this.openNode(s),this.addText(i),this.closeNode())}addText(i){""!==i&&this.add(i)}addSublanguage(i,s){const u=i.root;u.kind=s,u.sublanguage=!0,this.add(u)}toHTML(){return new HTMLRenderer(this,this.options).value()}finalize(){return!0}}function source(i){return i?"string"==typeof i?i:i.source:null}const m=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./;const v="[a-zA-Z]\\w*",_="[a-zA-Z_]\\w*",j="\\b\\d+(\\.\\d+)?",M="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",$="\\b(0b[01]+)",W={begin:"\\\\[\\s\\S]",relevance:0},X={className:"string",begin:"'",end:"'",illegal:"\\n",contains:[W]},Y={className:"string",begin:'"',end:'"',illegal:"\\n",contains:[W]},Z={begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/},COMMENT=function(i,s,u={}){const m=inherit({className:"comment",begin:i,end:s,contains:[]},u);return m.contains.push(Z),m.contains.push({className:"doctag",begin:"(?:TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):",relevance:0}),m},ee=COMMENT("//","$"),ie=COMMENT("/\\*","\\*/"),ae=COMMENT("#","$"),le={className:"number",begin:j,relevance:0},ce={className:"number",begin:M,relevance:0},pe={className:"number",begin:$,relevance:0},de={className:"number",begin:j+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",relevance:0},fe={begin:/(?=\/[^/\n]*\/)/,contains:[{className:"regexp",begin:/\//,end:/\/[gimuy]*/,illegal:/\n/,contains:[W,{begin:/\[/,end:/\]/,relevance:0,contains:[W]}]}]},ye={className:"title",begin:v,relevance:0},be={className:"title",begin:_,relevance:0},_e={begin:"\\.\\s*"+_,relevance:0};var we=Object.freeze({__proto__:null,MATCH_NOTHING_RE:/\b\B/,IDENT_RE:v,UNDERSCORE_IDENT_RE:_,NUMBER_RE:j,C_NUMBER_RE:M,BINARY_NUMBER_RE:$,RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",SHEBANG:(i={})=>{const s=/^#![ ]*\//;return i.binary&&(i.begin=function concat(...i){return i.map((i=>source(i))).join("")}(s,/.*\b/,i.binary,/\b.*/)),inherit({className:"meta",begin:s,end:/$/,relevance:0,"on:begin":(i,s)=>{0!==i.index&&s.ignoreMatch()}},i)},BACKSLASH_ESCAPE:W,APOS_STRING_MODE:X,QUOTE_STRING_MODE:Y,PHRASAL_WORDS_MODE:Z,COMMENT,C_LINE_COMMENT_MODE:ee,C_BLOCK_COMMENT_MODE:ie,HASH_COMMENT_MODE:ae,NUMBER_MODE:le,C_NUMBER_MODE:ce,BINARY_NUMBER_MODE:pe,CSS_NUMBER_MODE:de,REGEXP_MODE:fe,TITLE_MODE:ye,UNDERSCORE_TITLE_MODE:be,METHOD_GUARD:_e,END_SAME_AS_BEGIN:function(i){return Object.assign(i,{"on:begin":(i,s)=>{s.data._beginMatch=i[1]},"on:end":(i,s)=>{s.data._beginMatch!==i[1]&&s.ignoreMatch()}})}});function skipIfhasPrecedingDot(i,s){"."===i.input[i.index-1]&&s.ignoreMatch()}function beginKeywords(i,s){s&&i.beginKeywords&&(i.begin="\\b("+i.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)",i.__beforeBegin=skipIfhasPrecedingDot,i.keywords=i.keywords||i.beginKeywords,delete i.beginKeywords,void 0===i.relevance&&(i.relevance=0))}function compileIllegal(i,s){Array.isArray(i.illegal)&&(i.illegal=function either(...i){return"("+i.map((i=>source(i))).join("|")+")"}(...i.illegal))}function compileMatch(i,s){if(i.match){if(i.begin||i.end)throw new Error("begin & end are not supported with match");i.begin=i.match,delete i.match}}function compileRelevance(i,s){void 0===i.relevance&&(i.relevance=1)}const Se=["of","and","for","in","not","or","if","then","parent","list","value"],xe="keyword";function compileKeywords(i,s,u=xe){const m={};return"string"==typeof i?compileList(u,i.split(" ")):Array.isArray(i)?compileList(u,i):Object.keys(i).forEach((function(u){Object.assign(m,compileKeywords(i[u],s,u))})),m;function compileList(i,u){s&&(u=u.map((i=>i.toLowerCase()))),u.forEach((function(s){const u=s.split("|");m[u[0]]=[i,scoreForKeyword(u[0],u[1])]}))}}function scoreForKeyword(i,s){return s?Number(s):function commonKeyword(i){return Se.includes(i.toLowerCase())}(i)?0:1}function compileLanguage(i,{plugins:s}){function langRe(s,u){return new RegExp(source(s),"m"+(i.case_insensitive?"i":"")+(u?"g":""))}class MultiRegex{constructor(){this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0}addRule(i,s){s.position=this.position++,this.matchIndexes[this.matchAt]=s,this.regexes.push([s,i]),this.matchAt+=function countMatchGroups(i){return new RegExp(i.toString()+"|").exec("").length-1}(i)+1}compile(){0===this.regexes.length&&(this.exec=()=>null);const i=this.regexes.map((i=>i[1]));this.matcherRe=langRe(function join(i,s="|"){let u=0;return i.map((i=>{u+=1;const s=u;let v=source(i),_="";for(;v.length>0;){const i=m.exec(v);if(!i){_+=v;break}_+=v.substring(0,i.index),v=v.substring(i.index+i[0].length),"\\"===i[0][0]&&i[1]?_+="\\"+String(Number(i[1])+s):(_+=i[0],"("===i[0]&&u++)}return _})).map((i=>`(${i})`)).join(s)}(i),!0),this.lastIndex=0}exec(i){this.matcherRe.lastIndex=this.lastIndex;const s=this.matcherRe.exec(i);if(!s)return null;const u=s.findIndex(((i,s)=>s>0&&void 0!==i)),m=this.matchIndexes[u];return s.splice(0,u),Object.assign(s,m)}}class ResumableMultiRegex{constructor(){this.rules=[],this.multiRegexes=[],this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(i){if(this.multiRegexes[i])return this.multiRegexes[i];const s=new MultiRegex;return this.rules.slice(i).forEach((([i,u])=>s.addRule(i,u))),s.compile(),this.multiRegexes[i]=s,s}resumingScanAtSamePosition(){return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(i,s){this.rules.push([i,s]),"begin"===s.type&&this.count++}exec(i){const s=this.getMatcher(this.regexIndex);s.lastIndex=this.lastIndex;let u=s.exec(i);if(this.resumingScanAtSamePosition())if(u&&u.index===this.lastIndex);else{const s=this.getMatcher(0);s.lastIndex=this.lastIndex+1,u=s.exec(i)}return u&&(this.regexIndex+=u.position+1,this.regexIndex===this.count&&this.considerAll()),u}}if(i.compilerExtensions||(i.compilerExtensions=[]),i.contains&&i.contains.includes("self"))throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.");return i.classNameAliases=inherit(i.classNameAliases||{}),function compileMode(s,u){const m=s;if(s.isCompiled)return m;[compileMatch].forEach((i=>i(s,u))),i.compilerExtensions.forEach((i=>i(s,u))),s.__beforeBegin=null,[beginKeywords,compileIllegal,compileRelevance].forEach((i=>i(s,u))),s.isCompiled=!0;let v=null;if("object"==typeof s.keywords&&(v=s.keywords.$pattern,delete s.keywords.$pattern),s.keywords&&(s.keywords=compileKeywords(s.keywords,i.case_insensitive)),s.lexemes&&v)throw new Error("ERR: Prefer `keywords.$pattern` to `mode.lexemes`, BOTH are not allowed. (see mode reference) ");return v=v||s.lexemes||/\w+/,m.keywordPatternRe=langRe(v,!0),u&&(s.begin||(s.begin=/\B|\b/),m.beginRe=langRe(s.begin),s.endSameAsBegin&&(s.end=s.begin),s.end||s.endsWithParent||(s.end=/\B|\b/),s.end&&(m.endRe=langRe(s.end)),m.terminatorEnd=source(s.end)||"",s.endsWithParent&&u.terminatorEnd&&(m.terminatorEnd+=(s.end?"|":"")+u.terminatorEnd)),s.illegal&&(m.illegalRe=langRe(s.illegal)),s.contains||(s.contains=[]),s.contains=[].concat(...s.contains.map((function(i){return function expandOrCloneMode(i){i.variants&&!i.cachedVariants&&(i.cachedVariants=i.variants.map((function(s){return inherit(i,{variants:null},s)})));if(i.cachedVariants)return i.cachedVariants;if(dependencyOnParent(i))return inherit(i,{starts:i.starts?inherit(i.starts):null});if(Object.isFrozen(i))return inherit(i);return i}("self"===i?s:i)}))),s.contains.forEach((function(i){compileMode(i,m)})),s.starts&&compileMode(s.starts,u),m.matcher=function buildModeRegex(i){const s=new ResumableMultiRegex;return i.contains.forEach((i=>s.addRule(i.begin,{rule:i,type:"begin"}))),i.terminatorEnd&&s.addRule(i.terminatorEnd,{type:"end"}),i.illegal&&s.addRule(i.illegal,{type:"illegal"}),s}(m),m}(i)}function dependencyOnParent(i){return!!i&&(i.endsWithParent||dependencyOnParent(i.starts))}function BuildVuePlugin(i){const s={props:["language","code","autodetect"],data:function(){return{detectedLanguage:"",unknownLanguage:!1}},computed:{className(){return this.unknownLanguage?"":"hljs "+this.detectedLanguage},highlighted(){if(!this.autoDetect&&!i.getLanguage(this.language))return console.warn(`The language "${this.language}" you specified could not be found.`),this.unknownLanguage=!0,escapeHTML(this.code);let s={};return this.autoDetect?(s=i.highlightAuto(this.code),this.detectedLanguage=s.language):(s=i.highlight(this.language,this.code,this.ignoreIllegals),this.detectedLanguage=this.language),s.value},autoDetect(){return!this.language||function hasValueOrEmptyAttribute(i){return Boolean(i||""===i)}(this.autodetect)},ignoreIllegals:()=>!0},render(i){return i("pre",{},[i("code",{class:this.className,domProps:{innerHTML:this.highlighted}})])}};return{Component:s,VuePlugin:{install(i){i.component("highlightjs",s)}}}}const Ie={"after:highlightElement":({el:i,result:s,text:u})=>{const m=nodeStream(i);if(!m.length)return;const v=document.createElement("div");v.innerHTML=s.value,s.value=function mergeStreams(i,s,u){let m=0,v="";const _=[];function selectStream(){return i.length&&s.length?i[0].offset!==s[0].offset?i[0].offset"}function close(i){v+=""}function render(i){("start"===i.event?open:close)(i.node)}for(;i.length||s.length;){let s=selectStream();if(v+=escapeHTML(u.substring(m,s[0].offset)),m=s[0].offset,s===i){_.reverse().forEach(close);do{render(s.splice(0,1)[0]),s=selectStream()}while(s===i&&s.length&&s[0].offset===m);_.reverse().forEach(open)}else"start"===s[0].event?_.push(s[0].node):_.pop(),render(s.splice(0,1)[0])}return v+escapeHTML(u.substr(m))}(m,nodeStream(v),u)}};function tag(i){return i.nodeName.toLowerCase()}function nodeStream(i){const s=[];return function _nodeStream(i,u){for(let m=i.firstChild;m;m=m.nextSibling)3===m.nodeType?u+=m.nodeValue.length:1===m.nodeType&&(s.push({event:"start",offset:u,node:m}),u=_nodeStream(m,u),tag(m).match(/br|hr|img|input/)||s.push({event:"stop",offset:u,node:m}));return u}(i,0),s}const Pe={},error=i=>{console.error(i)},warn=(i,...s)=>{console.log(`WARN: ${i}`,...s)},deprecated=(i,s)=>{Pe[`${i}/${s}`]||(console.log(`Deprecated as of ${i}. ${s}`),Pe[`${i}/${s}`]=!0)},Te=escapeHTML,Re=inherit,qe=Symbol("nomatch");var ze=function(i){const u=Object.create(null),m=Object.create(null),v=[];let _=!0;const j=/(^(<[^>]+>|\t|)+|\n)/gm,M="Could not find the language '{}', did you forget to load/include a language module?",$={disableAutodetect:!0,name:"Plain text",contains:[]};let W={noHighlightRe:/^(no-?highlight)$/i,languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:null,__emitter:TokenTreeEmitter};function shouldNotHighlight(i){return W.noHighlightRe.test(i)}function highlight(i,s,u,m){let v="",_="";"object"==typeof s?(v=i,u=s.ignoreIllegals,_=s.language,m=void 0):(deprecated("10.7.0","highlight(lang, code, ...args) has been deprecated."),deprecated("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"),_=i,v=s);const j={code:v,language:_};fire("before:highlight",j);const M=j.result?j.result:_highlight(j.language,j.code,u,m);return M.code=j.code,fire("after:highlight",M),M}function _highlight(i,s,m,j){function keywordData(i,s){const u=X.case_insensitive?s[0].toLowerCase():s[0];return Object.prototype.hasOwnProperty.call(i.keywords,u)&&i.keywords[u]}function processBuffer(){null!=ee.subLanguage?function processSubLanguage(){if(""===le)return;let i=null;if("string"==typeof ee.subLanguage){if(!u[ee.subLanguage])return void ae.addText(le);i=_highlight(ee.subLanguage,le,!0,ie[ee.subLanguage]),ie[ee.subLanguage]=i.top}else i=highlightAuto(le,ee.subLanguage.length?ee.subLanguage:null);ee.relevance>0&&(ce+=i.relevance),ae.addSublanguage(i.emitter,i.language)}():function processKeywords(){if(!ee.keywords)return void ae.addText(le);let i=0;ee.keywordPatternRe.lastIndex=0;let s=ee.keywordPatternRe.exec(le),u="";for(;s;){u+=le.substring(i,s.index);const m=keywordData(ee,s);if(m){const[i,v]=m;if(ae.addText(u),u="",ce+=v,i.startsWith("_"))u+=s[0];else{const u=X.classNameAliases[i]||i;ae.addKeyword(s[0],u)}}else u+=s[0];i=ee.keywordPatternRe.lastIndex,s=ee.keywordPatternRe.exec(le)}u+=le.substr(i),ae.addText(u)}(),le=""}function startNewMode(i){return i.className&&ae.openNode(X.classNameAliases[i.className]||i.className),ee=Object.create(i,{parent:{value:ee}}),ee}function endOfMode(i,s,u){let m=function startsWith(i,s){const u=i&&i.exec(s);return u&&0===u.index}(i.endRe,u);if(m){if(i["on:end"]){const u=new Response(i);i["on:end"](s,u),u.isMatchIgnored&&(m=!1)}if(m){for(;i.endsParent&&i.parent;)i=i.parent;return i}}if(i.endsWithParent)return endOfMode(i.parent,s,u)}function doIgnore(i){return 0===ee.matcher.regexIndex?(le+=i[0],1):(fe=!0,0)}function doBeginMatch(i){const s=i[0],u=i.rule,m=new Response(u),v=[u.__beforeBegin,u["on:begin"]];for(const u of v)if(u&&(u(i,m),m.isMatchIgnored))return doIgnore(s);return u&&u.endSameAsBegin&&(u.endRe=function escape(i){return new RegExp(i.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),"m")}(s)),u.skip?le+=s:(u.excludeBegin&&(le+=s),processBuffer(),u.returnBegin||u.excludeBegin||(le=s)),startNewMode(u),u.returnBegin?0:s.length}function doEndMatch(i){const u=i[0],m=s.substr(i.index),v=endOfMode(ee,i,m);if(!v)return qe;const _=ee;_.skip?le+=u:(_.returnEnd||_.excludeEnd||(le+=u),processBuffer(),_.excludeEnd&&(le=u));do{ee.className&&ae.closeNode(),ee.skip||ee.subLanguage||(ce+=ee.relevance),ee=ee.parent}while(ee!==v.parent);return v.starts&&(v.endSameAsBegin&&(v.starts.endRe=v.endRe),startNewMode(v.starts)),_.returnEnd?0:u.length}let $={};function processLexeme(u,v){const j=v&&v[0];if(le+=u,null==j)return processBuffer(),0;if("begin"===$.type&&"end"===v.type&&$.index===v.index&&""===j){if(le+=s.slice(v.index,v.index+1),!_){const s=new Error("0 width match regex");throw s.languageName=i,s.badRule=$.rule,s}return 1}if($=v,"begin"===v.type)return doBeginMatch(v);if("illegal"===v.type&&!m){const i=new Error('Illegal lexeme "'+j+'" for mode "'+(ee.className||"")+'"');throw i.mode=ee,i}if("end"===v.type){const i=doEndMatch(v);if(i!==qe)return i}if("illegal"===v.type&&""===j)return 1;if(de>1e5&&de>3*v.index){throw new Error("potential infinite loop, way more iterations than matches")}return le+=j,j.length}const X=getLanguage(i);if(!X)throw error(M.replace("{}",i)),new Error('Unknown language: "'+i+'"');const Y=compileLanguage(X,{plugins:v});let Z="",ee=j||Y;const ie={},ae=new W.__emitter(W);!function processContinuations(){const i=[];for(let s=ee;s!==X;s=s.parent)s.className&&i.unshift(s.className);i.forEach((i=>ae.openNode(i)))}();let le="",ce=0,pe=0,de=0,fe=!1;try{for(ee.matcher.considerAll();;){de++,fe?fe=!1:ee.matcher.considerAll(),ee.matcher.lastIndex=pe;const i=ee.matcher.exec(s);if(!i)break;const u=processLexeme(s.substring(pe,i.index),i);pe=i.index+u}return processLexeme(s.substr(pe)),ae.closeAllNodes(),ae.finalize(),Z=ae.toHTML(),{relevance:Math.floor(ce),value:Z,language:i,illegal:!1,emitter:ae,top:ee}}catch(u){if(u.message&&u.message.includes("Illegal"))return{illegal:!0,illegalBy:{msg:u.message,context:s.slice(pe-100,pe+100),mode:u.mode},sofar:Z,relevance:0,value:Te(s),emitter:ae};if(_)return{illegal:!1,relevance:0,value:Te(s),emitter:ae,language:i,top:ee,errorRaised:u};throw u}}function highlightAuto(i,s){s=s||W.languages||Object.keys(u);const m=function justTextHighlightResult(i){const s={relevance:0,emitter:new W.__emitter(W),value:Te(i),illegal:!1,top:$};return s.emitter.addText(i),s}(i),v=s.filter(getLanguage).filter(autoDetection).map((s=>_highlight(s,i,!1)));v.unshift(m);const _=v.sort(((i,s)=>{if(i.relevance!==s.relevance)return s.relevance-i.relevance;if(i.language&&s.language){if(getLanguage(i.language).supersetOf===s.language)return 1;if(getLanguage(s.language).supersetOf===i.language)return-1}return 0})),[j,M]=_,X=j;return X.second_best=M,X}const X={"before:highlightElement":({el:i})=>{W.useBR&&(i.innerHTML=i.innerHTML.replace(/\n/g,"").replace(//g,"\n"))},"after:highlightElement":({result:i})=>{W.useBR&&(i.value=i.value.replace(/\n/g,"
"))}},Y=/^(<[^>]+>|\t)+/gm,Z={"after:highlightElement":({result:i})=>{W.tabReplace&&(i.value=i.value.replace(Y,(i=>i.replace(/\t/g,W.tabReplace))))}};function highlightElement(i){let s=null;const u=function blockLanguage(i){let s=i.className+" ";s+=i.parentNode?i.parentNode.className:"";const u=W.languageDetectRe.exec(s);if(u){const s=getLanguage(u[1]);return s||(warn(M.replace("{}",u[1])),warn("Falling back to no-highlight mode for this block.",i)),s?u[1]:"no-highlight"}return s.split(/\s+/).find((i=>shouldNotHighlight(i)||getLanguage(i)))}(i);if(shouldNotHighlight(u))return;fire("before:highlightElement",{el:i,language:u}),s=i;const v=s.textContent,_=u?highlight(v,{language:u,ignoreIllegals:!0}):highlightAuto(v);fire("after:highlightElement",{el:i,result:_,text:v}),i.innerHTML=_.value,function updateClassName(i,s,u){const v=s?m[s]:u;i.classList.add("hljs"),v&&i.classList.add(v)}(i,u,_.language),i.result={language:_.language,re:_.relevance,relavance:_.relevance},_.second_best&&(i.second_best={language:_.second_best.language,re:_.second_best.relevance,relavance:_.second_best.relevance})}const initHighlighting=()=>{if(initHighlighting.called)return;initHighlighting.called=!0,deprecated("10.6.0","initHighlighting() is deprecated. Use highlightAll() instead.");document.querySelectorAll("pre code").forEach(highlightElement)};let ee=!1;function highlightAll(){if("loading"===document.readyState)return void(ee=!0);document.querySelectorAll("pre code").forEach(highlightElement)}function getLanguage(i){return i=(i||"").toLowerCase(),u[i]||u[m[i]]}function registerAliases(i,{languageName:s}){"string"==typeof i&&(i=[i]),i.forEach((i=>{m[i.toLowerCase()]=s}))}function autoDetection(i){const s=getLanguage(i);return s&&!s.disableAutodetect}function fire(i,s){const u=i;v.forEach((function(i){i[u]&&i[u](s)}))}"undefined"!=typeof window&&window.addEventListener&&window.addEventListener("DOMContentLoaded",(function boot(){ee&&highlightAll()}),!1),Object.assign(i,{highlight,highlightAuto,highlightAll,fixMarkup:function deprecateFixMarkup(i){return deprecated("10.2.0","fixMarkup will be removed entirely in v11.0"),deprecated("10.2.0","Please see https://github.com/highlightjs/highlight.js/issues/2534"),function fixMarkup(i){return W.tabReplace||W.useBR?i.replace(j,(i=>"\n"===i?W.useBR?"
":i:W.tabReplace?i.replace(/\t/g,W.tabReplace):i)):i}(i)},highlightElement,highlightBlock:function deprecateHighlightBlock(i){return deprecated("10.7.0","highlightBlock will be removed entirely in v12.0"),deprecated("10.7.0","Please use highlightElement now."),highlightElement(i)},configure:function configure(i){i.useBR&&(deprecated("10.3.0","'useBR' will be removed entirely in v11.0"),deprecated("10.3.0","Please see https://github.com/highlightjs/highlight.js/issues/2559")),W=Re(W,i)},initHighlighting,initHighlightingOnLoad:function initHighlightingOnLoad(){deprecated("10.6.0","initHighlightingOnLoad() is deprecated. Use highlightAll() instead."),ee=!0},registerLanguage:function registerLanguage(s,m){let v=null;try{v=m(i)}catch(i){if(error("Language definition for '{}' could not be registered.".replace("{}",s)),!_)throw i;error(i),v=$}v.name||(v.name=s),u[s]=v,v.rawDefinition=m.bind(null,i),v.aliases&®isterAliases(v.aliases,{languageName:s})},unregisterLanguage:function unregisterLanguage(i){delete u[i];for(const s of Object.keys(m))m[s]===i&&delete m[s]},listLanguages:function listLanguages(){return Object.keys(u)},getLanguage,registerAliases,requireLanguage:function requireLanguage(i){deprecated("10.4.0","requireLanguage will be removed entirely in v11."),deprecated("10.4.0","Please see https://github.com/highlightjs/highlight.js/pull/2844");const s=getLanguage(i);if(s)return s;throw new Error("The '{}' language is required, but not loaded.".replace("{}",i))},autoDetection,inherit:Re,addPlugin:function addPlugin(i){!function upgradePluginAPI(i){i["before:highlightBlock"]&&!i["before:highlightElement"]&&(i["before:highlightElement"]=s=>{i["before:highlightBlock"](Object.assign({block:s.el},s))}),i["after:highlightBlock"]&&!i["after:highlightElement"]&&(i["after:highlightElement"]=s=>{i["after:highlightBlock"](Object.assign({block:s.el},s))})}(i),v.push(i)},vuePlugin:BuildVuePlugin(i).VuePlugin}),i.debugMode=function(){_=!1},i.safeMode=function(){_=!0},i.versionString="10.7.3";for(const i in we)"object"==typeof we[i]&&s(we[i]);return Object.assign(i,we),i.addPlugin(X),i.addPlugin(Ie),i.addPlugin(Z),i}({});i.exports=ze},61519:i=>{function concat(...i){return i.map((i=>function source(i){return i?"string"==typeof i?i:i.source:null}(i))).join("")}i.exports=function bash(i){const s={},u={begin:/\$\{/,end:/\}/,contains:["self",{begin:/:-/,contains:[s]}]};Object.assign(s,{className:"variable",variants:[{begin:concat(/\$[\w\d#@][\w\d_]*/,"(?![\\w\\d])(?![$])")},u]});const m={className:"subst",begin:/\$\(/,end:/\)/,contains:[i.BACKSLASH_ESCAPE]},v={begin:/<<-?\s*(?=\w+)/,starts:{contains:[i.END_SAME_AS_BEGIN({begin:/(\w+)/,end:/(\w+)/,className:"string"})]}},_={className:"string",begin:/"/,end:/"/,contains:[i.BACKSLASH_ESCAPE,s,m]};m.contains.push(_);const j={begin:/\$\(\(/,end:/\)\)/,contains:[{begin:/\d+#[0-9a-f]+/,className:"number"},i.NUMBER_MODE,s]},M=i.SHEBANG({binary:`(${["fish","bash","zsh","sh","csh","ksh","tcsh","dash","scsh"].join("|")})`,relevance:10}),$={className:"function",begin:/\w[\w\d_]*\s*\(\s*\)\s*\{/,returnBegin:!0,contains:[i.inherit(i.TITLE_MODE,{begin:/\w[\w\d_]*/})],relevance:0};return{name:"Bash",aliases:["sh","zsh"],keywords:{$pattern:/\b[a-z._-]+\b/,keyword:"if then else elif fi for while in do done case esac function",literal:"true false",built_in:"break cd continue eval exec exit export getopts hash pwd readonly return shift test times trap umask unset alias bind builtin caller command declare echo enable help let local logout mapfile printf read readarray source type typeset ulimit unalias set shopt autoload bg bindkey bye cap chdir clone comparguments compcall compctl compdescribe compfiles compgroups compquote comptags comptry compvalues dirs disable disown echotc echoti emulate fc fg float functions getcap getln history integer jobs kill limit log noglob popd print pushd pushln rehash sched setcap setopt stat suspend ttyctl unfunction unhash unlimit unsetopt vared wait whence where which zcompile zformat zftp zle zmodload zparseopts zprof zpty zregexparse zsocket zstyle ztcp"},contains:[M,i.SHEBANG(),$,j,i.HASH_COMMENT_MODE,v,_,{className:"",begin:/\\"/},{className:"string",begin:/'/,end:/'/},s]}}},30786:i=>{function concat(...i){return i.map((i=>function source(i){return i?"string"==typeof i?i:i.source:null}(i))).join("")}i.exports=function http(i){const s="HTTP/(2|1\\.[01])",u={className:"attribute",begin:concat("^",/[A-Za-z][A-Za-z0-9-]*/,"(?=\\:\\s)"),starts:{contains:[{className:"punctuation",begin:/: /,relevance:0,starts:{end:"$",relevance:0}}]}},m=[u,{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0}}];return{name:"HTTP",aliases:["https"],illegal:/\S/,contains:[{begin:"^(?="+s+" \\d{3})",end:/$/,contains:[{className:"meta",begin:s},{className:"number",begin:"\\b\\d{3}\\b"}],starts:{end:/\b\B/,illegal:/\S/,contains:m}},{begin:"(?=^[A-Z]+ (.*?) "+s+"$)",end:/$/,contains:[{className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{className:"meta",begin:s},{className:"keyword",begin:"[A-Z]+"}],starts:{end:/\b\B/,illegal:/\S/,contains:m}},i.inherit(u,{relevance:0})]}}},96344:i=>{const s="[A-Za-z$_][0-9A-Za-z$_]*",u=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends"],m=["true","false","null","undefined","NaN","Infinity"],v=[].concat(["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],["arguments","this","super","console","window","document","localStorage","module","global"],["Intl","DataView","Number","Math","Date","String","RegExp","Object","Function","Boolean","Error","Symbol","Set","Map","WeakSet","WeakMap","Proxy","Reflect","JSON","Promise","Float64Array","Int16Array","Int32Array","Int8Array","Uint16Array","Uint32Array","Float32Array","Array","Uint8Array","Uint8ClampedArray","ArrayBuffer","BigInt64Array","BigUint64Array","BigInt"],["EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"]);function lookahead(i){return concat("(?=",i,")")}function concat(...i){return i.map((i=>function source(i){return i?"string"==typeof i?i:i.source:null}(i))).join("")}i.exports=function javascript(i){const _=s,j="<>",M="",$={begin:/<[A-Za-z0-9\\._:-]+/,end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(i,s)=>{const u=i[0].length+i.index,m=i.input[u];"<"!==m?">"===m&&(((i,{after:s})=>{const u="",returnBegin:!0,end:"\\s*=>",contains:[{className:"params",variants:[{begin:i.UNDERSCORE_IDENT_RE,relevance:0},{className:null,begin:/\(\s*\)/,skip:!0},{begin:/\(/,end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:W,contains:ye}]}]},{begin:/,/,relevance:0},{className:"",begin:/\s/,end:/\s*/,skip:!0},{variants:[{begin:j,end:M},{begin:$.begin,"on:begin":$.isTrulyOpeningTag,end:$.end}],subLanguage:"xml",contains:[{begin:$.begin,end:$.end,skip:!0,contains:["self"]}]}],relevance:0},{className:"function",beginKeywords:"function",end:/[{;]/,excludeEnd:!0,keywords:W,contains:["self",i.inherit(i.TITLE_MODE,{begin:_}),be],illegal:/%/},{beginKeywords:"while if switch catch for"},{className:"function",begin:i.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{",returnBegin:!0,contains:[be,i.inherit(i.TITLE_MODE,{begin:_})]},{variants:[{begin:"\\."+_},{begin:"\\$"+_}],relevance:0},{className:"class",beginKeywords:"class",end:/[{;=]/,excludeEnd:!0,illegal:/[:"[\]]/,contains:[{beginKeywords:"extends"},i.UNDERSCORE_TITLE_MODE]},{begin:/\b(?=constructor)/,end:/[{;]/,excludeEnd:!0,contains:[i.inherit(i.TITLE_MODE,{begin:_}),"self",be]},{begin:"(get|set)\\s+(?="+_+"\\()",end:/\{/,keywords:"get set",contains:[i.inherit(i.TITLE_MODE,{begin:_}),{begin:/\(\)/},be]},{begin:/\$[(.]/}]}}},82026:i=>{i.exports=function json(i){const s={literal:"true false null"},u=[i.C_LINE_COMMENT_MODE,i.C_BLOCK_COMMENT_MODE],m=[i.QUOTE_STRING_MODE,i.C_NUMBER_MODE],v={end:",",endsWithParent:!0,excludeEnd:!0,contains:m,keywords:s},_={begin:/\{/,end:/\}/,contains:[{className:"attr",begin:/"/,end:/"/,contains:[i.BACKSLASH_ESCAPE],illegal:"\\n"},i.inherit(v,{begin:/:/})].concat(u),illegal:"\\S"},j={begin:"\\[",end:"\\]",contains:[i.inherit(v)],illegal:"\\S"};return m.push(_,j),u.forEach((function(i){m.push(i)})),{name:"JSON",contains:m,keywords:s,illegal:"\\S"}}},66336:i=>{i.exports=function powershell(i){const s={$pattern:/-?[A-z\.\-]+\b/,keyword:"if else foreach return do while until elseif begin for trap data dynamicparam end break throw param continue finally in switch exit filter try process catch hidden static parameter",built_in:"ac asnp cat cd CFS chdir clc clear clhy cli clp cls clv cnsn compare copy cp cpi cpp curl cvpa dbp del diff dir dnsn ebp echo|0 epal epcsv epsn erase etsn exsn fc fhx fl ft fw gal gbp gc gcb gci gcm gcs gdr gerr ghy gi gin gjb gl gm gmo gp gps gpv group gsn gsnp gsv gtz gu gv gwmi h history icm iex ihy ii ipal ipcsv ipmo ipsn irm ise iwmi iwr kill lp ls man md measure mi mount move mp mv nal ndr ni nmo npssc nsn nv ogv oh popd ps pushd pwd r rbp rcjb rcsn rd rdr ren ri rjb rm rmdir rmo rni rnp rp rsn rsnp rujb rv rvpa rwmi sajb sal saps sasv sbp sc scb select set shcm si sl sleep sls sort sp spjb spps spsv start stz sujb sv swmi tee trcm type wget where wjb write"},u={begin:"`[\\s\\S]",relevance:0},m={className:"variable",variants:[{begin:/\$\B/},{className:"keyword",begin:/\$this/},{begin:/\$[\w\d][\w\d_:]*/}]},v={className:"string",variants:[{begin:/"/,end:/"/},{begin:/@"/,end:/^"@/}],contains:[u,m,{className:"variable",begin:/\$[A-z]/,end:/[^A-z]/}]},_={className:"string",variants:[{begin:/'/,end:/'/},{begin:/@'/,end:/^'@/}]},j=i.inherit(i.COMMENT(null,null),{variants:[{begin:/#/,end:/$/},{begin:/<#/,end:/#>/}],contains:[{className:"doctag",variants:[{begin:/\.(synopsis|description|example|inputs|outputs|notes|link|component|role|functionality)/},{begin:/\.(parameter|forwardhelptargetname|forwardhelpcategory|remotehelprunspace|externalhelp)\s+\S+/}]}]}),M={className:"built_in",variants:[{begin:"(".concat("Add|Clear|Close|Copy|Enter|Exit|Find|Format|Get|Hide|Join|Lock|Move|New|Open|Optimize|Pop|Push|Redo|Remove|Rename|Reset|Resize|Search|Select|Set|Show|Skip|Split|Step|Switch|Undo|Unlock|Watch|Backup|Checkpoint|Compare|Compress|Convert|ConvertFrom|ConvertTo|Dismount|Edit|Expand|Export|Group|Import|Initialize|Limit|Merge|Mount|Out|Publish|Restore|Save|Sync|Unpublish|Update|Approve|Assert|Build|Complete|Confirm|Deny|Deploy|Disable|Enable|Install|Invoke|Register|Request|Restart|Resume|Start|Stop|Submit|Suspend|Uninstall|Unregister|Wait|Debug|Measure|Ping|Repair|Resolve|Test|Trace|Connect|Disconnect|Read|Receive|Send|Write|Block|Grant|Protect|Revoke|Unblock|Unprotect|Use|ForEach|Sort|Tee|Where",")+(-)[\\w\\d]+")}]},$={className:"class",beginKeywords:"class enum",end:/\s*[{]/,excludeEnd:!0,relevance:0,contains:[i.TITLE_MODE]},W={className:"function",begin:/function\s+/,end:/\s*\{|$/,excludeEnd:!0,returnBegin:!0,relevance:0,contains:[{begin:"function",relevance:0,className:"keyword"},{className:"title",begin:/\w[\w\d]*((-)[\w\d]+)*/,relevance:0},{begin:/\(/,end:/\)/,className:"params",relevance:0,contains:[m]}]},X={begin:/using\s/,end:/$/,returnBegin:!0,contains:[v,_,{className:"keyword",begin:/(using|assembly|command|module|namespace|type)/}]},Y={variants:[{className:"operator",begin:"(".concat("-and|-as|-band|-bnot|-bor|-bxor|-casesensitive|-ccontains|-ceq|-cge|-cgt|-cle|-clike|-clt|-cmatch|-cne|-cnotcontains|-cnotlike|-cnotmatch|-contains|-creplace|-csplit|-eq|-exact|-f|-file|-ge|-gt|-icontains|-ieq|-ige|-igt|-ile|-ilike|-ilt|-imatch|-in|-ine|-inotcontains|-inotlike|-inotmatch|-ireplace|-is|-isnot|-isplit|-join|-le|-like|-lt|-match|-ne|-not|-notcontains|-notin|-notlike|-notmatch|-or|-regex|-replace|-shl|-shr|-split|-wildcard|-xor",")\\b")},{className:"literal",begin:/(-)[\w\d]+/,relevance:0}]},Z={className:"function",begin:/\[.*\]\s*[\w]+[ ]??\(/,end:/$/,returnBegin:!0,relevance:0,contains:[{className:"keyword",begin:"(".concat(s.keyword.toString().replace(/\s/g,"|"),")\\b"),endsParent:!0,relevance:0},i.inherit(i.TITLE_MODE,{endsParent:!0})]},ee=[Z,j,u,i.NUMBER_MODE,v,_,M,m,{className:"literal",begin:/\$(null|true|false)\b/},{className:"selector-tag",begin:/@\B/,relevance:0}],ie={begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0,relevance:0,contains:[].concat("self",ee,{begin:"("+["string","char","byte","int","long","bool","decimal","single","double","DateTime","xml","array","hashtable","void"].join("|")+")",className:"built_in",relevance:0},{className:"type",begin:/[\.\w\d]+/,relevance:0})};return Z.contains.unshift(ie),{name:"PowerShell",aliases:["ps","ps1"],case_insensitive:!0,keywords:s,contains:ee.concat($,W,X,Y,ie)}}},42157:i=>{function source(i){return i?"string"==typeof i?i:i.source:null}function lookahead(i){return concat("(?=",i,")")}function concat(...i){return i.map((i=>source(i))).join("")}function either(...i){return"("+i.map((i=>source(i))).join("|")+")"}i.exports=function xml(i){const s=concat(/[A-Z_]/,function optional(i){return concat("(",i,")?")}(/[A-Z0-9_.-]*:/),/[A-Z0-9_.-]*/),u={className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},m={begin:/\s/,contains:[{className:"meta-keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}]},v=i.inherit(m,{begin:/\(/,end:/\)/}),_=i.inherit(i.APOS_STRING_MODE,{className:"meta-string"}),j=i.inherit(i.QUOTE_STRING_MODE,{className:"meta-string"}),M={endsWithParent:!0,illegal:/`]+/}]}]}]};return{name:"HTML, XML",aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"],case_insensitive:!0,contains:[{className:"meta",begin://,relevance:10,contains:[m,j,_,v,{begin:/\[/,end:/\]/,contains:[{className:"meta",begin://,contains:[m,v,j,_]}]}]},i.COMMENT(//,{relevance:10}),{begin://,relevance:10},u,{className:"meta",begin:/<\?xml/,end:/\?>/,relevance:10},{className:"tag",begin:/)/,end:/>/,keywords:{name:"style"},contains:[M],starts:{end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag",begin:/)/,end:/>/,keywords:{name:"script"},contains:[M],starts:{end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{className:"tag",begin:/<>|<\/>/},{className:"tag",begin:concat(//,/>/,/\s/)))),end:/\/?>/,contains:[{className:"name",begin:s,relevance:0,starts:M}]},{className:"tag",begin:concat(/<\//,lookahead(concat(s,/>/))),contains:[{className:"name",begin:s,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}}},54587:i=>{i.exports=function yaml(i){var s="true false yes no null",u="[\\w#;/?:@&=+$,.~*'()[\\]]+",m={className:"string",relevance:0,variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/\S+/}],contains:[i.BACKSLASH_ESCAPE,{className:"template-variable",variants:[{begin:/\{\{/,end:/\}\}/},{begin:/%\{/,end:/\}/}]}]},v=i.inherit(m,{variants:[{begin:/'/,end:/'/},{begin:/"/,end:/"/},{begin:/[^\s,{}[\]]+/}]}),_={className:"number",begin:"\\b[0-9]{4}(-[0-9][0-9]){0,2}([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?(\\.[0-9]*)?([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?\\b"},j={end:",",endsWithParent:!0,excludeEnd:!0,keywords:s,relevance:0},M={begin:/\{/,end:/\}/,contains:[j],illegal:"\\n",relevance:0},$={begin:"\\[",end:"\\]",contains:[j],illegal:"\\n",relevance:0},W=[{className:"attr",variants:[{begin:"\\w[\\w :\\/.-]*:(?=[ \t]|$)"},{begin:'"\\w[\\w :\\/.-]*":(?=[ \t]|$)'},{begin:"'\\w[\\w :\\/.-]*':(?=[ \t]|$)"}]},{className:"meta",begin:"^---\\s*$",relevance:10},{className:"string",begin:"[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*"},{begin:"<%[%=-]?",end:"[%-]?%>",subLanguage:"ruby",excludeBegin:!0,excludeEnd:!0,relevance:0},{className:"type",begin:"!\\w+!"+u},{className:"type",begin:"!<"+u+">"},{className:"type",begin:"!"+u},{className:"type",begin:"!!"+u},{className:"meta",begin:"&"+i.UNDERSCORE_IDENT_RE+"$"},{className:"meta",begin:"\\*"+i.UNDERSCORE_IDENT_RE+"$"},{className:"bullet",begin:"-(?=[ ]|$)",relevance:0},i.HASH_COMMENT_MODE,{beginKeywords:s,keywords:{literal:s}},_,{className:"number",begin:i.C_NUMBER_RE+"\\b",relevance:0},M,$,m],X=[...W];return X.pop(),X.push(v),j.contains=X,{name:"YAML",case_insensitive:!0,aliases:["yml"],contains:W}}},8679:(i,s,u)=>{"use strict";var m=u(59864),v={childContextTypes:!0,contextType:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDefaultProps:!0,getDerivedStateFromError:!0,getDerivedStateFromProps:!0,mixins:!0,propTypes:!0,type:!0},_={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},j={$$typeof:!0,compare:!0,defaultProps:!0,displayName:!0,propTypes:!0,type:!0},M={};function getStatics(i){return m.isMemo(i)?j:M[i.$$typeof]||v}M[m.ForwardRef]={$$typeof:!0,render:!0,defaultProps:!0,displayName:!0,propTypes:!0},M[m.Memo]=j;var $=Object.defineProperty,W=Object.getOwnPropertyNames,X=Object.getOwnPropertySymbols,Y=Object.getOwnPropertyDescriptor,Z=Object.getPrototypeOf,ee=Object.prototype;i.exports=function hoistNonReactStatics(i,s,u){if("string"!=typeof s){if(ee){var m=Z(s);m&&m!==ee&&hoistNonReactStatics(i,m,u)}var v=W(s);X&&(v=v.concat(X(s)));for(var j=getStatics(i),M=getStatics(s),ie=0;ie{s.read=function(i,s,u,m,v){var _,j,M=8*v-m-1,$=(1<>1,X=-7,Y=u?v-1:0,Z=u?-1:1,ee=i[s+Y];for(Y+=Z,_=ee&(1<<-X)-1,ee>>=-X,X+=M;X>0;_=256*_+i[s+Y],Y+=Z,X-=8);for(j=_&(1<<-X)-1,_>>=-X,X+=m;X>0;j=256*j+i[s+Y],Y+=Z,X-=8);if(0===_)_=1-W;else{if(_===$)return j?NaN:1/0*(ee?-1:1);j+=Math.pow(2,m),_-=W}return(ee?-1:1)*j*Math.pow(2,_-m)},s.write=function(i,s,u,m,v,_){var j,M,$,W=8*_-v-1,X=(1<>1,Z=23===v?Math.pow(2,-24)-Math.pow(2,-77):0,ee=m?0:_-1,ie=m?1:-1,ae=s<0||0===s&&1/s<0?1:0;for(s=Math.abs(s),isNaN(s)||s===1/0?(M=isNaN(s)?1:0,j=X):(j=Math.floor(Math.log(s)/Math.LN2),s*($=Math.pow(2,-j))<1&&(j--,$*=2),(s+=j+Y>=1?Z/$:Z*Math.pow(2,1-Y))*$>=2&&(j++,$/=2),j+Y>=X?(M=0,j=X):j+Y>=1?(M=(s*$-1)*Math.pow(2,v),j+=Y):(M=s*Math.pow(2,Y-1)*Math.pow(2,v),j=0));v>=8;i[u+ee]=255&M,ee+=ie,M/=256,v-=8);for(j=j<0;i[u+ee]=255&j,ee+=ie,j/=256,W-=8);i[u+ee-ie]|=128*ae}},43393:function(i){i.exports=function(){"use strict";var i=Array.prototype.slice;function createClass(i,s){s&&(i.prototype=Object.create(s.prototype)),i.prototype.constructor=i}function Iterable(i){return isIterable(i)?i:Seq(i)}function KeyedIterable(i){return isKeyed(i)?i:KeyedSeq(i)}function IndexedIterable(i){return isIndexed(i)?i:IndexedSeq(i)}function SetIterable(i){return isIterable(i)&&!isAssociative(i)?i:SetSeq(i)}function isIterable(i){return!(!i||!i[s])}function isKeyed(i){return!(!i||!i[u])}function isIndexed(i){return!(!i||!i[m])}function isAssociative(i){return isKeyed(i)||isIndexed(i)}function isOrdered(i){return!(!i||!i[v])}createClass(KeyedIterable,Iterable),createClass(IndexedIterable,Iterable),createClass(SetIterable,Iterable),Iterable.isIterable=isIterable,Iterable.isKeyed=isKeyed,Iterable.isIndexed=isIndexed,Iterable.isAssociative=isAssociative,Iterable.isOrdered=isOrdered,Iterable.Keyed=KeyedIterable,Iterable.Indexed=IndexedIterable,Iterable.Set=SetIterable;var s="@@__IMMUTABLE_ITERABLE__@@",u="@@__IMMUTABLE_KEYED__@@",m="@@__IMMUTABLE_INDEXED__@@",v="@@__IMMUTABLE_ORDERED__@@",_="delete",j=5,M=1<>>0;if(""+u!==s||4294967295===u)return NaN;s=u}return s<0?ensureSize(i)+s:s}function returnTrue(){return!0}function wholeSlice(i,s,u){return(0===i||void 0!==u&&i<=-u)&&(void 0===s||void 0!==u&&s>=u)}function resolveBegin(i,s){return resolveIndex(i,s,0)}function resolveEnd(i,s){return resolveIndex(i,s,s)}function resolveIndex(i,s,u){return void 0===i?u:i<0?Math.max(0,s+i):void 0===s?i:Math.min(s,i)}var Z=0,ee=1,ie=2,ae="function"==typeof Symbol&&Symbol.iterator,le="@@iterator",ce=ae||le;function Iterator(i){this.next=i}function iteratorValue(i,s,u,m){var v=0===i?s:1===i?u:[s,u];return m?m.value=v:m={value:v,done:!1},m}function iteratorDone(){return{value:void 0,done:!0}}function hasIterator(i){return!!getIteratorFn(i)}function isIterator(i){return i&&"function"==typeof i.next}function getIterator(i){var s=getIteratorFn(i);return s&&s.call(i)}function getIteratorFn(i){var s=i&&(ae&&i[ae]||i[le]);if("function"==typeof s)return s}function isArrayLike(i){return i&&"number"==typeof i.length}function Seq(i){return null==i?emptySequence():isIterable(i)?i.toSeq():seqFromValue(i)}function KeyedSeq(i){return null==i?emptySequence().toKeyedSeq():isIterable(i)?isKeyed(i)?i.toSeq():i.fromEntrySeq():keyedSeqFromValue(i)}function IndexedSeq(i){return null==i?emptySequence():isIterable(i)?isKeyed(i)?i.entrySeq():i.toIndexedSeq():indexedSeqFromValue(i)}function SetSeq(i){return(null==i?emptySequence():isIterable(i)?isKeyed(i)?i.entrySeq():i:indexedSeqFromValue(i)).toSetSeq()}Iterator.prototype.toString=function(){return"[Iterator]"},Iterator.KEYS=Z,Iterator.VALUES=ee,Iterator.ENTRIES=ie,Iterator.prototype.inspect=Iterator.prototype.toSource=function(){return this.toString()},Iterator.prototype[ce]=function(){return this},createClass(Seq,Iterable),Seq.of=function(){return Seq(arguments)},Seq.prototype.toSeq=function(){return this},Seq.prototype.toString=function(){return this.__toString("Seq {","}")},Seq.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},Seq.prototype.__iterate=function(i,s){return seqIterate(this,i,s,!0)},Seq.prototype.__iterator=function(i,s){return seqIterator(this,i,s,!0)},createClass(KeyedSeq,Seq),KeyedSeq.prototype.toKeyedSeq=function(){return this},createClass(IndexedSeq,Seq),IndexedSeq.of=function(){return IndexedSeq(arguments)},IndexedSeq.prototype.toIndexedSeq=function(){return this},IndexedSeq.prototype.toString=function(){return this.__toString("Seq [","]")},IndexedSeq.prototype.__iterate=function(i,s){return seqIterate(this,i,s,!1)},IndexedSeq.prototype.__iterator=function(i,s){return seqIterator(this,i,s,!1)},createClass(SetSeq,Seq),SetSeq.of=function(){return SetSeq(arguments)},SetSeq.prototype.toSetSeq=function(){return this},Seq.isSeq=isSeq,Seq.Keyed=KeyedSeq,Seq.Set=SetSeq,Seq.Indexed=IndexedSeq;var pe,de,fe,ye="@@__IMMUTABLE_SEQ__@@";function ArraySeq(i){this._array=i,this.size=i.length}function ObjectSeq(i){var s=Object.keys(i);this._object=i,this._keys=s,this.size=s.length}function IterableSeq(i){this._iterable=i,this.size=i.length||i.size}function IteratorSeq(i){this._iterator=i,this._iteratorCache=[]}function isSeq(i){return!(!i||!i[ye])}function emptySequence(){return pe||(pe=new ArraySeq([]))}function keyedSeqFromValue(i){var s=Array.isArray(i)?new ArraySeq(i).fromEntrySeq():isIterator(i)?new IteratorSeq(i).fromEntrySeq():hasIterator(i)?new IterableSeq(i).fromEntrySeq():"object"==typeof i?new ObjectSeq(i):void 0;if(!s)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+i);return s}function indexedSeqFromValue(i){var s=maybeIndexedSeqFromValue(i);if(!s)throw new TypeError("Expected Array or iterable object of values: "+i);return s}function seqFromValue(i){var s=maybeIndexedSeqFromValue(i)||"object"==typeof i&&new ObjectSeq(i);if(!s)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+i);return s}function maybeIndexedSeqFromValue(i){return isArrayLike(i)?new ArraySeq(i):isIterator(i)?new IteratorSeq(i):hasIterator(i)?new IterableSeq(i):void 0}function seqIterate(i,s,u,m){var v=i._cache;if(v){for(var _=v.length-1,j=0;j<=_;j++){var M=v[u?_-j:j];if(!1===s(M[1],m?M[0]:j,i))return j+1}return j}return i.__iterateUncached(s,u)}function seqIterator(i,s,u,m){var v=i._cache;if(v){var _=v.length-1,j=0;return new Iterator((function(){var i=v[u?_-j:j];return j++>_?iteratorDone():iteratorValue(s,m?i[0]:j-1,i[1])}))}return i.__iteratorUncached(s,u)}function fromJS(i,s){return s?fromJSWith(s,i,"",{"":i}):fromJSDefault(i)}function fromJSWith(i,s,u,m){return Array.isArray(s)?i.call(m,u,IndexedSeq(s).map((function(u,m){return fromJSWith(i,u,m,s)}))):isPlainObj(s)?i.call(m,u,KeyedSeq(s).map((function(u,m){return fromJSWith(i,u,m,s)}))):s}function fromJSDefault(i){return Array.isArray(i)?IndexedSeq(i).map(fromJSDefault).toList():isPlainObj(i)?KeyedSeq(i).map(fromJSDefault).toMap():i}function isPlainObj(i){return i&&(i.constructor===Object||void 0===i.constructor)}function is(i,s){if(i===s||i!=i&&s!=s)return!0;if(!i||!s)return!1;if("function"==typeof i.valueOf&&"function"==typeof s.valueOf){if((i=i.valueOf())===(s=s.valueOf())||i!=i&&s!=s)return!0;if(!i||!s)return!1}return!("function"!=typeof i.equals||"function"!=typeof s.equals||!i.equals(s))}function deepEqual(i,s){if(i===s)return!0;if(!isIterable(s)||void 0!==i.size&&void 0!==s.size&&i.size!==s.size||void 0!==i.__hash&&void 0!==s.__hash&&i.__hash!==s.__hash||isKeyed(i)!==isKeyed(s)||isIndexed(i)!==isIndexed(s)||isOrdered(i)!==isOrdered(s))return!1;if(0===i.size&&0===s.size)return!0;var u=!isAssociative(i);if(isOrdered(i)){var m=i.entries();return s.every((function(i,s){var v=m.next().value;return v&&is(v[1],i)&&(u||is(v[0],s))}))&&m.next().done}var v=!1;if(void 0===i.size)if(void 0===s.size)"function"==typeof i.cacheResult&&i.cacheResult();else{v=!0;var _=i;i=s,s=_}var j=!0,M=s.__iterate((function(s,m){if(u?!i.has(s):v?!is(s,i.get(m,W)):!is(i.get(m,W),s))return j=!1,!1}));return j&&i.size===M}function Repeat(i,s){if(!(this instanceof Repeat))return new Repeat(i,s);if(this._value=i,this.size=void 0===s?1/0:Math.max(0,s),0===this.size){if(de)return de;de=this}}function invariant(i,s){if(!i)throw new Error(s)}function Range(i,s,u){if(!(this instanceof Range))return new Range(i,s,u);if(invariant(0!==u,"Cannot step a Range by 0"),i=i||0,void 0===s&&(s=1/0),u=void 0===u?1:Math.abs(u),sm?iteratorDone():iteratorValue(i,v,u[s?m-v++:v++])}))},createClass(ObjectSeq,KeyedSeq),ObjectSeq.prototype.get=function(i,s){return void 0===s||this.has(i)?this._object[i]:s},ObjectSeq.prototype.has=function(i){return this._object.hasOwnProperty(i)},ObjectSeq.prototype.__iterate=function(i,s){for(var u=this._object,m=this._keys,v=m.length-1,_=0;_<=v;_++){var j=m[s?v-_:_];if(!1===i(u[j],j,this))return _+1}return _},ObjectSeq.prototype.__iterator=function(i,s){var u=this._object,m=this._keys,v=m.length-1,_=0;return new Iterator((function(){var j=m[s?v-_:_];return _++>v?iteratorDone():iteratorValue(i,j,u[j])}))},ObjectSeq.prototype[v]=!0,createClass(IterableSeq,IndexedSeq),IterableSeq.prototype.__iterateUncached=function(i,s){if(s)return this.cacheResult().__iterate(i,s);var u=getIterator(this._iterable),m=0;if(isIterator(u))for(var v;!(v=u.next()).done&&!1!==i(v.value,m++,this););return m},IterableSeq.prototype.__iteratorUncached=function(i,s){if(s)return this.cacheResult().__iterator(i,s);var u=getIterator(this._iterable);if(!isIterator(u))return new Iterator(iteratorDone);var m=0;return new Iterator((function(){var s=u.next();return s.done?s:iteratorValue(i,m++,s.value)}))},createClass(IteratorSeq,IndexedSeq),IteratorSeq.prototype.__iterateUncached=function(i,s){if(s)return this.cacheResult().__iterate(i,s);for(var u,m=this._iterator,v=this._iteratorCache,_=0;_=m.length){var s=u.next();if(s.done)return s;m[v]=s.value}return iteratorValue(i,v,m[v++])}))},createClass(Repeat,IndexedSeq),Repeat.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},Repeat.prototype.get=function(i,s){return this.has(i)?this._value:s},Repeat.prototype.includes=function(i){return is(this._value,i)},Repeat.prototype.slice=function(i,s){var u=this.size;return wholeSlice(i,s,u)?this:new Repeat(this._value,resolveEnd(s,u)-resolveBegin(i,u))},Repeat.prototype.reverse=function(){return this},Repeat.prototype.indexOf=function(i){return is(this._value,i)?0:-1},Repeat.prototype.lastIndexOf=function(i){return is(this._value,i)?this.size:-1},Repeat.prototype.__iterate=function(i,s){for(var u=0;u=0&&s=0&&uu?iteratorDone():iteratorValue(i,_++,j)}))},Range.prototype.equals=function(i){return i instanceof Range?this._start===i._start&&this._end===i._end&&this._step===i._step:deepEqual(this,i)},createClass(Collection,Iterable),createClass(KeyedCollection,Collection),createClass(IndexedCollection,Collection),createClass(SetCollection,Collection),Collection.Keyed=KeyedCollection,Collection.Indexed=IndexedCollection,Collection.Set=SetCollection;var be="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function imul(i,s){var u=65535&(i|=0),m=65535&(s|=0);return u*m+((i>>>16)*m+u*(s>>>16)<<16>>>0)|0};function smi(i){return i>>>1&1073741824|3221225471&i}function hash(i){if(!1===i||null==i)return 0;if("function"==typeof i.valueOf&&(!1===(i=i.valueOf())||null==i))return 0;if(!0===i)return 1;var s=typeof i;if("number"===s){if(i!=i||i===1/0)return 0;var u=0|i;for(u!==i&&(u^=4294967295*i);i>4294967295;)u^=i/=4294967295;return smi(u)}if("string"===s)return i.length>Te?cachedHashString(i):hashString(i);if("function"==typeof i.hashCode)return i.hashCode();if("object"===s)return hashJSObj(i);if("function"==typeof i.toString)return hashString(i.toString());throw new Error("Value type "+s+" cannot be hashed.")}function cachedHashString(i){var s=ze[i];return void 0===s&&(s=hashString(i),qe===Re&&(qe=0,ze={}),qe++,ze[i]=s),s}function hashString(i){for(var s=0,u=0;u0)switch(i.nodeType){case 1:return i.uniqueID;case 9:return i.documentElement&&i.documentElement.uniqueID}}var Se,xe="function"==typeof WeakMap;xe&&(Se=new WeakMap);var Ie=0,Pe="__immutablehash__";"function"==typeof Symbol&&(Pe=Symbol(Pe));var Te=16,Re=255,qe=0,ze={};function assertNotInfinite(i){invariant(i!==1/0,"Cannot perform this action with an infinite size.")}function Map(i){return null==i?emptyMap():isMap(i)&&!isOrdered(i)?i:emptyMap().withMutations((function(s){var u=KeyedIterable(i);assertNotInfinite(u.size),u.forEach((function(i,u){return s.set(u,i)}))}))}function isMap(i){return!(!i||!i[We])}createClass(Map,KeyedCollection),Map.of=function(){var s=i.call(arguments,0);return emptyMap().withMutations((function(i){for(var u=0;u=s.length)throw new Error("Missing value for key: "+s[u]);i.set(s[u],s[u+1])}}))},Map.prototype.toString=function(){return this.__toString("Map {","}")},Map.prototype.get=function(i,s){return this._root?this._root.get(0,void 0,i,s):s},Map.prototype.set=function(i,s){return updateMap(this,i,s)},Map.prototype.setIn=function(i,s){return this.updateIn(i,W,(function(){return s}))},Map.prototype.remove=function(i){return updateMap(this,i,W)},Map.prototype.deleteIn=function(i){return this.updateIn(i,(function(){return W}))},Map.prototype.update=function(i,s,u){return 1===arguments.length?i(this):this.updateIn([i],s,u)},Map.prototype.updateIn=function(i,s,u){u||(u=s,s=void 0);var m=updateInDeepMap(this,forceIterator(i),s,u);return m===W?void 0:m},Map.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):emptyMap()},Map.prototype.merge=function(){return mergeIntoMapWith(this,void 0,arguments)},Map.prototype.mergeWith=function(s){return mergeIntoMapWith(this,s,i.call(arguments,1))},Map.prototype.mergeIn=function(s){var u=i.call(arguments,1);return this.updateIn(s,emptyMap(),(function(i){return"function"==typeof i.merge?i.merge.apply(i,u):u[u.length-1]}))},Map.prototype.mergeDeep=function(){return mergeIntoMapWith(this,deepMerger,arguments)},Map.prototype.mergeDeepWith=function(s){var u=i.call(arguments,1);return mergeIntoMapWith(this,deepMergerWith(s),u)},Map.prototype.mergeDeepIn=function(s){var u=i.call(arguments,1);return this.updateIn(s,emptyMap(),(function(i){return"function"==typeof i.mergeDeep?i.mergeDeep.apply(i,u):u[u.length-1]}))},Map.prototype.sort=function(i){return OrderedMap(sortFactory(this,i))},Map.prototype.sortBy=function(i,s){return OrderedMap(sortFactory(this,s,i))},Map.prototype.withMutations=function(i){var s=this.asMutable();return i(s),s.wasAltered()?s.__ensureOwner(this.__ownerID):this},Map.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new OwnerID)},Map.prototype.asImmutable=function(){return this.__ensureOwner()},Map.prototype.wasAltered=function(){return this.__altered},Map.prototype.__iterator=function(i,s){return new MapIterator(this,i,s)},Map.prototype.__iterate=function(i,s){var u=this,m=0;return this._root&&this._root.iterate((function(s){return m++,i(s[1],s[0],u)}),s),m},Map.prototype.__ensureOwner=function(i){return i===this.__ownerID?this:i?makeMap(this.size,this._root,i,this.__hash):(this.__ownerID=i,this.__altered=!1,this)},Map.isMap=isMap;var Ve,We="@@__IMMUTABLE_MAP__@@",He=Map.prototype;function ArrayMapNode(i,s){this.ownerID=i,this.entries=s}function BitmapIndexedNode(i,s,u){this.ownerID=i,this.bitmap=s,this.nodes=u}function HashArrayMapNode(i,s,u){this.ownerID=i,this.count=s,this.nodes=u}function HashCollisionNode(i,s,u){this.ownerID=i,this.keyHash=s,this.entries=u}function ValueNode(i,s,u){this.ownerID=i,this.keyHash=s,this.entry=u}function MapIterator(i,s,u){this._type=s,this._reverse=u,this._stack=i._root&&mapIteratorFrame(i._root)}function mapIteratorValue(i,s){return iteratorValue(i,s[0],s[1])}function mapIteratorFrame(i,s){return{node:i,index:0,__prev:s}}function makeMap(i,s,u,m){var v=Object.create(He);return v.size=i,v._root=s,v.__ownerID=u,v.__hash=m,v.__altered=!1,v}function emptyMap(){return Ve||(Ve=makeMap(0))}function updateMap(i,s,u){var m,v;if(i._root){var _=MakeRef(X),j=MakeRef(Y);if(m=updateNode(i._root,i.__ownerID,0,void 0,s,u,_,j),!j.value)return i;v=i.size+(_.value?u===W?-1:1:0)}else{if(u===W)return i;v=1,m=new ArrayMapNode(i.__ownerID,[[s,u]])}return i.__ownerID?(i.size=v,i._root=m,i.__hash=void 0,i.__altered=!0,i):m?makeMap(v,m):emptyMap()}function updateNode(i,s,u,m,v,_,j,M){return i?i.update(s,u,m,v,_,j,M):_===W?i:(SetRef(M),SetRef(j),new ValueNode(s,m,[v,_]))}function isLeafNode(i){return i.constructor===ValueNode||i.constructor===HashCollisionNode}function mergeIntoNode(i,s,u,m,v){if(i.keyHash===m)return new HashCollisionNode(s,m,[i.entry,v]);var _,M=(0===u?i.keyHash:i.keyHash>>>u)&$,W=(0===u?m:m>>>u)&$;return new BitmapIndexedNode(s,1<>>=1)j[$]=1&u?s[_++]:void 0;return j[m]=v,new HashArrayMapNode(i,_+1,j)}function mergeIntoMapWith(i,s,u){for(var m=[],v=0;v>1&1431655765))+(i>>2&858993459))+(i>>4)&252645135,i+=i>>8,127&(i+=i>>16)}function setIn(i,s,u,m){var v=m?i:arrCopy(i);return v[s]=u,v}function spliceIn(i,s,u,m){var v=i.length+1;if(m&&s+1===v)return i[s]=u,i;for(var _=new Array(v),j=0,M=0;M=Xe)return createNodes(i,$,m,v);var ee=i&&i===this.ownerID,ie=ee?$:arrCopy($);return Z?M?X===Y-1?ie.pop():ie[X]=ie.pop():ie[X]=[m,v]:ie.push([m,v]),ee?(this.entries=ie,this):new ArrayMapNode(i,ie)}},BitmapIndexedNode.prototype.get=function(i,s,u,m){void 0===s&&(s=hash(u));var v=1<<((0===i?s:s>>>i)&$),_=this.bitmap;return 0==(_&v)?m:this.nodes[popCount(_&v-1)].get(i+j,s,u,m)},BitmapIndexedNode.prototype.update=function(i,s,u,m,v,_,M){void 0===u&&(u=hash(m));var X=(0===s?u:u>>>s)&$,Y=1<=Ye)return expandNodes(i,ae,Z,X,ce);if(ee&&!ce&&2===ae.length&&isLeafNode(ae[1^ie]))return ae[1^ie];if(ee&&ce&&1===ae.length&&isLeafNode(ce))return ce;var pe=i&&i===this.ownerID,de=ee?ce?Z:Z^Y:Z|Y,fe=ee?ce?setIn(ae,ie,ce,pe):spliceOut(ae,ie,pe):spliceIn(ae,ie,ce,pe);return pe?(this.bitmap=de,this.nodes=fe,this):new BitmapIndexedNode(i,de,fe)},HashArrayMapNode.prototype.get=function(i,s,u,m){void 0===s&&(s=hash(u));var v=(0===i?s:s>>>i)&$,_=this.nodes[v];return _?_.get(i+j,s,u,m):m},HashArrayMapNode.prototype.update=function(i,s,u,m,v,_,M){void 0===u&&(u=hash(m));var X=(0===s?u:u>>>s)&$,Y=v===W,Z=this.nodes,ee=Z[X];if(Y&&!ee)return this;var ie=updateNode(ee,i,s+j,u,m,v,_,M);if(ie===ee)return this;var ae=this.count;if(ee){if(!ie&&--ae0&&m=0&&i>>s&$;if(m>=this.array.length)return new VNode([],i);var v,_=0===m;if(s>0){var M=this.array[m];if((v=M&&M.removeBefore(i,s-j,u))===M&&_)return this}if(_&&!v)return this;var W=editableVNode(this,i);if(!_)for(var X=0;X>>s&$;if(v>=this.array.length)return this;if(s>0){var _=this.array[v];if((m=_&&_.removeAfter(i,s-j,u))===_&&v===this.array.length-1)return this}var M=editableVNode(this,i);return M.array.splice(v+1),m&&(M.array[v]=m),M};var rt,nt,ot={};function iterateList(i,s){var u=i._origin,m=i._capacity,v=getTailOffset(m),_=i._tail;return iterateNodeOrLeaf(i._root,i._level,0);function iterateNodeOrLeaf(i,s,u){return 0===s?iterateLeaf(i,u):iterateNode(i,s,u)}function iterateLeaf(i,j){var $=j===v?_&&_.array:i&&i.array,W=j>u?0:u-j,X=m-j;return X>M&&(X=M),function(){if(W===X)return ot;var i=s?--X:W++;return $&&$[i]}}function iterateNode(i,v,_){var $,W=i&&i.array,X=_>u?0:u-_>>v,Y=1+(m-_>>v);return Y>M&&(Y=M),function(){for(;;){if($){var i=$();if(i!==ot)return i;$=null}if(X===Y)return ot;var u=s?--Y:X++;$=iterateNodeOrLeaf(W&&W[u],v-j,_+(u<=i.size||s<0)return i.withMutations((function(i){s<0?setListBounds(i,s).set(0,u):setListBounds(i,0,s+1).set(s,u)}));s+=i._origin;var m=i._tail,v=i._root,_=MakeRef(Y);return s>=getTailOffset(i._capacity)?m=updateVNode(m,i.__ownerID,0,s,u,_):v=updateVNode(v,i.__ownerID,i._level,s,u,_),_.value?i.__ownerID?(i._root=v,i._tail=m,i.__hash=void 0,i.__altered=!0,i):makeList(i._origin,i._capacity,i._level,v,m):i}function updateVNode(i,s,u,m,v,_){var M,W=m>>>u&$,X=i&&W0){var Y=i&&i.array[W],Z=updateVNode(Y,s,u-j,m,v,_);return Z===Y?i:((M=editableVNode(i,s)).array[W]=Z,M)}return X&&i.array[W]===v?i:(SetRef(_),M=editableVNode(i,s),void 0===v&&W===M.array.length-1?M.array.pop():M.array[W]=v,M)}function editableVNode(i,s){return s&&i&&s===i.ownerID?i:new VNode(i?i.array.slice():[],s)}function listNodeFor(i,s){if(s>=getTailOffset(i._capacity))return i._tail;if(s<1<0;)u=u.array[s>>>m&$],m-=j;return u}}function setListBounds(i,s,u){void 0!==s&&(s|=0),void 0!==u&&(u|=0);var m=i.__ownerID||new OwnerID,v=i._origin,_=i._capacity,M=v+s,W=void 0===u?_:u<0?_+u:v+u;if(M===v&&W===_)return i;if(M>=W)return i.clear();for(var X=i._level,Y=i._root,Z=0;M+Z<0;)Y=new VNode(Y&&Y.array.length?[void 0,Y]:[],m),Z+=1<<(X+=j);Z&&(M+=Z,v+=Z,W+=Z,_+=Z);for(var ee=getTailOffset(_),ie=getTailOffset(W);ie>=1<ee?new VNode([],m):ae;if(ae&&ie>ee&&M<_&&ae.array.length){for(var ce=Y=editableVNode(Y,m),pe=X;pe>j;pe-=j){var de=ee>>>pe&$;ce=ce.array[de]=editableVNode(ce.array[de],m)}ce.array[ee>>>j&$]=ae}if(W<_&&(le=le&&le.removeAfter(m,0,W)),M>=ie)M-=ie,W-=ie,X=j,Y=null,le=le&&le.removeBefore(m,0,M);else if(M>v||ie>>X&$;if(fe!==ie>>>X&$)break;fe&&(Z+=(1<v&&(Y=Y.removeBefore(m,X,M-Z)),Y&&iev&&(v=M.size),isIterable(j)||(M=M.map((function(i){return fromJS(i)}))),m.push(M)}return v>i.size&&(i=i.setSize(v)),mergeIntoCollectionWith(i,s,m)}function getTailOffset(i){return i>>j<=M&&j.size>=2*_.size?(m=(v=j.filter((function(i,s){return void 0!==i&&$!==s}))).toKeyedSeq().map((function(i){return i[0]})).flip().toMap(),i.__ownerID&&(m.__ownerID=v.__ownerID=i.__ownerID)):(m=_.remove(s),v=$===j.size-1?j.pop():j.set($,void 0))}else if(X){if(u===j.get($)[1])return i;m=_,v=j.set($,[s,u])}else m=_.set(s,j.size),v=j.set(j.size,[s,u]);return i.__ownerID?(i.size=m.size,i._map=m,i._list=v,i.__hash=void 0,i):makeOrderedMap(m,v)}function ToKeyedSequence(i,s){this._iter=i,this._useKeys=s,this.size=i.size}function ToIndexedSequence(i){this._iter=i,this.size=i.size}function ToSetSequence(i){this._iter=i,this.size=i.size}function FromEntriesSequence(i){this._iter=i,this.size=i.size}function flipFactory(i){var s=makeSequence(i);return s._iter=i,s.size=i.size,s.flip=function(){return i},s.reverse=function(){var s=i.reverse.apply(this);return s.flip=function(){return i.reverse()},s},s.has=function(s){return i.includes(s)},s.includes=function(s){return i.has(s)},s.cacheResult=cacheResultThrough,s.__iterateUncached=function(s,u){var m=this;return i.__iterate((function(i,u){return!1!==s(u,i,m)}),u)},s.__iteratorUncached=function(s,u){if(s===ie){var m=i.__iterator(s,u);return new Iterator((function(){var i=m.next();if(!i.done){var s=i.value[0];i.value[0]=i.value[1],i.value[1]=s}return i}))}return i.__iterator(s===ee?Z:ee,u)},s}function mapFactory(i,s,u){var m=makeSequence(i);return m.size=i.size,m.has=function(s){return i.has(s)},m.get=function(m,v){var _=i.get(m,W);return _===W?v:s.call(u,_,m,i)},m.__iterateUncached=function(m,v){var _=this;return i.__iterate((function(i,v,j){return!1!==m(s.call(u,i,v,j),v,_)}),v)},m.__iteratorUncached=function(m,v){var _=i.__iterator(ie,v);return new Iterator((function(){var v=_.next();if(v.done)return v;var j=v.value,M=j[0];return iteratorValue(m,M,s.call(u,j[1],M,i),v)}))},m}function reverseFactory(i,s){var u=makeSequence(i);return u._iter=i,u.size=i.size,u.reverse=function(){return i},i.flip&&(u.flip=function(){var s=flipFactory(i);return s.reverse=function(){return i.flip()},s}),u.get=function(u,m){return i.get(s?u:-1-u,m)},u.has=function(u){return i.has(s?u:-1-u)},u.includes=function(s){return i.includes(s)},u.cacheResult=cacheResultThrough,u.__iterate=function(s,u){var m=this;return i.__iterate((function(i,u){return s(i,u,m)}),!u)},u.__iterator=function(s,u){return i.__iterator(s,!u)},u}function filterFactory(i,s,u,m){var v=makeSequence(i);return m&&(v.has=function(m){var v=i.get(m,W);return v!==W&&!!s.call(u,v,m,i)},v.get=function(m,v){var _=i.get(m,W);return _!==W&&s.call(u,_,m,i)?_:v}),v.__iterateUncached=function(v,_){var j=this,M=0;return i.__iterate((function(i,_,$){if(s.call(u,i,_,$))return M++,v(i,m?_:M-1,j)}),_),M},v.__iteratorUncached=function(v,_){var j=i.__iterator(ie,_),M=0;return new Iterator((function(){for(;;){var _=j.next();if(_.done)return _;var $=_.value,W=$[0],X=$[1];if(s.call(u,X,W,i))return iteratorValue(v,m?W:M++,X,_)}}))},v}function countByFactory(i,s,u){var m=Map().asMutable();return i.__iterate((function(v,_){m.update(s.call(u,v,_,i),0,(function(i){return i+1}))})),m.asImmutable()}function groupByFactory(i,s,u){var m=isKeyed(i),v=(isOrdered(i)?OrderedMap():Map()).asMutable();i.__iterate((function(_,j){v.update(s.call(u,_,j,i),(function(i){return(i=i||[]).push(m?[j,_]:_),i}))}));var _=iterableClass(i);return v.map((function(s){return reify(i,_(s))}))}function sliceFactory(i,s,u,m){var v=i.size;if(void 0!==s&&(s|=0),void 0!==u&&(u===1/0?u=v:u|=0),wholeSlice(s,u,v))return i;var _=resolveBegin(s,v),j=resolveEnd(u,v);if(_!=_||j!=j)return sliceFactory(i.toSeq().cacheResult(),s,u,m);var M,$=j-_;$==$&&(M=$<0?0:$);var W=makeSequence(i);return W.size=0===M?M:i.size&&M||void 0,!m&&isSeq(i)&&M>=0&&(W.get=function(s,u){return(s=wrapIndex(this,s))>=0&&sM)return iteratorDone();var i=v.next();return m||s===ee?i:iteratorValue(s,$-1,s===Z?void 0:i.value[1],i)}))},W}function takeWhileFactory(i,s,u){var m=makeSequence(i);return m.__iterateUncached=function(m,v){var _=this;if(v)return this.cacheResult().__iterate(m,v);var j=0;return i.__iterate((function(i,v,M){return s.call(u,i,v,M)&&++j&&m(i,v,_)})),j},m.__iteratorUncached=function(m,v){var _=this;if(v)return this.cacheResult().__iterator(m,v);var j=i.__iterator(ie,v),M=!0;return new Iterator((function(){if(!M)return iteratorDone();var i=j.next();if(i.done)return i;var v=i.value,$=v[0],W=v[1];return s.call(u,W,$,_)?m===ie?i:iteratorValue(m,$,W,i):(M=!1,iteratorDone())}))},m}function skipWhileFactory(i,s,u,m){var v=makeSequence(i);return v.__iterateUncached=function(v,_){var j=this;if(_)return this.cacheResult().__iterate(v,_);var M=!0,$=0;return i.__iterate((function(i,_,W){if(!M||!(M=s.call(u,i,_,W)))return $++,v(i,m?_:$-1,j)})),$},v.__iteratorUncached=function(v,_){var j=this;if(_)return this.cacheResult().__iterator(v,_);var M=i.__iterator(ie,_),$=!0,W=0;return new Iterator((function(){var i,_,X;do{if((i=M.next()).done)return m||v===ee?i:iteratorValue(v,W++,v===Z?void 0:i.value[1],i);var Y=i.value;_=Y[0],X=Y[1],$&&($=s.call(u,X,_,j))}while($);return v===ie?i:iteratorValue(v,_,X,i)}))},v}function concatFactory(i,s){var u=isKeyed(i),m=[i].concat(s).map((function(i){return isIterable(i)?u&&(i=KeyedIterable(i)):i=u?keyedSeqFromValue(i):indexedSeqFromValue(Array.isArray(i)?i:[i]),i})).filter((function(i){return 0!==i.size}));if(0===m.length)return i;if(1===m.length){var v=m[0];if(v===i||u&&isKeyed(v)||isIndexed(i)&&isIndexed(v))return v}var _=new ArraySeq(m);return u?_=_.toKeyedSeq():isIndexed(i)||(_=_.toSetSeq()),(_=_.flatten(!0)).size=m.reduce((function(i,s){if(void 0!==i){var u=s.size;if(void 0!==u)return i+u}}),0),_}function flattenFactory(i,s,u){var m=makeSequence(i);return m.__iterateUncached=function(m,v){var _=0,j=!1;function flatDeep(i,M){var $=this;i.__iterate((function(i,v){return(!s||M0}function zipWithFactory(i,s,u){var m=makeSequence(i);return m.size=new ArraySeq(u).map((function(i){return i.size})).min(),m.__iterate=function(i,s){for(var u,m=this.__iterator(ee,s),v=0;!(u=m.next()).done&&!1!==i(u.value,v++,this););return v},m.__iteratorUncached=function(i,m){var v=u.map((function(i){return i=Iterable(i),getIterator(m?i.reverse():i)})),_=0,j=!1;return new Iterator((function(){var u;return j||(u=v.map((function(i){return i.next()})),j=u.some((function(i){return i.done}))),j?iteratorDone():iteratorValue(i,_++,s.apply(null,u.map((function(i){return i.value}))))}))},m}function reify(i,s){return isSeq(i)?s:i.constructor(s)}function validateEntry(i){if(i!==Object(i))throw new TypeError("Expected [K, V] tuple: "+i)}function resolveSize(i){return assertNotInfinite(i.size),ensureSize(i)}function iterableClass(i){return isKeyed(i)?KeyedIterable:isIndexed(i)?IndexedIterable:SetIterable}function makeSequence(i){return Object.create((isKeyed(i)?KeyedSeq:isIndexed(i)?IndexedSeq:SetSeq).prototype)}function cacheResultThrough(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):Seq.prototype.cacheResult.call(this)}function defaultComparator(i,s){return i>s?1:i=0;u--)s={value:arguments[u],next:s};return this.__ownerID?(this.size=i,this._head=s,this.__hash=void 0,this.__altered=!0,this):makeStack(i,s)},Stack.prototype.pushAll=function(i){if(0===(i=IndexedIterable(i)).size)return this;assertNotInfinite(i.size);var s=this.size,u=this._head;return i.reverse().forEach((function(i){s++,u={value:i,next:u}})),this.__ownerID?(this.size=s,this._head=u,this.__hash=void 0,this.__altered=!0,this):makeStack(s,u)},Stack.prototype.pop=function(){return this.slice(1)},Stack.prototype.unshift=function(){return this.push.apply(this,arguments)},Stack.prototype.unshiftAll=function(i){return this.pushAll(i)},Stack.prototype.shift=function(){return this.pop.apply(this,arguments)},Stack.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):emptyStack()},Stack.prototype.slice=function(i,s){if(wholeSlice(i,s,this.size))return this;var u=resolveBegin(i,this.size);if(resolveEnd(s,this.size)!==this.size)return IndexedCollection.prototype.slice.call(this,i,s);for(var m=this.size-u,v=this._head;u--;)v=v.next;return this.__ownerID?(this.size=m,this._head=v,this.__hash=void 0,this.__altered=!0,this):makeStack(m,v)},Stack.prototype.__ensureOwner=function(i){return i===this.__ownerID?this:i?makeStack(this.size,this._head,i,this.__hash):(this.__ownerID=i,this.__altered=!1,this)},Stack.prototype.__iterate=function(i,s){if(s)return this.reverse().__iterate(i);for(var u=0,m=this._head;m&&!1!==i(m.value,u++,this);)m=m.next;return u},Stack.prototype.__iterator=function(i,s){if(s)return this.reverse().__iterator(i);var u=0,m=this._head;return new Iterator((function(){if(m){var s=m.value;return m=m.next,iteratorValue(i,u++,s)}return iteratorDone()}))},Stack.isStack=isStack;var pt,ht="@@__IMMUTABLE_STACK__@@",dt=Stack.prototype;function makeStack(i,s,u,m){var v=Object.create(dt);return v.size=i,v._head=s,v.__ownerID=u,v.__hash=m,v.__altered=!1,v}function emptyStack(){return pt||(pt=makeStack(0))}function mixin(i,s){var keyCopier=function(u){i.prototype[u]=s[u]};return Object.keys(s).forEach(keyCopier),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(s).forEach(keyCopier),i}dt[ht]=!0,dt.withMutations=He.withMutations,dt.asMutable=He.asMutable,dt.asImmutable=He.asImmutable,dt.wasAltered=He.wasAltered,Iterable.Iterator=Iterator,mixin(Iterable,{toArray:function(){assertNotInfinite(this.size);var i=new Array(this.size||0);return this.valueSeq().__iterate((function(s,u){i[u]=s})),i},toIndexedSeq:function(){return new ToIndexedSequence(this)},toJS:function(){return this.toSeq().map((function(i){return i&&"function"==typeof i.toJS?i.toJS():i})).__toJS()},toJSON:function(){return this.toSeq().map((function(i){return i&&"function"==typeof i.toJSON?i.toJSON():i})).__toJS()},toKeyedSeq:function(){return new ToKeyedSequence(this,!0)},toMap:function(){return Map(this.toKeyedSeq())},toObject:function(){assertNotInfinite(this.size);var i={};return this.__iterate((function(s,u){i[u]=s})),i},toOrderedMap:function(){return OrderedMap(this.toKeyedSeq())},toOrderedSet:function(){return OrderedSet(isKeyed(this)?this.valueSeq():this)},toSet:function(){return Set(isKeyed(this)?this.valueSeq():this)},toSetSeq:function(){return new ToSetSequence(this)},toSeq:function(){return isIndexed(this)?this.toIndexedSeq():isKeyed(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return Stack(isKeyed(this)?this.valueSeq():this)},toList:function(){return List(isKeyed(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(i,s){return 0===this.size?i+s:i+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+s},concat:function(){return reify(this,concatFactory(this,i.call(arguments,0)))},includes:function(i){return this.some((function(s){return is(s,i)}))},entries:function(){return this.__iterator(ie)},every:function(i,s){assertNotInfinite(this.size);var u=!0;return this.__iterate((function(m,v,_){if(!i.call(s,m,v,_))return u=!1,!1})),u},filter:function(i,s){return reify(this,filterFactory(this,i,s,!0))},find:function(i,s,u){var m=this.findEntry(i,s);return m?m[1]:u},forEach:function(i,s){return assertNotInfinite(this.size),this.__iterate(s?i.bind(s):i)},join:function(i){assertNotInfinite(this.size),i=void 0!==i?""+i:",";var s="",u=!0;return this.__iterate((function(m){u?u=!1:s+=i,s+=null!=m?m.toString():""})),s},keys:function(){return this.__iterator(Z)},map:function(i,s){return reify(this,mapFactory(this,i,s))},reduce:function(i,s,u){var m,v;return assertNotInfinite(this.size),arguments.length<2?v=!0:m=s,this.__iterate((function(s,_,j){v?(v=!1,m=s):m=i.call(u,m,s,_,j)})),m},reduceRight:function(i,s,u){var m=this.toKeyedSeq().reverse();return m.reduce.apply(m,arguments)},reverse:function(){return reify(this,reverseFactory(this,!0))},slice:function(i,s){return reify(this,sliceFactory(this,i,s,!0))},some:function(i,s){return!this.every(not(i),s)},sort:function(i){return reify(this,sortFactory(this,i))},values:function(){return this.__iterator(ee)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some((function(){return!0}))},count:function(i,s){return ensureSize(i?this.toSeq().filter(i,s):this)},countBy:function(i,s){return countByFactory(this,i,s)},equals:function(i){return deepEqual(this,i)},entrySeq:function(){var i=this;if(i._cache)return new ArraySeq(i._cache);var s=i.toSeq().map(entryMapper).toIndexedSeq();return s.fromEntrySeq=function(){return i.toSeq()},s},filterNot:function(i,s){return this.filter(not(i),s)},findEntry:function(i,s,u){var m=u;return this.__iterate((function(u,v,_){if(i.call(s,u,v,_))return m=[v,u],!1})),m},findKey:function(i,s){var u=this.findEntry(i,s);return u&&u[0]},findLast:function(i,s,u){return this.toKeyedSeq().reverse().find(i,s,u)},findLastEntry:function(i,s,u){return this.toKeyedSeq().reverse().findEntry(i,s,u)},findLastKey:function(i,s){return this.toKeyedSeq().reverse().findKey(i,s)},first:function(){return this.find(returnTrue)},flatMap:function(i,s){return reify(this,flatMapFactory(this,i,s))},flatten:function(i){return reify(this,flattenFactory(this,i,!0))},fromEntrySeq:function(){return new FromEntriesSequence(this)},get:function(i,s){return this.find((function(s,u){return is(u,i)}),void 0,s)},getIn:function(i,s){for(var u,m=this,v=forceIterator(i);!(u=v.next()).done;){var _=u.value;if((m=m&&m.get?m.get(_,W):W)===W)return s}return m},groupBy:function(i,s){return groupByFactory(this,i,s)},has:function(i){return this.get(i,W)!==W},hasIn:function(i){return this.getIn(i,W)!==W},isSubset:function(i){return i="function"==typeof i.includes?i:Iterable(i),this.every((function(s){return i.includes(s)}))},isSuperset:function(i){return(i="function"==typeof i.isSubset?i:Iterable(i)).isSubset(this)},keyOf:function(i){return this.findKey((function(s){return is(s,i)}))},keySeq:function(){return this.toSeq().map(keyMapper).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(i){return this.toKeyedSeq().reverse().keyOf(i)},max:function(i){return maxFactory(this,i)},maxBy:function(i,s){return maxFactory(this,s,i)},min:function(i){return maxFactory(this,i?neg(i):defaultNegComparator)},minBy:function(i,s){return maxFactory(this,s?neg(s):defaultNegComparator,i)},rest:function(){return this.slice(1)},skip:function(i){return this.slice(Math.max(0,i))},skipLast:function(i){return reify(this,this.toSeq().reverse().skip(i).reverse())},skipWhile:function(i,s){return reify(this,skipWhileFactory(this,i,s,!0))},skipUntil:function(i,s){return this.skipWhile(not(i),s)},sortBy:function(i,s){return reify(this,sortFactory(this,s,i))},take:function(i){return this.slice(0,Math.max(0,i))},takeLast:function(i){return reify(this,this.toSeq().reverse().take(i).reverse())},takeWhile:function(i,s){return reify(this,takeWhileFactory(this,i,s))},takeUntil:function(i,s){return this.takeWhile(not(i),s)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=hashIterable(this))}});var mt=Iterable.prototype;mt[s]=!0,mt[ce]=mt.values,mt.__toJS=mt.toArray,mt.__toStringMapper=quoteString,mt.inspect=mt.toSource=function(){return this.toString()},mt.chain=mt.flatMap,mt.contains=mt.includes,mixin(KeyedIterable,{flip:function(){return reify(this,flipFactory(this))},mapEntries:function(i,s){var u=this,m=0;return reify(this,this.toSeq().map((function(v,_){return i.call(s,[_,v],m++,u)})).fromEntrySeq())},mapKeys:function(i,s){var u=this;return reify(this,this.toSeq().flip().map((function(m,v){return i.call(s,m,v,u)})).flip())}});var gt=KeyedIterable.prototype;function keyMapper(i,s){return s}function entryMapper(i,s){return[s,i]}function not(i){return function(){return!i.apply(this,arguments)}}function neg(i){return function(){return-i.apply(this,arguments)}}function quoteString(i){return"string"==typeof i?JSON.stringify(i):String(i)}function defaultZipper(){return arrCopy(arguments)}function defaultNegComparator(i,s){return is?-1:0}function hashIterable(i){if(i.size===1/0)return 0;var s=isOrdered(i),u=isKeyed(i),m=s?1:0;return murmurHashOfSize(i.__iterate(u?s?function(i,s){m=31*m+hashMerge(hash(i),hash(s))|0}:function(i,s){m=m+hashMerge(hash(i),hash(s))|0}:s?function(i){m=31*m+hash(i)|0}:function(i){m=m+hash(i)|0}),m)}function murmurHashOfSize(i,s){return s=be(s,3432918353),s=be(s<<15|s>>>-15,461845907),s=be(s<<13|s>>>-13,5),s=be((s=(s+3864292196|0)^i)^s>>>16,2246822507),s=smi((s=be(s^s>>>13,3266489909))^s>>>16)}function hashMerge(i,s){return i^s+2654435769+(i<<6)+(i>>2)|0}return gt[u]=!0,gt[ce]=mt.entries,gt.__toJS=mt.toObject,gt.__toStringMapper=function(i,s){return JSON.stringify(s)+": "+quoteString(i)},mixin(IndexedIterable,{toKeyedSeq:function(){return new ToKeyedSequence(this,!1)},filter:function(i,s){return reify(this,filterFactory(this,i,s,!1))},findIndex:function(i,s){var u=this.findEntry(i,s);return u?u[0]:-1},indexOf:function(i){var s=this.keyOf(i);return void 0===s?-1:s},lastIndexOf:function(i){var s=this.lastKeyOf(i);return void 0===s?-1:s},reverse:function(){return reify(this,reverseFactory(this,!1))},slice:function(i,s){return reify(this,sliceFactory(this,i,s,!1))},splice:function(i,s){var u=arguments.length;if(s=Math.max(0|s,0),0===u||2===u&&!s)return this;i=resolveBegin(i,i<0?this.count():this.size);var m=this.slice(0,i);return reify(this,1===u?m:m.concat(arrCopy(arguments,2),this.slice(i+s)))},findLastIndex:function(i,s){var u=this.findLastEntry(i,s);return u?u[0]:-1},first:function(){return this.get(0)},flatten:function(i){return reify(this,flattenFactory(this,i,!1))},get:function(i,s){return(i=wrapIndex(this,i))<0||this.size===1/0||void 0!==this.size&&i>this.size?s:this.find((function(s,u){return u===i}),void 0,s)},has:function(i){return(i=wrapIndex(this,i))>=0&&(void 0!==this.size?this.size===1/0||i{"function"==typeof Object.create?i.exports=function inherits(i,s){s&&(i.super_=s,i.prototype=Object.create(s.prototype,{constructor:{value:i,enumerable:!1,writable:!0,configurable:!0}}))}:i.exports=function inherits(i,s){if(s){i.super_=s;var TempCtor=function(){};TempCtor.prototype=s.prototype,i.prototype=new TempCtor,i.prototype.constructor=i}}},35823:i=>{i.exports=function(i,s,u,m){var v=new Blob(void 0!==m?[m,i]:[i],{type:u||"application/octet-stream"});if(void 0!==window.navigator.msSaveBlob)window.navigator.msSaveBlob(v,s);else{var _=window.URL&&window.URL.createObjectURL?window.URL.createObjectURL(v):window.webkitURL.createObjectURL(v),j=document.createElement("a");j.style.display="none",j.href=_,j.setAttribute("download",s),void 0===j.download&&j.setAttribute("target","_blank"),document.body.appendChild(j),j.click(),setTimeout((function(){document.body.removeChild(j),window.URL.revokeObjectURL(_)}),200)}}},91296:(i,s,u)=>{var m=NaN,v="[object Symbol]",_=/^\s+|\s+$/g,j=/^[-+]0x[0-9a-f]+$/i,M=/^0b[01]+$/i,$=/^0o[0-7]+$/i,W=parseInt,X="object"==typeof u.g&&u.g&&u.g.Object===Object&&u.g,Y="object"==typeof self&&self&&self.Object===Object&&self,Z=X||Y||Function("return this")(),ee=Object.prototype.toString,ie=Math.max,ae=Math.min,now=function(){return Z.Date.now()};function isObject(i){var s=typeof i;return!!i&&("object"==s||"function"==s)}function toNumber(i){if("number"==typeof i)return i;if(function isSymbol(i){return"symbol"==typeof i||function isObjectLike(i){return!!i&&"object"==typeof i}(i)&&ee.call(i)==v}(i))return m;if(isObject(i)){var s="function"==typeof i.valueOf?i.valueOf():i;i=isObject(s)?s+"":s}if("string"!=typeof i)return 0===i?i:+i;i=i.replace(_,"");var u=M.test(i);return u||$.test(i)?W(i.slice(2),u?2:8):j.test(i)?m:+i}i.exports=function debounce(i,s,u){var m,v,_,j,M,$,W=0,X=!1,Y=!1,Z=!0;if("function"!=typeof i)throw new TypeError("Expected a function");function invokeFunc(s){var u=m,_=v;return m=v=void 0,W=s,j=i.apply(_,u)}function shouldInvoke(i){var u=i-$;return void 0===$||u>=s||u<0||Y&&i-W>=_}function timerExpired(){var i=now();if(shouldInvoke(i))return trailingEdge(i);M=setTimeout(timerExpired,function remainingWait(i){var u=s-(i-$);return Y?ae(u,_-(i-W)):u}(i))}function trailingEdge(i){return M=void 0,Z&&m?invokeFunc(i):(m=v=void 0,j)}function debounced(){var i=now(),u=shouldInvoke(i);if(m=arguments,v=this,$=i,u){if(void 0===M)return function leadingEdge(i){return W=i,M=setTimeout(timerExpired,s),X?invokeFunc(i):j}($);if(Y)return M=setTimeout(timerExpired,s),invokeFunc($)}return void 0===M&&(M=setTimeout(timerExpired,s)),j}return s=toNumber(s)||0,isObject(u)&&(X=!!u.leading,_=(Y="maxWait"in u)?ie(toNumber(u.maxWait)||0,s):_,Z="trailing"in u?!!u.trailing:Z),debounced.cancel=function cancel(){void 0!==M&&clearTimeout(M),W=0,m=$=v=M=void 0},debounced.flush=function flush(){return void 0===M?j:trailingEdge(now())},debounced}},18552:(i,s,u)=>{var m=u(10852)(u(55639),"DataView");i.exports=m},1989:(i,s,u)=>{var m=u(51789),v=u(80401),_=u(57667),j=u(21327),M=u(81866);function Hash(i){var s=-1,u=null==i?0:i.length;for(this.clear();++s{var m=u(3118),v=u(9435);function LazyWrapper(i){this.__wrapped__=i,this.__actions__=[],this.__dir__=1,this.__filtered__=!1,this.__iteratees__=[],this.__takeCount__=4294967295,this.__views__=[]}LazyWrapper.prototype=m(v.prototype),LazyWrapper.prototype.constructor=LazyWrapper,i.exports=LazyWrapper},38407:(i,s,u)=>{var m=u(27040),v=u(14125),_=u(82117),j=u(67518),M=u(54705);function ListCache(i){var s=-1,u=null==i?0:i.length;for(this.clear();++s{var m=u(3118),v=u(9435);function LodashWrapper(i,s){this.__wrapped__=i,this.__actions__=[],this.__chain__=!!s,this.__index__=0,this.__values__=void 0}LodashWrapper.prototype=m(v.prototype),LodashWrapper.prototype.constructor=LodashWrapper,i.exports=LodashWrapper},57071:(i,s,u)=>{var m=u(10852)(u(55639),"Map");i.exports=m},83369:(i,s,u)=>{var m=u(24785),v=u(11285),_=u(96e3),j=u(49916),M=u(95265);function MapCache(i){var s=-1,u=null==i?0:i.length;for(this.clear();++s{var m=u(10852)(u(55639),"Promise");i.exports=m},58525:(i,s,u)=>{var m=u(10852)(u(55639),"Set");i.exports=m},88668:(i,s,u)=>{var m=u(83369),v=u(90619),_=u(72385);function SetCache(i){var s=-1,u=null==i?0:i.length;for(this.__data__=new m;++s{var m=u(38407),v=u(37465),_=u(63779),j=u(67599),M=u(44758),$=u(34309);function Stack(i){var s=this.__data__=new m(i);this.size=s.size}Stack.prototype.clear=v,Stack.prototype.delete=_,Stack.prototype.get=j,Stack.prototype.has=M,Stack.prototype.set=$,i.exports=Stack},62705:(i,s,u)=>{var m=u(55639).Symbol;i.exports=m},11149:(i,s,u)=>{var m=u(55639).Uint8Array;i.exports=m},70577:(i,s,u)=>{var m=u(10852)(u(55639),"WeakMap");i.exports=m},96874:i=>{i.exports=function apply(i,s,u){switch(u.length){case 0:return i.call(s);case 1:return i.call(s,u[0]);case 2:return i.call(s,u[0],u[1]);case 3:return i.call(s,u[0],u[1],u[2])}return i.apply(s,u)}},77412:i=>{i.exports=function arrayEach(i,s){for(var u=-1,m=null==i?0:i.length;++u{i.exports=function arrayFilter(i,s){for(var u=-1,m=null==i?0:i.length,v=0,_=[];++u{var m=u(42118);i.exports=function arrayIncludes(i,s){return!!(null==i?0:i.length)&&m(i,s,0)>-1}},14636:(i,s,u)=>{var m=u(22545),v=u(35694),_=u(1469),j=u(44144),M=u(65776),$=u(36719),W=Object.prototype.hasOwnProperty;i.exports=function arrayLikeKeys(i,s){var u=_(i),X=!u&&v(i),Y=!u&&!X&&j(i),Z=!u&&!X&&!Y&&$(i),ee=u||X||Y||Z,ie=ee?m(i.length,String):[],ae=ie.length;for(var le in i)!s&&!W.call(i,le)||ee&&("length"==le||Y&&("offset"==le||"parent"==le)||Z&&("buffer"==le||"byteLength"==le||"byteOffset"==le)||M(le,ae))||ie.push(le);return ie}},29932:i=>{i.exports=function arrayMap(i,s){for(var u=-1,m=null==i?0:i.length,v=Array(m);++u{i.exports=function arrayPush(i,s){for(var u=-1,m=s.length,v=i.length;++u{i.exports=function arrayReduce(i,s,u,m){var v=-1,_=null==i?0:i.length;for(m&&_&&(u=i[++v]);++v<_;)u=s(u,i[v],v,i);return u}},82908:i=>{i.exports=function arraySome(i,s){for(var u=-1,m=null==i?0:i.length;++u{i.exports=function asciiToArray(i){return i.split("")}},49029:i=>{var s=/[^\x00-\x2f\x3a-\x40\x5b-\x60\x7b-\x7f]+/g;i.exports=function asciiWords(i){return i.match(s)||[]}},86556:(i,s,u)=>{var m=u(89465),v=u(77813);i.exports=function assignMergeValue(i,s,u){(void 0!==u&&!v(i[s],u)||void 0===u&&!(s in i))&&m(i,s,u)}},34865:(i,s,u)=>{var m=u(89465),v=u(77813),_=Object.prototype.hasOwnProperty;i.exports=function assignValue(i,s,u){var j=i[s];_.call(i,s)&&v(j,u)&&(void 0!==u||s in i)||m(i,s,u)}},18470:(i,s,u)=>{var m=u(77813);i.exports=function assocIndexOf(i,s){for(var u=i.length;u--;)if(m(i[u][0],s))return u;return-1}},44037:(i,s,u)=>{var m=u(98363),v=u(3674);i.exports=function baseAssign(i,s){return i&&m(s,v(s),i)}},63886:(i,s,u)=>{var m=u(98363),v=u(81704);i.exports=function baseAssignIn(i,s){return i&&m(s,v(s),i)}},89465:(i,s,u)=>{var m=u(38777);i.exports=function baseAssignValue(i,s,u){"__proto__"==s&&m?m(i,s,{configurable:!0,enumerable:!0,value:u,writable:!0}):i[s]=u}},85990:(i,s,u)=>{var m=u(46384),v=u(77412),_=u(34865),j=u(44037),M=u(63886),$=u(64626),W=u(278),X=u(18805),Y=u(1911),Z=u(58234),ee=u(46904),ie=u(64160),ae=u(43824),le=u(29148),ce=u(38517),pe=u(1469),de=u(44144),fe=u(56688),ye=u(13218),be=u(72928),_e=u(3674),we=u(81704),Se="[object Arguments]",xe="[object Function]",Ie="[object Object]",Pe={};Pe[Se]=Pe["[object Array]"]=Pe["[object ArrayBuffer]"]=Pe["[object DataView]"]=Pe["[object Boolean]"]=Pe["[object Date]"]=Pe["[object Float32Array]"]=Pe["[object Float64Array]"]=Pe["[object Int8Array]"]=Pe["[object Int16Array]"]=Pe["[object Int32Array]"]=Pe["[object Map]"]=Pe["[object Number]"]=Pe[Ie]=Pe["[object RegExp]"]=Pe["[object Set]"]=Pe["[object String]"]=Pe["[object Symbol]"]=Pe["[object Uint8Array]"]=Pe["[object Uint8ClampedArray]"]=Pe["[object Uint16Array]"]=Pe["[object Uint32Array]"]=!0,Pe["[object Error]"]=Pe[xe]=Pe["[object WeakMap]"]=!1,i.exports=function baseClone(i,s,u,Te,Re,qe){var ze,Ve=1&s,We=2&s,He=4&s;if(u&&(ze=Re?u(i,Te,Re,qe):u(i)),void 0!==ze)return ze;if(!ye(i))return i;var Xe=pe(i);if(Xe){if(ze=ae(i),!Ve)return W(i,ze)}else{var Ye=ie(i),Qe=Ye==xe||"[object GeneratorFunction]"==Ye;if(de(i))return $(i,Ve);if(Ye==Ie||Ye==Se||Qe&&!Re){if(ze=We||Qe?{}:ce(i),!Ve)return We?Y(i,M(ze,i)):X(i,j(ze,i))}else{if(!Pe[Ye])return Re?i:{};ze=le(i,Ye,Ve)}}qe||(qe=new m);var et=qe.get(i);if(et)return et;qe.set(i,ze),be(i)?i.forEach((function(m){ze.add(baseClone(m,s,u,m,i,qe))})):fe(i)&&i.forEach((function(m,v){ze.set(v,baseClone(m,s,u,v,i,qe))}));var tt=Xe?void 0:(He?We?ee:Z:We?we:_e)(i);return v(tt||i,(function(m,v){tt&&(m=i[v=m]),_(ze,v,baseClone(m,s,u,v,i,qe))})),ze}},3118:(i,s,u)=>{var m=u(13218),v=Object.create,_=function(){function object(){}return function(i){if(!m(i))return{};if(v)return v(i);object.prototype=i;var s=new object;return object.prototype=void 0,s}}();i.exports=_},89881:(i,s,u)=>{var m=u(47816),v=u(99291)(m);i.exports=v},41848:i=>{i.exports=function baseFindIndex(i,s,u,m){for(var v=i.length,_=u+(m?1:-1);m?_--:++_{var m=u(62488),v=u(37285);i.exports=function baseFlatten(i,s,u,_,j){var M=-1,$=i.length;for(u||(u=v),j||(j=[]);++M<$;){var W=i[M];s>0&&u(W)?s>1?baseFlatten(W,s-1,u,_,j):m(j,W):_||(j[j.length]=W)}return j}},28483:(i,s,u)=>{var m=u(25063)();i.exports=m},47816:(i,s,u)=>{var m=u(28483),v=u(3674);i.exports=function baseForOwn(i,s){return i&&m(i,s,v)}},97786:(i,s,u)=>{var m=u(71811),v=u(40327);i.exports=function baseGet(i,s){for(var u=0,_=(s=m(s,i)).length;null!=i&&u<_;)i=i[v(s[u++])];return u&&u==_?i:void 0}},68866:(i,s,u)=>{var m=u(62488),v=u(1469);i.exports=function baseGetAllKeys(i,s,u){var _=s(i);return v(i)?_:m(_,u(i))}},44239:(i,s,u)=>{var m=u(62705),v=u(89607),_=u(2333),j=m?m.toStringTag:void 0;i.exports=function baseGetTag(i){return null==i?void 0===i?"[object Undefined]":"[object Null]":j&&j in Object(i)?v(i):_(i)}},13:i=>{i.exports=function baseHasIn(i,s){return null!=i&&s in Object(i)}},42118:(i,s,u)=>{var m=u(41848),v=u(62722),_=u(42351);i.exports=function baseIndexOf(i,s,u){return s==s?_(i,s,u):m(i,v,u)}},9454:(i,s,u)=>{var m=u(44239),v=u(37005);i.exports=function baseIsArguments(i){return v(i)&&"[object Arguments]"==m(i)}},90939:(i,s,u)=>{var m=u(2492),v=u(37005);i.exports=function baseIsEqual(i,s,u,_,j){return i===s||(null==i||null==s||!v(i)&&!v(s)?i!=i&&s!=s:m(i,s,u,_,baseIsEqual,j))}},2492:(i,s,u)=>{var m=u(46384),v=u(67114),_=u(18351),j=u(16096),M=u(64160),$=u(1469),W=u(44144),X=u(36719),Y="[object Arguments]",Z="[object Array]",ee="[object Object]",ie=Object.prototype.hasOwnProperty;i.exports=function baseIsEqualDeep(i,s,u,ae,le,ce){var pe=$(i),de=$(s),fe=pe?Z:M(i),ye=de?Z:M(s),be=(fe=fe==Y?ee:fe)==ee,_e=(ye=ye==Y?ee:ye)==ee,we=fe==ye;if(we&&W(i)){if(!W(s))return!1;pe=!0,be=!1}if(we&&!be)return ce||(ce=new m),pe||X(i)?v(i,s,u,ae,le,ce):_(i,s,fe,u,ae,le,ce);if(!(1&u)){var Se=be&&ie.call(i,"__wrapped__"),xe=_e&&ie.call(s,"__wrapped__");if(Se||xe){var Ie=Se?i.value():i,Pe=xe?s.value():s;return ce||(ce=new m),le(Ie,Pe,u,ae,ce)}}return!!we&&(ce||(ce=new m),j(i,s,u,ae,le,ce))}},25588:(i,s,u)=>{var m=u(64160),v=u(37005);i.exports=function baseIsMap(i){return v(i)&&"[object Map]"==m(i)}},2958:(i,s,u)=>{var m=u(46384),v=u(90939);i.exports=function baseIsMatch(i,s,u,_){var j=u.length,M=j,$=!_;if(null==i)return!M;for(i=Object(i);j--;){var W=u[j];if($&&W[2]?W[1]!==i[W[0]]:!(W[0]in i))return!1}for(;++j{i.exports=function baseIsNaN(i){return i!=i}},28458:(i,s,u)=>{var m=u(23560),v=u(15346),_=u(13218),j=u(80346),M=/^\[object .+?Constructor\]$/,$=Function.prototype,W=Object.prototype,X=$.toString,Y=W.hasOwnProperty,Z=RegExp("^"+X.call(Y).replace(/[\\^$.*+?()[\]{}|]/g,"\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g,"$1.*?")+"$");i.exports=function baseIsNative(i){return!(!_(i)||v(i))&&(m(i)?Z:M).test(j(i))}},29221:(i,s,u)=>{var m=u(64160),v=u(37005);i.exports=function baseIsSet(i){return v(i)&&"[object Set]"==m(i)}},38749:(i,s,u)=>{var m=u(44239),v=u(41780),_=u(37005),j={};j["[object Float32Array]"]=j["[object Float64Array]"]=j["[object Int8Array]"]=j["[object Int16Array]"]=j["[object Int32Array]"]=j["[object Uint8Array]"]=j["[object Uint8ClampedArray]"]=j["[object Uint16Array]"]=j["[object Uint32Array]"]=!0,j["[object Arguments]"]=j["[object Array]"]=j["[object ArrayBuffer]"]=j["[object Boolean]"]=j["[object DataView]"]=j["[object Date]"]=j["[object Error]"]=j["[object Function]"]=j["[object Map]"]=j["[object Number]"]=j["[object Object]"]=j["[object RegExp]"]=j["[object Set]"]=j["[object String]"]=j["[object WeakMap]"]=!1,i.exports=function baseIsTypedArray(i){return _(i)&&v(i.length)&&!!j[m(i)]}},67206:(i,s,u)=>{var m=u(91573),v=u(16432),_=u(6557),j=u(1469),M=u(39601);i.exports=function baseIteratee(i){return"function"==typeof i?i:null==i?_:"object"==typeof i?j(i)?v(i[0],i[1]):m(i):M(i)}},280:(i,s,u)=>{var m=u(25726),v=u(86916),_=Object.prototype.hasOwnProperty;i.exports=function baseKeys(i){if(!m(i))return v(i);var s=[];for(var u in Object(i))_.call(i,u)&&"constructor"!=u&&s.push(u);return s}},10313:(i,s,u)=>{var m=u(13218),v=u(25726),_=u(33498),j=Object.prototype.hasOwnProperty;i.exports=function baseKeysIn(i){if(!m(i))return _(i);var s=v(i),u=[];for(var M in i)("constructor"!=M||!s&&j.call(i,M))&&u.push(M);return u}},9435:i=>{i.exports=function baseLodash(){}},91573:(i,s,u)=>{var m=u(2958),v=u(1499),_=u(42634);i.exports=function baseMatches(i){var s=v(i);return 1==s.length&&s[0][2]?_(s[0][0],s[0][1]):function(u){return u===i||m(u,i,s)}}},16432:(i,s,u)=>{var m=u(90939),v=u(27361),_=u(79095),j=u(15403),M=u(89162),$=u(42634),W=u(40327);i.exports=function baseMatchesProperty(i,s){return j(i)&&M(s)?$(W(i),s):function(u){var j=v(u,i);return void 0===j&&j===s?_(u,i):m(s,j,3)}}},42980:(i,s,u)=>{var m=u(46384),v=u(86556),_=u(28483),j=u(59783),M=u(13218),$=u(81704),W=u(36390);i.exports=function baseMerge(i,s,u,X,Y){i!==s&&_(s,(function(_,$){if(Y||(Y=new m),M(_))j(i,s,$,u,baseMerge,X,Y);else{var Z=X?X(W(i,$),_,$+"",i,s,Y):void 0;void 0===Z&&(Z=_),v(i,$,Z)}}),$)}},59783:(i,s,u)=>{var m=u(86556),v=u(64626),_=u(77133),j=u(278),M=u(38517),$=u(35694),W=u(1469),X=u(29246),Y=u(44144),Z=u(23560),ee=u(13218),ie=u(68630),ae=u(36719),le=u(36390),ce=u(59881);i.exports=function baseMergeDeep(i,s,u,pe,de,fe,ye){var be=le(i,u),_e=le(s,u),we=ye.get(_e);if(we)m(i,u,we);else{var Se=fe?fe(be,_e,u+"",i,s,ye):void 0,xe=void 0===Se;if(xe){var Ie=W(_e),Pe=!Ie&&Y(_e),Te=!Ie&&!Pe&&ae(_e);Se=_e,Ie||Pe||Te?W(be)?Se=be:X(be)?Se=j(be):Pe?(xe=!1,Se=v(_e,!0)):Te?(xe=!1,Se=_(_e,!0)):Se=[]:ie(_e)||$(_e)?(Se=be,$(be)?Se=ce(be):ee(be)&&!Z(be)||(Se=M(_e))):xe=!1}xe&&(ye.set(_e,Se),de(Se,_e,pe,fe,ye),ye.delete(_e)),m(i,u,Se)}}},40371:i=>{i.exports=function baseProperty(i){return function(s){return null==s?void 0:s[i]}}},79152:(i,s,u)=>{var m=u(97786);i.exports=function basePropertyDeep(i){return function(s){return m(s,i)}}},18674:i=>{i.exports=function basePropertyOf(i){return function(s){return null==i?void 0:i[s]}}},10107:i=>{i.exports=function baseReduce(i,s,u,m,v){return v(i,(function(i,v,_){u=m?(m=!1,i):s(u,i,v,_)})),u}},5976:(i,s,u)=>{var m=u(6557),v=u(45357),_=u(30061);i.exports=function baseRest(i,s){return _(v(i,s,m),i+"")}},10611:(i,s,u)=>{var m=u(34865),v=u(71811),_=u(65776),j=u(13218),M=u(40327);i.exports=function baseSet(i,s,u,$){if(!j(i))return i;for(var W=-1,X=(s=v(s,i)).length,Y=X-1,Z=i;null!=Z&&++W{var m=u(6557),v=u(89250),_=v?function(i,s){return v.set(i,s),i}:m;i.exports=_},56560:(i,s,u)=>{var m=u(75703),v=u(38777),_=u(6557),j=v?function(i,s){return v(i,"toString",{configurable:!0,enumerable:!1,value:m(s),writable:!0})}:_;i.exports=j},14259:i=>{i.exports=function baseSlice(i,s,u){var m=-1,v=i.length;s<0&&(s=-s>v?0:v+s),(u=u>v?v:u)<0&&(u+=v),v=s>u?0:u-s>>>0,s>>>=0;for(var _=Array(v);++m{var m=u(89881);i.exports=function baseSome(i,s){var u;return m(i,(function(i,m,v){return!(u=s(i,m,v))})),!!u}},22545:i=>{i.exports=function baseTimes(i,s){for(var u=-1,m=Array(i);++u{var m=u(62705),v=u(29932),_=u(1469),j=u(33448),M=m?m.prototype:void 0,$=M?M.toString:void 0;i.exports=function baseToString(i){if("string"==typeof i)return i;if(_(i))return v(i,baseToString)+"";if(j(i))return $?$.call(i):"";var s=i+"";return"0"==s&&1/i==-Infinity?"-0":s}},27561:(i,s,u)=>{var m=u(67990),v=/^\s+/;i.exports=function baseTrim(i){return i?i.slice(0,m(i)+1).replace(v,""):i}},7518:i=>{i.exports=function baseUnary(i){return function(s){return i(s)}}},57406:(i,s,u)=>{var m=u(71811),v=u(10928),_=u(40292),j=u(40327);i.exports=function baseUnset(i,s){return s=m(s,i),null==(i=_(i,s))||delete i[j(v(s))]}},1757:i=>{i.exports=function baseZipObject(i,s,u){for(var m=-1,v=i.length,_=s.length,j={};++m{i.exports=function cacheHas(i,s){return i.has(s)}},71811:(i,s,u)=>{var m=u(1469),v=u(15403),_=u(55514),j=u(79833);i.exports=function castPath(i,s){return m(i)?i:v(i,s)?[i]:_(j(i))}},40180:(i,s,u)=>{var m=u(14259);i.exports=function castSlice(i,s,u){var v=i.length;return u=void 0===u?v:u,!s&&u>=v?i:m(i,s,u)}},74318:(i,s,u)=>{var m=u(11149);i.exports=function cloneArrayBuffer(i){var s=new i.constructor(i.byteLength);return new m(s).set(new m(i)),s}},64626:(i,s,u)=>{i=u.nmd(i);var m=u(55639),v=s&&!s.nodeType&&s,_=v&&i&&!i.nodeType&&i,j=_&&_.exports===v?m.Buffer:void 0,M=j?j.allocUnsafe:void 0;i.exports=function cloneBuffer(i,s){if(s)return i.slice();var u=i.length,m=M?M(u):new i.constructor(u);return i.copy(m),m}},57157:(i,s,u)=>{var m=u(74318);i.exports=function cloneDataView(i,s){var u=s?m(i.buffer):i.buffer;return new i.constructor(u,i.byteOffset,i.byteLength)}},93147:i=>{var s=/\w*$/;i.exports=function cloneRegExp(i){var u=new i.constructor(i.source,s.exec(i));return u.lastIndex=i.lastIndex,u}},40419:(i,s,u)=>{var m=u(62705),v=m?m.prototype:void 0,_=v?v.valueOf:void 0;i.exports=function cloneSymbol(i){return _?Object(_.call(i)):{}}},77133:(i,s,u)=>{var m=u(74318);i.exports=function cloneTypedArray(i,s){var u=s?m(i.buffer):i.buffer;return new i.constructor(u,i.byteOffset,i.length)}},52157:i=>{var s=Math.max;i.exports=function composeArgs(i,u,m,v){for(var _=-1,j=i.length,M=m.length,$=-1,W=u.length,X=s(j-M,0),Y=Array(W+X),Z=!v;++${var s=Math.max;i.exports=function composeArgsRight(i,u,m,v){for(var _=-1,j=i.length,M=-1,$=m.length,W=-1,X=u.length,Y=s(j-$,0),Z=Array(Y+X),ee=!v;++_{i.exports=function copyArray(i,s){var u=-1,m=i.length;for(s||(s=Array(m));++u{var m=u(34865),v=u(89465);i.exports=function copyObject(i,s,u,_){var j=!u;u||(u={});for(var M=-1,$=s.length;++M<$;){var W=s[M],X=_?_(u[W],i[W],W,u,i):void 0;void 0===X&&(X=i[W]),j?v(u,W,X):m(u,W,X)}return u}},18805:(i,s,u)=>{var m=u(98363),v=u(99551);i.exports=function copySymbols(i,s){return m(i,v(i),s)}},1911:(i,s,u)=>{var m=u(98363),v=u(51442);i.exports=function copySymbolsIn(i,s){return m(i,v(i),s)}},14429:(i,s,u)=>{var m=u(55639)["__core-js_shared__"];i.exports=m},97991:i=>{i.exports=function countHolders(i,s){for(var u=i.length,m=0;u--;)i[u]===s&&++m;return m}},21463:(i,s,u)=>{var m=u(5976),v=u(16612);i.exports=function createAssigner(i){return m((function(s,u){var m=-1,_=u.length,j=_>1?u[_-1]:void 0,M=_>2?u[2]:void 0;for(j=i.length>3&&"function"==typeof j?(_--,j):void 0,M&&v(u[0],u[1],M)&&(j=_<3?void 0:j,_=1),s=Object(s);++m<_;){var $=u[m];$&&i(s,$,m,j)}return s}))}},99291:(i,s,u)=>{var m=u(98612);i.exports=function createBaseEach(i,s){return function(u,v){if(null==u)return u;if(!m(u))return i(u,v);for(var _=u.length,j=s?_:-1,M=Object(u);(s?j--:++j<_)&&!1!==v(M[j],j,M););return u}}},25063:i=>{i.exports=function createBaseFor(i){return function(s,u,m){for(var v=-1,_=Object(s),j=m(s),M=j.length;M--;){var $=j[i?M:++v];if(!1===u(_[$],$,_))break}return s}}},22402:(i,s,u)=>{var m=u(71774),v=u(55639);i.exports=function createBind(i,s,u){var _=1&s,j=m(i);return function wrapper(){return(this&&this!==v&&this instanceof wrapper?j:i).apply(_?u:this,arguments)}}},98805:(i,s,u)=>{var m=u(40180),v=u(62689),_=u(83140),j=u(79833);i.exports=function createCaseFirst(i){return function(s){s=j(s);var u=v(s)?_(s):void 0,M=u?u[0]:s.charAt(0),$=u?m(u,1).join(""):s.slice(1);return M[i]()+$}}},35393:(i,s,u)=>{var m=u(62663),v=u(53816),_=u(58748),j=RegExp("['’]","g");i.exports=function createCompounder(i){return function(s){return m(_(v(s).replace(j,"")),i,"")}}},71774:(i,s,u)=>{var m=u(3118),v=u(13218);i.exports=function createCtor(i){return function(){var s=arguments;switch(s.length){case 0:return new i;case 1:return new i(s[0]);case 2:return new i(s[0],s[1]);case 3:return new i(s[0],s[1],s[2]);case 4:return new i(s[0],s[1],s[2],s[3]);case 5:return new i(s[0],s[1],s[2],s[3],s[4]);case 6:return new i(s[0],s[1],s[2],s[3],s[4],s[5]);case 7:return new i(s[0],s[1],s[2],s[3],s[4],s[5],s[6])}var u=m(i.prototype),_=i.apply(u,s);return v(_)?_:u}}},46347:(i,s,u)=>{var m=u(96874),v=u(71774),_=u(86935),j=u(94487),M=u(20893),$=u(46460),W=u(55639);i.exports=function createCurry(i,s,u){var X=v(i);return function wrapper(){for(var v=arguments.length,Y=Array(v),Z=v,ee=M(wrapper);Z--;)Y[Z]=arguments[Z];var ie=v<3&&Y[0]!==ee&&Y[v-1]!==ee?[]:$(Y,ee);return(v-=ie.length){var m=u(67206),v=u(98612),_=u(3674);i.exports=function createFind(i){return function(s,u,j){var M=Object(s);if(!v(s)){var $=m(u,3);s=_(s),u=function(i){return $(M[i],i,M)}}var W=i(s,u,j);return W>-1?M[$?s[W]:W]:void 0}}},86935:(i,s,u)=>{var m=u(52157),v=u(14054),_=u(97991),j=u(71774),M=u(94487),$=u(20893),W=u(90451),X=u(46460),Y=u(55639);i.exports=function createHybrid(i,s,u,Z,ee,ie,ae,le,ce,pe){var de=128&s,fe=1&s,ye=2&s,be=24&s,_e=512&s,we=ye?void 0:j(i);return function wrapper(){for(var Se=arguments.length,xe=Array(Se),Ie=Se;Ie--;)xe[Ie]=arguments[Ie];if(be)var Pe=$(wrapper),Te=_(xe,Pe);if(Z&&(xe=m(xe,Z,ee,be)),ie&&(xe=v(xe,ie,ae,be)),Se-=Te,be&&Se1&&xe.reverse(),de&&ce{var m=u(96874),v=u(71774),_=u(55639);i.exports=function createPartial(i,s,u,j){var M=1&s,$=v(i);return function wrapper(){for(var s=-1,v=arguments.length,W=-1,X=j.length,Y=Array(X+v),Z=this&&this!==_&&this instanceof wrapper?$:i;++W{var m=u(86528),v=u(258),_=u(69255);i.exports=function createRecurry(i,s,u,j,M,$,W,X,Y,Z){var ee=8&s;s|=ee?32:64,4&(s&=~(ee?64:32))||(s&=-4);var ie=[i,s,M,ee?$:void 0,ee?W:void 0,ee?void 0:$,ee?void 0:W,X,Y,Z],ae=u.apply(void 0,ie);return m(i)&&v(ae,ie),ae.placeholder=j,_(ae,i,s)}},97727:(i,s,u)=>{var m=u(28045),v=u(22402),_=u(46347),j=u(86935),M=u(84375),$=u(66833),W=u(63833),X=u(258),Y=u(69255),Z=u(40554),ee=Math.max;i.exports=function createWrap(i,s,u,ie,ae,le,ce,pe){var de=2&s;if(!de&&"function"!=typeof i)throw new TypeError("Expected a function");var fe=ie?ie.length:0;if(fe||(s&=-97,ie=ae=void 0),ce=void 0===ce?ce:ee(Z(ce),0),pe=void 0===pe?pe:Z(pe),fe-=ae?ae.length:0,64&s){var ye=ie,be=ae;ie=ae=void 0}var _e=de?void 0:$(i),we=[i,s,u,ie,ae,ye,be,le,ce,pe];if(_e&&W(we,_e),i=we[0],s=we[1],u=we[2],ie=we[3],ae=we[4],!(pe=we[9]=void 0===we[9]?de?0:i.length:ee(we[9]-fe,0))&&24&s&&(s&=-25),s&&1!=s)Se=8==s||16==s?_(i,s,pe):32!=s&&33!=s||ae.length?j.apply(void 0,we):M(i,s,u,ie);else var Se=v(i,s,u);return Y((_e?m:X)(Se,we),i,s)}},60696:(i,s,u)=>{var m=u(68630);i.exports=function customOmitClone(i){return m(i)?void 0:i}},69389:(i,s,u)=>{var m=u(18674)({À:"A",Á:"A",Â:"A",Ã:"A",Ä:"A",Å:"A",à:"a",á:"a",â:"a",ã:"a",ä:"a",å:"a",Ç:"C",ç:"c",Ð:"D",ð:"d",È:"E",É:"E",Ê:"E",Ë:"E",è:"e",é:"e",ê:"e",ë:"e",Ì:"I",Í:"I",Î:"I",Ï:"I",ì:"i",í:"i",î:"i",ï:"i",Ñ:"N",ñ:"n",Ò:"O",Ó:"O",Ô:"O",Õ:"O",Ö:"O",Ø:"O",ò:"o",ó:"o",ô:"o",õ:"o",ö:"o",ø:"o",Ù:"U",Ú:"U",Û:"U",Ü:"U",ù:"u",ú:"u",û:"u",ü:"u",Ý:"Y",ý:"y",ÿ:"y",Æ:"Ae",æ:"ae",Þ:"Th",þ:"th",ß:"ss",Ā:"A",Ă:"A",Ą:"A",ā:"a",ă:"a",ą:"a",Ć:"C",Ĉ:"C",Ċ:"C",Č:"C",ć:"c",ĉ:"c",ċ:"c",č:"c",Ď:"D",Đ:"D",ď:"d",đ:"d",Ē:"E",Ĕ:"E",Ė:"E",Ę:"E",Ě:"E",ē:"e",ĕ:"e",ė:"e",ę:"e",ě:"e",Ĝ:"G",Ğ:"G",Ġ:"G",Ģ:"G",ĝ:"g",ğ:"g",ġ:"g",ģ:"g",Ĥ:"H",Ħ:"H",ĥ:"h",ħ:"h",Ĩ:"I",Ī:"I",Ĭ:"I",Į:"I",İ:"I",ĩ:"i",ī:"i",ĭ:"i",į:"i",ı:"i",Ĵ:"J",ĵ:"j",Ķ:"K",ķ:"k",ĸ:"k",Ĺ:"L",Ļ:"L",Ľ:"L",Ŀ:"L",Ł:"L",ĺ:"l",ļ:"l",ľ:"l",ŀ:"l",ł:"l",Ń:"N",Ņ:"N",Ň:"N",Ŋ:"N",ń:"n",ņ:"n",ň:"n",ŋ:"n",Ō:"O",Ŏ:"O",Ő:"O",ō:"o",ŏ:"o",ő:"o",Ŕ:"R",Ŗ:"R",Ř:"R",ŕ:"r",ŗ:"r",ř:"r",Ś:"S",Ŝ:"S",Ş:"S",Š:"S",ś:"s",ŝ:"s",ş:"s",š:"s",Ţ:"T",Ť:"T",Ŧ:"T",ţ:"t",ť:"t",ŧ:"t",Ũ:"U",Ū:"U",Ŭ:"U",Ů:"U",Ű:"U",Ų:"U",ũ:"u",ū:"u",ŭ:"u",ů:"u",ű:"u",ų:"u",Ŵ:"W",ŵ:"w",Ŷ:"Y",ŷ:"y",Ÿ:"Y",Ź:"Z",Ż:"Z",Ž:"Z",ź:"z",ż:"z",ž:"z",IJ:"IJ",ij:"ij",Œ:"Oe",œ:"oe",ʼn:"'n",ſ:"s"});i.exports=m},38777:(i,s,u)=>{var m=u(10852),v=function(){try{var i=m(Object,"defineProperty");return i({},"",{}),i}catch(i){}}();i.exports=v},67114:(i,s,u)=>{var m=u(88668),v=u(82908),_=u(74757);i.exports=function equalArrays(i,s,u,j,M,$){var W=1&u,X=i.length,Y=s.length;if(X!=Y&&!(W&&Y>X))return!1;var Z=$.get(i),ee=$.get(s);if(Z&&ee)return Z==s&&ee==i;var ie=-1,ae=!0,le=2&u?new m:void 0;for($.set(i,s),$.set(s,i);++ie{var m=u(62705),v=u(11149),_=u(77813),j=u(67114),M=u(68776),$=u(21814),W=m?m.prototype:void 0,X=W?W.valueOf:void 0;i.exports=function equalByTag(i,s,u,m,W,Y,Z){switch(u){case"[object DataView]":if(i.byteLength!=s.byteLength||i.byteOffset!=s.byteOffset)return!1;i=i.buffer,s=s.buffer;case"[object ArrayBuffer]":return!(i.byteLength!=s.byteLength||!Y(new v(i),new v(s)));case"[object Boolean]":case"[object Date]":case"[object Number]":return _(+i,+s);case"[object Error]":return i.name==s.name&&i.message==s.message;case"[object RegExp]":case"[object String]":return i==s+"";case"[object Map]":var ee=M;case"[object Set]":var ie=1&m;if(ee||(ee=$),i.size!=s.size&&!ie)return!1;var ae=Z.get(i);if(ae)return ae==s;m|=2,Z.set(i,s);var le=j(ee(i),ee(s),m,W,Y,Z);return Z.delete(i),le;case"[object Symbol]":if(X)return X.call(i)==X.call(s)}return!1}},16096:(i,s,u)=>{var m=u(58234),v=Object.prototype.hasOwnProperty;i.exports=function equalObjects(i,s,u,_,j,M){var $=1&u,W=m(i),X=W.length;if(X!=m(s).length&&!$)return!1;for(var Y=X;Y--;){var Z=W[Y];if(!($?Z in s:v.call(s,Z)))return!1}var ee=M.get(i),ie=M.get(s);if(ee&&ie)return ee==s&&ie==i;var ae=!0;M.set(i,s),M.set(s,i);for(var le=$;++Y{var m=u(85564),v=u(45357),_=u(30061);i.exports=function flatRest(i){return _(v(i,void 0,m),i+"")}},31957:(i,s,u)=>{var m="object"==typeof u.g&&u.g&&u.g.Object===Object&&u.g;i.exports=m},58234:(i,s,u)=>{var m=u(68866),v=u(99551),_=u(3674);i.exports=function getAllKeys(i){return m(i,_,v)}},46904:(i,s,u)=>{var m=u(68866),v=u(51442),_=u(81704);i.exports=function getAllKeysIn(i){return m(i,_,v)}},66833:(i,s,u)=>{var m=u(89250),v=u(50308),_=m?function(i){return m.get(i)}:v;i.exports=_},97658:(i,s,u)=>{var m=u(52060),v=Object.prototype.hasOwnProperty;i.exports=function getFuncName(i){for(var s=i.name+"",u=m[s],_=v.call(m,s)?u.length:0;_--;){var j=u[_],M=j.func;if(null==M||M==i)return j.name}return s}},20893:i=>{i.exports=function getHolder(i){return i.placeholder}},45050:(i,s,u)=>{var m=u(37019);i.exports=function getMapData(i,s){var u=i.__data__;return m(s)?u["string"==typeof s?"string":"hash"]:u.map}},1499:(i,s,u)=>{var m=u(89162),v=u(3674);i.exports=function getMatchData(i){for(var s=v(i),u=s.length;u--;){var _=s[u],j=i[_];s[u]=[_,j,m(j)]}return s}},10852:(i,s,u)=>{var m=u(28458),v=u(47801);i.exports=function getNative(i,s){var u=v(i,s);return m(u)?u:void 0}},85924:(i,s,u)=>{var m=u(5569)(Object.getPrototypeOf,Object);i.exports=m},89607:(i,s,u)=>{var m=u(62705),v=Object.prototype,_=v.hasOwnProperty,j=v.toString,M=m?m.toStringTag:void 0;i.exports=function getRawTag(i){var s=_.call(i,M),u=i[M];try{i[M]=void 0;var m=!0}catch(i){}var v=j.call(i);return m&&(s?i[M]=u:delete i[M]),v}},99551:(i,s,u)=>{var m=u(34963),v=u(70479),_=Object.prototype.propertyIsEnumerable,j=Object.getOwnPropertySymbols,M=j?function(i){return null==i?[]:(i=Object(i),m(j(i),(function(s){return _.call(i,s)})))}:v;i.exports=M},51442:(i,s,u)=>{var m=u(62488),v=u(85924),_=u(99551),j=u(70479),M=Object.getOwnPropertySymbols?function(i){for(var s=[];i;)m(s,_(i)),i=v(i);return s}:j;i.exports=M},64160:(i,s,u)=>{var m=u(18552),v=u(57071),_=u(53818),j=u(58525),M=u(70577),$=u(44239),W=u(80346),X="[object Map]",Y="[object Promise]",Z="[object Set]",ee="[object WeakMap]",ie="[object DataView]",ae=W(m),le=W(v),ce=W(_),pe=W(j),de=W(M),fe=$;(m&&fe(new m(new ArrayBuffer(1)))!=ie||v&&fe(new v)!=X||_&&fe(_.resolve())!=Y||j&&fe(new j)!=Z||M&&fe(new M)!=ee)&&(fe=function(i){var s=$(i),u="[object Object]"==s?i.constructor:void 0,m=u?W(u):"";if(m)switch(m){case ae:return ie;case le:return X;case ce:return Y;case pe:return Z;case de:return ee}return s}),i.exports=fe},47801:i=>{i.exports=function getValue(i,s){return null==i?void 0:i[s]}},58775:i=>{var s=/\{\n\/\* \[wrapped with (.+)\] \*/,u=/,? & /;i.exports=function getWrapDetails(i){var m=i.match(s);return m?m[1].split(u):[]}},222:(i,s,u)=>{var m=u(71811),v=u(35694),_=u(1469),j=u(65776),M=u(41780),$=u(40327);i.exports=function hasPath(i,s,u){for(var W=-1,X=(s=m(s,i)).length,Y=!1;++W{var s=RegExp("[\\u200d\\ud800-\\udfff\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff\\ufe0e\\ufe0f]");i.exports=function hasUnicode(i){return s.test(i)}},93157:i=>{var s=/[a-z][A-Z]|[A-Z]{2}[a-z]|[0-9][a-zA-Z]|[a-zA-Z][0-9]|[^a-zA-Z0-9 ]/;i.exports=function hasUnicodeWord(i){return s.test(i)}},51789:(i,s,u)=>{var m=u(94536);i.exports=function hashClear(){this.__data__=m?m(null):{},this.size=0}},80401:i=>{i.exports=function hashDelete(i){var s=this.has(i)&&delete this.__data__[i];return this.size-=s?1:0,s}},57667:(i,s,u)=>{var m=u(94536),v=Object.prototype.hasOwnProperty;i.exports=function hashGet(i){var s=this.__data__;if(m){var u=s[i];return"__lodash_hash_undefined__"===u?void 0:u}return v.call(s,i)?s[i]:void 0}},21327:(i,s,u)=>{var m=u(94536),v=Object.prototype.hasOwnProperty;i.exports=function hashHas(i){var s=this.__data__;return m?void 0!==s[i]:v.call(s,i)}},81866:(i,s,u)=>{var m=u(94536);i.exports=function hashSet(i,s){var u=this.__data__;return this.size+=this.has(i)?0:1,u[i]=m&&void 0===s?"__lodash_hash_undefined__":s,this}},43824:i=>{var s=Object.prototype.hasOwnProperty;i.exports=function initCloneArray(i){var u=i.length,m=new i.constructor(u);return u&&"string"==typeof i[0]&&s.call(i,"index")&&(m.index=i.index,m.input=i.input),m}},29148:(i,s,u)=>{var m=u(74318),v=u(57157),_=u(93147),j=u(40419),M=u(77133);i.exports=function initCloneByTag(i,s,u){var $=i.constructor;switch(s){case"[object ArrayBuffer]":return m(i);case"[object Boolean]":case"[object Date]":return new $(+i);case"[object DataView]":return v(i,u);case"[object Float32Array]":case"[object Float64Array]":case"[object Int8Array]":case"[object Int16Array]":case"[object Int32Array]":case"[object Uint8Array]":case"[object Uint8ClampedArray]":case"[object Uint16Array]":case"[object Uint32Array]":return M(i,u);case"[object Map]":case"[object Set]":return new $;case"[object Number]":case"[object String]":return new $(i);case"[object RegExp]":return _(i);case"[object Symbol]":return j(i)}}},38517:(i,s,u)=>{var m=u(3118),v=u(85924),_=u(25726);i.exports=function initCloneObject(i){return"function"!=typeof i.constructor||_(i)?{}:m(v(i))}},83112:i=>{var s=/\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/;i.exports=function insertWrapDetails(i,u){var m=u.length;if(!m)return i;var v=m-1;return u[v]=(m>1?"& ":"")+u[v],u=u.join(m>2?", ":" "),i.replace(s,"{\n/* [wrapped with "+u+"] */\n")}},37285:(i,s,u)=>{var m=u(62705),v=u(35694),_=u(1469),j=m?m.isConcatSpreadable:void 0;i.exports=function isFlattenable(i){return _(i)||v(i)||!!(j&&i&&i[j])}},65776:i=>{var s=/^(?:0|[1-9]\d*)$/;i.exports=function isIndex(i,u){var m=typeof i;return!!(u=null==u?9007199254740991:u)&&("number"==m||"symbol"!=m&&s.test(i))&&i>-1&&i%1==0&&i{var m=u(77813),v=u(98612),_=u(65776),j=u(13218);i.exports=function isIterateeCall(i,s,u){if(!j(u))return!1;var M=typeof s;return!!("number"==M?v(u)&&_(s,u.length):"string"==M&&s in u)&&m(u[s],i)}},15403:(i,s,u)=>{var m=u(1469),v=u(33448),_=/\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/,j=/^\w*$/;i.exports=function isKey(i,s){if(m(i))return!1;var u=typeof i;return!("number"!=u&&"symbol"!=u&&"boolean"!=u&&null!=i&&!v(i))||(j.test(i)||!_.test(i)||null!=s&&i in Object(s))}},37019:i=>{i.exports=function isKeyable(i){var s=typeof i;return"string"==s||"number"==s||"symbol"==s||"boolean"==s?"__proto__"!==i:null===i}},86528:(i,s,u)=>{var m=u(96425),v=u(66833),_=u(97658),j=u(8111);i.exports=function isLaziable(i){var s=_(i),u=j[s];if("function"!=typeof u||!(s in m.prototype))return!1;if(i===u)return!0;var M=v(u);return!!M&&i===M[0]}},15346:(i,s,u)=>{var m,v=u(14429),_=(m=/[^.]+$/.exec(v&&v.keys&&v.keys.IE_PROTO||""))?"Symbol(src)_1."+m:"";i.exports=function isMasked(i){return!!_&&_ in i}},25726:i=>{var s=Object.prototype;i.exports=function isPrototype(i){var u=i&&i.constructor;return i===("function"==typeof u&&u.prototype||s)}},89162:(i,s,u)=>{var m=u(13218);i.exports=function isStrictComparable(i){return i==i&&!m(i)}},27040:i=>{i.exports=function listCacheClear(){this.__data__=[],this.size=0}},14125:(i,s,u)=>{var m=u(18470),v=Array.prototype.splice;i.exports=function listCacheDelete(i){var s=this.__data__,u=m(s,i);return!(u<0)&&(u==s.length-1?s.pop():v.call(s,u,1),--this.size,!0)}},82117:(i,s,u)=>{var m=u(18470);i.exports=function listCacheGet(i){var s=this.__data__,u=m(s,i);return u<0?void 0:s[u][1]}},67518:(i,s,u)=>{var m=u(18470);i.exports=function listCacheHas(i){return m(this.__data__,i)>-1}},54705:(i,s,u)=>{var m=u(18470);i.exports=function listCacheSet(i,s){var u=this.__data__,v=m(u,i);return v<0?(++this.size,u.push([i,s])):u[v][1]=s,this}},24785:(i,s,u)=>{var m=u(1989),v=u(38407),_=u(57071);i.exports=function mapCacheClear(){this.size=0,this.__data__={hash:new m,map:new(_||v),string:new m}}},11285:(i,s,u)=>{var m=u(45050);i.exports=function mapCacheDelete(i){var s=m(this,i).delete(i);return this.size-=s?1:0,s}},96e3:(i,s,u)=>{var m=u(45050);i.exports=function mapCacheGet(i){return m(this,i).get(i)}},49916:(i,s,u)=>{var m=u(45050);i.exports=function mapCacheHas(i){return m(this,i).has(i)}},95265:(i,s,u)=>{var m=u(45050);i.exports=function mapCacheSet(i,s){var u=m(this,i),v=u.size;return u.set(i,s),this.size+=u.size==v?0:1,this}},68776:i=>{i.exports=function mapToArray(i){var s=-1,u=Array(i.size);return i.forEach((function(i,m){u[++s]=[m,i]})),u}},42634:i=>{i.exports=function matchesStrictComparable(i,s){return function(u){return null!=u&&(u[i]===s&&(void 0!==s||i in Object(u)))}}},24523:(i,s,u)=>{var m=u(88306);i.exports=function memoizeCapped(i){var s=m(i,(function(i){return 500===u.size&&u.clear(),i})),u=s.cache;return s}},63833:(i,s,u)=>{var m=u(52157),v=u(14054),_=u(46460),j="__lodash_placeholder__",M=128,$=Math.min;i.exports=function mergeData(i,s){var u=i[1],W=s[1],X=u|W,Y=X<131,Z=W==M&&8==u||W==M&&256==u&&i[7].length<=s[8]||384==W&&s[7].length<=s[8]&&8==u;if(!Y&&!Z)return i;1&W&&(i[2]=s[2],X|=1&u?0:4);var ee=s[3];if(ee){var ie=i[3];i[3]=ie?m(ie,ee,s[4]):ee,i[4]=ie?_(i[3],j):s[4]}return(ee=s[5])&&(ie=i[5],i[5]=ie?v(ie,ee,s[6]):ee,i[6]=ie?_(i[5],j):s[6]),(ee=s[7])&&(i[7]=ee),W&M&&(i[8]=null==i[8]?s[8]:$(i[8],s[8])),null==i[9]&&(i[9]=s[9]),i[0]=s[0],i[1]=X,i}},89250:(i,s,u)=>{var m=u(70577),v=m&&new m;i.exports=v},94536:(i,s,u)=>{var m=u(10852)(Object,"create");i.exports=m},86916:(i,s,u)=>{var m=u(5569)(Object.keys,Object);i.exports=m},33498:i=>{i.exports=function nativeKeysIn(i){var s=[];if(null!=i)for(var u in Object(i))s.push(u);return s}},31167:(i,s,u)=>{i=u.nmd(i);var m=u(31957),v=s&&!s.nodeType&&s,_=v&&i&&!i.nodeType&&i,j=_&&_.exports===v&&m.process,M=function(){try{var i=_&&_.require&&_.require("util").types;return i||j&&j.binding&&j.binding("util")}catch(i){}}();i.exports=M},2333:i=>{var s=Object.prototype.toString;i.exports=function objectToString(i){return s.call(i)}},5569:i=>{i.exports=function overArg(i,s){return function(u){return i(s(u))}}},45357:(i,s,u)=>{var m=u(96874),v=Math.max;i.exports=function overRest(i,s,u){return s=v(void 0===s?i.length-1:s,0),function(){for(var _=arguments,j=-1,M=v(_.length-s,0),$=Array(M);++j{var m=u(97786),v=u(14259);i.exports=function parent(i,s){return s.length<2?i:m(i,v(s,0,-1))}},52060:i=>{i.exports={}},90451:(i,s,u)=>{var m=u(278),v=u(65776),_=Math.min;i.exports=function reorder(i,s){for(var u=i.length,j=_(s.length,u),M=m(i);j--;){var $=s[j];i[j]=v($,u)?M[$]:void 0}return i}},46460:i=>{var s="__lodash_placeholder__";i.exports=function replaceHolders(i,u){for(var m=-1,v=i.length,_=0,j=[];++m{var m=u(31957),v="object"==typeof self&&self&&self.Object===Object&&self,_=m||v||Function("return this")();i.exports=_},36390:i=>{i.exports=function safeGet(i,s){if(("constructor"!==s||"function"!=typeof i[s])&&"__proto__"!=s)return i[s]}},90619:i=>{i.exports=function setCacheAdd(i){return this.__data__.set(i,"__lodash_hash_undefined__"),this}},72385:i=>{i.exports=function setCacheHas(i){return this.__data__.has(i)}},258:(i,s,u)=>{var m=u(28045),v=u(21275)(m);i.exports=v},21814:i=>{i.exports=function setToArray(i){var s=-1,u=Array(i.size);return i.forEach((function(i){u[++s]=i})),u}},30061:(i,s,u)=>{var m=u(56560),v=u(21275)(m);i.exports=v},69255:(i,s,u)=>{var m=u(58775),v=u(83112),_=u(30061),j=u(87241);i.exports=function setWrapToString(i,s,u){var M=s+"";return _(i,v(M,j(m(M),u)))}},21275:i=>{var s=Date.now;i.exports=function shortOut(i){var u=0,m=0;return function(){var v=s(),_=16-(v-m);if(m=v,_>0){if(++u>=800)return arguments[0]}else u=0;return i.apply(void 0,arguments)}}},37465:(i,s,u)=>{var m=u(38407);i.exports=function stackClear(){this.__data__=new m,this.size=0}},63779:i=>{i.exports=function stackDelete(i){var s=this.__data__,u=s.delete(i);return this.size=s.size,u}},67599:i=>{i.exports=function stackGet(i){return this.__data__.get(i)}},44758:i=>{i.exports=function stackHas(i){return this.__data__.has(i)}},34309:(i,s,u)=>{var m=u(38407),v=u(57071),_=u(83369);i.exports=function stackSet(i,s){var u=this.__data__;if(u instanceof m){var j=u.__data__;if(!v||j.length<199)return j.push([i,s]),this.size=++u.size,this;u=this.__data__=new _(j)}return u.set(i,s),this.size=u.size,this}},42351:i=>{i.exports=function strictIndexOf(i,s,u){for(var m=u-1,v=i.length;++m{var m=u(44286),v=u(62689),_=u(676);i.exports=function stringToArray(i){return v(i)?_(i):m(i)}},55514:(i,s,u)=>{var m=u(24523),v=/[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g,_=/\\(\\)?/g,j=m((function(i){var s=[];return 46===i.charCodeAt(0)&&s.push(""),i.replace(v,(function(i,u,m,v){s.push(m?v.replace(_,"$1"):u||i)})),s}));i.exports=j},40327:(i,s,u)=>{var m=u(33448);i.exports=function toKey(i){if("string"==typeof i||m(i))return i;var s=i+"";return"0"==s&&1/i==-Infinity?"-0":s}},80346:i=>{var s=Function.prototype.toString;i.exports=function toSource(i){if(null!=i){try{return s.call(i)}catch(i){}try{return i+""}catch(i){}}return""}},67990:i=>{var s=/\s/;i.exports=function trimmedEndIndex(i){for(var u=i.length;u--&&s.test(i.charAt(u)););return u}},676:i=>{var s="\\ud800-\\udfff",u="["+s+"]",m="[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]",v="\\ud83c[\\udffb-\\udfff]",_="[^"+s+"]",j="(?:\\ud83c[\\udde6-\\uddff]){2}",M="[\\ud800-\\udbff][\\udc00-\\udfff]",$="(?:"+m+"|"+v+")"+"?",W="[\\ufe0e\\ufe0f]?",X=W+$+("(?:\\u200d(?:"+[_,j,M].join("|")+")"+W+$+")*"),Y="(?:"+[_+m+"?",m,j,M,u].join("|")+")",Z=RegExp(v+"(?="+v+")|"+Y+X,"g");i.exports=function unicodeToArray(i){return i.match(Z)||[]}},2757:i=>{var s="\\ud800-\\udfff",u="\\u2700-\\u27bf",m="a-z\\xdf-\\xf6\\xf8-\\xff",v="A-Z\\xc0-\\xd6\\xd8-\\xde",_="\\xac\\xb1\\xd7\\xf7\\x00-\\x2f\\x3a-\\x40\\x5b-\\x60\\x7b-\\xbf\\u2000-\\u206f \\t\\x0b\\f\\xa0\\ufeff\\n\\r\\u2028\\u2029\\u1680\\u180e\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200a\\u202f\\u205f\\u3000",j="["+_+"]",M="\\d+",$="["+u+"]",W="["+m+"]",X="[^"+s+_+M+u+m+v+"]",Y="(?:\\ud83c[\\udde6-\\uddff]){2}",Z="[\\ud800-\\udbff][\\udc00-\\udfff]",ee="["+v+"]",ie="(?:"+W+"|"+X+")",ae="(?:"+ee+"|"+X+")",le="(?:['’](?:d|ll|m|re|s|t|ve))?",ce="(?:['’](?:D|LL|M|RE|S|T|VE))?",pe="(?:[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]|\\ud83c[\\udffb-\\udfff])?",de="[\\ufe0e\\ufe0f]?",fe=de+pe+("(?:\\u200d(?:"+["[^"+s+"]",Y,Z].join("|")+")"+de+pe+")*"),ye="(?:"+[$,Y,Z].join("|")+")"+fe,be=RegExp([ee+"?"+W+"+"+le+"(?="+[j,ee,"$"].join("|")+")",ae+"+"+ce+"(?="+[j,ee+ie,"$"].join("|")+")",ee+"?"+ie+"+"+le,ee+"+"+ce,"\\d*(?:1ST|2ND|3RD|(?![123])\\dTH)(?=\\b|[a-z_])","\\d*(?:1st|2nd|3rd|(?![123])\\dth)(?=\\b|[A-Z_])",M,ye].join("|"),"g");i.exports=function unicodeWords(i){return i.match(be)||[]}},87241:(i,s,u)=>{var m=u(77412),v=u(47443),_=[["ary",128],["bind",1],["bindKey",2],["curry",8],["curryRight",16],["flip",512],["partial",32],["partialRight",64],["rearg",256]];i.exports=function updateWrapDetails(i,s){return m(_,(function(u){var m="_."+u[0];s&u[1]&&!v(i,m)&&i.push(m)})),i.sort()}},21913:(i,s,u)=>{var m=u(96425),v=u(7548),_=u(278);i.exports=function wrapperClone(i){if(i instanceof m)return i.clone();var s=new v(i.__wrapped__,i.__chain__);return s.__actions__=_(i.__actions__),s.__index__=i.__index__,s.__values__=i.__values__,s}},39514:(i,s,u)=>{var m=u(97727);i.exports=function ary(i,s,u){return s=u?void 0:s,s=i&&null==s?i.length:s,m(i,128,void 0,void 0,void 0,void 0,s)}},68929:(i,s,u)=>{var m=u(48403),v=u(35393)((function(i,s,u){return s=s.toLowerCase(),i+(u?m(s):s)}));i.exports=v},48403:(i,s,u)=>{var m=u(79833),v=u(11700);i.exports=function capitalize(i){return v(m(i).toLowerCase())}},66678:(i,s,u)=>{var m=u(85990);i.exports=function clone(i){return m(i,4)}},75703:i=>{i.exports=function constant(i){return function(){return i}}},40087:(i,s,u)=>{var m=u(97727);function curry(i,s,u){var v=m(i,8,void 0,void 0,void 0,void 0,void 0,s=u?void 0:s);return v.placeholder=curry.placeholder,v}curry.placeholder={},i.exports=curry},23279:(i,s,u)=>{var m=u(13218),v=u(7771),_=u(14841),j=Math.max,M=Math.min;i.exports=function debounce(i,s,u){var $,W,X,Y,Z,ee,ie=0,ae=!1,le=!1,ce=!0;if("function"!=typeof i)throw new TypeError("Expected a function");function invokeFunc(s){var u=$,m=W;return $=W=void 0,ie=s,Y=i.apply(m,u)}function shouldInvoke(i){var u=i-ee;return void 0===ee||u>=s||u<0||le&&i-ie>=X}function timerExpired(){var i=v();if(shouldInvoke(i))return trailingEdge(i);Z=setTimeout(timerExpired,function remainingWait(i){var u=s-(i-ee);return le?M(u,X-(i-ie)):u}(i))}function trailingEdge(i){return Z=void 0,ce&&$?invokeFunc(i):($=W=void 0,Y)}function debounced(){var i=v(),u=shouldInvoke(i);if($=arguments,W=this,ee=i,u){if(void 0===Z)return function leadingEdge(i){return ie=i,Z=setTimeout(timerExpired,s),ae?invokeFunc(i):Y}(ee);if(le)return clearTimeout(Z),Z=setTimeout(timerExpired,s),invokeFunc(ee)}return void 0===Z&&(Z=setTimeout(timerExpired,s)),Y}return s=_(s)||0,m(u)&&(ae=!!u.leading,X=(le="maxWait"in u)?j(_(u.maxWait)||0,s):X,ce="trailing"in u?!!u.trailing:ce),debounced.cancel=function cancel(){void 0!==Z&&clearTimeout(Z),ie=0,$=ee=W=Z=void 0},debounced.flush=function flush(){return void 0===Z?Y:trailingEdge(v())},debounced}},53816:(i,s,u)=>{var m=u(69389),v=u(79833),_=/[\xc0-\xd6\xd8-\xf6\xf8-\xff\u0100-\u017f]/g,j=RegExp("[\\u0300-\\u036f\\ufe20-\\ufe2f\\u20d0-\\u20ff]","g");i.exports=function deburr(i){return(i=v(i))&&i.replace(_,m).replace(j,"")}},77813:i=>{i.exports=function eq(i,s){return i===s||i!=i&&s!=s}},13311:(i,s,u)=>{var m=u(67740)(u(30998));i.exports=m},30998:(i,s,u)=>{var m=u(41848),v=u(67206),_=u(40554),j=Math.max;i.exports=function findIndex(i,s,u){var M=null==i?0:i.length;if(!M)return-1;var $=null==u?0:_(u);return $<0&&($=j(M+$,0)),m(i,v(s,3),$)}},85564:(i,s,u)=>{var m=u(21078);i.exports=function flatten(i){return(null==i?0:i.length)?m(i,1):[]}},84599:(i,s,u)=>{var m=u(68836),v=u(69306),_=Array.prototype.push;function baseAry(i,s){return 2==s?function(s,u){return i(s,u)}:function(s){return i(s)}}function cloneArray(i){for(var s=i?i.length:0,u=Array(s);s--;)u[s]=i[s];return u}function wrapImmutable(i,s){return function(){var u=arguments.length;if(u){for(var m=Array(u);u--;)m[u]=arguments[u];var v=m[0]=s.apply(void 0,m);return i.apply(void 0,m),v}}}i.exports=function baseConvert(i,s,u,j){var M="function"==typeof s,$=s===Object(s);if($&&(j=u,u=s,s=void 0),null==u)throw new TypeError;j||(j={});var W={cap:!("cap"in j)||j.cap,curry:!("curry"in j)||j.curry,fixed:!("fixed"in j)||j.fixed,immutable:!("immutable"in j)||j.immutable,rearg:!("rearg"in j)||j.rearg},X=M?u:v,Y="curry"in j&&j.curry,Z="fixed"in j&&j.fixed,ee="rearg"in j&&j.rearg,ie=M?u.runInContext():void 0,ae=M?u:{ary:i.ary,assign:i.assign,clone:i.clone,curry:i.curry,forEach:i.forEach,isArray:i.isArray,isError:i.isError,isFunction:i.isFunction,isWeakMap:i.isWeakMap,iteratee:i.iteratee,keys:i.keys,rearg:i.rearg,toInteger:i.toInteger,toPath:i.toPath},le=ae.ary,ce=ae.assign,pe=ae.clone,de=ae.curry,fe=ae.forEach,ye=ae.isArray,be=ae.isError,_e=ae.isFunction,we=ae.isWeakMap,Se=ae.keys,xe=ae.rearg,Ie=ae.toInteger,Pe=ae.toPath,Te=Se(m.aryMethod),Re={castArray:function(i){return function(){var s=arguments[0];return ye(s)?i(cloneArray(s)):i.apply(void 0,arguments)}},iteratee:function(i){return function(){var s=arguments[1],u=i(arguments[0],s),m=u.length;return W.cap&&"number"==typeof s?(s=s>2?s-2:1,m&&m<=s?u:baseAry(u,s)):u}},mixin:function(i){return function(s){var u=this;if(!_e(u))return i(u,Object(s));var m=[];return fe(Se(s),(function(i){_e(s[i])&&m.push([i,u.prototype[i]])})),i(u,Object(s)),fe(m,(function(i){var s=i[1];_e(s)?u.prototype[i[0]]=s:delete u.prototype[i[0]]})),u}},nthArg:function(i){return function(s){var u=s<0?1:Ie(s)+1;return de(i(s),u)}},rearg:function(i){return function(s,u){var m=u?u.length:0;return de(i(s,u),m)}},runInContext:function(s){return function(u){return baseConvert(i,s(u),j)}}};function castCap(i,s){if(W.cap){var u=m.iterateeRearg[i];if(u)return function iterateeRearg(i,s){return overArg(i,(function(i){var u=s.length;return function baseArity(i,s){return 2==s?function(s,u){return i.apply(void 0,arguments)}:function(s){return i.apply(void 0,arguments)}}(xe(baseAry(i,u),s),u)}))}(s,u);var v=!M&&m.iterateeAry[i];if(v)return function iterateeAry(i,s){return overArg(i,(function(i){return"function"==typeof i?baseAry(i,s):i}))}(s,v)}return s}function castFixed(i,s,u){if(W.fixed&&(Z||!m.skipFixed[i])){var v=m.methodSpread[i],j=v&&v.start;return void 0===j?le(s,u):function flatSpread(i,s){return function(){for(var u=arguments.length,m=u-1,v=Array(u);u--;)v[u]=arguments[u];var j=v[s],M=v.slice(0,s);return j&&_.apply(M,j),s!=m&&_.apply(M,v.slice(s+1)),i.apply(this,M)}}(s,j)}return s}function castRearg(i,s,u){return W.rearg&&u>1&&(ee||!m.skipRearg[i])?xe(s,m.methodRearg[i]||m.aryRearg[u]):s}function cloneByPath(i,s){for(var u=-1,m=(s=Pe(s)).length,v=m-1,_=pe(Object(i)),j=_;null!=j&&++u1?de(s,u):s}(0,v=castCap(_,v),i),!1}})),!v})),v||(v=j),v==s&&(v=Y?de(v,1):function(){return s.apply(this,arguments)}),v.convert=createConverter(_,s),v.placeholder=s.placeholder=u,v}if(!$)return wrap(s,u,X);var qe=u,ze=[];return fe(Te,(function(i){fe(m.aryMethod[i],(function(i){var s=qe[m.remap[i]||i];s&&ze.push([i,wrap(i,s,qe)])}))})),fe(Se(qe),(function(i){var s=qe[i];if("function"==typeof s){for(var u=ze.length;u--;)if(ze[u][0]==i)return;s.convert=createConverter(i,s),ze.push([i,s])}})),fe(ze,(function(i){qe[i[0]]=i[1]})),qe.convert=function convertLib(i){return qe.runInContext.convert(i)(void 0)},qe.placeholder=qe,fe(Se(qe),(function(i){fe(m.realToAlias[i]||[],(function(s){qe[s]=qe[i]}))})),qe}},68836:(i,s)=>{s.aliasToReal={each:"forEach",eachRight:"forEachRight",entries:"toPairs",entriesIn:"toPairsIn",extend:"assignIn",extendAll:"assignInAll",extendAllWith:"assignInAllWith",extendWith:"assignInWith",first:"head",conforms:"conformsTo",matches:"isMatch",property:"get",__:"placeholder",F:"stubFalse",T:"stubTrue",all:"every",allPass:"overEvery",always:"constant",any:"some",anyPass:"overSome",apply:"spread",assoc:"set",assocPath:"set",complement:"negate",compose:"flowRight",contains:"includes",dissoc:"unset",dissocPath:"unset",dropLast:"dropRight",dropLastWhile:"dropRightWhile",equals:"isEqual",identical:"eq",indexBy:"keyBy",init:"initial",invertObj:"invert",juxt:"over",omitAll:"omit",nAry:"ary",path:"get",pathEq:"matchesProperty",pathOr:"getOr",paths:"at",pickAll:"pick",pipe:"flow",pluck:"map",prop:"get",propEq:"matchesProperty",propOr:"getOr",props:"at",symmetricDifference:"xor",symmetricDifferenceBy:"xorBy",symmetricDifferenceWith:"xorWith",takeLast:"takeRight",takeLastWhile:"takeRightWhile",unapply:"rest",unnest:"flatten",useWith:"overArgs",where:"conformsTo",whereEq:"isMatch",zipObj:"zipObject"},s.aryMethod={1:["assignAll","assignInAll","attempt","castArray","ceil","create","curry","curryRight","defaultsAll","defaultsDeepAll","floor","flow","flowRight","fromPairs","invert","iteratee","memoize","method","mergeAll","methodOf","mixin","nthArg","over","overEvery","overSome","rest","reverse","round","runInContext","spread","template","trim","trimEnd","trimStart","uniqueId","words","zipAll"],2:["add","after","ary","assign","assignAllWith","assignIn","assignInAllWith","at","before","bind","bindAll","bindKey","chunk","cloneDeepWith","cloneWith","concat","conformsTo","countBy","curryN","curryRightN","debounce","defaults","defaultsDeep","defaultTo","delay","difference","divide","drop","dropRight","dropRightWhile","dropWhile","endsWith","eq","every","filter","find","findIndex","findKey","findLast","findLastIndex","findLastKey","flatMap","flatMapDeep","flattenDepth","forEach","forEachRight","forIn","forInRight","forOwn","forOwnRight","get","groupBy","gt","gte","has","hasIn","includes","indexOf","intersection","invertBy","invoke","invokeMap","isEqual","isMatch","join","keyBy","lastIndexOf","lt","lte","map","mapKeys","mapValues","matchesProperty","maxBy","meanBy","merge","mergeAllWith","minBy","multiply","nth","omit","omitBy","overArgs","pad","padEnd","padStart","parseInt","partial","partialRight","partition","pick","pickBy","propertyOf","pull","pullAll","pullAt","random","range","rangeRight","rearg","reject","remove","repeat","restFrom","result","sampleSize","some","sortBy","sortedIndex","sortedIndexOf","sortedLastIndex","sortedLastIndexOf","sortedUniqBy","split","spreadFrom","startsWith","subtract","sumBy","take","takeRight","takeRightWhile","takeWhile","tap","throttle","thru","times","trimChars","trimCharsEnd","trimCharsStart","truncate","union","uniqBy","uniqWith","unset","unzipWith","without","wrap","xor","zip","zipObject","zipObjectDeep"],3:["assignInWith","assignWith","clamp","differenceBy","differenceWith","findFrom","findIndexFrom","findLastFrom","findLastIndexFrom","getOr","includesFrom","indexOfFrom","inRange","intersectionBy","intersectionWith","invokeArgs","invokeArgsMap","isEqualWith","isMatchWith","flatMapDepth","lastIndexOfFrom","mergeWith","orderBy","padChars","padCharsEnd","padCharsStart","pullAllBy","pullAllWith","rangeStep","rangeStepRight","reduce","reduceRight","replace","set","slice","sortedIndexBy","sortedLastIndexBy","transform","unionBy","unionWith","update","xorBy","xorWith","zipWith"],4:["fill","setWith","updateWith"]},s.aryRearg={2:[1,0],3:[2,0,1],4:[3,2,0,1]},s.iterateeAry={dropRightWhile:1,dropWhile:1,every:1,filter:1,find:1,findFrom:1,findIndex:1,findIndexFrom:1,findKey:1,findLast:1,findLastFrom:1,findLastIndex:1,findLastIndexFrom:1,findLastKey:1,flatMap:1,flatMapDeep:1,flatMapDepth:1,forEach:1,forEachRight:1,forIn:1,forInRight:1,forOwn:1,forOwnRight:1,map:1,mapKeys:1,mapValues:1,partition:1,reduce:2,reduceRight:2,reject:1,remove:1,some:1,takeRightWhile:1,takeWhile:1,times:1,transform:2},s.iterateeRearg={mapKeys:[1],reduceRight:[1,0]},s.methodRearg={assignInAllWith:[1,0],assignInWith:[1,2,0],assignAllWith:[1,0],assignWith:[1,2,0],differenceBy:[1,2,0],differenceWith:[1,2,0],getOr:[2,1,0],intersectionBy:[1,2,0],intersectionWith:[1,2,0],isEqualWith:[1,2,0],isMatchWith:[2,1,0],mergeAllWith:[1,0],mergeWith:[1,2,0],padChars:[2,1,0],padCharsEnd:[2,1,0],padCharsStart:[2,1,0],pullAllBy:[2,1,0],pullAllWith:[2,1,0],rangeStep:[1,2,0],rangeStepRight:[1,2,0],setWith:[3,1,2,0],sortedIndexBy:[2,1,0],sortedLastIndexBy:[2,1,0],unionBy:[1,2,0],unionWith:[1,2,0],updateWith:[3,1,2,0],xorBy:[1,2,0],xorWith:[1,2,0],zipWith:[1,2,0]},s.methodSpread={assignAll:{start:0},assignAllWith:{start:0},assignInAll:{start:0},assignInAllWith:{start:0},defaultsAll:{start:0},defaultsDeepAll:{start:0},invokeArgs:{start:2},invokeArgsMap:{start:2},mergeAll:{start:0},mergeAllWith:{start:0},partial:{start:1},partialRight:{start:1},without:{start:1},zipAll:{start:0}},s.mutate={array:{fill:!0,pull:!0,pullAll:!0,pullAllBy:!0,pullAllWith:!0,pullAt:!0,remove:!0,reverse:!0},object:{assign:!0,assignAll:!0,assignAllWith:!0,assignIn:!0,assignInAll:!0,assignInAllWith:!0,assignInWith:!0,assignWith:!0,defaults:!0,defaultsAll:!0,defaultsDeep:!0,defaultsDeepAll:!0,merge:!0,mergeAll:!0,mergeAllWith:!0,mergeWith:!0},set:{set:!0,setWith:!0,unset:!0,update:!0,updateWith:!0}},s.realToAlias=function(){var i=Object.prototype.hasOwnProperty,u=s.aliasToReal,m={};for(var v in u){var _=u[v];i.call(m,_)?m[_].push(v):m[_]=[v]}return m}(),s.remap={assignAll:"assign",assignAllWith:"assignWith",assignInAll:"assignIn",assignInAllWith:"assignInWith",curryN:"curry",curryRightN:"curryRight",defaultsAll:"defaults",defaultsDeepAll:"defaultsDeep",findFrom:"find",findIndexFrom:"findIndex",findLastFrom:"findLast",findLastIndexFrom:"findLastIndex",getOr:"get",includesFrom:"includes",indexOfFrom:"indexOf",invokeArgs:"invoke",invokeArgsMap:"invokeMap",lastIndexOfFrom:"lastIndexOf",mergeAll:"merge",mergeAllWith:"mergeWith",padChars:"pad",padCharsEnd:"padEnd",padCharsStart:"padStart",propertyOf:"get",rangeStep:"range",rangeStepRight:"rangeRight",restFrom:"rest",spreadFrom:"spread",trimChars:"trim",trimCharsEnd:"trimEnd",trimCharsStart:"trimStart",zipAll:"zip"},s.skipFixed={castArray:!0,flow:!0,flowRight:!0,iteratee:!0,mixin:!0,rearg:!0,runInContext:!0},s.skipRearg={add:!0,assign:!0,assignIn:!0,bind:!0,bindKey:!0,concat:!0,difference:!0,divide:!0,eq:!0,gt:!0,gte:!0,isEqual:!0,lt:!0,lte:!0,matchesProperty:!0,merge:!0,multiply:!0,overArgs:!0,partial:!0,partialRight:!0,propertyOf:!0,random:!0,range:!0,rangeRight:!0,subtract:!0,zip:!0,zipObject:!0,zipObjectDeep:!0}},4269:(i,s,u)=>{i.exports={ary:u(39514),assign:u(44037),clone:u(66678),curry:u(40087),forEach:u(77412),isArray:u(1469),isError:u(64647),isFunction:u(23560),isWeakMap:u(81018),iteratee:u(72594),keys:u(280),rearg:u(4963),toInteger:u(40554),toPath:u(30084)}},72700:(i,s,u)=>{i.exports=u(28252)},92822:(i,s,u)=>{var m=u(84599),v=u(4269);i.exports=function convert(i,s,u){return m(v,i,s,u)}},69306:i=>{i.exports={}},28252:(i,s,u)=>{var m=u(92822)("set",u(36968));m.placeholder=u(69306),i.exports=m},27361:(i,s,u)=>{var m=u(97786);i.exports=function get(i,s,u){var v=null==i?void 0:m(i,s);return void 0===v?u:v}},79095:(i,s,u)=>{var m=u(13),v=u(222);i.exports=function hasIn(i,s){return null!=i&&v(i,s,m)}},6557:i=>{i.exports=function identity(i){return i}},35694:(i,s,u)=>{var m=u(9454),v=u(37005),_=Object.prototype,j=_.hasOwnProperty,M=_.propertyIsEnumerable,$=m(function(){return arguments}())?m:function(i){return v(i)&&j.call(i,"callee")&&!M.call(i,"callee")};i.exports=$},1469:i=>{var s=Array.isArray;i.exports=s},98612:(i,s,u)=>{var m=u(23560),v=u(41780);i.exports=function isArrayLike(i){return null!=i&&v(i.length)&&!m(i)}},29246:(i,s,u)=>{var m=u(98612),v=u(37005);i.exports=function isArrayLikeObject(i){return v(i)&&m(i)}},51584:(i,s,u)=>{var m=u(44239),v=u(37005);i.exports=function isBoolean(i){return!0===i||!1===i||v(i)&&"[object Boolean]"==m(i)}},44144:(i,s,u)=>{i=u.nmd(i);var m=u(55639),v=u(95062),_=s&&!s.nodeType&&s,j=_&&i&&!i.nodeType&&i,M=j&&j.exports===_?m.Buffer:void 0,$=(M?M.isBuffer:void 0)||v;i.exports=$},41609:(i,s,u)=>{var m=u(280),v=u(64160),_=u(35694),j=u(1469),M=u(98612),$=u(44144),W=u(25726),X=u(36719),Y=Object.prototype.hasOwnProperty;i.exports=function isEmpty(i){if(null==i)return!0;if(M(i)&&(j(i)||"string"==typeof i||"function"==typeof i.splice||$(i)||X(i)||_(i)))return!i.length;var s=v(i);if("[object Map]"==s||"[object Set]"==s)return!i.size;if(W(i))return!m(i).length;for(var u in i)if(Y.call(i,u))return!1;return!0}},18446:(i,s,u)=>{var m=u(90939);i.exports=function isEqual(i,s){return m(i,s)}},64647:(i,s,u)=>{var m=u(44239),v=u(37005),_=u(68630);i.exports=function isError(i){if(!v(i))return!1;var s=m(i);return"[object Error]"==s||"[object DOMException]"==s||"string"==typeof i.message&&"string"==typeof i.name&&!_(i)}},23560:(i,s,u)=>{var m=u(44239),v=u(13218);i.exports=function isFunction(i){if(!v(i))return!1;var s=m(i);return"[object Function]"==s||"[object GeneratorFunction]"==s||"[object AsyncFunction]"==s||"[object Proxy]"==s}},41780:i=>{i.exports=function isLength(i){return"number"==typeof i&&i>-1&&i%1==0&&i<=9007199254740991}},56688:(i,s,u)=>{var m=u(25588),v=u(7518),_=u(31167),j=_&&_.isMap,M=j?v(j):m;i.exports=M},45220:i=>{i.exports=function isNull(i){return null===i}},81763:(i,s,u)=>{var m=u(44239),v=u(37005);i.exports=function isNumber(i){return"number"==typeof i||v(i)&&"[object Number]"==m(i)}},13218:i=>{i.exports=function isObject(i){var s=typeof i;return null!=i&&("object"==s||"function"==s)}},37005:i=>{i.exports=function isObjectLike(i){return null!=i&&"object"==typeof i}},68630:(i,s,u)=>{var m=u(44239),v=u(85924),_=u(37005),j=Function.prototype,M=Object.prototype,$=j.toString,W=M.hasOwnProperty,X=$.call(Object);i.exports=function isPlainObject(i){if(!_(i)||"[object Object]"!=m(i))return!1;var s=v(i);if(null===s)return!0;var u=W.call(s,"constructor")&&s.constructor;return"function"==typeof u&&u instanceof u&&$.call(u)==X}},72928:(i,s,u)=>{var m=u(29221),v=u(7518),_=u(31167),j=_&&_.isSet,M=j?v(j):m;i.exports=M},47037:(i,s,u)=>{var m=u(44239),v=u(1469),_=u(37005);i.exports=function isString(i){return"string"==typeof i||!v(i)&&_(i)&&"[object String]"==m(i)}},33448:(i,s,u)=>{var m=u(44239),v=u(37005);i.exports=function isSymbol(i){return"symbol"==typeof i||v(i)&&"[object Symbol]"==m(i)}},36719:(i,s,u)=>{var m=u(38749),v=u(7518),_=u(31167),j=_&&_.isTypedArray,M=j?v(j):m;i.exports=M},81018:(i,s,u)=>{var m=u(64160),v=u(37005);i.exports=function isWeakMap(i){return v(i)&&"[object WeakMap]"==m(i)}},72594:(i,s,u)=>{var m=u(85990),v=u(67206);i.exports=function iteratee(i){return v("function"==typeof i?i:m(i,1))}},3674:(i,s,u)=>{var m=u(14636),v=u(280),_=u(98612);i.exports=function keys(i){return _(i)?m(i):v(i)}},81704:(i,s,u)=>{var m=u(14636),v=u(10313),_=u(98612);i.exports=function keysIn(i){return _(i)?m(i,!0):v(i)}},10928:i=>{i.exports=function last(i){var s=null==i?0:i.length;return s?i[s-1]:void 0}},88306:(i,s,u)=>{var m=u(83369);function memoize(i,s){if("function"!=typeof i||null!=s&&"function"!=typeof s)throw new TypeError("Expected a function");var memoized=function(){var u=arguments,m=s?s.apply(this,u):u[0],v=memoized.cache;if(v.has(m))return v.get(m);var _=i.apply(this,u);return memoized.cache=v.set(m,_)||v,_};return memoized.cache=new(memoize.Cache||m),memoized}memoize.Cache=m,i.exports=memoize},82492:(i,s,u)=>{var m=u(42980),v=u(21463)((function(i,s,u){m(i,s,u)}));i.exports=v},94885:i=>{i.exports=function negate(i){if("function"!=typeof i)throw new TypeError("Expected a function");return function(){var s=arguments;switch(s.length){case 0:return!i.call(this);case 1:return!i.call(this,s[0]);case 2:return!i.call(this,s[0],s[1]);case 3:return!i.call(this,s[0],s[1],s[2])}return!i.apply(this,s)}}},50308:i=>{i.exports=function noop(){}},7771:(i,s,u)=>{var m=u(55639);i.exports=function(){return m.Date.now()}},57557:(i,s,u)=>{var m=u(29932),v=u(85990),_=u(57406),j=u(71811),M=u(98363),$=u(60696),W=u(99021),X=u(46904),Y=W((function(i,s){var u={};if(null==i)return u;var W=!1;s=m(s,(function(s){return s=j(s,i),W||(W=s.length>1),s})),M(i,X(i),u),W&&(u=v(u,7,$));for(var Y=s.length;Y--;)_(u,s[Y]);return u}));i.exports=Y},39601:(i,s,u)=>{var m=u(40371),v=u(79152),_=u(15403),j=u(40327);i.exports=function property(i){return _(i)?m(j(i)):v(i)}},4963:(i,s,u)=>{var m=u(97727),v=u(99021),_=v((function(i,s){return m(i,256,void 0,void 0,void 0,s)}));i.exports=_},54061:(i,s,u)=>{var m=u(62663),v=u(89881),_=u(67206),j=u(10107),M=u(1469);i.exports=function reduce(i,s,u){var $=M(i)?m:j,W=arguments.length<3;return $(i,_(s,4),u,W,v)}},36968:(i,s,u)=>{var m=u(10611);i.exports=function set(i,s,u){return null==i?i:m(i,s,u)}},59704:(i,s,u)=>{var m=u(82908),v=u(67206),_=u(5076),j=u(1469),M=u(16612);i.exports=function some(i,s,u){var $=j(i)?m:_;return u&&M(i,s,u)&&(s=void 0),$(i,v(s,3))}},70479:i=>{i.exports=function stubArray(){return[]}},95062:i=>{i.exports=function stubFalse(){return!1}},18601:(i,s,u)=>{var m=u(14841),v=1/0;i.exports=function toFinite(i){return i?(i=m(i))===v||i===-1/0?17976931348623157e292*(i<0?-1:1):i==i?i:0:0===i?i:0}},40554:(i,s,u)=>{var m=u(18601);i.exports=function toInteger(i){var s=m(i),u=s%1;return s==s?u?s-u:s:0}},7334:(i,s,u)=>{var m=u(79833);i.exports=function toLower(i){return m(i).toLowerCase()}},14841:(i,s,u)=>{var m=u(27561),v=u(13218),_=u(33448),j=/^[-+]0x[0-9a-f]+$/i,M=/^0b[01]+$/i,$=/^0o[0-7]+$/i,W=parseInt;i.exports=function toNumber(i){if("number"==typeof i)return i;if(_(i))return NaN;if(v(i)){var s="function"==typeof i.valueOf?i.valueOf():i;i=v(s)?s+"":s}if("string"!=typeof i)return 0===i?i:+i;i=m(i);var u=M.test(i);return u||$.test(i)?W(i.slice(2),u?2:8):j.test(i)?NaN:+i}},30084:(i,s,u)=>{var m=u(29932),v=u(278),_=u(1469),j=u(33448),M=u(55514),$=u(40327),W=u(79833);i.exports=function toPath(i){return _(i)?m(i,$):j(i)?[i]:v(M(W(i)))}},59881:(i,s,u)=>{var m=u(98363),v=u(81704);i.exports=function toPlainObject(i){return m(i,v(i))}},79833:(i,s,u)=>{var m=u(80531);i.exports=function toString(i){return null==i?"":m(i)}},11700:(i,s,u)=>{var m=u(98805)("toUpperCase");i.exports=m},58748:(i,s,u)=>{var m=u(49029),v=u(93157),_=u(79833),j=u(2757);i.exports=function words(i,s,u){return i=_(i),void 0===(s=u?void 0:s)?v(i)?j(i):m(i):i.match(s)||[]}},8111:(i,s,u)=>{var m=u(96425),v=u(7548),_=u(9435),j=u(1469),M=u(37005),$=u(21913),W=Object.prototype.hasOwnProperty;function lodash(i){if(M(i)&&!j(i)&&!(i instanceof m)){if(i instanceof v)return i;if(W.call(i,"__wrapped__"))return $(i)}return new v(i)}lodash.prototype=_.prototype,lodash.prototype.constructor=lodash,i.exports=lodash},7287:(i,s,u)=>{var m=u(34865),v=u(1757);i.exports=function zipObject(i,s){return v(i||[],s||[],m)}},96470:(i,s,u)=>{"use strict";var m=u(47802),v=u(21102);s.highlight=highlight,s.highlightAuto=function highlightAuto(i,s){var u,j,M,$,W=s||{},X=W.subset||m.listLanguages(),Y=W.prefix,Z=X.length,ee=-1;null==Y&&(Y=_);if("string"!=typeof i)throw v("Expected `string` for value, got `%s`",i);j={relevance:0,language:null,value:[]},u={relevance:0,language:null,value:[]};for(;++eej.relevance&&(j=M),M.relevance>u.relevance&&(j=u,u=M));j.language&&(u.secondBest=j);return u},s.registerLanguage=function registerLanguage(i,s){m.registerLanguage(i,s)},s.listLanguages=function listLanguages(){return m.listLanguages()},s.registerAlias=function registerAlias(i,s){var u,v=i;s&&((v={})[i]=s);for(u in v)m.registerAliases(v[u],{languageName:u})},Emitter.prototype.addText=function text(i){var s,u,m=this.stack;if(""===i)return;s=m[m.length-1],(u=s.children[s.children.length-1])&&"text"===u.type?u.value+=i:s.children.push({type:"text",value:i})},Emitter.prototype.addKeyword=function addKeyword(i,s){this.openNode(s),this.addText(i),this.closeNode()},Emitter.prototype.addSublanguage=function addSublanguage(i,s){var u=this.stack,m=u[u.length-1],v=i.rootNode.children,_=s?{type:"element",tagName:"span",properties:{className:[s]},children:v}:v;m.children=m.children.concat(_)},Emitter.prototype.openNode=function open(i){var s=this.stack,u=this.options.classPrefix+i,m=s[s.length-1],v={type:"element",tagName:"span",properties:{className:[u]},children:[]};m.children.push(v),s.push(v)},Emitter.prototype.closeNode=function close(){this.stack.pop()},Emitter.prototype.closeAllNodes=noop,Emitter.prototype.finalize=noop,Emitter.prototype.toHTML=function toHtmlNoop(){return""};var _="hljs-";function highlight(i,s,u){var j,M=m.configure({}),$=(u||{}).prefix;if("string"!=typeof i)throw v("Expected `string` for name, got `%s`",i);if(!m.getLanguage(i))throw v("Unknown language: `%s` is not registered",i);if("string"!=typeof s)throw v("Expected `string` for value, got `%s`",s);if(null==$&&($=_),m.configure({__emitter:Emitter,classPrefix:$}),j=m.highlight(s,{language:i,ignoreIllegals:!0}),m.configure(M||{}),j.errorRaised)throw j.errorRaised;return{relevance:j.relevance,language:j.language,value:j.emitter.rootNode.children}}function Emitter(i){this.options=i,this.rootNode={children:[]},this.stack=[this.rootNode]}function noop(){}},42566:(i,s,u)=>{const m=u(94885);function coerceElementMatchingCallback(i){return"string"==typeof i?s=>s.element===i:i.constructor&&i.extend?s=>s instanceof i:i}class ArraySlice{constructor(i){this.elements=i||[]}toValue(){return this.elements.map((i=>i.toValue()))}map(i,s){return this.elements.map(i,s)}flatMap(i,s){return this.map(i,s).reduce(((i,s)=>i.concat(s)),[])}compactMap(i,s){const u=[];return this.forEach((m=>{const v=i.bind(s)(m);v&&u.push(v)})),u}filter(i,s){return i=coerceElementMatchingCallback(i),new ArraySlice(this.elements.filter(i,s))}reject(i,s){return i=coerceElementMatchingCallback(i),new ArraySlice(this.elements.filter(m(i),s))}find(i,s){return i=coerceElementMatchingCallback(i),this.elements.find(i,s)}forEach(i,s){this.elements.forEach(i,s)}reduce(i,s){return this.elements.reduce(i,s)}includes(i){return this.elements.some((s=>s.equals(i)))}shift(){return this.elements.shift()}unshift(i){this.elements.unshift(this.refract(i))}push(i){return this.elements.push(this.refract(i)),this}add(i){this.push(i)}get(i){return this.elements[i]}getValue(i){const s=this.elements[i];if(s)return s.toValue()}get length(){return this.elements.length}get isEmpty(){return 0===this.elements.length}get first(){return this.elements[0]}}"undefined"!=typeof Symbol&&(ArraySlice.prototype[Symbol.iterator]=function symbol(){return this.elements[Symbol.iterator]()}),i.exports=ArraySlice},17645:i=>{class KeyValuePair{constructor(i,s){this.key=i,this.value=s}clone(){const i=new KeyValuePair;return this.key&&(i.key=this.key.clone()),this.value&&(i.value=this.value.clone()),i}}i.exports=KeyValuePair},78520:(i,s,u)=>{const m=u(45220),v=u(47037),_=u(81763),j=u(51584),M=u(13218),$=u(28219),W=u(99829);class Namespace{constructor(i){this.elementMap={},this.elementDetection=[],this.Element=W.Element,this.KeyValuePair=W.KeyValuePair,i&&i.noDefault||this.useDefault(),this._attributeElementKeys=[],this._attributeElementArrayKeys=[]}use(i){return i.namespace&&i.namespace({base:this}),i.load&&i.load({base:this}),this}useDefault(){return this.register("null",W.NullElement).register("string",W.StringElement).register("number",W.NumberElement).register("boolean",W.BooleanElement).register("array",W.ArrayElement).register("object",W.ObjectElement).register("member",W.MemberElement).register("ref",W.RefElement).register("link",W.LinkElement),this.detect(m,W.NullElement,!1).detect(v,W.StringElement,!1).detect(_,W.NumberElement,!1).detect(j,W.BooleanElement,!1).detect(Array.isArray,W.ArrayElement,!1).detect(M,W.ObjectElement,!1),this}register(i,s){return this._elements=void 0,this.elementMap[i]=s,this}unregister(i){return this._elements=void 0,delete this.elementMap[i],this}detect(i,s,u){return void 0===u||u?this.elementDetection.unshift([i,s]):this.elementDetection.push([i,s]),this}toElement(i){if(i instanceof this.Element)return i;let s;for(let u=0;u{const s=i[0].toUpperCase()+i.substr(1);this._elements[s]=this.elementMap[i]}))),this._elements}get serialiser(){return new $(this)}}$.prototype.Namespace=Namespace,i.exports=Namespace},87526:(i,s,u)=>{const m=u(94885),v=u(42566);class ObjectSlice extends v{map(i,s){return this.elements.map((u=>i.bind(s)(u.value,u.key,u)))}filter(i,s){return new ObjectSlice(this.elements.filter((u=>i.bind(s)(u.value,u.key,u))))}reject(i,s){return this.filter(m(i.bind(s)))}forEach(i,s){return this.elements.forEach(((u,m)=>{i.bind(s)(u.value,u.key,u,m)}))}keys(){return this.map(((i,s)=>s.toValue()))}values(){return this.map((i=>i.toValue()))}}i.exports=ObjectSlice},99829:(i,s,u)=>{const m=u(3079),v=u(96295),_=u(16036),j=u(91090),M=u(18866),$=u(35804),W=u(5946),X=u(76735),Y=u(59964),Z=u(38588),ee=u(42566),ie=u(87526),ae=u(17645);function refract(i){if(i instanceof m)return i;if("string"==typeof i)return new _(i);if("number"==typeof i)return new j(i);if("boolean"==typeof i)return new M(i);if(null===i)return new v;if(Array.isArray(i))return new $(i.map(refract));if("object"==typeof i){return new X(i)}return i}m.prototype.ObjectElement=X,m.prototype.RefElement=Z,m.prototype.MemberElement=W,m.prototype.refract=refract,ee.prototype.refract=refract,i.exports={Element:m,NullElement:v,StringElement:_,NumberElement:j,BooleanElement:M,ArrayElement:$,MemberElement:W,ObjectElement:X,LinkElement:Y,RefElement:Z,refract,ArraySlice:ee,ObjectSlice:ie,KeyValuePair:ae}},59964:(i,s,u)=>{const m=u(3079);i.exports=class LinkElement extends m{constructor(i,s,u){super(i||[],s,u),this.element="link"}get relation(){return this.attributes.get("relation")}set relation(i){this.attributes.set("relation",i)}get href(){return this.attributes.get("href")}set href(i){this.attributes.set("href",i)}}},38588:(i,s,u)=>{const m=u(3079);i.exports=class RefElement extends m{constructor(i,s,u){super(i||[],s,u),this.element="ref",this.path||(this.path="element")}get path(){return this.attributes.get("path")}set path(i){this.attributes.set("path",i)}}},43500:(i,s,u)=>{const m=u(78520),v=u(99829);s.lS=m,s.KeyValuePair=u(17645),s.O4=v.ArraySlice,s.rm=v.ObjectSlice,s.W_=v.Element,s.RP=v.StringElement,s.VL=v.NumberElement,s.hh=v.BooleanElement,s.zr=v.NullElement,s.ON=v.ArrayElement,s.Sb=v.ObjectElement,s.c6=v.MemberElement,s.tK=v.RefElement,s.EA=v.LinkElement,s.Qc=v.refract,u(28219),u(3414)},35804:(i,s,u)=>{const m=u(94885),v=u(3079),_=u(42566);class ArrayElement extends v{constructor(i,s,u){super(i||[],s,u),this.element="array"}primitive(){return"array"}get(i){return this.content[i]}getValue(i){const s=this.get(i);if(s)return s.toValue()}getIndex(i){return this.content[i]}set(i,s){return this.content[i]=this.refract(s),this}remove(i){const s=this.content.splice(i,1);return s.length?s[0]:null}map(i,s){return this.content.map(i,s)}flatMap(i,s){return this.map(i,s).reduce(((i,s)=>i.concat(s)),[])}compactMap(i,s){const u=[];return this.forEach((m=>{const v=i.bind(s)(m);v&&u.push(v)})),u}filter(i,s){return new _(this.content.filter(i,s))}reject(i,s){return this.filter(m(i),s)}reduce(i,s){let u,m;void 0!==s?(u=0,m=this.refract(s)):(u=1,m="object"===this.primitive()?this.first.value:this.first);for(let s=u;s{i.bind(s)(u,this.refract(m))}))}shift(){return this.content.shift()}unshift(i){this.content.unshift(this.refract(i))}push(i){return this.content.push(this.refract(i)),this}add(i){this.push(i)}findElements(i,s){const u=s||{},m=!!u.recursive,v=void 0===u.results?[]:u.results;return this.forEach(((s,u,_)=>{m&&void 0!==s.findElements&&s.findElements(i,{results:v,recursive:m}),i(s,u,_)&&v.push(s)})),v}find(i){return new _(this.findElements(i,{recursive:!0}))}findByElement(i){return this.find((s=>s.element===i))}findByClass(i){return this.find((s=>s.classes.includes(i)))}getById(i){return this.find((s=>s.id.toValue()===i)).first}includes(i){return this.content.some((s=>s.equals(i)))}contains(i){return this.includes(i)}empty(){return new this.constructor([])}"fantasy-land/empty"(){return this.empty()}concat(i){return new this.constructor(this.content.concat(i.content))}"fantasy-land/concat"(i){return this.concat(i)}"fantasy-land/map"(i){return new this.constructor(this.map(i))}"fantasy-land/chain"(i){return this.map((s=>i(s)),this).reduce(((i,s)=>i.concat(s)),this.empty())}"fantasy-land/filter"(i){return new this.constructor(this.content.filter(i))}"fantasy-land/reduce"(i,s){return this.content.reduce(i,s)}get length(){return this.content.length}get isEmpty(){return 0===this.content.length}get first(){return this.getIndex(0)}get second(){return this.getIndex(1)}get last(){return this.getIndex(this.length-1)}}ArrayElement.empty=function empty(){return new this},ArrayElement["fantasy-land/empty"]=ArrayElement.empty,"undefined"!=typeof Symbol&&(ArrayElement.prototype[Symbol.iterator]=function symbol(){return this.content[Symbol.iterator]()}),i.exports=ArrayElement},18866:(i,s,u)=>{const m=u(3079);i.exports=class BooleanElement extends m{constructor(i,s,u){super(i,s,u),this.element="boolean"}primitive(){return"boolean"}}},3079:(i,s,u)=>{const m=u(18446),v=u(17645),_=u(42566);class Element{constructor(i,s,u){s&&(this.meta=s),u&&(this.attributes=u),this.content=i}freeze(){Object.isFrozen(this)||(this._meta&&(this.meta.parent=this,this.meta.freeze()),this._attributes&&(this.attributes.parent=this,this.attributes.freeze()),this.children.forEach((i=>{i.parent=this,i.freeze()}),this),this.content&&Array.isArray(this.content)&&Object.freeze(this.content),Object.freeze(this))}primitive(){}clone(){const i=new this.constructor;return i.element=this.element,this.meta.length&&(i._meta=this.meta.clone()),this.attributes.length&&(i._attributes=this.attributes.clone()),this.content?this.content.clone?i.content=this.content.clone():Array.isArray(this.content)?i.content=this.content.map((i=>i.clone())):i.content=this.content:i.content=this.content,i}toValue(){return this.content instanceof Element?this.content.toValue():this.content instanceof v?{key:this.content.key.toValue(),value:this.content.value?this.content.value.toValue():void 0}:this.content&&this.content.map?this.content.map((i=>i.toValue()),this):this.content}toRef(i){if(""===this.id.toValue())throw Error("Cannot create reference to an element that does not contain an ID");const s=new this.RefElement(this.id.toValue());return i&&(s.path=i),s}findRecursive(...i){if(arguments.length>1&&!this.isFrozen)throw new Error("Cannot find recursive with multiple element names without first freezing the element. Call `element.freeze()`");const s=i.pop();let u=new _;const append=(i,s)=>(i.push(s),i),checkElement=(i,u)=>{u.element===s&&i.push(u);const m=u.findRecursive(s);return m&&m.reduce(append,i),u.content instanceof v&&(u.content.key&&checkElement(i,u.content.key),u.content.value&&checkElement(i,u.content.value)),i};return this.content&&(this.content.element&&checkElement(u,this.content),Array.isArray(this.content)&&this.content.reduce(checkElement,u)),i.isEmpty||(u=u.filter((s=>{let u=s.parents.map((i=>i.element));for(const s in i){const m=i[s],v=u.indexOf(m);if(-1===v)return!1;u=u.splice(0,v)}return!0}))),u}set(i){return this.content=i,this}equals(i){return m(this.toValue(),i)}getMetaProperty(i,s){if(!this.meta.hasKey(i)){if(this.isFrozen){const i=this.refract(s);return i.freeze(),i}this.meta.set(i,s)}return this.meta.get(i)}setMetaProperty(i,s){this.meta.set(i,s)}get element(){return this._storedElement||"element"}set element(i){this._storedElement=i}get content(){return this._content}set content(i){if(i instanceof Element)this._content=i;else if(i instanceof _)this.content=i.elements;else if("string"==typeof i||"number"==typeof i||"boolean"==typeof i||"null"===i||null==i)this._content=i;else if(i instanceof v)this._content=i;else if(Array.isArray(i))this._content=i.map(this.refract);else{if("object"!=typeof i)throw new Error("Cannot set content to given value");this._content=Object.keys(i).map((s=>new this.MemberElement(s,i[s])))}}get meta(){if(!this._meta){if(this.isFrozen){const i=new this.ObjectElement;return i.freeze(),i}this._meta=new this.ObjectElement}return this._meta}set meta(i){i instanceof this.ObjectElement?this._meta=i:this.meta.set(i||{})}get attributes(){if(!this._attributes){if(this.isFrozen){const i=new this.ObjectElement;return i.freeze(),i}this._attributes=new this.ObjectElement}return this._attributes}set attributes(i){i instanceof this.ObjectElement?this._attributes=i:this.attributes.set(i||{})}get id(){return this.getMetaProperty("id","")}set id(i){this.setMetaProperty("id",i)}get classes(){return this.getMetaProperty("classes",[])}set classes(i){this.setMetaProperty("classes",i)}get title(){return this.getMetaProperty("title","")}set title(i){this.setMetaProperty("title",i)}get description(){return this.getMetaProperty("description","")}set description(i){this.setMetaProperty("description",i)}get links(){return this.getMetaProperty("links",[])}set links(i){this.setMetaProperty("links",i)}get isFrozen(){return Object.isFrozen(this)}get parents(){let{parent:i}=this;const s=new _;for(;i;)s.push(i),i=i.parent;return s}get children(){if(Array.isArray(this.content))return new _(this.content);if(this.content instanceof v){const i=new _([this.content.key]);return this.content.value&&i.push(this.content.value),i}return this.content instanceof Element?new _([this.content]):new _}get recursiveChildren(){const i=new _;return this.children.forEach((s=>{i.push(s),s.recursiveChildren.forEach((s=>{i.push(s)}))})),i}}i.exports=Element},5946:(i,s,u)=>{const m=u(17645),v=u(3079);i.exports=class MemberElement extends v{constructor(i,s,u,v){super(new m,u,v),this.element="member",this.key=i,this.value=s}get key(){return this.content.key}set key(i){this.content.key=this.refract(i)}get value(){return this.content.value}set value(i){this.content.value=this.refract(i)}}},96295:(i,s,u)=>{const m=u(3079);i.exports=class NullElement extends m{constructor(i,s,u){super(i||null,s,u),this.element="null"}primitive(){return"null"}set(){return new Error("Cannot set the value of null")}}},91090:(i,s,u)=>{const m=u(3079);i.exports=class NumberElement extends m{constructor(i,s,u){super(i,s,u),this.element="number"}primitive(){return"number"}}},76735:(i,s,u)=>{const m=u(94885),v=u(13218),_=u(35804),j=u(5946),M=u(87526);i.exports=class ObjectElement extends _{constructor(i,s,u){super(i||[],s,u),this.element="object"}primitive(){return"object"}toValue(){return this.content.reduce(((i,s)=>(i[s.key.toValue()]=s.value?s.value.toValue():void 0,i)),{})}get(i){const s=this.getMember(i);if(s)return s.value}getMember(i){if(void 0!==i)return this.content.find((s=>s.key.toValue()===i))}remove(i){let s=null;return this.content=this.content.filter((u=>u.key.toValue()!==i||(s=u,!1))),s}getKey(i){const s=this.getMember(i);if(s)return s.key}set(i,s){if(v(i))return Object.keys(i).forEach((s=>{this.set(s,i[s])})),this;const u=i,m=this.getMember(u);return m?m.value=s:this.content.push(new j(u,s)),this}keys(){return this.content.map((i=>i.key.toValue()))}values(){return this.content.map((i=>i.value.toValue()))}hasKey(i){return this.content.some((s=>s.key.equals(i)))}items(){return this.content.map((i=>[i.key.toValue(),i.value.toValue()]))}map(i,s){return this.content.map((u=>i.bind(s)(u.value,u.key,u)))}compactMap(i,s){const u=[];return this.forEach(((m,v,_)=>{const j=i.bind(s)(m,v,_);j&&u.push(j)})),u}filter(i,s){return new M(this.content).filter(i,s)}reject(i,s){return this.filter(m(i),s)}forEach(i,s){return this.content.forEach((u=>i.bind(s)(u.value,u.key,u)))}}},16036:(i,s,u)=>{const m=u(3079);i.exports=class StringElement extends m{constructor(i,s,u){super(i,s,u),this.element="string"}primitive(){return"string"}get length(){return this.content.length}}},3414:(i,s,u)=>{const m=u(28219);i.exports=class JSON06Serialiser extends m{serialise(i){if(!(i instanceof this.namespace.elements.Element))throw new TypeError(`Given element \`${i}\` is not an Element instance`);let s;i._attributes&&i.attributes.get("variable")&&(s=i.attributes.get("variable"));const u={element:i.element};i._meta&&i._meta.length>0&&(u.meta=this.serialiseObject(i.meta));const m="enum"===i.element||-1!==i.attributes.keys().indexOf("enumerations");if(m){const s=this.enumSerialiseAttributes(i);s&&(u.attributes=s)}else if(i._attributes&&i._attributes.length>0){let{attributes:m}=i;m.get("metadata")&&(m=m.clone(),m.set("meta",m.get("metadata")),m.remove("metadata")),"member"===i.element&&s&&(m=m.clone(),m.remove("variable")),m.length>0&&(u.attributes=this.serialiseObject(m))}if(m)u.content=this.enumSerialiseContent(i,u);else if(this[`${i.element}SerialiseContent`])u.content=this[`${i.element}SerialiseContent`](i,u);else if(void 0!==i.content){let m;s&&i.content.key?(m=i.content.clone(),m.key.attributes.set("variable",s),m=this.serialiseContent(m)):m=this.serialiseContent(i.content),this.shouldSerialiseContent(i,m)&&(u.content=m)}else this.shouldSerialiseContent(i,i.content)&&i instanceof this.namespace.elements.Array&&(u.content=[]);return u}shouldSerialiseContent(i,s){return"parseResult"===i.element||"httpRequest"===i.element||"httpResponse"===i.element||"category"===i.element||"link"===i.element||void 0!==s&&(!Array.isArray(s)||0!==s.length)}refSerialiseContent(i,s){return delete s.attributes,{href:i.toValue(),path:i.path.toValue()}}sourceMapSerialiseContent(i){return i.toValue()}dataStructureSerialiseContent(i){return[this.serialiseContent(i.content)]}enumSerialiseAttributes(i){const s=i.attributes.clone(),u=s.remove("enumerations")||new this.namespace.elements.Array([]),m=s.get("default");let v=s.get("samples")||new this.namespace.elements.Array([]);if(m&&m.content&&(m.content.attributes&&m.content.attributes.remove("typeAttributes"),s.set("default",new this.namespace.elements.Array([m.content]))),v.forEach((i=>{i.content&&i.content.element&&i.content.attributes.remove("typeAttributes")})),i.content&&0!==u.length&&v.unshift(i.content),v=v.map((i=>i instanceof this.namespace.elements.Array?[i]:new this.namespace.elements.Array([i.content]))),v.length&&s.set("samples",v),s.length>0)return this.serialiseObject(s)}enumSerialiseContent(i){if(i._attributes){const s=i.attributes.get("enumerations");if(s&&s.length>0)return s.content.map((i=>{const s=i.clone();return s.attributes.remove("typeAttributes"),this.serialise(s)}))}if(i.content){const s=i.content.clone();return s.attributes.remove("typeAttributes"),[this.serialise(s)]}return[]}deserialise(i){if("string"==typeof i)return new this.namespace.elements.String(i);if("number"==typeof i)return new this.namespace.elements.Number(i);if("boolean"==typeof i)return new this.namespace.elements.Boolean(i);if(null===i)return new this.namespace.elements.Null;if(Array.isArray(i))return new this.namespace.elements.Array(i.map(this.deserialise,this));const s=this.namespace.getElementClass(i.element),u=new s;u.element!==i.element&&(u.element=i.element),i.meta&&this.deserialiseObject(i.meta,u.meta),i.attributes&&this.deserialiseObject(i.attributes,u.attributes);const m=this.deserialiseContent(i.content);if(void 0===m&&null!==u.content||(u.content=m),"enum"===u.element){u.content&&u.attributes.set("enumerations",u.content);let i=u.attributes.get("samples");if(u.attributes.remove("samples"),i){const m=i;i=new this.namespace.elements.Array,m.forEach((m=>{m.forEach((m=>{const v=new s(m);v.element=u.element,i.push(v)}))}));const v=i.shift();u.content=v?v.content:void 0,u.attributes.set("samples",i)}else u.content=void 0;let m=u.attributes.get("default");if(m&&m.length>0){m=m.get(0);const i=new s(m);i.element=u.element,u.attributes.set("default",i)}}else if("dataStructure"===u.element&&Array.isArray(u.content))[u.content]=u.content;else if("category"===u.element){const i=u.attributes.get("meta");i&&(u.attributes.set("metadata",i),u.attributes.remove("meta"))}else"member"===u.element&&u.key&&u.key._attributes&&u.key._attributes.getValue("variable")&&(u.attributes.set("variable",u.key.attributes.get("variable")),u.key.attributes.remove("variable"));return u}serialiseContent(i){if(i instanceof this.namespace.elements.Element)return this.serialise(i);if(i instanceof this.namespace.KeyValuePair){const s={key:this.serialise(i.key)};return i.value&&(s.value=this.serialise(i.value)),s}return i&&i.map?i.map(this.serialise,this):i}deserialiseContent(i){if(i){if(i.element)return this.deserialise(i);if(i.key){const s=new this.namespace.KeyValuePair(this.deserialise(i.key));return i.value&&(s.value=this.deserialise(i.value)),s}if(i.map)return i.map(this.deserialise,this)}return i}shouldRefract(i){return!!(i._attributes&&i.attributes.keys().length||i._meta&&i.meta.keys().length)||"enum"!==i.element&&(i.element!==i.primitive()||"member"===i.element)}convertKeyToRefract(i,s){return this.shouldRefract(s)?this.serialise(s):"enum"===s.element?this.serialiseEnum(s):"array"===s.element?s.map((s=>this.shouldRefract(s)||"default"===i?this.serialise(s):"array"===s.element||"object"===s.element||"enum"===s.element?s.children.map((i=>this.serialise(i))):s.toValue())):"object"===s.element?(s.content||[]).map(this.serialise,this):s.toValue()}serialiseEnum(i){return i.children.map((i=>this.serialise(i)))}serialiseObject(i){const s={};return i.forEach(((i,u)=>{if(i){const m=u.toValue();s[m]=this.convertKeyToRefract(m,i)}})),s}deserialiseObject(i,s){Object.keys(i).forEach((u=>{s.set(u,this.deserialise(i[u]))}))}}},28219:i=>{i.exports=class JSONSerialiser{constructor(i){this.namespace=i||new this.Namespace}serialise(i){if(!(i instanceof this.namespace.elements.Element))throw new TypeError(`Given element \`${i}\` is not an Element instance`);const s={element:i.element};i._meta&&i._meta.length>0&&(s.meta=this.serialiseObject(i.meta)),i._attributes&&i._attributes.length>0&&(s.attributes=this.serialiseObject(i.attributes));const u=this.serialiseContent(i.content);return void 0!==u&&(s.content=u),s}deserialise(i){if(!i.element)throw new Error("Given value is not an object containing an element name");const s=new(this.namespace.getElementClass(i.element));s.element!==i.element&&(s.element=i.element),i.meta&&this.deserialiseObject(i.meta,s.meta),i.attributes&&this.deserialiseObject(i.attributes,s.attributes);const u=this.deserialiseContent(i.content);return void 0===u&&null!==s.content||(s.content=u),s}serialiseContent(i){if(i instanceof this.namespace.elements.Element)return this.serialise(i);if(i instanceof this.namespace.KeyValuePair){const s={key:this.serialise(i.key)};return i.value&&(s.value=this.serialise(i.value)),s}if(i&&i.map){if(0===i.length)return;return i.map(this.serialise,this)}return i}deserialiseContent(i){if(i){if(i.element)return this.deserialise(i);if(i.key){const s=new this.namespace.KeyValuePair(this.deserialise(i.key));return i.value&&(s.value=this.deserialise(i.value)),s}if(i.map)return i.map(this.deserialise,this)}return i}serialiseObject(i){const s={};if(i.forEach(((i,u)=>{i&&(s[u.toValue()]=this.serialise(i))})),0!==Object.keys(s).length)return s}deserialiseObject(i,s){Object.keys(i).forEach((u=>{s.set(u,this.deserialise(i[u]))}))}}},27418:i=>{"use strict";var s=Object.getOwnPropertySymbols,u=Object.prototype.hasOwnProperty,m=Object.prototype.propertyIsEnumerable;i.exports=function shouldUseNative(){try{if(!Object.assign)return!1;var i=new String("abc");if(i[5]="de","5"===Object.getOwnPropertyNames(i)[0])return!1;for(var s={},u=0;u<10;u++)s["_"+String.fromCharCode(u)]=u;if("0123456789"!==Object.getOwnPropertyNames(s).map((function(i){return s[i]})).join(""))return!1;var m={};return"abcdefghijklmnopqrst".split("").forEach((function(i){m[i]=i})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},m)).join("")}catch(i){return!1}}()?Object.assign:function(i,v){for(var _,j,M=function toObject(i){if(null==i)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(i)}(i),$=1;${var m="function"==typeof Map&&Map.prototype,v=Object.getOwnPropertyDescriptor&&m?Object.getOwnPropertyDescriptor(Map.prototype,"size"):null,_=m&&v&&"function"==typeof v.get?v.get:null,j=m&&Map.prototype.forEach,M="function"==typeof Set&&Set.prototype,$=Object.getOwnPropertyDescriptor&&M?Object.getOwnPropertyDescriptor(Set.prototype,"size"):null,W=M&&$&&"function"==typeof $.get?$.get:null,X=M&&Set.prototype.forEach,Y="function"==typeof WeakMap&&WeakMap.prototype?WeakMap.prototype.has:null,Z="function"==typeof WeakSet&&WeakSet.prototype?WeakSet.prototype.has:null,ee="function"==typeof WeakRef&&WeakRef.prototype?WeakRef.prototype.deref:null,ie=Boolean.prototype.valueOf,ae=Object.prototype.toString,le=Function.prototype.toString,ce=String.prototype.match,pe=String.prototype.slice,de=String.prototype.replace,fe=String.prototype.toUpperCase,ye=String.prototype.toLowerCase,be=RegExp.prototype.test,_e=Array.prototype.concat,we=Array.prototype.join,Se=Array.prototype.slice,xe=Math.floor,Ie="function"==typeof BigInt?BigInt.prototype.valueOf:null,Pe=Object.getOwnPropertySymbols,Te="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?Symbol.prototype.toString:null,Re="function"==typeof Symbol&&"object"==typeof Symbol.iterator,qe="function"==typeof Symbol&&Symbol.toStringTag&&(typeof Symbol.toStringTag===Re||"symbol")?Symbol.toStringTag:null,ze=Object.prototype.propertyIsEnumerable,Ve=("function"==typeof Reflect?Reflect.getPrototypeOf:Object.getPrototypeOf)||([].__proto__===Array.prototype?function(i){return i.__proto__}:null);function addNumericSeparator(i,s){if(i===1/0||i===-1/0||i!=i||i&&i>-1e3&&i<1e3||be.call(/e/,s))return s;var u=/[0-9](?=(?:[0-9]{3})+(?![0-9]))/g;if("number"==typeof i){var m=i<0?-xe(-i):xe(i);if(m!==i){var v=String(m),_=pe.call(s,v.length+1);return de.call(v,u,"$&_")+"."+de.call(de.call(_,/([0-9]{3})/g,"$&_"),/_$/,"")}}return de.call(s,u,"$&_")}var We=u(24654),He=We.custom,Xe=isSymbol(He)?He:null;function wrapQuotes(i,s,u){var m="double"===(u.quoteStyle||s)?'"':"'";return m+i+m}function quote(i){return de.call(String(i),/"/g,""")}function isArray(i){return!("[object Array]"!==toStr(i)||qe&&"object"==typeof i&&qe in i)}function isRegExp(i){return!("[object RegExp]"!==toStr(i)||qe&&"object"==typeof i&&qe in i)}function isSymbol(i){if(Re)return i&&"object"==typeof i&&i instanceof Symbol;if("symbol"==typeof i)return!0;if(!i||"object"!=typeof i||!Te)return!1;try{return Te.call(i),!0}catch(i){}return!1}i.exports=function inspect_(i,s,u,m){var v=s||{};if(has(v,"quoteStyle")&&"single"!==v.quoteStyle&&"double"!==v.quoteStyle)throw new TypeError('option "quoteStyle" must be "single" or "double"');if(has(v,"maxStringLength")&&("number"==typeof v.maxStringLength?v.maxStringLength<0&&v.maxStringLength!==1/0:null!==v.maxStringLength))throw new TypeError('option "maxStringLength", if provided, must be a positive integer, Infinity, or `null`');var M=!has(v,"customInspect")||v.customInspect;if("boolean"!=typeof M&&"symbol"!==M)throw new TypeError("option \"customInspect\", if provided, must be `true`, `false`, or `'symbol'`");if(has(v,"indent")&&null!==v.indent&&"\t"!==v.indent&&!(parseInt(v.indent,10)===v.indent&&v.indent>0))throw new TypeError('option "indent" must be "\\t", an integer > 0, or `null`');if(has(v,"numericSeparator")&&"boolean"!=typeof v.numericSeparator)throw new TypeError('option "numericSeparator", if provided, must be `true` or `false`');var $=v.numericSeparator;if(void 0===i)return"undefined";if(null===i)return"null";if("boolean"==typeof i)return i?"true":"false";if("string"==typeof i)return inspectString(i,v);if("number"==typeof i){if(0===i)return 1/0/i>0?"0":"-0";var ae=String(i);return $?addNumericSeparator(i,ae):ae}if("bigint"==typeof i){var fe=String(i)+"n";return $?addNumericSeparator(i,fe):fe}var be=void 0===v.depth?5:v.depth;if(void 0===u&&(u=0),u>=be&&be>0&&"object"==typeof i)return isArray(i)?"[Array]":"[Object]";var xe=function getIndent(i,s){var u;if("\t"===i.indent)u="\t";else{if(!("number"==typeof i.indent&&i.indent>0))return null;u=we.call(Array(i.indent+1)," ")}return{base:u,prev:we.call(Array(s+1),u)}}(v,u);if(void 0===m)m=[];else if(indexOf(m,i)>=0)return"[Circular]";function inspect(i,s,_){if(s&&(m=Se.call(m)).push(s),_){var j={depth:v.depth};return has(v,"quoteStyle")&&(j.quoteStyle=v.quoteStyle),inspect_(i,j,u+1,m)}return inspect_(i,v,u+1,m)}if("function"==typeof i&&!isRegExp(i)){var Pe=function nameOf(i){if(i.name)return i.name;var s=ce.call(le.call(i),/^function\s*([\w$]+)/);if(s)return s[1];return null}(i),He=arrObjKeys(i,inspect);return"[Function"+(Pe?": "+Pe:" (anonymous)")+"]"+(He.length>0?" { "+we.call(He,", ")+" }":"")}if(isSymbol(i)){var Ye=Re?de.call(String(i),/^(Symbol\(.*\))_[^)]*$/,"$1"):Te.call(i);return"object"!=typeof i||Re?Ye:markBoxed(Ye)}if(function isElement(i){if(!i||"object"!=typeof i)return!1;if("undefined"!=typeof HTMLElement&&i instanceof HTMLElement)return!0;return"string"==typeof i.nodeName&&"function"==typeof i.getAttribute}(i)){for(var Qe="<"+ye.call(String(i.nodeName)),et=i.attributes||[],tt=0;tt"}if(isArray(i)){if(0===i.length)return"[]";var rt=arrObjKeys(i,inspect);return xe&&!function singleLineValues(i){for(var s=0;s=0)return!1;return!0}(rt)?"["+indentedJoin(rt,xe)+"]":"[ "+we.call(rt,", ")+" ]"}if(function isError(i){return!("[object Error]"!==toStr(i)||qe&&"object"==typeof i&&qe in i)}(i)){var nt=arrObjKeys(i,inspect);return"cause"in Error.prototype||!("cause"in i)||ze.call(i,"cause")?0===nt.length?"["+String(i)+"]":"{ ["+String(i)+"] "+we.call(nt,", ")+" }":"{ ["+String(i)+"] "+we.call(_e.call("[cause]: "+inspect(i.cause),nt),", ")+" }"}if("object"==typeof i&&M){if(Xe&&"function"==typeof i[Xe]&&We)return We(i,{depth:be-u});if("symbol"!==M&&"function"==typeof i.inspect)return i.inspect()}if(function isMap(i){if(!_||!i||"object"!=typeof i)return!1;try{_.call(i);try{W.call(i)}catch(i){return!0}return i instanceof Map}catch(i){}return!1}(i)){var ot=[];return j&&j.call(i,(function(s,u){ot.push(inspect(u,i,!0)+" => "+inspect(s,i))})),collectionOf("Map",_.call(i),ot,xe)}if(function isSet(i){if(!W||!i||"object"!=typeof i)return!1;try{W.call(i);try{_.call(i)}catch(i){return!0}return i instanceof Set}catch(i){}return!1}(i)){var it=[];return X&&X.call(i,(function(s){it.push(inspect(s,i))})),collectionOf("Set",W.call(i),it,xe)}if(function isWeakMap(i){if(!Y||!i||"object"!=typeof i)return!1;try{Y.call(i,Y);try{Z.call(i,Z)}catch(i){return!0}return i instanceof WeakMap}catch(i){}return!1}(i))return weakCollectionOf("WeakMap");if(function isWeakSet(i){if(!Z||!i||"object"!=typeof i)return!1;try{Z.call(i,Z);try{Y.call(i,Y)}catch(i){return!0}return i instanceof WeakSet}catch(i){}return!1}(i))return weakCollectionOf("WeakSet");if(function isWeakRef(i){if(!ee||!i||"object"!=typeof i)return!1;try{return ee.call(i),!0}catch(i){}return!1}(i))return weakCollectionOf("WeakRef");if(function isNumber(i){return!("[object Number]"!==toStr(i)||qe&&"object"==typeof i&&qe in i)}(i))return markBoxed(inspect(Number(i)));if(function isBigInt(i){if(!i||"object"!=typeof i||!Ie)return!1;try{return Ie.call(i),!0}catch(i){}return!1}(i))return markBoxed(inspect(Ie.call(i)));if(function isBoolean(i){return!("[object Boolean]"!==toStr(i)||qe&&"object"==typeof i&&qe in i)}(i))return markBoxed(ie.call(i));if(function isString(i){return!("[object String]"!==toStr(i)||qe&&"object"==typeof i&&qe in i)}(i))return markBoxed(inspect(String(i)));if(!function isDate(i){return!("[object Date]"!==toStr(i)||qe&&"object"==typeof i&&qe in i)}(i)&&!isRegExp(i)){var at=arrObjKeys(i,inspect),st=Ve?Ve(i)===Object.prototype:i instanceof Object||i.constructor===Object,lt=i instanceof Object?"":"null prototype",ct=!st&&qe&&Object(i)===i&&qe in i?pe.call(toStr(i),8,-1):lt?"Object":"",ut=(st||"function"!=typeof i.constructor?"":i.constructor.name?i.constructor.name+" ":"")+(ct||lt?"["+we.call(_e.call([],ct||[],lt||[]),": ")+"] ":"");return 0===at.length?ut+"{}":xe?ut+"{"+indentedJoin(at,xe)+"}":ut+"{ "+we.call(at,", ")+" }"}return String(i)};var Ye=Object.prototype.hasOwnProperty||function(i){return i in this};function has(i,s){return Ye.call(i,s)}function toStr(i){return ae.call(i)}function indexOf(i,s){if(i.indexOf)return i.indexOf(s);for(var u=0,m=i.length;us.maxStringLength){var u=i.length-s.maxStringLength,m="... "+u+" more character"+(u>1?"s":"");return inspectString(pe.call(i,0,s.maxStringLength),s)+m}return wrapQuotes(de.call(de.call(i,/(['\\])/g,"\\$1"),/[\x00-\x1f]/g,lowbyte),"single",s)}function lowbyte(i){var s=i.charCodeAt(0),u={8:"b",9:"t",10:"n",12:"f",13:"r"}[s];return u?"\\"+u:"\\x"+(s<16?"0":"")+fe.call(s.toString(16))}function markBoxed(i){return"Object("+i+")"}function weakCollectionOf(i){return i+" { ? }"}function collectionOf(i,s,u,m){return i+" ("+s+") {"+(m?indentedJoin(u,m):we.call(u,", "))+"}"}function indentedJoin(i,s){if(0===i.length)return"";var u="\n"+s.prev+s.base;return u+we.call(i,","+u)+"\n"+s.prev}function arrObjKeys(i,s){var u=isArray(i),m=[];if(u){m.length=i.length;for(var v=0;v{var s,u,m=i.exports={};function defaultSetTimout(){throw new Error("setTimeout has not been defined")}function defaultClearTimeout(){throw new Error("clearTimeout has not been defined")}function runTimeout(i){if(s===setTimeout)return setTimeout(i,0);if((s===defaultSetTimout||!s)&&setTimeout)return s=setTimeout,setTimeout(i,0);try{return s(i,0)}catch(u){try{return s.call(null,i,0)}catch(u){return s.call(this,i,0)}}}!function(){try{s="function"==typeof setTimeout?setTimeout:defaultSetTimout}catch(i){s=defaultSetTimout}try{u="function"==typeof clearTimeout?clearTimeout:defaultClearTimeout}catch(i){u=defaultClearTimeout}}();var v,_=[],j=!1,M=-1;function cleanUpNextTick(){j&&v&&(j=!1,v.length?_=v.concat(_):M=-1,_.length&&drainQueue())}function drainQueue(){if(!j){var i=runTimeout(cleanUpNextTick);j=!0;for(var s=_.length;s;){for(v=_,_=[];++M1)for(var u=1;u{"use strict";var m=u(50414);function emptyFunction(){}function emptyFunctionWithReset(){}emptyFunctionWithReset.resetWarningCache=emptyFunction,i.exports=function(){function shim(i,s,u,v,_,j){if(j!==m){var M=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw M.name="Invariant Violation",M}}function getShim(){return shim}shim.isRequired=shim;var i={array:shim,bigint:shim,bool:shim,func:shim,number:shim,object:shim,string:shim,symbol:shim,any:shim,arrayOf:getShim,element:shim,elementType:shim,instanceOf:getShim,node:shim,objectOf:getShim,oneOf:getShim,oneOfType:getShim,shape:getShim,exact:getShim,checkPropTypes:emptyFunctionWithReset,resetWarningCache:emptyFunction};return i.PropTypes=i,i}},45697:(i,s,u)=>{i.exports=u(92703)()},50414:i=>{"use strict";i.exports="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED"},55798:i=>{"use strict";var s=String.prototype.replace,u=/%20/g,m="RFC1738",v="RFC3986";i.exports={default:v,formatters:{RFC1738:function(i){return s.call(i,u,"+")},RFC3986:function(i){return String(i)}},RFC1738:m,RFC3986:v}},80129:(i,s,u)=>{"use strict";var m=u(58261),v=u(55235),_=u(55798);i.exports={formats:_,parse:v,stringify:m}},55235:(i,s,u)=>{"use strict";var m=u(12769),v=Object.prototype.hasOwnProperty,_=Array.isArray,j={allowDots:!1,allowPrototypes:!1,allowSparse:!1,arrayLimit:20,charset:"utf-8",charsetSentinel:!1,comma:!1,decoder:m.decode,delimiter:"&",depth:5,ignoreQueryPrefix:!1,interpretNumericEntities:!1,parameterLimit:1e3,parseArrays:!0,plainObjects:!1,strictNullHandling:!1},interpretNumericEntities=function(i){return i.replace(/&#(\d+);/g,(function(i,s){return String.fromCharCode(parseInt(s,10))}))},parseArrayValue=function(i,s){return i&&"string"==typeof i&&s.comma&&i.indexOf(",")>-1?i.split(","):i},M=function parseQueryStringKeys(i,s,u,m){if(i){var _=u.allowDots?i.replace(/\.([^.[]+)/g,"[$1]"):i,j=/(\[[^[\]]*])/g,M=u.depth>0&&/(\[[^[\]]*])/.exec(_),$=M?_.slice(0,M.index):_,W=[];if($){if(!u.plainObjects&&v.call(Object.prototype,$)&&!u.allowPrototypes)return;W.push($)}for(var X=0;u.depth>0&&null!==(M=j.exec(_))&&X=0;--_){var j,M=i[_];if("[]"===M&&u.parseArrays)j=[].concat(v);else{j=u.plainObjects?Object.create(null):{};var $="["===M.charAt(0)&&"]"===M.charAt(M.length-1)?M.slice(1,-1):M,W=parseInt($,10);u.parseArrays||""!==$?!isNaN(W)&&M!==$&&String(W)===$&&W>=0&&u.parseArrays&&W<=u.arrayLimit?(j=[])[W]=v:"__proto__"!==$&&(j[$]=v):j={0:v}}v=j}return v}(W,s,u,m)}};i.exports=function(i,s){var u=function normalizeParseOptions(i){if(!i)return j;if(null!==i.decoder&&void 0!==i.decoder&&"function"!=typeof i.decoder)throw new TypeError("Decoder has to be a function.");if(void 0!==i.charset&&"utf-8"!==i.charset&&"iso-8859-1"!==i.charset)throw new TypeError("The charset option must be either utf-8, iso-8859-1, or undefined");var s=void 0===i.charset?j.charset:i.charset;return{allowDots:void 0===i.allowDots?j.allowDots:!!i.allowDots,allowPrototypes:"boolean"==typeof i.allowPrototypes?i.allowPrototypes:j.allowPrototypes,allowSparse:"boolean"==typeof i.allowSparse?i.allowSparse:j.allowSparse,arrayLimit:"number"==typeof i.arrayLimit?i.arrayLimit:j.arrayLimit,charset:s,charsetSentinel:"boolean"==typeof i.charsetSentinel?i.charsetSentinel:j.charsetSentinel,comma:"boolean"==typeof i.comma?i.comma:j.comma,decoder:"function"==typeof i.decoder?i.decoder:j.decoder,delimiter:"string"==typeof i.delimiter||m.isRegExp(i.delimiter)?i.delimiter:j.delimiter,depth:"number"==typeof i.depth||!1===i.depth?+i.depth:j.depth,ignoreQueryPrefix:!0===i.ignoreQueryPrefix,interpretNumericEntities:"boolean"==typeof i.interpretNumericEntities?i.interpretNumericEntities:j.interpretNumericEntities,parameterLimit:"number"==typeof i.parameterLimit?i.parameterLimit:j.parameterLimit,parseArrays:!1!==i.parseArrays,plainObjects:"boolean"==typeof i.plainObjects?i.plainObjects:j.plainObjects,strictNullHandling:"boolean"==typeof i.strictNullHandling?i.strictNullHandling:j.strictNullHandling}}(s);if(""===i||null==i)return u.plainObjects?Object.create(null):{};for(var $="string"==typeof i?function parseQueryStringValues(i,s){var u,M={},$=s.ignoreQueryPrefix?i.replace(/^\?/,""):i,W=s.parameterLimit===1/0?void 0:s.parameterLimit,X=$.split(s.delimiter,W),Y=-1,Z=s.charset;if(s.charsetSentinel)for(u=0;u-1&&(ie=_(ie)?[ie]:ie),v.call(M,ee)?M[ee]=m.combine(M[ee],ie):M[ee]=ie}return M}(i,u):i,W=u.plainObjects?Object.create(null):{},X=Object.keys($),Y=0;Y{"use strict";var m=u(37478),v=u(12769),_=u(55798),j=Object.prototype.hasOwnProperty,M={brackets:function brackets(i){return i+"[]"},comma:"comma",indices:function indices(i,s){return i+"["+s+"]"},repeat:function repeat(i){return i}},$=Array.isArray,W=String.prototype.split,X=Array.prototype.push,pushToArray=function(i,s){X.apply(i,$(s)?s:[s])},Y=Date.prototype.toISOString,Z=_.default,ee={addQueryPrefix:!1,allowDots:!1,charset:"utf-8",charsetSentinel:!1,delimiter:"&",encode:!0,encoder:v.encode,encodeValuesOnly:!1,format:Z,formatter:_.formatters[Z],indices:!1,serializeDate:function serializeDate(i){return Y.call(i)},skipNulls:!1,strictNullHandling:!1},ie={},ae=function stringify(i,s,u,_,j,M,X,Y,Z,ae,le,ce,pe,de,fe,ye){for(var be=i,_e=ye,we=0,Se=!1;void 0!==(_e=_e.get(ie))&&!Se;){var xe=_e.get(i);if(we+=1,void 0!==xe){if(xe===we)throw new RangeError("Cyclic object value");Se=!0}void 0===_e.get(ie)&&(we=0)}if("function"==typeof Y?be=Y(s,be):be instanceof Date?be=le(be):"comma"===u&&$(be)&&(be=v.maybeMap(be,(function(i){return i instanceof Date?le(i):i}))),null===be){if(j)return X&&!de?X(s,ee.encoder,fe,"key",ce):s;be=""}if(function isNonNullishPrimitive(i){return"string"==typeof i||"number"==typeof i||"boolean"==typeof i||"symbol"==typeof i||"bigint"==typeof i}(be)||v.isBuffer(be)){if(X){var Ie=de?s:X(s,ee.encoder,fe,"key",ce);if("comma"===u&&de){for(var Pe=W.call(String(be),","),Te="",Re=0;Re0?be.join(",")||null:void 0}];else if($(Y))qe=Y;else{var Ve=Object.keys(be);qe=Z?Ve.sort(Z):Ve}for(var We=_&&$(be)&&1===be.length?s+"[]":s,He=0;He0?fe+de:""}},12769:(i,s,u)=>{"use strict";var m=u(55798),v=Object.prototype.hasOwnProperty,_=Array.isArray,j=function(){for(var i=[],s=0;s<256;++s)i.push("%"+((s<16?"0":"")+s.toString(16)).toUpperCase());return i}(),M=function arrayToObject(i,s){for(var u=s&&s.plainObjects?Object.create(null):{},m=0;m1;){var s=i.pop(),u=s.obj[s.prop];if(_(u)){for(var m=[],v=0;v=48&&X<=57||X>=65&&X<=90||X>=97&&X<=122||_===m.RFC1738&&(40===X||41===X)?$+=M.charAt(W):X<128?$+=j[X]:X<2048?$+=j[192|X>>6]+j[128|63&X]:X<55296||X>=57344?$+=j[224|X>>12]+j[128|X>>6&63]+j[128|63&X]:(W+=1,X=65536+((1023&X)<<10|1023&M.charCodeAt(W)),$+=j[240|X>>18]+j[128|X>>12&63]+j[128|X>>6&63]+j[128|63&X])}return $},isBuffer:function isBuffer(i){return!(!i||"object"!=typeof i)&&!!(i.constructor&&i.constructor.isBuffer&&i.constructor.isBuffer(i))},isRegExp:function isRegExp(i){return"[object RegExp]"===Object.prototype.toString.call(i)},maybeMap:function maybeMap(i,s){if(_(i)){for(var u=[],m=0;m{"use strict";var u=Object.prototype.hasOwnProperty;function decode(i){try{return decodeURIComponent(i.replace(/\+/g," "))}catch(i){return null}}function encode(i){try{return encodeURIComponent(i)}catch(i){return null}}s.stringify=function querystringify(i,s){s=s||"";var m,v,_=[];for(v in"string"!=typeof s&&(s="?"),i)if(u.call(i,v)){if((m=i[v])||null!=m&&!isNaN(m)||(m=""),v=encode(v),m=encode(m),null===v||null===m)continue;_.push(v+"="+m)}return _.length?s+_.join("&"):""},s.parse=function querystring(i){for(var s,u=/([^=?#&]+)=?([^&]*)/g,m={};s=u.exec(i);){var v=decode(s[1]),_=decode(s[2]);null===v||null===_||v in m||(m[v]=_)}return m}},14419:(i,s,u)=>{const m=u(60697),v=u(69450),_=m.types;i.exports=class RandExp{constructor(i,s){if(this._setDefaults(i),i instanceof RegExp)this.ignoreCase=i.ignoreCase,this.multiline=i.multiline,i=i.source;else{if("string"!=typeof i)throw new Error("Expected a regexp or string");this.ignoreCase=s&&-1!==s.indexOf("i"),this.multiline=s&&-1!==s.indexOf("m")}this.tokens=m(i)}_setDefaults(i){this.max=null!=i.max?i.max:null!=RandExp.prototype.max?RandExp.prototype.max:100,this.defaultRange=i.defaultRange?i.defaultRange:this.defaultRange.clone(),i.randInt&&(this.randInt=i.randInt)}gen(){return this._gen(this.tokens,[])}_gen(i,s){var u,m,v,j,M;switch(i.type){case _.ROOT:case _.GROUP:if(i.followedBy||i.notFollowedBy)return"";for(i.remember&&void 0===i.groupNumber&&(i.groupNumber=s.push(null)-1),m="",j=0,M=(u=i.options?this._randSelect(i.options):i.stack).length;j{"use strict";var m=u(34155),v=65536,_=4294967295;var j=u(89509).Buffer,M=u.g.crypto||u.g.msCrypto;M&&M.getRandomValues?i.exports=function randomBytes(i,s){if(i>_)throw new RangeError("requested too many random bytes");var u=j.allocUnsafe(i);if(i>0)if(i>v)for(var $=0;${"use strict";function _typeof(i){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(i){return typeof i}:function(i){return i&&"function"==typeof Symbol&&i.constructor===Symbol&&i!==Symbol.prototype?"symbol":typeof i},_typeof(i)}Object.defineProperty(s,"__esModule",{value:!0}),s.CopyToClipboard=void 0;var m=_interopRequireDefault(u(67294)),v=_interopRequireDefault(u(20640)),_=["text","onCopy","options","children"];function _interopRequireDefault(i){return i&&i.__esModule?i:{default:i}}function ownKeys(i,s){var u=Object.keys(i);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(i);s&&(m=m.filter((function(s){return Object.getOwnPropertyDescriptor(i,s).enumerable}))),u.push.apply(u,m)}return u}function _objectSpread(i){for(var s=1;s=0||(v[u]=i[u]);return v}(i,s);if(Object.getOwnPropertySymbols){var _=Object.getOwnPropertySymbols(i);for(m=0;m<_.length;m++)u=_[m],s.indexOf(u)>=0||Object.prototype.propertyIsEnumerable.call(i,u)&&(v[u]=i[u])}return v}function _defineProperties(i,s){for(var u=0;u{"use strict";var m=u(74300).CopyToClipboard;m.CopyToClipboard=m,i.exports=m},53441:(i,s,u)=>{"use strict";function _typeof(i){return _typeof="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(i){return typeof i}:function(i){return i&&"function"==typeof Symbol&&i.constructor===Symbol&&i!==Symbol.prototype?"symbol":typeof i},_typeof(i)}Object.defineProperty(s,"__esModule",{value:!0}),s.DebounceInput=void 0;var m=_interopRequireDefault(u(67294)),v=_interopRequireDefault(u(91296)),_=["element","onChange","value","minLength","debounceTimeout","forceNotifyByEnter","forceNotifyOnBlur","onKeyDown","onBlur","inputRef"];function _interopRequireDefault(i){return i&&i.__esModule?i:{default:i}}function _objectWithoutProperties(i,s){if(null==i)return{};var u,m,v=function _objectWithoutPropertiesLoose(i,s){if(null==i)return{};var u,m,v={},_=Object.keys(i);for(m=0;m<_.length;m++)u=_[m],s.indexOf(u)>=0||(v[u]=i[u]);return v}(i,s);if(Object.getOwnPropertySymbols){var _=Object.getOwnPropertySymbols(i);for(m=0;m<_.length;m++)u=_[m],s.indexOf(u)>=0||Object.prototype.propertyIsEnumerable.call(i,u)&&(v[u]=i[u])}return v}function ownKeys(i,s){var u=Object.keys(i);if(Object.getOwnPropertySymbols){var m=Object.getOwnPropertySymbols(i);s&&(m=m.filter((function(s){return Object.getOwnPropertyDescriptor(i,s).enumerable}))),u.push.apply(u,m)}return u}function _objectSpread(i){for(var s=1;s=m?u.notify(i):s.length>v.length&&u.notify(_objectSpread(_objectSpread({},i),{},{target:_objectSpread(_objectSpread({},i.target),{},{value:""})}))}))})),_defineProperty(_assertThisInitialized(u),"onKeyDown",(function(i){"Enter"===i.key&&u.forceNotify(i);var s=u.props.onKeyDown;s&&(i.persist(),s(i))})),_defineProperty(_assertThisInitialized(u),"onBlur",(function(i){u.forceNotify(i);var s=u.props.onBlur;s&&(i.persist(),s(i))})),_defineProperty(_assertThisInitialized(u),"createNotifier",(function(i){if(i<0)u.notify=function(){return null};else if(0===i)u.notify=u.doNotify;else{var s=(0,v.default)((function(i){u.isDebouncing=!1,u.doNotify(i)}),i);u.notify=function(i){u.isDebouncing=!0,s(i)},u.flush=function(){return s.flush()},u.cancel=function(){u.isDebouncing=!1,s.cancel()}}})),_defineProperty(_assertThisInitialized(u),"doNotify",(function(){u.props.onChange.apply(void 0,arguments)})),_defineProperty(_assertThisInitialized(u),"forceNotify",(function(i){var s=u.props.debounceTimeout;if(u.isDebouncing||!(s>0)){u.cancel&&u.cancel();var m=u.state.value,v=u.props.minLength;m.length>=v?u.doNotify(i):u.doNotify(_objectSpread(_objectSpread({},i),{},{target:_objectSpread(_objectSpread({},i.target),{},{value:m})}))}})),u.isDebouncing=!1,u.state={value:void 0===i.value||null===i.value?"":i.value};var m=u.props.debounceTimeout;return u.createNotifier(m),u}return function _createClass(i,s,u){return s&&_defineProperties(i.prototype,s),u&&_defineProperties(i,u),Object.defineProperty(i,"prototype",{writable:!1}),i}(DebounceInput,[{key:"componentDidUpdate",value:function componentDidUpdate(i){if(!this.isDebouncing){var s=this.props,u=s.value,m=s.debounceTimeout,v=i.debounceTimeout,_=i.value,j=this.state.value;void 0!==u&&_!==u&&j!==u&&this.setState({value:u}),m!==v&&this.createNotifier(m)}}},{key:"componentWillUnmount",value:function componentWillUnmount(){this.flush&&this.flush()}},{key:"render",value:function render(){var i,s,u=this.props,v=u.element,j=(u.onChange,u.value,u.minLength,u.debounceTimeout,u.forceNotifyByEnter),M=u.forceNotifyOnBlur,$=u.onKeyDown,W=u.onBlur,X=u.inputRef,Y=_objectWithoutProperties(u,_),Z=this.state.value;i=j?{onKeyDown:this.onKeyDown}:$?{onKeyDown:$}:{},s=M?{onBlur:this.onBlur}:W?{onBlur:W}:{};var ee=X?{ref:X}:{};return m.default.createElement(v,_objectSpread(_objectSpread(_objectSpread(_objectSpread({},Y),{},{onChange:this.onChange,value:Z},i),s),ee))}}]),DebounceInput}(m.default.PureComponent);s.DebounceInput=j,_defineProperty(j,"defaultProps",{element:"input",type:"text",onKeyDown:void 0,onBlur:void 0,value:void 0,minLength:0,debounceTimeout:100,forceNotifyByEnter:!0,forceNotifyOnBlur:!0,inputRef:void 0})},775:(i,s,u)=>{"use strict";var m=u(53441).DebounceInput;m.DebounceInput=m,i.exports=m},64448:(i,s,u)=>{"use strict";var m=u(67294),v=u(27418),_=u(63840);function y(i){for(var s="https://reactjs.org/docs/error-decoder.html?invariant="+i,u=1;u