` to any timeseries scraped from this config.
+ - job_name: 'prometheus'
+
+ # Override the global default and scrape targets from this job every 5 seconds.
+ scrape_interval: 5s
+
+ # scheme defaults to 'http' enable https in case your application is server via https
+ #scheme: https
+ # basic auth is not needed by default. See https://www.jhipster.tech/monitoring/#configuring-metrics-forwarding for details
+ #basic_auth:
+ # username: admin
+ # password: admin
+ metrics_path: /management/prometheus
+ static_configs:
+ - targets:
+ # On MacOS, replace localhost by host.docker.internal
+ - localhost:8080
diff --git a/myApp/src/main/docker/sonar.yml b/myApp/src/main/docker/sonar.yml
new file mode 100644
index 000000000..8de2c9f40
--- /dev/null
+++ b/myApp/src/main/docker/sonar.yml
@@ -0,0 +1,13 @@
+# This configuration is intended for development purpose, it's **your** responsibility to harden it for production
+version: '3.8'
+services:
+ myapp-sonar:
+ image: sonarqube:9.1.0-community
+ # Authentication is turned off for out of the box experience while trying out SonarQube
+ # For real use cases delete sonar.forceAuthentication variable or set sonar.forceAuthentication=true
+ environment:
+ - sonar.forceAuthentication=false
+ # If you want to expose these ports outside your dev PC,
+ # remove the "127.0.0.1:" prefix
+ ports:
+ - 127.0.0.1:9001:9000
diff --git a/myApp/src/main/java/com/mycompany/myapp/ApplicationWebXml.java b/myApp/src/main/java/com/mycompany/myapp/ApplicationWebXml.java
new file mode 100644
index 000000000..1aef8740c
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/ApplicationWebXml.java
@@ -0,0 +1,19 @@
+package com.mycompany.myapp;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+import tech.jhipster.config.DefaultProfileUtil;
+
+/**
+ * This is a helper Java class that provides an alternative to creating a {@code web.xml}.
+ * This will be invoked only when the application is deployed to a Servlet container like Tomcat, JBoss etc.
+ */
+public class ApplicationWebXml extends SpringBootServletInitializer {
+
+ @Override
+ protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+ // set a default to use when no profile is configured.
+ DefaultProfileUtil.addDefaultProfile(application.application());
+ return application.sources(MyApp.class);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/GeneratedByJHipster.java b/myApp/src/main/java/com/mycompany/myapp/GeneratedByJHipster.java
new file mode 100644
index 000000000..e37e03d58
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/GeneratedByJHipster.java
@@ -0,0 +1,13 @@
+package com.mycompany.myapp;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import javax.annotation.Generated;
+
+@Generated(value = "JHipster", comments = "Generated by JHipster 7.5.0")
+@Retention(RetentionPolicy.SOURCE)
+@Target({ ElementType.TYPE })
+public @interface GeneratedByJHipster {
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/MyApp.java b/myApp/src/main/java/com/mycompany/myapp/MyApp.java
new file mode 100644
index 000000000..3ec32947e
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/MyApp.java
@@ -0,0 +1,103 @@
+package com.mycompany.myapp;
+
+import com.mycompany.myapp.config.ApplicationProperties;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Optional;
+import javax.annotation.PostConstruct;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.core.env.Environment;
+import tech.jhipster.config.DefaultProfileUtil;
+import tech.jhipster.config.JHipsterConstants;
+
+@SpringBootApplication
+@EnableConfigurationProperties({ LiquibaseProperties.class, ApplicationProperties.class })
+public class MyApp {
+
+ private static final Logger log = LoggerFactory.getLogger(MyApp.class);
+
+ private final Environment env;
+
+ public MyApp(Environment env) {
+ this.env = env;
+ }
+
+ /**
+ * Initializes myApp.
+ *
+ * Spring profiles can be configured with a program argument --spring.profiles.active=your-active-profile
+ *
+ * You can find more information on how profiles work with JHipster on https://www.jhipster.tech/profiles/ .
+ */
+ @PostConstruct
+ public void initApplication() {
+ Collection activeProfiles = Arrays.asList(env.getActiveProfiles());
+ if (
+ activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) &&
+ activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)
+ ) {
+ log.error(
+ "You have misconfigured your application! It should not run " + "with both the 'dev' and 'prod' profiles at the same time."
+ );
+ }
+ if (
+ activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT) &&
+ activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_CLOUD)
+ ) {
+ log.error(
+ "You have misconfigured your application! It should not " + "run with both the 'dev' and 'cloud' profiles at the same time."
+ );
+ }
+ }
+//testing commits
+ /**
+ * Main method, used to run the application.
+ *
+ * @param args the command line arguments.
+ */
+ public static void main(String[] args) {
+ SpringApplication app = new SpringApplication(MyApp.class);
+ DefaultProfileUtil.addDefaultProfile(app);
+ Environment env = app.run(args).getEnvironment();
+ logApplicationStartup(env);
+ }
+
+ private static void logApplicationStartup(Environment env) {
+ String protocol = Optional.ofNullable(env.getProperty("server.ssl.key-store")).map(key -> "https").orElse("http");
+ String serverPort = env.getProperty("server.port");
+ String contextPath = Optional
+ .ofNullable(env.getProperty("server.servlet.context-path"))
+ .filter(StringUtils::isNotBlank)
+ .orElse("/");
+ String hostAddress = "localhost";
+ try {
+ hostAddress = InetAddress.getLocalHost().getHostAddress();
+ } catch (UnknownHostException e) {
+ log.warn("The host name could not be determined, using `localhost` as fallback");
+ }
+ log.info(
+ "\n----------------------------------------------------------\n\t" +
+ "Application '{}' is running! Access URLs:\n\t" +
+ "Local: \t\t{}://localhost:{}{}\n\t" +
+ "External: \t{}://{}:{}{}\n\t" +
+ "Profile(s): \t{}\n----------------------------------------------------------",
+ env.getProperty("spring.application.name"),
+ protocol,
+ serverPort,
+ contextPath,
+ protocol,
+ hostAddress,
+ serverPort,
+ contextPath,
+ env.getActiveProfiles().length == 0 ? env.getDefaultProfiles() : env.getActiveProfiles()
+ );
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/aop/logging/LoggingAspect.java b/myApp/src/main/java/com/mycompany/myapp/aop/logging/LoggingAspect.java
new file mode 100644
index 000000000..3504c2661
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/aop/logging/LoggingAspect.java
@@ -0,0 +1,115 @@
+package com.mycompany.myapp.aop.logging;
+
+import java.util.Arrays;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.Profiles;
+import tech.jhipster.config.JHipsterConstants;
+
+/**
+ * Aspect for logging execution of service and repository Spring components.
+ *
+ * By default, it only runs with the "dev" profile.
+ */
+@Aspect
+public class LoggingAspect {
+
+ private final Environment env;
+
+ public LoggingAspect(Environment env) {
+ this.env = env;
+ }
+
+ /**
+ * Pointcut that matches all repositories, services and Web REST endpoints.
+ */
+ @Pointcut(
+ "within(@org.springframework.stereotype.Repository *)" +
+ " || within(@org.springframework.stereotype.Service *)" +
+ " || within(@org.springframework.web.bind.annotation.RestController *)"
+ )
+ public void springBeanPointcut() {
+ // Method is empty as this is just a Pointcut, the implementations are in the advices.
+ }
+
+ /**
+ * Pointcut that matches all Spring beans in the application's main packages.
+ */
+ @Pointcut(
+ "within(com.mycompany.myapp.repository..*)" +
+ " || within(com.mycompany.myapp.service..*)" +
+ " || within(com.mycompany.myapp.web.rest..*)"
+ )
+ public void applicationPackagePointcut() {
+ // Method is empty as this is just a Pointcut, the implementations are in the advices.
+ }
+
+ /**
+ * Retrieves the {@link Logger} associated to the given {@link JoinPoint}.
+ *
+ * @param joinPoint join point we want the logger for.
+ * @return {@link Logger} associated to the given {@link JoinPoint}.
+ */
+ private Logger logger(JoinPoint joinPoint) {
+ return LoggerFactory.getLogger(joinPoint.getSignature().getDeclaringTypeName());
+ }
+
+ /**
+ * Advice that logs methods throwing exceptions.
+ *
+ * @param joinPoint join point for advice.
+ * @param e exception.
+ */
+ @AfterThrowing(pointcut = "applicationPackagePointcut() && springBeanPointcut()", throwing = "e")
+ public void logAfterThrowing(JoinPoint joinPoint, Throwable e) {
+ if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) {
+ logger(joinPoint)
+ .error(
+ "Exception in {}() with cause = '{}' and exception = '{}'",
+ joinPoint.getSignature().getName(),
+ e.getCause() != null ? e.getCause() : "NULL",
+ e.getMessage(),
+ e
+ );
+ } else {
+ logger(joinPoint)
+ .error(
+ "Exception in {}() with cause = {}",
+ joinPoint.getSignature().getName(),
+ e.getCause() != null ? e.getCause() : "NULL"
+ );
+ }
+ }
+
+ /**
+ * Advice that logs when a method is entered and exited.
+ *
+ * @param joinPoint join point for advice.
+ * @return result.
+ * @throws Throwable throws {@link IllegalArgumentException}.
+ */
+ @Around("applicationPackagePointcut() && springBeanPointcut()")
+ public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
+ Logger log = logger(joinPoint);
+ if (log.isDebugEnabled()) {
+ log.debug("Enter: {}() with argument[s] = {}", joinPoint.getSignature().getName(), Arrays.toString(joinPoint.getArgs()));
+ }
+ try {
+ Object result = joinPoint.proceed();
+ if (log.isDebugEnabled()) {
+ log.debug("Exit: {}() with result = {}", joinPoint.getSignature().getName(), result);
+ }
+ return result;
+ } catch (IllegalArgumentException e) {
+ log.error("Illegal argument: {} in {}()", Arrays.toString(joinPoint.getArgs()), joinPoint.getSignature().getName());
+ throw e;
+ }
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/ApplicationProperties.java b/myApp/src/main/java/com/mycompany/myapp/config/ApplicationProperties.java
new file mode 100644
index 000000000..afc43cf0c
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/ApplicationProperties.java
@@ -0,0 +1,12 @@
+package com.mycompany.myapp.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+/**
+ * Properties specific to My App.
+ *
+ * Properties are configured in the {@code application.yml} file.
+ * See {@link tech.jhipster.config.JHipsterProperties} for a good example.
+ */
+@ConfigurationProperties(prefix = "application", ignoreUnknownFields = false)
+public class ApplicationProperties {}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/AsyncConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/AsyncConfiguration.java
new file mode 100644
index 000000000..93329fc01
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/AsyncConfiguration.java
@@ -0,0 +1,46 @@
+package com.mycompany.myapp.config;
+
+import java.util.concurrent.Executor;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
+import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
+import org.springframework.boot.autoconfigure.task.TaskExecutionProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.AsyncConfigurer;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor;
+
+@Configuration
+@EnableAsync
+@EnableScheduling
+public class AsyncConfiguration implements AsyncConfigurer {
+
+ private final Logger log = LoggerFactory.getLogger(AsyncConfiguration.class);
+
+ private final TaskExecutionProperties taskExecutionProperties;
+
+ public AsyncConfiguration(TaskExecutionProperties taskExecutionProperties) {
+ this.taskExecutionProperties = taskExecutionProperties;
+ }
+
+ @Override
+ @Bean(name = "taskExecutor")
+ public Executor getAsyncExecutor() {
+ log.debug("Creating Async Task Executor");
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(taskExecutionProperties.getPool().getCoreSize());
+ executor.setMaxPoolSize(taskExecutionProperties.getPool().getMaxSize());
+ executor.setQueueCapacity(taskExecutionProperties.getPool().getQueueCapacity());
+ executor.setThreadNamePrefix(taskExecutionProperties.getThreadNamePrefix());
+ return new ExceptionHandlingAsyncTaskExecutor(executor);
+ }
+
+ @Override
+ public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
+ return new SimpleAsyncUncaughtExceptionHandler();
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/CacheConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/CacheConfiguration.java
new file mode 100644
index 000000000..76c07f0ea
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/CacheConfiguration.java
@@ -0,0 +1,78 @@
+package com.mycompany.myapp.config;
+
+import java.time.Duration;
+import org.ehcache.config.builders.*;
+import org.ehcache.jsr107.Eh107Configuration;
+import org.hibernate.cache.jcache.ConfigSettings;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.cache.JCacheManagerCustomizer;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
+import org.springframework.boot.info.BuildProperties;
+import org.springframework.boot.info.GitProperties;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.cache.interceptor.KeyGenerator;
+import org.springframework.context.annotation.*;
+import tech.jhipster.config.JHipsterProperties;
+import tech.jhipster.config.cache.PrefixedKeyGenerator;
+
+@Configuration
+@EnableCaching
+public class CacheConfiguration {
+
+ private GitProperties gitProperties;
+ private BuildProperties buildProperties;
+ private final javax.cache.configuration.Configuration jcacheConfiguration;
+
+ public CacheConfiguration(JHipsterProperties jHipsterProperties) {
+ JHipsterProperties.Cache.Ehcache ehcache = jHipsterProperties.getCache().getEhcache();
+
+ jcacheConfiguration =
+ Eh107Configuration.fromEhcacheCacheConfiguration(
+ CacheConfigurationBuilder
+ .newCacheConfigurationBuilder(Object.class, Object.class, ResourcePoolsBuilder.heap(ehcache.getMaxEntries()))
+ .withExpiry(ExpiryPolicyBuilder.timeToLiveExpiration(Duration.ofSeconds(ehcache.getTimeToLiveSeconds())))
+ .build()
+ );
+ }
+
+ @Bean
+ public HibernatePropertiesCustomizer hibernatePropertiesCustomizer(javax.cache.CacheManager cacheManager) {
+ return hibernateProperties -> hibernateProperties.put(ConfigSettings.CACHE_MANAGER, cacheManager);
+ }
+
+ @Bean
+ public JCacheManagerCustomizer cacheManagerCustomizer() {
+ return cm -> {
+ createCache(cm, com.mycompany.myapp.repository.UserRepository.USERS_BY_LOGIN_CACHE);
+ createCache(cm, com.mycompany.myapp.repository.UserRepository.USERS_BY_EMAIL_CACHE);
+ createCache(cm, com.mycompany.myapp.domain.User.class.getName());
+ createCache(cm, com.mycompany.myapp.domain.Authority.class.getName());
+ createCache(cm, com.mycompany.myapp.domain.User.class.getName() + ".authorities");
+ // jhipster-needle-ehcache-add-entry
+ };
+ }
+
+ private void createCache(javax.cache.CacheManager cm, String cacheName) {
+ javax.cache.Cache cache = cm.getCache(cacheName);
+ if (cache != null) {
+ cache.clear();
+ } else {
+ cm.createCache(cacheName, jcacheConfiguration);
+ }
+ }
+
+ @Autowired(required = false)
+ public void setGitProperties(GitProperties gitProperties) {
+ this.gitProperties = gitProperties;
+ }
+
+ @Autowired(required = false)
+ public void setBuildProperties(BuildProperties buildProperties) {
+ this.buildProperties = buildProperties;
+ }
+
+ @Bean
+ public KeyGenerator keyGenerator() {
+ return new PrefixedKeyGenerator(this.gitProperties, this.buildProperties);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/Constants.java b/myApp/src/main/java/com/mycompany/myapp/config/Constants.java
new file mode 100644
index 000000000..b582288f7
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/Constants.java
@@ -0,0 +1,15 @@
+package com.mycompany.myapp.config;
+
+/**
+ * Application constants.
+ */
+public final class Constants {
+
+ // Regex for acceptable logins
+ public static final String LOGIN_REGEX = "^(?>[a-zA-Z0-9!$&*+=?^_`{|}~.-]+@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*)|(?>[_.@A-Za-z0-9-]+)$";
+
+ public static final String SYSTEM = "system";
+ public static final String DEFAULT_LANGUAGE = "en";
+
+ private Constants() {}
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/DatabaseConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/DatabaseConfiguration.java
new file mode 100644
index 000000000..1fac71a52
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/DatabaseConfiguration.java
@@ -0,0 +1,57 @@
+package com.mycompany.myapp.config;
+
+import java.sql.SQLException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.core.env.Environment;
+import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
+import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+import tech.jhipster.config.JHipsterConstants;
+import tech.jhipster.config.h2.H2ConfigurationHelper;
+
+@Configuration
+@EnableJpaRepositories({ "com.mycompany.myapp.repository" })
+@EnableJpaAuditing(auditorAwareRef = "springSecurityAuditorAware")
+@EnableTransactionManagement
+public class DatabaseConfiguration {
+
+ private final Logger log = LoggerFactory.getLogger(DatabaseConfiguration.class);
+
+ private final Environment env;
+
+ public DatabaseConfiguration(Environment env) {
+ this.env = env;
+ }
+
+ /**
+ * Open the TCP port for the H2 database, so it is available remotely.
+ *
+ * @return the H2 database TCP server.
+ * @throws SQLException if the server failed to start.
+ */
+ @Bean(initMethod = "start", destroyMethod = "stop")
+ @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
+ public Object h2TCPServer() throws SQLException {
+ String port = getValidPortForH2();
+ log.debug("H2 database is available on port {}", port);
+ return H2ConfigurationHelper.createServer(port);
+ }
+
+ private String getValidPortForH2() {
+ int port = Integer.parseInt(env.getProperty("server.port"));
+ if (port < 10000) {
+ port = 10000 + port;
+ } else {
+ if (port < 63536) {
+ port = port + 2000;
+ } else {
+ port = port - 2000;
+ }
+ }
+ return String.valueOf(port);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/DateTimeFormatConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/DateTimeFormatConfiguration.java
new file mode 100644
index 000000000..468c7991b
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/DateTimeFormatConfiguration.java
@@ -0,0 +1,20 @@
+package com.mycompany.myapp.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.format.FormatterRegistry;
+import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * Configure the converters to use the ISO format for dates by default.
+ */
+@Configuration
+public class DateTimeFormatConfiguration implements WebMvcConfigurer {
+
+ @Override
+ public void addFormatters(FormatterRegistry registry) {
+ DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
+ registrar.setUseIsoFormat(true);
+ registrar.registerFormatters(registry);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/JacksonConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/JacksonConfiguration.java
new file mode 100644
index 000000000..d438ffb16
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/JacksonConfiguration.java
@@ -0,0 +1,51 @@
+package com.mycompany.myapp.config;
+
+import com.fasterxml.jackson.datatype.hibernate5.Hibernate5Module;
+import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.zalando.problem.jackson.ProblemModule;
+import org.zalando.problem.violations.ConstraintViolationProblemModule;
+
+@Configuration
+public class JacksonConfiguration {
+
+ /**
+ * Support for Java date and time API.
+ * @return the corresponding Jackson module.
+ */
+ @Bean
+ public JavaTimeModule javaTimeModule() {
+ return new JavaTimeModule();
+ }
+
+ @Bean
+ public Jdk8Module jdk8TimeModule() {
+ return new Jdk8Module();
+ }
+
+ /*
+ * Support for Hibernate types in Jackson.
+ */
+ @Bean
+ public Hibernate5Module hibernate5Module() {
+ return new Hibernate5Module();
+ }
+
+ /*
+ * Module for serialization/deserialization of RFC7807 Problem.
+ */
+ @Bean
+ public ProblemModule problemModule() {
+ return new ProblemModule();
+ }
+
+ /*
+ * Module for serialization/deserialization of ConstraintViolationProblem.
+ */
+ @Bean
+ public ConstraintViolationProblemModule constraintViolationProblemModule() {
+ return new ConstraintViolationProblemModule();
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/LiquibaseConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/LiquibaseConfiguration.java
new file mode 100644
index 000000000..7fd49b408
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/LiquibaseConfiguration.java
@@ -0,0 +1,69 @@
+package com.mycompany.myapp.config;
+
+import java.util.concurrent.Executor;
+import javax.sql.DataSource;
+import liquibase.integration.spring.SpringLiquibase;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.autoconfigure.liquibase.LiquibaseDataSource;
+import org.springframework.boot.autoconfigure.liquibase.LiquibaseProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.Profiles;
+import tech.jhipster.config.JHipsterConstants;
+import tech.jhipster.config.liquibase.SpringLiquibaseUtil;
+
+@Configuration
+public class LiquibaseConfiguration {
+
+ private final Logger log = LoggerFactory.getLogger(LiquibaseConfiguration.class);
+
+ private final Environment env;
+
+ public LiquibaseConfiguration(Environment env) {
+ this.env = env;
+ }
+
+ @Bean
+ public SpringLiquibase liquibase(
+ @Qualifier("taskExecutor") Executor executor,
+ @LiquibaseDataSource ObjectProvider liquibaseDataSource,
+ LiquibaseProperties liquibaseProperties,
+ ObjectProvider dataSource,
+ DataSourceProperties dataSourceProperties
+ ) {
+ // If you don't want Liquibase to start asynchronously, substitute by this:
+ // SpringLiquibase liquibase = SpringLiquibaseUtil.createSpringLiquibase(liquibaseDataSource.getIfAvailable(), liquibaseProperties, dataSource.getIfUnique(), dataSourceProperties);
+ SpringLiquibase liquibase = SpringLiquibaseUtil.createAsyncSpringLiquibase(
+ this.env,
+ executor,
+ liquibaseDataSource.getIfAvailable(),
+ liquibaseProperties,
+ dataSource.getIfUnique(),
+ dataSourceProperties
+ );
+ liquibase.setChangeLog("classpath:config/liquibase/master.xml");
+ liquibase.setContexts(liquibaseProperties.getContexts());
+ liquibase.setDefaultSchema(liquibaseProperties.getDefaultSchema());
+ liquibase.setLiquibaseSchema(liquibaseProperties.getLiquibaseSchema());
+ liquibase.setLiquibaseTablespace(liquibaseProperties.getLiquibaseTablespace());
+ liquibase.setDatabaseChangeLogLockTable(liquibaseProperties.getDatabaseChangeLogLockTable());
+ liquibase.setDatabaseChangeLogTable(liquibaseProperties.getDatabaseChangeLogTable());
+ liquibase.setDropFirst(liquibaseProperties.isDropFirst());
+ liquibase.setLabels(liquibaseProperties.getLabels());
+ liquibase.setChangeLogParameters(liquibaseProperties.getParameters());
+ liquibase.setRollbackFile(liquibaseProperties.getRollbackFile());
+ liquibase.setTestRollbackOnUpdate(liquibaseProperties.isTestRollbackOnUpdate());
+ if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_NO_LIQUIBASE))) {
+ liquibase.setShouldRun(false);
+ } else {
+ liquibase.setShouldRun(liquibaseProperties.isEnabled());
+ log.debug("Configuring Liquibase");
+ }
+ return liquibase;
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/LocaleConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/LocaleConfiguration.java
new file mode 100644
index 000000000..cb1c7d034
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/LocaleConfiguration.java
@@ -0,0 +1,26 @@
+package com.mycompany.myapp.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.config.annotation.*;
+import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
+import tech.jhipster.config.locale.AngularCookieLocaleResolver;
+
+@Configuration
+public class LocaleConfiguration implements WebMvcConfigurer {
+
+ @Bean
+ public LocaleResolver localeResolver() {
+ AngularCookieLocaleResolver cookieLocaleResolver = new AngularCookieLocaleResolver();
+ cookieLocaleResolver.setCookieName("NG_TRANSLATE_LANG_KEY");
+ return cookieLocaleResolver;
+ }
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ LocaleChangeInterceptor localeChangeInterceptor = new LocaleChangeInterceptor();
+ localeChangeInterceptor.setParamName("language");
+ registry.addInterceptor(localeChangeInterceptor);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/LoggingAspectConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/LoggingAspectConfiguration.java
new file mode 100644
index 000000000..49175e64d
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/LoggingAspectConfiguration.java
@@ -0,0 +1,17 @@
+package com.mycompany.myapp.config;
+
+import com.mycompany.myapp.aop.logging.LoggingAspect;
+import org.springframework.context.annotation.*;
+import org.springframework.core.env.Environment;
+import tech.jhipster.config.JHipsterConstants;
+
+@Configuration
+@EnableAspectJAutoProxy
+public class LoggingAspectConfiguration {
+
+ @Bean
+ @Profile(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT)
+ public LoggingAspect loggingAspect(Environment env) {
+ return new LoggingAspect(env);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java
new file mode 100644
index 000000000..177de08ea
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/LoggingConfiguration.java
@@ -0,0 +1,47 @@
+package com.mycompany.myapp.config;
+
+import static tech.jhipster.config.logging.LoggingUtils.*;
+
+import ch.qos.logback.classic.LoggerContext;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.util.HashMap;
+import java.util.Map;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import tech.jhipster.config.JHipsterProperties;
+
+/*
+ * Configures the console and Logstash log appenders from the app properties
+ */
+@Configuration
+public class LoggingConfiguration {
+
+ public LoggingConfiguration(
+ @Value("${spring.application.name}") String appName,
+ @Value("${server.port}") String serverPort,
+ JHipsterProperties jHipsterProperties,
+ ObjectMapper mapper
+ ) throws JsonProcessingException {
+ LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
+
+ Map map = new HashMap<>();
+ map.put("app_name", appName);
+ map.put("app_port", serverPort);
+ String customFields = mapper.writeValueAsString(map);
+
+ JHipsterProperties.Logging loggingProperties = jHipsterProperties.getLogging();
+ JHipsterProperties.Logging.Logstash logstashProperties = loggingProperties.getLogstash();
+
+ if (loggingProperties.isUseJsonFormat()) {
+ addJsonConsoleAppender(context, customFields);
+ }
+ if (logstashProperties.isEnabled()) {
+ addLogstashTcpSocketAppender(context, customFields, logstashProperties);
+ }
+ if (loggingProperties.isUseJsonFormat() || logstashProperties.isEnabled()) {
+ addContextListener(context, customFields, loggingProperties);
+ }
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java
new file mode 100644
index 000000000..380de4a29
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/SecurityConfiguration.java
@@ -0,0 +1,111 @@
+package com.mycompany.myapp.config;
+
+import com.mycompany.myapp.security.*;
+import com.mycompany.myapp.security.jwt.*;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.builders.WebSecurity;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.header.writers.ReferrerPolicyHeaderWriter;
+import org.springframework.web.filter.CorsFilter;
+import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;
+import tech.jhipster.config.JHipsterProperties;
+
+@EnableWebSecurity
+@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
+@Import(SecurityProblemSupport.class)
+public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
+
+ private final JHipsterProperties jHipsterProperties;
+
+ private final TokenProvider tokenProvider;
+
+ private final CorsFilter corsFilter;
+ private final SecurityProblemSupport problemSupport;
+
+ public SecurityConfiguration(
+ TokenProvider tokenProvider,
+ CorsFilter corsFilter,
+ JHipsterProperties jHipsterProperties,
+ SecurityProblemSupport problemSupport
+ ) {
+ this.tokenProvider = tokenProvider;
+ this.corsFilter = corsFilter;
+ this.problemSupport = problemSupport;
+ this.jHipsterProperties = jHipsterProperties;
+ }
+
+ @Bean
+ public PasswordEncoder passwordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+ @Override
+ public void configure(WebSecurity web) {
+ web
+ .ignoring()
+ .antMatchers(HttpMethod.OPTIONS, "/**")
+ .antMatchers("/app/**/*.{js,html}")
+ .antMatchers("/i18n/**")
+ .antMatchers("/content/**")
+ .antMatchers("/h2-console/**")
+ .antMatchers("/swagger-ui/**")
+ .antMatchers("/test/**");
+ }
+
+ @Override
+ public void configure(HttpSecurity http) throws Exception {
+ // @formatter:off
+ http
+ .csrf()
+ .disable()
+ .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
+ .exceptionHandling()
+ .authenticationEntryPoint(problemSupport)
+ .accessDeniedHandler(problemSupport)
+ .and()
+ .headers()
+ .contentSecurityPolicy(jHipsterProperties.getSecurity().getContentSecurityPolicy())
+ .and()
+ .referrerPolicy(ReferrerPolicyHeaderWriter.ReferrerPolicy.STRICT_ORIGIN_WHEN_CROSS_ORIGIN)
+ .and()
+ .permissionsPolicy().policy("camera=(), fullscreen=(self), geolocation=(), gyroscope=(), magnetometer=(), microphone=(), midi=(), payment=(), sync-xhr=()")
+ .and()
+ .frameOptions()
+ .deny()
+ .and()
+ .sessionManagement()
+ .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
+ .and()
+ .authorizeRequests()
+ .antMatchers("/api/authenticate").permitAll()
+ .antMatchers("/api/register").permitAll()
+ .antMatchers("/api/activate").permitAll()
+ .antMatchers("/api/account/reset-password/init").permitAll()
+ .antMatchers("/api/account/reset-password/finish").permitAll()
+ .antMatchers("/api/admin/**").hasAuthority(AuthoritiesConstants.ADMIN)
+ .antMatchers("/api/**").authenticated()
+ .antMatchers("/management/health").permitAll()
+ .antMatchers("/management/health/**").permitAll()
+ .antMatchers("/management/info").permitAll()
+ .antMatchers("/management/prometheus").permitAll()
+ .antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
+ .and()
+ .httpBasic()
+ .and()
+ .apply(securityConfigurerAdapter());
+ // @formatter:on
+ }
+
+ private JWTConfigurer securityConfigurerAdapter() {
+ return new JWTConfigurer(tokenProvider);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/StaticResourcesWebConfiguration.java b/myApp/src/main/java/com/mycompany/myapp/config/StaticResourcesWebConfiguration.java
new file mode 100644
index 000000000..585d93405
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/StaticResourcesWebConfiguration.java
@@ -0,0 +1,59 @@
+package com.mycompany.myapp.config;
+
+import java.util.concurrent.TimeUnit;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.http.CacheControl;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import tech.jhipster.config.JHipsterConstants;
+import tech.jhipster.config.JHipsterProperties;
+
+@Configuration
+@Profile({ JHipsterConstants.SPRING_PROFILE_PRODUCTION })
+public class StaticResourcesWebConfiguration implements WebMvcConfigurer {
+
+ protected static final String[] RESOURCE_LOCATIONS = new String[] {
+ "classpath:/static/",
+ "classpath:/static/content/",
+ "classpath:/static/i18n/",
+ };
+ protected static final String[] RESOURCE_PATHS = new String[] {
+ "/*.js",
+ "/*.css",
+ "/*.svg",
+ "/*.png",
+ "*.ico",
+ "/content/**",
+ "/i18n/*",
+ };
+
+ private final JHipsterProperties jhipsterProperties;
+
+ public StaticResourcesWebConfiguration(JHipsterProperties jHipsterProperties) {
+ this.jhipsterProperties = jHipsterProperties;
+ }
+
+ @Override
+ public void addResourceHandlers(ResourceHandlerRegistry registry) {
+ ResourceHandlerRegistration resourceHandlerRegistration = appendResourceHandler(registry);
+ initializeResourceHandler(resourceHandlerRegistration);
+ }
+
+ protected ResourceHandlerRegistration appendResourceHandler(ResourceHandlerRegistry registry) {
+ return registry.addResourceHandler(RESOURCE_PATHS);
+ }
+
+ protected void initializeResourceHandler(ResourceHandlerRegistration resourceHandlerRegistration) {
+ resourceHandlerRegistration.addResourceLocations(RESOURCE_LOCATIONS).setCacheControl(getCacheControl());
+ }
+
+ protected CacheControl getCacheControl() {
+ return CacheControl.maxAge(getJHipsterHttpCacheProperty(), TimeUnit.DAYS).cachePublic();
+ }
+
+ private int getJHipsterHttpCacheProperty() {
+ return jhipsterProperties.getHttp().getCache().getTimeToLiveInDays();
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/WebConfigurer.java b/myApp/src/main/java/com/mycompany/myapp/config/WebConfigurer.java
new file mode 100644
index 000000000..83cb0ca29
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/WebConfigurer.java
@@ -0,0 +1,111 @@
+package com.mycompany.myapp.config;
+
+import static java.net.URLDecoder.decode;
+
+import java.io.File;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
+import javax.servlet.*;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.web.server.*;
+import org.springframework.boot.web.servlet.ServletContextInitializer;
+import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.core.env.Profiles;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+import tech.jhipster.config.JHipsterConstants;
+import tech.jhipster.config.JHipsterProperties;
+import tech.jhipster.config.h2.H2ConfigurationHelper;
+
+/**
+ * Configuration of web application with Servlet 3.0 APIs.
+ */
+@Configuration
+public class WebConfigurer implements ServletContextInitializer, WebServerFactoryCustomizer {
+
+ private final Logger log = LoggerFactory.getLogger(WebConfigurer.class);
+
+ private final Environment env;
+
+ private final JHipsterProperties jHipsterProperties;
+
+ public WebConfigurer(Environment env, JHipsterProperties jHipsterProperties) {
+ this.env = env;
+ this.jHipsterProperties = jHipsterProperties;
+ }
+
+ @Override
+ public void onStartup(ServletContext servletContext) throws ServletException {
+ if (env.getActiveProfiles().length != 0) {
+ log.info("Web application configuration, using profiles: {}", (Object[]) env.getActiveProfiles());
+ }
+
+ if (env.acceptsProfiles(Profiles.of(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT))) {
+ initH2Console(servletContext);
+ }
+ log.info("Web application fully configured");
+ }
+
+ /**
+ * Customize the Servlet engine: Mime types, the document root, the cache.
+ */
+ @Override
+ public void customize(WebServerFactory server) {
+ // When running in an IDE or with ./mvnw spring-boot:run, set location of the static web assets.
+ setLocationForStaticAssets(server);
+ }
+
+ private void setLocationForStaticAssets(WebServerFactory server) {
+ if (server instanceof ConfigurableServletWebServerFactory) {
+ ConfigurableServletWebServerFactory servletWebServer = (ConfigurableServletWebServerFactory) server;
+ File root;
+ String prefixPath = resolvePathPrefix();
+ root = new File(prefixPath + "target/classes/static/");
+ if (root.exists() && root.isDirectory()) {
+ servletWebServer.setDocumentRoot(root);
+ }
+ }
+ }
+
+ /**
+ * Resolve path prefix to static resources.
+ */
+ private String resolvePathPrefix() {
+ String fullExecutablePath = decode(this.getClass().getResource("").getPath(), StandardCharsets.UTF_8);
+ String rootPath = Paths.get(".").toUri().normalize().getPath();
+ String extractedPath = fullExecutablePath.replace(rootPath, "");
+ int extractionEndIndex = extractedPath.indexOf("target/");
+ if (extractionEndIndex <= 0) {
+ return "";
+ }
+ return extractedPath.substring(0, extractionEndIndex);
+ }
+
+ @Bean
+ public CorsFilter corsFilter() {
+ UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+ CorsConfiguration config = jHipsterProperties.getCors();
+ if (!CollectionUtils.isEmpty(config.getAllowedOrigins()) || !CollectionUtils.isEmpty(config.getAllowedOriginPatterns())) {
+ log.debug("Registering CORS filter");
+ source.registerCorsConfiguration("/api/**", config);
+ source.registerCorsConfiguration("/management/**", config);
+ source.registerCorsConfiguration("/v3/api-docs", config);
+ source.registerCorsConfiguration("/swagger-ui/**", config);
+ }
+ return new CorsFilter(source);
+ }
+
+ /**
+ * Initializes H2 console.
+ */
+ private void initH2Console(ServletContext servletContext) {
+ log.debug("Initialize H2 console");
+ H2ConfigurationHelper.initH2Console(servletContext);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/config/package-info.java b/myApp/src/main/java/com/mycompany/myapp/config/package-info.java
new file mode 100644
index 000000000..1defe291e
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/config/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Spring Framework configuration files.
+ */
+package com.mycompany.myapp.config;
diff --git a/myApp/src/main/java/com/mycompany/myapp/domain/AbstractAuditingEntity.java b/myApp/src/main/java/com/mycompany/myapp/domain/AbstractAuditingEntity.java
new file mode 100644
index 000000000..7f65305a1
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/domain/AbstractAuditingEntity.java
@@ -0,0 +1,76 @@
+package com.mycompany.myapp.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import java.io.Serializable;
+import java.time.Instant;
+import javax.persistence.Column;
+import javax.persistence.EntityListeners;
+import javax.persistence.MappedSuperclass;
+import org.springframework.data.annotation.CreatedBy;
+import org.springframework.data.annotation.CreatedDate;
+import org.springframework.data.annotation.LastModifiedBy;
+import org.springframework.data.annotation.LastModifiedDate;
+import org.springframework.data.jpa.domain.support.AuditingEntityListener;
+
+/**
+ * Base abstract class for entities which will hold definitions for created, last modified, created by,
+ * last modified by attributes.
+ */
+@MappedSuperclass
+@EntityListeners(AuditingEntityListener.class)
+public abstract class AbstractAuditingEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @CreatedBy
+ @Column(name = "created_by", nullable = false, length = 50, updatable = false)
+ @JsonIgnore
+ private String createdBy;
+
+ @CreatedDate
+ @Column(name = "created_date", updatable = false)
+ @JsonIgnore
+ private Instant createdDate = Instant.now();
+
+ @LastModifiedBy
+ @Column(name = "last_modified_by", length = 50)
+ @JsonIgnore
+ private String lastModifiedBy;
+
+ @LastModifiedDate
+ @Column(name = "last_modified_date")
+ @JsonIgnore
+ private Instant lastModifiedDate = Instant.now();
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public Instant getCreatedDate() {
+ return createdDate;
+ }
+
+ public void setCreatedDate(Instant createdDate) {
+ this.createdDate = createdDate;
+ }
+
+ public String getLastModifiedBy() {
+ return lastModifiedBy;
+ }
+
+ public void setLastModifiedBy(String lastModifiedBy) {
+ this.lastModifiedBy = lastModifiedBy;
+ }
+
+ public Instant getLastModifiedDate() {
+ return lastModifiedDate;
+ }
+
+ public void setLastModifiedDate(Instant lastModifiedDate) {
+ this.lastModifiedDate = lastModifiedDate;
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/domain/Authority.java b/myApp/src/main/java/com/mycompany/myapp/domain/Authority.java
new file mode 100644
index 000000000..50ae3a1b3
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/domain/Authority.java
@@ -0,0 +1,61 @@
+package com.mycompany.myapp.domain;
+
+import java.io.Serializable;
+import java.util.Objects;
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+/**
+ * An authority (a security role) used by Spring Security.
+ */
+@Entity
+@Table(name = "jhi_authority")
+@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
+public class Authority implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @NotNull
+ @Size(max = 50)
+ @Id
+ @Column(length = 50)
+ private String name;
+
+ public String getName() {
+ return name;
+ }
+
+ public void setName(String name) {
+ this.name = name;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof Authority)) {
+ return false;
+ }
+ return Objects.equals(name, ((Authority) o).name);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(name);
+ }
+
+ // prettier-ignore
+ @Override
+ public String toString() {
+ return "Authority{" +
+ "name='" + name + '\'' +
+ "}";
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/domain/User.java b/myApp/src/main/java/com/mycompany/myapp/domain/User.java
new file mode 100644
index 000000000..a6cc4dd30
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/domain/User.java
@@ -0,0 +1,232 @@
+package com.mycompany.myapp.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.mycompany.myapp.config.Constants;
+import java.io.Serializable;
+import java.time.Instant;
+import java.util.HashSet;
+import java.util.Locale;
+import java.util.Set;
+import javax.persistence.*;
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.StringUtils;
+import org.hibernate.annotations.BatchSize;
+import org.hibernate.annotations.Cache;
+import org.hibernate.annotations.CacheConcurrencyStrategy;
+
+/**
+ * A user.
+ */
+@Entity
+@Table(name = "jhi_user")
+@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
+public class User extends AbstractAuditingEntity implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
+ @SequenceGenerator(name = "sequenceGenerator")
+ private Long id;
+
+ @NotNull
+ @Pattern(regexp = Constants.LOGIN_REGEX)
+ @Size(min = 1, max = 50)
+ @Column(length = 50, unique = true, nullable = false)
+ private String login;
+
+ @JsonIgnore
+ @NotNull
+ @Size(min = 60, max = 60)
+ @Column(name = "password_hash", length = 60, nullable = false)
+ private String password;
+
+ @Size(max = 50)
+ @Column(name = "first_name", length = 50)
+ private String firstName;
+
+ @Size(max = 50)
+ @Column(name = "last_name", length = 50)
+ private String lastName;
+
+ @Email
+ @Size(min = 5, max = 254)
+ @Column(length = 254, unique = true)
+ private String email;
+
+ @NotNull
+ @Column(nullable = false)
+ private boolean activated = false;
+
+ @Size(min = 2, max = 10)
+ @Column(name = "lang_key", length = 10)
+ private String langKey;
+
+ @Size(max = 256)
+ @Column(name = "image_url", length = 256)
+ private String imageUrl;
+
+ @Size(max = 20)
+ @Column(name = "activation_key", length = 20)
+ @JsonIgnore
+ private String activationKey;
+
+ @Size(max = 20)
+ @Column(name = "reset_key", length = 20)
+ @JsonIgnore
+ private String resetKey;
+
+ @Column(name = "reset_date")
+ private Instant resetDate = null;
+
+ @JsonIgnore
+ @ManyToMany
+ @JoinTable(
+ name = "jhi_user_authority",
+ joinColumns = { @JoinColumn(name = "user_id", referencedColumnName = "id") },
+ inverseJoinColumns = { @JoinColumn(name = "authority_name", referencedColumnName = "name") }
+ )
+ @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
+ @BatchSize(size = 20)
+ private Set authorities = new HashSet<>();
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ // Lowercase the login before saving it in database
+ public void setLogin(String login) {
+ this.login = StringUtils.lowerCase(login, Locale.ENGLISH);
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getImageUrl() {
+ return imageUrl;
+ }
+
+ public void setImageUrl(String imageUrl) {
+ this.imageUrl = imageUrl;
+ }
+
+ public boolean isActivated() {
+ return activated;
+ }
+
+ public void setActivated(boolean activated) {
+ this.activated = activated;
+ }
+
+ public String getActivationKey() {
+ return activationKey;
+ }
+
+ public void setActivationKey(String activationKey) {
+ this.activationKey = activationKey;
+ }
+
+ public String getResetKey() {
+ return resetKey;
+ }
+
+ public void setResetKey(String resetKey) {
+ this.resetKey = resetKey;
+ }
+
+ public Instant getResetDate() {
+ return resetDate;
+ }
+
+ public void setResetDate(Instant resetDate) {
+ this.resetDate = resetDate;
+ }
+
+ public String getLangKey() {
+ return langKey;
+ }
+
+ public void setLangKey(String langKey) {
+ this.langKey = langKey;
+ }
+
+ public Set getAuthorities() {
+ return authorities;
+ }
+
+ public void setAuthorities(Set authorities) {
+ this.authorities = authorities;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (!(o instanceof User)) {
+ return false;
+ }
+ return id != null && id.equals(((User) o).id);
+ }
+
+ @Override
+ public int hashCode() {
+ // see https://vladmihalcea.com/how-to-implement-equals-and-hashcode-using-the-jpa-entity-identifier/
+ return getClass().hashCode();
+ }
+
+ // prettier-ignore
+ @Override
+ public String toString() {
+ return "User{" +
+ "login='" + login + '\'' +
+ ", firstName='" + firstName + '\'' +
+ ", lastName='" + lastName + '\'' +
+ ", email='" + email + '\'' +
+ ", imageUrl='" + imageUrl + '\'' +
+ ", activated='" + activated + '\'' +
+ ", langKey='" + langKey + '\'' +
+ ", activationKey='" + activationKey + '\'' +
+ "}";
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/domain/package-info.java b/myApp/src/main/java/com/mycompany/myapp/domain/package-info.java
new file mode 100644
index 000000000..9539739e6
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/domain/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * JPA domain objects.
+ */
+package com.mycompany.myapp.domain;
diff --git a/myApp/src/main/java/com/mycompany/myapp/management/SecurityMetersService.java b/myApp/src/main/java/com/mycompany/myapp/management/SecurityMetersService.java
new file mode 100644
index 000000000..f35255112
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/management/SecurityMetersService.java
@@ -0,0 +1,51 @@
+package com.mycompany.myapp.management;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import org.springframework.stereotype.Service;
+
+@Service
+public class SecurityMetersService {
+
+ public static final String INVALID_TOKENS_METER_NAME = "security.authentication.invalid-tokens";
+ public static final String INVALID_TOKENS_METER_DESCRIPTION =
+ "Indicates validation error count of the tokens presented by the clients.";
+ public static final String INVALID_TOKENS_METER_BASE_UNIT = "errors";
+ public static final String INVALID_TOKENS_METER_CAUSE_DIMENSION = "cause";
+
+ private final Counter tokenInvalidSignatureCounter;
+ private final Counter tokenExpiredCounter;
+ private final Counter tokenUnsupportedCounter;
+ private final Counter tokenMalformedCounter;
+
+ public SecurityMetersService(MeterRegistry registry) {
+ this.tokenInvalidSignatureCounter = invalidTokensCounterForCauseBuilder("invalid-signature").register(registry);
+ this.tokenExpiredCounter = invalidTokensCounterForCauseBuilder("expired").register(registry);
+ this.tokenUnsupportedCounter = invalidTokensCounterForCauseBuilder("unsupported").register(registry);
+ this.tokenMalformedCounter = invalidTokensCounterForCauseBuilder("malformed").register(registry);
+ }
+
+ private Counter.Builder invalidTokensCounterForCauseBuilder(String cause) {
+ return Counter
+ .builder(INVALID_TOKENS_METER_NAME)
+ .baseUnit(INVALID_TOKENS_METER_BASE_UNIT)
+ .description(INVALID_TOKENS_METER_DESCRIPTION)
+ .tag(INVALID_TOKENS_METER_CAUSE_DIMENSION, cause);
+ }
+
+ public void trackTokenInvalidSignature() {
+ this.tokenInvalidSignatureCounter.increment();
+ }
+
+ public void trackTokenExpired() {
+ this.tokenExpiredCounter.increment();
+ }
+
+ public void trackTokenUnsupported() {
+ this.tokenUnsupportedCounter.increment();
+ }
+
+ public void trackTokenMalformed() {
+ this.tokenMalformedCounter.increment();
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/repository/AuthorityRepository.java b/myApp/src/main/java/com/mycompany/myapp/repository/AuthorityRepository.java
new file mode 100644
index 000000000..4ccba30c4
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/repository/AuthorityRepository.java
@@ -0,0 +1,11 @@
+package com.mycompany.myapp.repository;
+
+import com.mycompany.myapp.domain.Authority;
+import org.springframework.data.jpa.repository.JpaRepository;
+
+/**
+ * Spring Data JPA repository for the {@link Authority} entity.
+ */
+public interface AuthorityRepository extends JpaRepository {
+
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/repository/UserRepository.java b/myApp/src/main/java/com/mycompany/myapp/repository/UserRepository.java
new file mode 100644
index 000000000..ab7538027
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/repository/UserRepository.java
@@ -0,0 +1,42 @@
+package com.mycompany.myapp.repository;
+
+import com.mycompany.myapp.domain.User;
+import java.time.Instant;
+import java.util.List;
+import java.util.Optional;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.repository.EntityGraph;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Spring Data JPA repository for the {@link User} entity.
+ */
+@Repository
+public interface UserRepository extends JpaRepository {
+ String USERS_BY_LOGIN_CACHE = "usersByLogin";
+
+ String USERS_BY_EMAIL_CACHE = "usersByEmail";
+
+ Optional findOneByActivationKey(String activationKey);
+
+ List findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(Instant dateTime);
+
+ Optional findOneByResetKey(String resetKey);
+
+ Optional findOneByEmailIgnoreCase(String email);
+
+ Optional findOneByLogin(String login);
+
+ @EntityGraph(attributePaths = "authorities")
+ @Cacheable(cacheNames = USERS_BY_LOGIN_CACHE)
+ Optional findOneWithAuthoritiesByLogin(String login);
+
+ @EntityGraph(attributePaths = "authorities")
+ @Cacheable(cacheNames = USERS_BY_EMAIL_CACHE)
+ Optional findOneWithAuthoritiesByEmailIgnoreCase(String email);
+
+ Page findAllByIdNotNullAndActivatedIsTrue(Pageable pageable);
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/repository/package-info.java b/myApp/src/main/java/com/mycompany/myapp/repository/package-info.java
new file mode 100644
index 000000000..c3d3f61c8
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/repository/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Spring Data JPA repositories.
+ */
+package com.mycompany.myapp.repository;
diff --git a/myApp/src/main/java/com/mycompany/myapp/security/AuthoritiesConstants.java b/myApp/src/main/java/com/mycompany/myapp/security/AuthoritiesConstants.java
new file mode 100644
index 000000000..e148fa064
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/security/AuthoritiesConstants.java
@@ -0,0 +1,15 @@
+package com.mycompany.myapp.security;
+
+/**
+ * Constants for Spring Security authorities.
+ */
+public final class AuthoritiesConstants {
+
+ public static final String ADMIN = "ROLE_ADMIN";
+
+ public static final String USER = "ROLE_USER";
+
+ public static final String ANONYMOUS = "ROLE_ANONYMOUS";
+
+ private AuthoritiesConstants() {}
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/security/DomainUserDetailsService.java b/myApp/src/main/java/com/mycompany/myapp/security/DomainUserDetailsService.java
new file mode 100644
index 000000000..015ac0191
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/security/DomainUserDetailsService.java
@@ -0,0 +1,62 @@
+package com.mycompany.myapp.security;
+
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.UserRepository;
+import java.util.*;
+import java.util.stream.Collectors;
+import org.hibernate.validator.internal.constraintvalidators.hv.EmailValidator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Component;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Authenticate a user from the database.
+ */
+@Component("userDetailsService")
+public class DomainUserDetailsService implements UserDetailsService {
+
+ private final Logger log = LoggerFactory.getLogger(DomainUserDetailsService.class);
+
+ private final UserRepository userRepository;
+
+ public DomainUserDetailsService(UserRepository userRepository) {
+ this.userRepository = userRepository;
+ }
+
+ @Override
+ @Transactional
+ public UserDetails loadUserByUsername(final String login) {
+ log.debug("Authenticating {}", login);
+
+ if (new EmailValidator().isValid(login, null)) {
+ return userRepository
+ .findOneWithAuthoritiesByEmailIgnoreCase(login)
+ .map(user -> createSpringSecurityUser(login, user))
+ .orElseThrow(() -> new UsernameNotFoundException("User with email " + login + " was not found in the database"));
+ }
+
+ String lowercaseLogin = login.toLowerCase(Locale.ENGLISH);
+ return userRepository
+ .findOneWithAuthoritiesByLogin(lowercaseLogin)
+ .map(user -> createSpringSecurityUser(lowercaseLogin, user))
+ .orElseThrow(() -> new UsernameNotFoundException("User " + lowercaseLogin + " was not found in the database"));
+ }
+
+ private org.springframework.security.core.userdetails.User createSpringSecurityUser(String lowercaseLogin, User user) {
+ if (!user.isActivated()) {
+ throw new UserNotActivatedException("User " + lowercaseLogin + " was not activated");
+ }
+ List grantedAuthorities = user
+ .getAuthorities()
+ .stream()
+ .map(authority -> new SimpleGrantedAuthority(authority.getName()))
+ .collect(Collectors.toList());
+ return new org.springframework.security.core.userdetails.User(user.getLogin(), user.getPassword(), grantedAuthorities);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/security/SecurityUtils.java b/myApp/src/main/java/com/mycompany/myapp/security/SecurityUtils.java
new file mode 100644
index 000000000..0515a071e
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/security/SecurityUtils.java
@@ -0,0 +1,100 @@
+package com.mycompany.myapp.security;
+
+import java.util.Arrays;
+import java.util.Optional;
+import java.util.stream.Stream;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.core.userdetails.UserDetails;
+
+/**
+ * Utility class for Spring Security.
+ */
+public final class SecurityUtils {
+
+ private SecurityUtils() {}
+
+ /**
+ * Get the login of the current user.
+ *
+ * @return the login of the current user.
+ */
+ public static Optional getCurrentUserLogin() {
+ SecurityContext securityContext = SecurityContextHolder.getContext();
+ return Optional.ofNullable(extractPrincipal(securityContext.getAuthentication()));
+ }
+
+ private static String extractPrincipal(Authentication authentication) {
+ if (authentication == null) {
+ return null;
+ } else if (authentication.getPrincipal() instanceof UserDetails) {
+ UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
+ return springSecurityUser.getUsername();
+ } else if (authentication.getPrincipal() instanceof String) {
+ return (String) authentication.getPrincipal();
+ }
+ return null;
+ }
+
+ /**
+ * Get the JWT of the current user.
+ *
+ * @return the JWT of the current user.
+ */
+ public static Optional getCurrentUserJWT() {
+ SecurityContext securityContext = SecurityContextHolder.getContext();
+ return Optional
+ .ofNullable(securityContext.getAuthentication())
+ .filter(authentication -> authentication.getCredentials() instanceof String)
+ .map(authentication -> (String) authentication.getCredentials());
+ }
+
+ /**
+ * Check if a user is authenticated.
+ *
+ * @return true if the user is authenticated, false otherwise.
+ */
+ public static boolean isAuthenticated() {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ return authentication != null && getAuthorities(authentication).noneMatch(AuthoritiesConstants.ANONYMOUS::equals);
+ }
+
+ /**
+ * Checks if the current user has any of the authorities.
+ *
+ * @param authorities the authorities to check.
+ * @return true if the current user has any of the authorities, false otherwise.
+ */
+ public static boolean hasCurrentUserAnyOfAuthorities(String... authorities) {
+ Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
+ return (
+ authentication != null && getAuthorities(authentication).anyMatch(authority -> Arrays.asList(authorities).contains(authority))
+ );
+ }
+
+ /**
+ * Checks if the current user has none of the authorities.
+ *
+ * @param authorities the authorities to check.
+ * @return true if the current user has none of the authorities, false otherwise.
+ */
+ public static boolean hasCurrentUserNoneOfAuthorities(String... authorities) {
+ return !hasCurrentUserAnyOfAuthorities(authorities);
+ }
+
+ /**
+ * Checks if the current user has a specific authority.
+ *
+ * @param authority the authority to check.
+ * @return true if the current user has the authority, false otherwise.
+ */
+ public static boolean hasCurrentUserThisAuthority(String authority) {
+ return hasCurrentUserAnyOfAuthorities(authority);
+ }
+
+ private static Stream getAuthorities(Authentication authentication) {
+ return authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/security/SpringSecurityAuditorAware.java b/myApp/src/main/java/com/mycompany/myapp/security/SpringSecurityAuditorAware.java
new file mode 100644
index 000000000..be2f2d57a
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/security/SpringSecurityAuditorAware.java
@@ -0,0 +1,18 @@
+package com.mycompany.myapp.security;
+
+import com.mycompany.myapp.config.Constants;
+import java.util.Optional;
+import org.springframework.data.domain.AuditorAware;
+import org.springframework.stereotype.Component;
+
+/**
+ * Implementation of {@link AuditorAware} based on Spring Security.
+ */
+@Component
+public class SpringSecurityAuditorAware implements AuditorAware {
+
+ @Override
+ public Optional getCurrentAuditor() {
+ return Optional.of(SecurityUtils.getCurrentUserLogin().orElse(Constants.SYSTEM));
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/security/UserNotActivatedException.java b/myApp/src/main/java/com/mycompany/myapp/security/UserNotActivatedException.java
new file mode 100644
index 000000000..423305660
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/security/UserNotActivatedException.java
@@ -0,0 +1,19 @@
+package com.mycompany.myapp.security;
+
+import org.springframework.security.core.AuthenticationException;
+
+/**
+ * This exception is thrown in case of a not activated user trying to authenticate.
+ */
+public class UserNotActivatedException extends AuthenticationException {
+
+ private static final long serialVersionUID = 1L;
+
+ public UserNotActivatedException(String message) {
+ super(message);
+ }
+
+ public UserNotActivatedException(String message, Throwable t) {
+ super(message, t);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/security/jwt/JWTConfigurer.java b/myApp/src/main/java/com/mycompany/myapp/security/jwt/JWTConfigurer.java
new file mode 100644
index 000000000..2726a5190
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/security/jwt/JWTConfigurer.java
@@ -0,0 +1,21 @@
+package com.mycompany.myapp.security.jwt;
+
+import org.springframework.security.config.annotation.SecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.web.DefaultSecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+
+public class JWTConfigurer extends SecurityConfigurerAdapter {
+
+ private final TokenProvider tokenProvider;
+
+ public JWTConfigurer(TokenProvider tokenProvider) {
+ this.tokenProvider = tokenProvider;
+ }
+
+ @Override
+ public void configure(HttpSecurity http) {
+ JWTFilter customFilter = new JWTFilter(tokenProvider);
+ http.addFilterBefore(customFilter, UsernamePasswordAuthenticationFilter.class);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/security/jwt/JWTFilter.java b/myApp/src/main/java/com/mycompany/myapp/security/jwt/JWTFilter.java
new file mode 100644
index 000000000..a55a71f43
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/security/jwt/JWTFilter.java
@@ -0,0 +1,47 @@
+package com.mycompany.myapp.security.jwt;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.util.StringUtils;
+import org.springframework.web.filter.GenericFilterBean;
+
+/**
+ * Filters incoming requests and installs a Spring Security principal if a header corresponding to a valid user is
+ * found.
+ */
+public class JWTFilter extends GenericFilterBean {
+
+ public static final String AUTHORIZATION_HEADER = "Authorization";
+
+ private final TokenProvider tokenProvider;
+
+ public JWTFilter(TokenProvider tokenProvider) {
+ this.tokenProvider = tokenProvider;
+ }
+
+ @Override
+ public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
+ throws IOException, ServletException {
+ HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
+ String jwt = resolveToken(httpServletRequest);
+ if (StringUtils.hasText(jwt) && this.tokenProvider.validateToken(jwt)) {
+ Authentication authentication = this.tokenProvider.getAuthentication(jwt);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ }
+ filterChain.doFilter(servletRequest, servletResponse);
+ }
+
+ private String resolveToken(HttpServletRequest request) {
+ String bearerToken = request.getHeader(AUTHORIZATION_HEADER);
+ if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
+ return bearerToken.substring(7);
+ }
+ return null;
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/security/jwt/TokenProvider.java b/myApp/src/main/java/com/mycompany/myapp/security/jwt/TokenProvider.java
new file mode 100644
index 000000000..41df03b27
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/security/jwt/TokenProvider.java
@@ -0,0 +1,126 @@
+package com.mycompany.myapp.security.jwt;
+
+import com.mycompany.myapp.management.SecurityMetersService;
+import io.jsonwebtoken.*;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.security.Keys;
+import io.jsonwebtoken.security.SignatureException;
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import java.util.*;
+import java.util.stream.Collectors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.userdetails.User;
+import org.springframework.stereotype.Component;
+import org.springframework.util.ObjectUtils;
+import tech.jhipster.config.JHipsterProperties;
+
+@Component
+public class TokenProvider {
+
+ private final Logger log = LoggerFactory.getLogger(TokenProvider.class);
+
+ private static final String AUTHORITIES_KEY = "auth";
+
+ private static final String INVALID_JWT_TOKEN = "Invalid JWT token.";
+
+ private final Key key;
+
+ private final JwtParser jwtParser;
+
+ private final long tokenValidityInMilliseconds;
+
+ private final long tokenValidityInMillisecondsForRememberMe;
+
+ private final SecurityMetersService securityMetersService;
+
+ public TokenProvider(JHipsterProperties jHipsterProperties, SecurityMetersService securityMetersService) {
+ byte[] keyBytes;
+ String secret = jHipsterProperties.getSecurity().getAuthentication().getJwt().getBase64Secret();
+ if (!ObjectUtils.isEmpty(secret)) {
+ log.debug("Using a Base64-encoded JWT secret key");
+ keyBytes = Decoders.BASE64.decode(secret);
+ } else {
+ log.warn(
+ "Warning: the JWT key used is not Base64-encoded. " +
+ "We recommend using the `jhipster.security.authentication.jwt.base64-secret` key for optimum security."
+ );
+ secret = jHipsterProperties.getSecurity().getAuthentication().getJwt().getSecret();
+ keyBytes = secret.getBytes(StandardCharsets.UTF_8);
+ }
+ key = Keys.hmacShaKeyFor(keyBytes);
+ jwtParser = Jwts.parserBuilder().setSigningKey(key).build();
+ this.tokenValidityInMilliseconds = 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSeconds();
+ this.tokenValidityInMillisecondsForRememberMe =
+ 1000 * jHipsterProperties.getSecurity().getAuthentication().getJwt().getTokenValidityInSecondsForRememberMe();
+
+ this.securityMetersService = securityMetersService;
+ }
+
+ public String createToken(Authentication authentication, boolean rememberMe) {
+ String authorities = authentication.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.joining(","));
+
+ long now = (new Date()).getTime();
+ Date validity;
+ if (rememberMe) {
+ validity = new Date(now + this.tokenValidityInMillisecondsForRememberMe);
+ } else {
+ validity = new Date(now + this.tokenValidityInMilliseconds);
+ }
+
+ return Jwts
+ .builder()
+ .setSubject(authentication.getName())
+ .claim(AUTHORITIES_KEY, authorities)
+ .signWith(key, SignatureAlgorithm.HS512)
+ .setExpiration(validity)
+ .compact();
+ }
+
+ public Authentication getAuthentication(String token) {
+ Claims claims = jwtParser.parseClaimsJws(token).getBody();
+
+ Collection extends GrantedAuthority> authorities = Arrays
+ .stream(claims.get(AUTHORITIES_KEY).toString().split(","))
+ .filter(auth -> !auth.trim().isEmpty())
+ .map(SimpleGrantedAuthority::new)
+ .collect(Collectors.toList());
+
+ User principal = new User(claims.getSubject(), "", authorities);
+
+ return new UsernamePasswordAuthenticationToken(principal, token, authorities);
+ }
+
+ public boolean validateToken(String authToken) {
+ try {
+ jwtParser.parseClaimsJws(authToken);
+
+ return true;
+ } catch (ExpiredJwtException e) {
+ this.securityMetersService.trackTokenExpired();
+
+ log.trace(INVALID_JWT_TOKEN, e);
+ } catch (UnsupportedJwtException e) {
+ this.securityMetersService.trackTokenUnsupported();
+
+ log.trace(INVALID_JWT_TOKEN, e);
+ } catch (MalformedJwtException e) {
+ this.securityMetersService.trackTokenMalformed();
+
+ log.trace(INVALID_JWT_TOKEN, e);
+ } catch (SignatureException e) {
+ this.securityMetersService.trackTokenInvalidSignature();
+
+ log.trace(INVALID_JWT_TOKEN, e);
+ } catch (IllegalArgumentException e) { // TODO: should we let it bubble (no catch), to avoid defensive programming and follow the fail-fast principle?
+ log.error("Token validation error {}", e.getMessage());
+ }
+
+ return false;
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/security/package-info.java b/myApp/src/main/java/com/mycompany/myapp/security/package-info.java
new file mode 100644
index 000000000..8ae77eef0
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/security/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Spring Security configuration.
+ */
+package com.mycompany.myapp.security;
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/EmailAlreadyUsedException.java b/myApp/src/main/java/com/mycompany/myapp/service/EmailAlreadyUsedException.java
new file mode 100644
index 000000000..37915800e
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/EmailAlreadyUsedException.java
@@ -0,0 +1,10 @@
+package com.mycompany.myapp.service;
+
+public class EmailAlreadyUsedException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public EmailAlreadyUsedException() {
+ super("Email is already in use!");
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/InvalidPasswordException.java b/myApp/src/main/java/com/mycompany/myapp/service/InvalidPasswordException.java
new file mode 100644
index 000000000..244d6cc65
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/InvalidPasswordException.java
@@ -0,0 +1,10 @@
+package com.mycompany.myapp.service;
+
+public class InvalidPasswordException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public InvalidPasswordException() {
+ super("Incorrect password");
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/MailService.java b/myApp/src/main/java/com/mycompany/myapp/service/MailService.java
new file mode 100644
index 000000000..5566035b3
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/MailService.java
@@ -0,0 +1,112 @@
+package com.mycompany.myapp.service;
+
+import com.mycompany.myapp.domain.User;
+import java.nio.charset.StandardCharsets;
+import java.util.Locale;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeMessage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.MessageSource;
+import org.springframework.mail.MailException;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+import org.thymeleaf.context.Context;
+import org.thymeleaf.spring5.SpringTemplateEngine;
+import tech.jhipster.config.JHipsterProperties;
+
+/**
+ * Service for sending emails.
+ *
+ * We use the {@link Async} annotation to send emails asynchronously.
+ */
+@Service
+public class MailService {
+
+ private final Logger log = LoggerFactory.getLogger(MailService.class);
+
+ private static final String USER = "user";
+
+ private static final String BASE_URL = "baseUrl";
+
+ private final JHipsterProperties jHipsterProperties;
+
+ private final JavaMailSender javaMailSender;
+
+ private final MessageSource messageSource;
+
+ private final SpringTemplateEngine templateEngine;
+
+ public MailService(
+ JHipsterProperties jHipsterProperties,
+ JavaMailSender javaMailSender,
+ MessageSource messageSource,
+ SpringTemplateEngine templateEngine
+ ) {
+ this.jHipsterProperties = jHipsterProperties;
+ this.javaMailSender = javaMailSender;
+ this.messageSource = messageSource;
+ this.templateEngine = templateEngine;
+ }
+
+ @Async
+ public void sendEmail(String to, String subject, String content, boolean isMultipart, boolean isHtml) {
+ log.debug(
+ "Send email[multipart '{}' and html '{}'] to '{}' with subject '{}' and content={}",
+ isMultipart,
+ isHtml,
+ to,
+ subject,
+ content
+ );
+
+ // Prepare message using a Spring helper
+ MimeMessage mimeMessage = javaMailSender.createMimeMessage();
+ try {
+ MimeMessageHelper message = new MimeMessageHelper(mimeMessage, isMultipart, StandardCharsets.UTF_8.name());
+ message.setTo(to);
+ message.setFrom(jHipsterProperties.getMail().getFrom());
+ message.setSubject(subject);
+ message.setText(content, isHtml);
+ javaMailSender.send(mimeMessage);
+ log.debug("Sent email to User '{}'", to);
+ } catch (MailException | MessagingException e) {
+ log.warn("Email could not be sent to user '{}'", to, e);
+ }
+ }
+
+ @Async
+ public void sendEmailFromTemplate(User user, String templateName, String titleKey) {
+ if (user.getEmail() == null) {
+ log.debug("Email doesn't exist for user '{}'", user.getLogin());
+ return;
+ }
+ Locale locale = Locale.forLanguageTag(user.getLangKey());
+ Context context = new Context(locale);
+ context.setVariable(USER, user);
+ context.setVariable(BASE_URL, jHipsterProperties.getMail().getBaseUrl());
+ String content = templateEngine.process(templateName, context);
+ String subject = messageSource.getMessage(titleKey, null, locale);
+ sendEmail(user.getEmail(), subject, content, false, true);
+ }
+
+ @Async
+ public void sendActivationEmail(User user) {
+ log.debug("Sending activation email to '{}'", user.getEmail());
+ sendEmailFromTemplate(user, "mail/activationEmail", "email.activation.title");
+ }
+
+ @Async
+ public void sendCreationEmail(User user) {
+ log.debug("Sending creation email to '{}'", user.getEmail());
+ sendEmailFromTemplate(user, "mail/creationEmail", "email.activation.title");
+ }
+
+ @Async
+ public void sendPasswordResetMail(User user) {
+ log.debug("Sending password reset email to '{}'", user.getEmail());
+ sendEmailFromTemplate(user, "mail/passwordResetEmail", "email.reset.title");
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/UserService.java b/myApp/src/main/java/com/mycompany/myapp/service/UserService.java
new file mode 100644
index 000000000..6947c58b1
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/UserService.java
@@ -0,0 +1,325 @@
+package com.mycompany.myapp.service;
+
+import com.mycompany.myapp.config.Constants;
+import com.mycompany.myapp.domain.Authority;
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.AuthorityRepository;
+import com.mycompany.myapp.repository.UserRepository;
+import com.mycompany.myapp.security.AuthoritiesConstants;
+import com.mycompany.myapp.security.SecurityUtils;
+import com.mycompany.myapp.service.dto.AdminUserDTO;
+import com.mycompany.myapp.service.dto.UserDTO;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.*;
+import java.util.stream.Collectors;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.cache.CacheManager;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import tech.jhipster.security.RandomUtil;
+
+/**
+ * Service class for managing users.
+ */
+@Service
+@Transactional
+public class UserService {
+
+ private final Logger log = LoggerFactory.getLogger(UserService.class);
+
+ private final UserRepository userRepository;
+
+ private final PasswordEncoder passwordEncoder;
+
+ private final AuthorityRepository authorityRepository;
+
+ private final CacheManager cacheManager;
+
+ public UserService(
+ UserRepository userRepository,
+ PasswordEncoder passwordEncoder,
+ AuthorityRepository authorityRepository,
+ CacheManager cacheManager
+ ) {
+ this.userRepository = userRepository;
+ this.passwordEncoder = passwordEncoder;
+ this.authorityRepository = authorityRepository;
+ this.cacheManager = cacheManager;
+ }
+
+ public Optional activateRegistration(String key) {
+ log.debug("Activating user for activation key {}", key);
+ return userRepository
+ .findOneByActivationKey(key)
+ .map(user -> {
+ // activate given user for the registration key.
+ user.setActivated(true);
+ user.setActivationKey(null);
+ this.clearUserCaches(user);
+ log.debug("Activated user: {}", user);
+ return user;
+ });
+ }
+
+ public Optional completePasswordReset(String newPassword, String key) {
+ log.debug("Reset user password for reset key {}", key);
+ return userRepository
+ .findOneByResetKey(key)
+ .filter(user -> user.getResetDate().isAfter(Instant.now().minus(1, ChronoUnit.DAYS)))
+ .map(user -> {
+ user.setPassword(passwordEncoder.encode(newPassword));
+ user.setResetKey(null);
+ user.setResetDate(null);
+ this.clearUserCaches(user);
+ return user;
+ });
+ }
+
+ public Optional requestPasswordReset(String mail) {
+ return userRepository
+ .findOneByEmailIgnoreCase(mail)
+ .filter(User::isActivated)
+ .map(user -> {
+ user.setResetKey(RandomUtil.generateResetKey());
+ user.setResetDate(Instant.now());
+ this.clearUserCaches(user);
+ return user;
+ });
+ }
+
+ public User registerUser(AdminUserDTO userDTO, String password) {
+ userRepository
+ .findOneByLogin(userDTO.getLogin().toLowerCase())
+ .ifPresent(existingUser -> {
+ boolean removed = removeNonActivatedUser(existingUser);
+ if (!removed) {
+ throw new UsernameAlreadyUsedException();
+ }
+ });
+ userRepository
+ .findOneByEmailIgnoreCase(userDTO.getEmail())
+ .ifPresent(existingUser -> {
+ boolean removed = removeNonActivatedUser(existingUser);
+ if (!removed) {
+ throw new EmailAlreadyUsedException();
+ }
+ });
+ User newUser = new User();
+ String encryptedPassword = passwordEncoder.encode(password);
+ newUser.setLogin(userDTO.getLogin().toLowerCase());
+ // new user gets initially a generated password
+ newUser.setPassword(encryptedPassword);
+ newUser.setFirstName(userDTO.getFirstName());
+ newUser.setLastName(userDTO.getLastName());
+ if (userDTO.getEmail() != null) {
+ newUser.setEmail(userDTO.getEmail().toLowerCase());
+ }
+ newUser.setImageUrl(userDTO.getImageUrl());
+ newUser.setLangKey(userDTO.getLangKey());
+ // new user is not active
+ newUser.setActivated(false);
+ // new user gets registration key
+ newUser.setActivationKey(RandomUtil.generateActivationKey());
+ Set authorities = new HashSet<>();
+ authorityRepository.findById(AuthoritiesConstants.USER).ifPresent(authorities::add);
+ newUser.setAuthorities(authorities);
+ userRepository.save(newUser);
+ this.clearUserCaches(newUser);
+ log.debug("Created Information for User: {}", newUser);
+ return newUser;
+ }
+
+ private boolean removeNonActivatedUser(User existingUser) {
+ if (existingUser.isActivated()) {
+ return false;
+ }
+ userRepository.delete(existingUser);
+ userRepository.flush();
+ this.clearUserCaches(existingUser);
+ return true;
+ }
+
+ public User createUser(AdminUserDTO userDTO) {
+ User user = new User();
+ user.setLogin(userDTO.getLogin().toLowerCase());
+ user.setFirstName(userDTO.getFirstName());
+ user.setLastName(userDTO.getLastName());
+ if (userDTO.getEmail() != null) {
+ user.setEmail(userDTO.getEmail().toLowerCase());
+ }
+ user.setImageUrl(userDTO.getImageUrl());
+ if (userDTO.getLangKey() == null) {
+ user.setLangKey(Constants.DEFAULT_LANGUAGE); // default language
+ } else {
+ user.setLangKey(userDTO.getLangKey());
+ }
+ String encryptedPassword = passwordEncoder.encode(RandomUtil.generatePassword());
+ user.setPassword(encryptedPassword);
+ user.setResetKey(RandomUtil.generateResetKey());
+ user.setResetDate(Instant.now());
+ user.setActivated(true);
+ if (userDTO.getAuthorities() != null) {
+ Set authorities = userDTO
+ .getAuthorities()
+ .stream()
+ .map(authorityRepository::findById)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .collect(Collectors.toSet());
+ user.setAuthorities(authorities);
+ }
+ userRepository.save(user);
+ this.clearUserCaches(user);
+ log.debug("Created Information for User: {}", user);
+ return user;
+ }
+
+ /**
+ * Update all information for a specific user, and return the modified user.
+ *
+ * @param userDTO user to update.
+ * @return updated user.
+ */
+ public Optional updateUser(AdminUserDTO userDTO) {
+ return Optional
+ .of(userRepository.findById(userDTO.getId()))
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .map(user -> {
+ this.clearUserCaches(user);
+ user.setLogin(userDTO.getLogin().toLowerCase());
+ user.setFirstName(userDTO.getFirstName());
+ user.setLastName(userDTO.getLastName());
+ if (userDTO.getEmail() != null) {
+ user.setEmail(userDTO.getEmail().toLowerCase());
+ }
+ user.setImageUrl(userDTO.getImageUrl());
+ user.setActivated(userDTO.isActivated());
+ user.setLangKey(userDTO.getLangKey());
+ Set managedAuthorities = user.getAuthorities();
+ managedAuthorities.clear();
+ userDTO
+ .getAuthorities()
+ .stream()
+ .map(authorityRepository::findById)
+ .filter(Optional::isPresent)
+ .map(Optional::get)
+ .forEach(managedAuthorities::add);
+ this.clearUserCaches(user);
+ log.debug("Changed Information for User: {}", user);
+ return user;
+ })
+ .map(AdminUserDTO::new);
+ }
+
+ public void deleteUser(String login) {
+ userRepository
+ .findOneByLogin(login)
+ .ifPresent(user -> {
+ userRepository.delete(user);
+ this.clearUserCaches(user);
+ log.debug("Deleted User: {}", user);
+ });
+ }
+
+ /**
+ * Update basic information (first name, last name, email, language) for the current user.
+ *
+ * @param firstName first name of user.
+ * @param lastName last name of user.
+ * @param email email id of user.
+ * @param langKey language key.
+ * @param imageUrl image URL of user.
+ */
+ public void updateUser(String firstName, String lastName, String email, String langKey, String imageUrl) {
+ SecurityUtils
+ .getCurrentUserLogin()
+ .flatMap(userRepository::findOneByLogin)
+ .ifPresent(user -> {
+ user.setFirstName(firstName);
+ user.setLastName(lastName);
+ if (email != null) {
+ user.setEmail(email.toLowerCase());
+ }
+ user.setLangKey(langKey);
+ user.setImageUrl(imageUrl);
+ this.clearUserCaches(user);
+ log.debug("Changed Information for User: {}", user);
+ });
+ }
+
+ @Transactional
+ public void changePassword(String currentClearTextPassword, String newPassword) {
+ SecurityUtils
+ .getCurrentUserLogin()
+ .flatMap(userRepository::findOneByLogin)
+ .ifPresent(user -> {
+ String currentEncryptedPassword = user.getPassword();
+ if (!passwordEncoder.matches(currentClearTextPassword, currentEncryptedPassword)) {
+ throw new InvalidPasswordException();
+ }
+ String encryptedPassword = passwordEncoder.encode(newPassword);
+ user.setPassword(encryptedPassword);
+ this.clearUserCaches(user);
+ log.debug("Changed password for User: {}", user);
+ });
+ }
+
+ @Transactional(readOnly = true)
+ public Page getAllManagedUsers(Pageable pageable) {
+ return userRepository.findAll(pageable).map(AdminUserDTO::new);
+ }
+
+ @Transactional(readOnly = true)
+ public Page getAllPublicUsers(Pageable pageable) {
+ return userRepository.findAllByIdNotNullAndActivatedIsTrue(pageable).map(UserDTO::new);
+ }
+
+ @Transactional(readOnly = true)
+ public Optional getUserWithAuthoritiesByLogin(String login) {
+ return userRepository.findOneWithAuthoritiesByLogin(login);
+ }
+
+ @Transactional(readOnly = true)
+ public Optional getUserWithAuthorities() {
+ return SecurityUtils.getCurrentUserLogin().flatMap(userRepository::findOneWithAuthoritiesByLogin);
+ }
+
+ /**
+ * Not activated users should be automatically deleted after 3 days.
+ *
+ * This is scheduled to get fired everyday, at 01:00 (am).
+ */
+ @Scheduled(cron = "0 0 1 * * ?")
+ public void removeNotActivatedUsers() {
+ userRepository
+ .findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(Instant.now().minus(3, ChronoUnit.DAYS))
+ .forEach(user -> {
+ log.debug("Deleting not activated user {}", user.getLogin());
+ userRepository.delete(user);
+ this.clearUserCaches(user);
+ });
+ }
+
+ /**
+ * Gets a list of all the authorities.
+ * @return a list of all the authorities.
+ */
+ @Transactional(readOnly = true)
+ public List getAuthorities() {
+ return authorityRepository.findAll().stream().map(Authority::getName).collect(Collectors.toList());
+ }
+
+ private void clearUserCaches(User user) {
+ Objects.requireNonNull(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE)).evict(user.getLogin());
+ if (user.getEmail() != null) {
+ Objects.requireNonNull(cacheManager.getCache(UserRepository.USERS_BY_EMAIL_CACHE)).evict(user.getEmail());
+ }
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/UsernameAlreadyUsedException.java b/myApp/src/main/java/com/mycompany/myapp/service/UsernameAlreadyUsedException.java
new file mode 100644
index 000000000..4b9005bc7
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/UsernameAlreadyUsedException.java
@@ -0,0 +1,10 @@
+package com.mycompany.myapp.service;
+
+public class UsernameAlreadyUsedException extends RuntimeException {
+
+ private static final long serialVersionUID = 1L;
+
+ public UsernameAlreadyUsedException() {
+ super("Login name already used!");
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/dto/AdminUserDTO.java b/myApp/src/main/java/com/mycompany/myapp/service/dto/AdminUserDTO.java
new file mode 100644
index 000000000..bfb175e61
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/dto/AdminUserDTO.java
@@ -0,0 +1,193 @@
+package com.mycompany.myapp.service.dto;
+
+import com.mycompany.myapp.config.Constants;
+import com.mycompany.myapp.domain.Authority;
+import com.mycompany.myapp.domain.User;
+import java.time.Instant;
+import java.util.Set;
+import java.util.stream.Collectors;
+import javax.validation.constraints.*;
+
+/**
+ * A DTO representing a user, with his authorities.
+ */
+public class AdminUserDTO {
+
+ private Long id;
+
+ @NotBlank
+ @Pattern(regexp = Constants.LOGIN_REGEX)
+ @Size(min = 1, max = 50)
+ private String login;
+
+ @Size(max = 50)
+ private String firstName;
+
+ @Size(max = 50)
+ private String lastName;
+
+ @Email
+ @Size(min = 5, max = 254)
+ private String email;
+
+ @Size(max = 256)
+ private String imageUrl;
+
+ private boolean activated = false;
+
+ @Size(min = 2, max = 10)
+ private String langKey;
+
+ private String createdBy;
+
+ private Instant createdDate;
+
+ private String lastModifiedBy;
+
+ private Instant lastModifiedDate;
+
+ private Set authorities;
+
+ public AdminUserDTO() {
+ // Empty constructor needed for Jackson.
+ }
+
+ public AdminUserDTO(User user) {
+ this.id = user.getId();
+ this.login = user.getLogin();
+ this.firstName = user.getFirstName();
+ this.lastName = user.getLastName();
+ this.email = user.getEmail();
+ this.activated = user.isActivated();
+ this.imageUrl = user.getImageUrl();
+ this.langKey = user.getLangKey();
+ this.createdBy = user.getCreatedBy();
+ this.createdDate = user.getCreatedDate();
+ this.lastModifiedBy = user.getLastModifiedBy();
+ this.lastModifiedDate = user.getLastModifiedDate();
+ this.authorities = user.getAuthorities().stream().map(Authority::getName).collect(Collectors.toSet());
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ public void setLogin(String login) {
+ this.login = login;
+ }
+
+ public String getFirstName() {
+ return firstName;
+ }
+
+ public void setFirstName(String firstName) {
+ this.firstName = firstName;
+ }
+
+ public String getLastName() {
+ return lastName;
+ }
+
+ public void setLastName(String lastName) {
+ this.lastName = lastName;
+ }
+
+ public String getEmail() {
+ return email;
+ }
+
+ public void setEmail(String email) {
+ this.email = email;
+ }
+
+ public String getImageUrl() {
+ return imageUrl;
+ }
+
+ public void setImageUrl(String imageUrl) {
+ this.imageUrl = imageUrl;
+ }
+
+ public boolean isActivated() {
+ return activated;
+ }
+
+ public void setActivated(boolean activated) {
+ this.activated = activated;
+ }
+
+ public String getLangKey() {
+ return langKey;
+ }
+
+ public void setLangKey(String langKey) {
+ this.langKey = langKey;
+ }
+
+ public String getCreatedBy() {
+ return createdBy;
+ }
+
+ public void setCreatedBy(String createdBy) {
+ this.createdBy = createdBy;
+ }
+
+ public Instant getCreatedDate() {
+ return createdDate;
+ }
+
+ public void setCreatedDate(Instant createdDate) {
+ this.createdDate = createdDate;
+ }
+
+ public String getLastModifiedBy() {
+ return lastModifiedBy;
+ }
+
+ public void setLastModifiedBy(String lastModifiedBy) {
+ this.lastModifiedBy = lastModifiedBy;
+ }
+
+ public Instant getLastModifiedDate() {
+ return lastModifiedDate;
+ }
+
+ public void setLastModifiedDate(Instant lastModifiedDate) {
+ this.lastModifiedDate = lastModifiedDate;
+ }
+
+ public Set getAuthorities() {
+ return authorities;
+ }
+
+ public void setAuthorities(Set authorities) {
+ this.authorities = authorities;
+ }
+
+ // prettier-ignore
+ @Override
+ public String toString() {
+ return "AdminUserDTO{" +
+ "login='" + login + '\'' +
+ ", firstName='" + firstName + '\'' +
+ ", lastName='" + lastName + '\'' +
+ ", email='" + email + '\'' +
+ ", imageUrl='" + imageUrl + '\'' +
+ ", activated=" + activated +
+ ", langKey='" + langKey + '\'' +
+ ", createdBy=" + createdBy +
+ ", createdDate=" + createdDate +
+ ", lastModifiedBy='" + lastModifiedBy + '\'' +
+ ", lastModifiedDate=" + lastModifiedDate +
+ ", authorities=" + authorities +
+ "}";
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/dto/PasswordChangeDTO.java b/myApp/src/main/java/com/mycompany/myapp/service/dto/PasswordChangeDTO.java
new file mode 100644
index 000000000..cc49c0d04
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/dto/PasswordChangeDTO.java
@@ -0,0 +1,35 @@
+package com.mycompany.myapp.service.dto;
+
+/**
+ * A DTO representing a password change required data - current and new password.
+ */
+public class PasswordChangeDTO {
+
+ private String currentPassword;
+ private String newPassword;
+
+ public PasswordChangeDTO() {
+ // Empty constructor needed for Jackson.
+ }
+
+ public PasswordChangeDTO(String currentPassword, String newPassword) {
+ this.currentPassword = currentPassword;
+ this.newPassword = newPassword;
+ }
+
+ public String getCurrentPassword() {
+ return currentPassword;
+ }
+
+ public void setCurrentPassword(String currentPassword) {
+ this.currentPassword = currentPassword;
+ }
+
+ public String getNewPassword() {
+ return newPassword;
+ }
+
+ public void setNewPassword(String newPassword) {
+ this.newPassword = newPassword;
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/dto/UserDTO.java b/myApp/src/main/java/com/mycompany/myapp/service/dto/UserDTO.java
new file mode 100644
index 000000000..4a2d62955
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/dto/UserDTO.java
@@ -0,0 +1,48 @@
+package com.mycompany.myapp.service.dto;
+
+import com.mycompany.myapp.domain.User;
+
+/**
+ * A DTO representing a user, with only the public attributes.
+ */
+public class UserDTO {
+
+ private Long id;
+
+ private String login;
+
+ public UserDTO() {
+ // Empty constructor needed for Jackson.
+ }
+
+ public UserDTO(User user) {
+ this.id = user.getId();
+ // Customize it here if you need, or not, firstName/lastName/etc
+ this.login = user.getLogin();
+ }
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ public void setLogin(String login) {
+ this.login = login;
+ }
+
+ // prettier-ignore
+ @Override
+ public String toString() {
+ return "UserDTO{" +
+ "id='" + id + '\'' +
+ ", login='" + login + '\'' +
+ "}";
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/dto/package-info.java b/myApp/src/main/java/com/mycompany/myapp/service/dto/package-info.java
new file mode 100644
index 000000000..439e686ac
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/dto/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Data Transfer Objects.
+ */
+package com.mycompany.myapp.service.dto;
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/mapper/UserMapper.java b/myApp/src/main/java/com/mycompany/myapp/service/mapper/UserMapper.java
new file mode 100644
index 000000000..6fe5b0cc5
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/mapper/UserMapper.java
@@ -0,0 +1,147 @@
+package com.mycompany.myapp.service.mapper;
+
+import com.mycompany.myapp.domain.Authority;
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.service.dto.AdminUserDTO;
+import com.mycompany.myapp.service.dto.UserDTO;
+import java.util.*;
+import java.util.stream.Collectors;
+import org.mapstruct.BeanMapping;
+import org.mapstruct.Mapping;
+import org.mapstruct.Named;
+import org.springframework.stereotype.Service;
+
+/**
+ * Mapper for the entity {@link User} and its DTO called {@link UserDTO}.
+ *
+ * Normal mappers are generated using MapStruct, this one is hand-coded as MapStruct
+ * support is still in beta, and requires a manual step with an IDE.
+ */
+@Service
+public class UserMapper {
+
+ public List usersToUserDTOs(List users) {
+ return users.stream().filter(Objects::nonNull).map(this::userToUserDTO).collect(Collectors.toList());
+ }
+
+ public UserDTO userToUserDTO(User user) {
+ return new UserDTO(user);
+ }
+
+ public List usersToAdminUserDTOs(List users) {
+ return users.stream().filter(Objects::nonNull).map(this::userToAdminUserDTO).collect(Collectors.toList());
+ }
+
+ public AdminUserDTO userToAdminUserDTO(User user) {
+ return new AdminUserDTO(user);
+ }
+
+ public List userDTOsToUsers(List userDTOs) {
+ return userDTOs.stream().filter(Objects::nonNull).map(this::userDTOToUser).collect(Collectors.toList());
+ }
+
+ public User userDTOToUser(AdminUserDTO userDTO) {
+ if (userDTO == null) {
+ return null;
+ } else {
+ User user = new User();
+ user.setId(userDTO.getId());
+ user.setLogin(userDTO.getLogin());
+ user.setFirstName(userDTO.getFirstName());
+ user.setLastName(userDTO.getLastName());
+ user.setEmail(userDTO.getEmail());
+ user.setImageUrl(userDTO.getImageUrl());
+ user.setActivated(userDTO.isActivated());
+ user.setLangKey(userDTO.getLangKey());
+ Set authorities = this.authoritiesFromStrings(userDTO.getAuthorities());
+ user.setAuthorities(authorities);
+ return user;
+ }
+ }
+
+ private Set authoritiesFromStrings(Set authoritiesAsString) {
+ Set authorities = new HashSet<>();
+
+ if (authoritiesAsString != null) {
+ authorities =
+ authoritiesAsString
+ .stream()
+ .map(string -> {
+ Authority auth = new Authority();
+ auth.setName(string);
+ return auth;
+ })
+ .collect(Collectors.toSet());
+ }
+
+ return authorities;
+ }
+
+ public User userFromId(Long id) {
+ if (id == null) {
+ return null;
+ }
+ User user = new User();
+ user.setId(id);
+ return user;
+ }
+
+ @Named("id")
+ @BeanMapping(ignoreByDefault = true)
+ @Mapping(target = "id", source = "id")
+ public UserDTO toDtoId(User user) {
+ if (user == null) {
+ return null;
+ }
+ UserDTO userDto = new UserDTO();
+ userDto.setId(user.getId());
+ return userDto;
+ }
+
+ @Named("idSet")
+ @BeanMapping(ignoreByDefault = true)
+ @Mapping(target = "id", source = "id")
+ public Set toDtoIdSet(Set users) {
+ if (users == null) {
+ return Collections.emptySet();
+ }
+
+ Set userSet = new HashSet<>();
+ for (User userEntity : users) {
+ userSet.add(this.toDtoId(userEntity));
+ }
+
+ return userSet;
+ }
+
+ @Named("login")
+ @BeanMapping(ignoreByDefault = true)
+ @Mapping(target = "id", source = "id")
+ @Mapping(target = "login", source = "login")
+ public UserDTO toDtoLogin(User user) {
+ if (user == null) {
+ return null;
+ }
+ UserDTO userDto = new UserDTO();
+ userDto.setId(user.getId());
+ userDto.setLogin(user.getLogin());
+ return userDto;
+ }
+
+ @Named("loginSet")
+ @BeanMapping(ignoreByDefault = true)
+ @Mapping(target = "id", source = "id")
+ @Mapping(target = "login", source = "login")
+ public Set toDtoLoginSet(Set users) {
+ if (users == null) {
+ return Collections.emptySet();
+ }
+
+ Set userSet = new HashSet<>();
+ for (User userEntity : users) {
+ userSet.add(this.toDtoLogin(userEntity));
+ }
+
+ return userSet;
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/mapper/package-info.java b/myApp/src/main/java/com/mycompany/myapp/service/mapper/package-info.java
new file mode 100644
index 000000000..c19a35c99
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/mapper/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * MapStruct mappers for mapping domain objects and Data Transfer Objects.
+ */
+package com.mycompany.myapp.service.mapper;
diff --git a/myApp/src/main/java/com/mycompany/myapp/service/package-info.java b/myApp/src/main/java/com/mycompany/myapp/service/package-info.java
new file mode 100644
index 000000000..57474e2a7
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/service/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Service layer beans.
+ */
+package com.mycompany.myapp.service;
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/AccountResource.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/AccountResource.java
new file mode 100644
index 000000000..8b8e013c6
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/AccountResource.java
@@ -0,0 +1,194 @@
+package com.mycompany.myapp.web.rest;
+
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.UserRepository;
+import com.mycompany.myapp.security.SecurityUtils;
+import com.mycompany.myapp.service.MailService;
+import com.mycompany.myapp.service.UserService;
+import com.mycompany.myapp.service.dto.AdminUserDTO;
+import com.mycompany.myapp.service.dto.PasswordChangeDTO;
+import com.mycompany.myapp.web.rest.errors.*;
+import com.mycompany.myapp.web.rest.vm.KeyAndPasswordVM;
+import com.mycompany.myapp.web.rest.vm.ManagedUserVM;
+import java.util.*;
+import javax.servlet.http.HttpServletRequest;
+import javax.validation.Valid;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * REST controller for managing the current user's account.
+ */
+@RestController
+@RequestMapping("/api")
+public class AccountResource {
+
+ private static class AccountResourceException extends RuntimeException {
+
+ private AccountResourceException(String message) {
+ super(message);
+ }
+ }
+
+ private final Logger log = LoggerFactory.getLogger(AccountResource.class);
+
+ private final UserRepository userRepository;
+
+ private final UserService userService;
+
+ private final MailService mailService;
+
+ public AccountResource(UserRepository userRepository, UserService userService, MailService mailService) {
+ this.userRepository = userRepository;
+ this.userService = userService;
+ this.mailService = mailService;
+ }
+
+ /**
+ * {@code POST /register} : register the user.
+ *
+ * @param managedUserVM the managed user View Model.
+ * @throws InvalidPasswordException {@code 400 (Bad Request)} if the password is incorrect.
+ * @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already used.
+ * @throws LoginAlreadyUsedException {@code 400 (Bad Request)} if the login is already used.
+ */
+ @PostMapping("/register")
+ @ResponseStatus(HttpStatus.CREATED)
+ public void registerAccount(@Valid @RequestBody ManagedUserVM managedUserVM) {
+ if (isPasswordLengthInvalid(managedUserVM.getPassword())) {
+ throw new InvalidPasswordException();
+ }
+ User user = userService.registerUser(managedUserVM, managedUserVM.getPassword());
+ mailService.sendActivationEmail(user);
+ }
+
+ /**
+ * {@code GET /activate} : activate the registered user.
+ *
+ * @param key the activation key.
+ * @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be activated.
+ */
+ @GetMapping("/activate")
+ public void activateAccount(@RequestParam(value = "key") String key) {
+ Optional user = userService.activateRegistration(key);
+ if (!user.isPresent()) {
+ throw new AccountResourceException("No user was found for this activation key");
+ }
+ }
+
+ /**
+ * {@code GET /authenticate} : check if the user is authenticated, and return its login.
+ *
+ * @param request the HTTP request.
+ * @return the login if the user is authenticated.
+ */
+ @GetMapping("/authenticate")
+ public String isAuthenticated(HttpServletRequest request) {
+ log.debug("REST request to check if the current user is authenticated");
+ return request.getRemoteUser();
+ }
+
+ /**
+ * {@code GET /account} : get the current user.
+ *
+ * @return the current user.
+ * @throws RuntimeException {@code 500 (Internal Server Error)} if the user couldn't be returned.
+ */
+ @GetMapping("/account")
+ public AdminUserDTO getAccount() {
+ return userService
+ .getUserWithAuthorities()
+ .map(AdminUserDTO::new)
+ .orElseThrow(() -> new AccountResourceException("User could not be found"));
+ }
+
+ /**
+ * {@code POST /account} : update the current user information.
+ *
+ * @param userDTO the current user information.
+ * @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already used.
+ * @throws RuntimeException {@code 500 (Internal Server Error)} if the user login wasn't found.
+ */
+ @PostMapping("/account")
+ public void saveAccount(@Valid @RequestBody AdminUserDTO userDTO) {
+ String userLogin = SecurityUtils
+ .getCurrentUserLogin()
+ .orElseThrow(() -> new AccountResourceException("Current user login not found"));
+ Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail());
+ if (existingUser.isPresent() && (!existingUser.get().getLogin().equalsIgnoreCase(userLogin))) {
+ throw new EmailAlreadyUsedException();
+ }
+ Optional user = userRepository.findOneByLogin(userLogin);
+ if (!user.isPresent()) {
+ throw new AccountResourceException("User could not be found");
+ }
+ userService.updateUser(
+ userDTO.getFirstName(),
+ userDTO.getLastName(),
+ userDTO.getEmail(),
+ userDTO.getLangKey(),
+ userDTO.getImageUrl()
+ );
+ }
+
+ /**
+ * {@code POST /account/change-password} : changes the current user's password.
+ *
+ * @param passwordChangeDto current and new password.
+ * @throws InvalidPasswordException {@code 400 (Bad Request)} if the new password is incorrect.
+ */
+ @PostMapping(path = "/account/change-password")
+ public void changePassword(@RequestBody PasswordChangeDTO passwordChangeDto) {
+ if (isPasswordLengthInvalid(passwordChangeDto.getNewPassword())) {
+ throw new InvalidPasswordException();
+ }
+ userService.changePassword(passwordChangeDto.getCurrentPassword(), passwordChangeDto.getNewPassword());
+ }
+
+ /**
+ * {@code POST /account/reset-password/init} : Send an email to reset the password of the user.
+ *
+ * @param mail the mail of the user.
+ */
+ @PostMapping(path = "/account/reset-password/init")
+ public void requestPasswordReset(@RequestBody String mail) {
+ Optional user = userService.requestPasswordReset(mail);
+ if (user.isPresent()) {
+ mailService.sendPasswordResetMail(user.get());
+ } else {
+ // Pretend the request has been successful to prevent checking which emails really exist
+ // but log that an invalid attempt has been made
+ log.warn("Password reset requested for non existing mail");
+ }
+ }
+
+ /**
+ * {@code POST /account/reset-password/finish} : Finish to reset the password of the user.
+ *
+ * @param keyAndPassword the generated key and the new password.
+ * @throws InvalidPasswordException {@code 400 (Bad Request)} if the password is incorrect.
+ * @throws RuntimeException {@code 500 (Internal Server Error)} if the password could not be reset.
+ */
+ @PostMapping(path = "/account/reset-password/finish")
+ public void finishPasswordReset(@RequestBody KeyAndPasswordVM keyAndPassword) {
+ if (isPasswordLengthInvalid(keyAndPassword.getNewPassword())) {
+ throw new InvalidPasswordException();
+ }
+ Optional user = userService.completePasswordReset(keyAndPassword.getNewPassword(), keyAndPassword.getKey());
+
+ if (!user.isPresent()) {
+ throw new AccountResourceException("No user was found for this reset key");
+ }
+ }
+
+ private static boolean isPasswordLengthInvalid(String password) {
+ return (
+ StringUtils.isEmpty(password) ||
+ password.length() < ManagedUserVM.PASSWORD_MIN_LENGTH ||
+ password.length() > ManagedUserVM.PASSWORD_MAX_LENGTH
+ );
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/ClientForwardController.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/ClientForwardController.java
new file mode 100644
index 000000000..9744da0bb
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/ClientForwardController.java
@@ -0,0 +1,17 @@
+package com.mycompany.myapp.web.rest;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+@Controller
+public class ClientForwardController {
+
+ /**
+ * Forwards any unmapped paths (except those containing a period) to the client {@code index.html}.
+ * @return forward to client {@code index.html}.
+ */
+ @GetMapping(value = "/**/{path:[^\\.]*}")
+ public String forward() {
+ return "forward:/";
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/PublicUserResource.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/PublicUserResource.java
new file mode 100644
index 000000000..cf575ed48
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/PublicUserResource.java
@@ -0,0 +1,65 @@
+package com.mycompany.myapp.web.rest;
+
+import com.mycompany.myapp.service.UserService;
+import com.mycompany.myapp.service.dto.UserDTO;
+import java.util.*;
+import java.util.Collections;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+import tech.jhipster.web.util.PaginationUtil;
+
+@RestController
+@RequestMapping("/api")
+public class PublicUserResource {
+
+ private static final List ALLOWED_ORDERED_PROPERTIES = Collections.unmodifiableList(
+ Arrays.asList("id", "login", "firstName", "lastName", "email", "activated", "langKey")
+ );
+
+ private final Logger log = LoggerFactory.getLogger(PublicUserResource.class);
+
+ private final UserService userService;
+
+ public PublicUserResource(UserService userService) {
+ this.userService = userService;
+ }
+
+ /**
+ * {@code GET /users} : get all users with only the public informations - calling this are allowed for anyone.
+ *
+ * @param pageable the pagination information.
+ * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body all users.
+ */
+ @GetMapping("/users")
+ public ResponseEntity> getAllPublicUsers(@org.springdoc.api.annotations.ParameterObject Pageable pageable) {
+ log.debug("REST request to get all public User names");
+ if (!onlyContainsAllowedProperties(pageable)) {
+ return ResponseEntity.badRequest().build();
+ }
+
+ final Page page = userService.getAllPublicUsers(pageable);
+ HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page);
+ return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
+ }
+
+ private boolean onlyContainsAllowedProperties(Pageable pageable) {
+ return pageable.getSort().stream().map(Sort.Order::getProperty).allMatch(ALLOWED_ORDERED_PROPERTIES::contains);
+ }
+
+ /**
+ * Gets a list of all roles.
+ * @return a string list of all roles.
+ */
+ @GetMapping("/authorities")
+ public List getAuthorities() {
+ return userService.getAuthorities();
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/UserJWTController.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/UserJWTController.java
new file mode 100644
index 000000000..fd921f0b1
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/UserJWTController.java
@@ -0,0 +1,68 @@
+package com.mycompany.myapp.web.rest;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+import com.mycompany.myapp.security.jwt.JWTFilter;
+import com.mycompany.myapp.security.jwt.TokenProvider;
+import com.mycompany.myapp.web.rest.vm.LoginVM;
+import javax.validation.Valid;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * Controller to authenticate users.
+ */
+@RestController
+@RequestMapping("/api")
+public class UserJWTController {
+
+ private final TokenProvider tokenProvider;
+
+ private final AuthenticationManagerBuilder authenticationManagerBuilder;
+
+ public UserJWTController(TokenProvider tokenProvider, AuthenticationManagerBuilder authenticationManagerBuilder) {
+ this.tokenProvider = tokenProvider;
+ this.authenticationManagerBuilder = authenticationManagerBuilder;
+ }
+
+ @PostMapping("/authenticate")
+ public ResponseEntity authorize(@Valid @RequestBody LoginVM loginVM) {
+ UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(
+ loginVM.getUsername(),
+ loginVM.getPassword()
+ );
+
+ Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
+ SecurityContextHolder.getContext().setAuthentication(authentication);
+ String jwt = tokenProvider.createToken(authentication, loginVM.isRememberMe());
+ HttpHeaders httpHeaders = new HttpHeaders();
+ httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt);
+ return new ResponseEntity<>(new JWTToken(jwt), httpHeaders, HttpStatus.OK);
+ }
+
+ /**
+ * Object to return as body in JWT Authentication.
+ */
+ static class JWTToken {
+
+ private String idToken;
+
+ JWTToken(String idToken) {
+ this.idToken = idToken;
+ }
+
+ @JsonProperty("id_token")
+ String getIdToken() {
+ return idToken;
+ }
+
+ void setIdToken(String idToken) {
+ this.idToken = idToken;
+ }
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/UserResource.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/UserResource.java
new file mode 100644
index 000000000..b8f199e47
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/UserResource.java
@@ -0,0 +1,207 @@
+package com.mycompany.myapp.web.rest;
+
+import com.mycompany.myapp.config.Constants;
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.UserRepository;
+import com.mycompany.myapp.security.AuthoritiesConstants;
+import com.mycompany.myapp.service.MailService;
+import com.mycompany.myapp.service.UserService;
+import com.mycompany.myapp.service.dto.AdminUserDTO;
+import com.mycompany.myapp.web.rest.errors.BadRequestAlertException;
+import com.mycompany.myapp.web.rest.errors.EmailAlreadyUsedException;
+import com.mycompany.myapp.web.rest.errors.LoginAlreadyUsedException;
+import java.net.URI;
+import java.net.URISyntaxException;
+import java.util.*;
+import java.util.Collections;
+import javax.validation.Valid;
+import javax.validation.constraints.Pattern;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.domain.Sort;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
+import tech.jhipster.web.util.HeaderUtil;
+import tech.jhipster.web.util.PaginationUtil;
+import tech.jhipster.web.util.ResponseUtil;
+
+/**
+ * REST controller for managing users.
+ *
+ * This class accesses the {@link User} entity, and needs to fetch its collection of authorities.
+ *
+ * For a normal use-case, it would be better to have an eager relationship between User and Authority,
+ * and send everything to the client side: there would be no View Model and DTO, a lot less code, and an outer-join
+ * which would be good for performance.
+ *
+ * We use a View Model and a DTO for 3 reasons:
+ *
+ * We want to keep a lazy association between the user and the authorities, because people will
+ * quite often do relationships with the user, and we don't want them to get the authorities all
+ * the time for nothing (for performance reasons). This is the #1 goal: we should not impact our users'
+ * application because of this use-case.
+ * Not having an outer join causes n+1 requests to the database. This is not a real issue as
+ * we have by default a second-level cache. This means on the first HTTP call we do the n+1 requests,
+ * but then all authorities come from the cache, so in fact it's much better than doing an outer join
+ * (which will get lots of data from the database, for each HTTP call).
+ * As this manages users, for security reasons, we'd rather have a DTO layer.
+ *
+ *
+ * Another option would be to have a specific JPA entity graph to handle this case.
+ */
+@RestController
+@RequestMapping("/api/admin")
+public class UserResource {
+
+ private static final List ALLOWED_ORDERED_PROPERTIES = Collections.unmodifiableList(
+ Arrays.asList(
+ "id",
+ "login",
+ "firstName",
+ "lastName",
+ "email",
+ "activated",
+ "langKey",
+ "createdBy",
+ "createdDate",
+ "lastModifiedBy",
+ "lastModifiedDate"
+ )
+ );
+
+ private final Logger log = LoggerFactory.getLogger(UserResource.class);
+
+ @Value("${jhipster.clientApp.name}")
+ private String applicationName;
+
+ private final UserService userService;
+
+ private final UserRepository userRepository;
+
+ private final MailService mailService;
+
+ public UserResource(UserService userService, UserRepository userRepository, MailService mailService) {
+ this.userService = userService;
+ this.userRepository = userRepository;
+ this.mailService = mailService;
+ }
+
+ /**
+ * {@code POST /admin/users} : Creates a new user.
+ *
+ * Creates a new user if the login and email are not already used, and sends an
+ * mail with an activation link.
+ * The user needs to be activated on creation.
+ *
+ * @param userDTO the user to create.
+ * @return the {@link ResponseEntity} with status {@code 201 (Created)} and with body the new user, or with status {@code 400 (Bad Request)} if the login or email is already in use.
+ * @throws URISyntaxException if the Location URI syntax is incorrect.
+ * @throws BadRequestAlertException {@code 400 (Bad Request)} if the login or email is already in use.
+ */
+ @PostMapping("/users")
+ @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
+ public ResponseEntity createUser(@Valid @RequestBody AdminUserDTO userDTO) throws URISyntaxException {
+ log.debug("REST request to save User : {}", userDTO);
+
+ if (userDTO.getId() != null) {
+ throw new BadRequestAlertException("A new user cannot already have an ID", "userManagement", "idexists");
+ // Lowercase the user login before comparing with database
+ } else if (userRepository.findOneByLogin(userDTO.getLogin().toLowerCase()).isPresent()) {
+ throw new LoginAlreadyUsedException();
+ } else if (userRepository.findOneByEmailIgnoreCase(userDTO.getEmail()).isPresent()) {
+ throw new EmailAlreadyUsedException();
+ } else {
+ User newUser = userService.createUser(userDTO);
+ mailService.sendCreationEmail(newUser);
+ return ResponseEntity
+ .created(new URI("/api/admin/users/" + newUser.getLogin()))
+ .headers(HeaderUtil.createAlert(applicationName, "userManagement.created", newUser.getLogin()))
+ .body(newUser);
+ }
+ }
+
+ /**
+ * {@code PUT /admin/users} : Updates an existing User.
+ *
+ * @param userDTO the user to update.
+ * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the updated user.
+ * @throws EmailAlreadyUsedException {@code 400 (Bad Request)} if the email is already in use.
+ * @throws LoginAlreadyUsedException {@code 400 (Bad Request)} if the login is already in use.
+ */
+ @PutMapping("/users")
+ @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
+ public ResponseEntity updateUser(@Valid @RequestBody AdminUserDTO userDTO) {
+ log.debug("REST request to update User : {}", userDTO);
+ Optional existingUser = userRepository.findOneByEmailIgnoreCase(userDTO.getEmail());
+ if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) {
+ throw new EmailAlreadyUsedException();
+ }
+ existingUser = userRepository.findOneByLogin(userDTO.getLogin().toLowerCase());
+ if (existingUser.isPresent() && (!existingUser.get().getId().equals(userDTO.getId()))) {
+ throw new LoginAlreadyUsedException();
+ }
+ Optional updatedUser = userService.updateUser(userDTO);
+
+ return ResponseUtil.wrapOrNotFound(
+ updatedUser,
+ HeaderUtil.createAlert(applicationName, "userManagement.updated", userDTO.getLogin())
+ );
+ }
+
+ /**
+ * {@code GET /admin/users} : get all users with all the details - calling this are only allowed for the administrators.
+ *
+ * @param pageable the pagination information.
+ * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body all users.
+ */
+ @GetMapping("/users")
+ @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
+ public ResponseEntity> getAllUsers(@org.springdoc.api.annotations.ParameterObject Pageable pageable) {
+ log.debug("REST request to get all User for an admin");
+ if (!onlyContainsAllowedProperties(pageable)) {
+ return ResponseEntity.badRequest().build();
+ }
+
+ final Page page = userService.getAllManagedUsers(pageable);
+ HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(ServletUriComponentsBuilder.fromCurrentRequest(), page);
+ return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
+ }
+
+ private boolean onlyContainsAllowedProperties(Pageable pageable) {
+ return pageable.getSort().stream().map(Sort.Order::getProperty).allMatch(ALLOWED_ORDERED_PROPERTIES::contains);
+ }
+
+ /**
+ * {@code GET /admin/users/:login} : get the "login" user.
+ *
+ * @param login the login of the user to find.
+ * @return the {@link ResponseEntity} with status {@code 200 (OK)} and with body the "login" user, or with status {@code 404 (Not Found)}.
+ */
+ @GetMapping("/users/{login}")
+ @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
+ public ResponseEntity getUser(@PathVariable @Pattern(regexp = Constants.LOGIN_REGEX) String login) {
+ log.debug("REST request to get User : {}", login);
+ return ResponseUtil.wrapOrNotFound(userService.getUserWithAuthoritiesByLogin(login).map(AdminUserDTO::new));
+ }
+
+ /**
+ * {@code DELETE /admin/users/:login} : delete the "login" User.
+ *
+ * @param login the login of the user to delete.
+ * @return the {@link ResponseEntity} with status {@code 204 (NO_CONTENT)}.
+ */
+ @DeleteMapping("/users/{login}")
+ @PreAuthorize("hasAuthority(\"" + AuthoritiesConstants.ADMIN + "\")")
+ public ResponseEntity deleteUser(@PathVariable @Pattern(regexp = Constants.LOGIN_REGEX) String login) {
+ log.debug("REST request to delete User: {}", login);
+ userService.deleteUser(login);
+ return ResponseEntity.noContent().headers(HeaderUtil.createAlert(applicationName, "userManagement.deleted", login)).build();
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/BadRequestAlertException.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/BadRequestAlertException.java
new file mode 100644
index 000000000..e0f3a38f5
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/BadRequestAlertException.java
@@ -0,0 +1,41 @@
+package com.mycompany.myapp.web.rest.errors;
+
+import java.net.URI;
+import java.util.HashMap;
+import java.util.Map;
+import org.zalando.problem.AbstractThrowableProblem;
+import org.zalando.problem.Status;
+
+public class BadRequestAlertException extends AbstractThrowableProblem {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String entityName;
+
+ private final String errorKey;
+
+ public BadRequestAlertException(String defaultMessage, String entityName, String errorKey) {
+ this(ErrorConstants.DEFAULT_TYPE, defaultMessage, entityName, errorKey);
+ }
+
+ public BadRequestAlertException(URI type, String defaultMessage, String entityName, String errorKey) {
+ super(type, defaultMessage, Status.BAD_REQUEST, null, null, null, getAlertParameters(entityName, errorKey));
+ this.entityName = entityName;
+ this.errorKey = errorKey;
+ }
+
+ public String getEntityName() {
+ return entityName;
+ }
+
+ public String getErrorKey() {
+ return errorKey;
+ }
+
+ private static Map getAlertParameters(String entityName, String errorKey) {
+ Map parameters = new HashMap<>();
+ parameters.put("message", "error." + errorKey);
+ parameters.put("params", entityName);
+ return parameters;
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/EmailAlreadyUsedException.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/EmailAlreadyUsedException.java
new file mode 100644
index 000000000..42b64acdb
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/EmailAlreadyUsedException.java
@@ -0,0 +1,10 @@
+package com.mycompany.myapp.web.rest.errors;
+
+public class EmailAlreadyUsedException extends BadRequestAlertException {
+
+ private static final long serialVersionUID = 1L;
+
+ public EmailAlreadyUsedException() {
+ super(ErrorConstants.EMAIL_ALREADY_USED_TYPE, "Email is already in use!", "userManagement", "emailexists");
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/ErrorConstants.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/ErrorConstants.java
new file mode 100644
index 000000000..9497d6343
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/ErrorConstants.java
@@ -0,0 +1,17 @@
+package com.mycompany.myapp.web.rest.errors;
+
+import java.net.URI;
+
+public final class ErrorConstants {
+
+ public static final String ERR_CONCURRENCY_FAILURE = "error.concurrencyFailure";
+ public static final String ERR_VALIDATION = "error.validation";
+ public static final String PROBLEM_BASE_URL = "https://www.jhipster.tech/problem";
+ public static final URI DEFAULT_TYPE = URI.create(PROBLEM_BASE_URL + "/problem-with-message");
+ public static final URI CONSTRAINT_VIOLATION_TYPE = URI.create(PROBLEM_BASE_URL + "/constraint-violation");
+ public static final URI INVALID_PASSWORD_TYPE = URI.create(PROBLEM_BASE_URL + "/invalid-password");
+ public static final URI EMAIL_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/email-already-used");
+ public static final URI LOGIN_ALREADY_USED_TYPE = URI.create(PROBLEM_BASE_URL + "/login-already-used");
+
+ private ErrorConstants() {}
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/ExceptionTranslator.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/ExceptionTranslator.java
new file mode 100644
index 000000000..ff79e98e1
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/ExceptionTranslator.java
@@ -0,0 +1,222 @@
+package com.mycompany.myapp.web.rest.errors;
+
+import java.net.URI;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.core.env.Environment;
+import org.springframework.dao.ConcurrencyFailureException;
+import org.springframework.dao.DataAccessException;
+import org.springframework.http.ResponseEntity;
+import org.springframework.http.converter.HttpMessageConversionException;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.zalando.problem.DefaultProblem;
+import org.zalando.problem.Problem;
+import org.zalando.problem.ProblemBuilder;
+import org.zalando.problem.Status;
+import org.zalando.problem.StatusType;
+import org.zalando.problem.spring.web.advice.ProblemHandling;
+import org.zalando.problem.spring.web.advice.security.SecurityAdviceTrait;
+import org.zalando.problem.violations.ConstraintViolationProblem;
+import tech.jhipster.config.JHipsterConstants;
+import tech.jhipster.web.util.HeaderUtil;
+
+/**
+ * Controller advice to translate the server side exceptions to client-friendly json structures.
+ * The error response follows RFC7807 - Problem Details for HTTP APIs (https://tools.ietf.org/html/rfc7807).
+ */
+@ControllerAdvice
+public class ExceptionTranslator implements ProblemHandling, SecurityAdviceTrait {
+
+ private static final String FIELD_ERRORS_KEY = "fieldErrors";
+ private static final String MESSAGE_KEY = "message";
+ private static final String PATH_KEY = "path";
+ private static final String VIOLATIONS_KEY = "violations";
+
+ @Value("${jhipster.clientApp.name}")
+ private String applicationName;
+
+ private final Environment env;
+
+ public ExceptionTranslator(Environment env) {
+ this.env = env;
+ }
+
+ /**
+ * Post-process the Problem payload to add the message key for the front-end if needed.
+ */
+ @Override
+ public ResponseEntity process(@Nullable ResponseEntity entity, NativeWebRequest request) {
+ if (entity == null) {
+ return null;
+ }
+ Problem problem = entity.getBody();
+ if (!(problem instanceof ConstraintViolationProblem || problem instanceof DefaultProblem)) {
+ return entity;
+ }
+
+ HttpServletRequest nativeRequest = request.getNativeRequest(HttpServletRequest.class);
+ String requestUri = nativeRequest != null ? nativeRequest.getRequestURI() : StringUtils.EMPTY;
+ ProblemBuilder builder = Problem
+ .builder()
+ .withType(Problem.DEFAULT_TYPE.equals(problem.getType()) ? ErrorConstants.DEFAULT_TYPE : problem.getType())
+ .withStatus(problem.getStatus())
+ .withTitle(problem.getTitle())
+ .with(PATH_KEY, requestUri);
+
+ if (problem instanceof ConstraintViolationProblem) {
+ builder
+ .with(VIOLATIONS_KEY, ((ConstraintViolationProblem) problem).getViolations())
+ .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION);
+ } else {
+ builder.withCause(((DefaultProblem) problem).getCause()).withDetail(problem.getDetail()).withInstance(problem.getInstance());
+ problem.getParameters().forEach(builder::with);
+ if (!problem.getParameters().containsKey(MESSAGE_KEY) && problem.getStatus() != null) {
+ builder.with(MESSAGE_KEY, "error.http." + problem.getStatus().getStatusCode());
+ }
+ }
+ return new ResponseEntity<>(builder.build(), entity.getHeaders(), entity.getStatusCode());
+ }
+
+ @Override
+ public ResponseEntity handleMethodArgumentNotValid(MethodArgumentNotValidException ex, @Nonnull NativeWebRequest request) {
+ BindingResult result = ex.getBindingResult();
+ List fieldErrors = result
+ .getFieldErrors()
+ .stream()
+ .map(f ->
+ new FieldErrorVM(
+ f.getObjectName().replaceFirst("DTO$", ""),
+ f.getField(),
+ StringUtils.isNotBlank(f.getDefaultMessage()) ? f.getDefaultMessage() : f.getCode()
+ )
+ )
+ .collect(Collectors.toList());
+
+ Problem problem = Problem
+ .builder()
+ .withType(ErrorConstants.CONSTRAINT_VIOLATION_TYPE)
+ .withTitle("Method argument not valid")
+ .withStatus(defaultConstraintViolationStatus())
+ .with(MESSAGE_KEY, ErrorConstants.ERR_VALIDATION)
+ .with(FIELD_ERRORS_KEY, fieldErrors)
+ .build();
+ return create(ex, problem, request);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity handleEmailAlreadyUsedException(
+ com.mycompany.myapp.service.EmailAlreadyUsedException ex,
+ NativeWebRequest request
+ ) {
+ EmailAlreadyUsedException problem = new EmailAlreadyUsedException();
+ return create(
+ problem,
+ request,
+ HeaderUtil.createFailureAlert(applicationName, true, problem.getEntityName(), problem.getErrorKey(), problem.getMessage())
+ );
+ }
+
+ @ExceptionHandler
+ public ResponseEntity handleUsernameAlreadyUsedException(
+ com.mycompany.myapp.service.UsernameAlreadyUsedException ex,
+ NativeWebRequest request
+ ) {
+ LoginAlreadyUsedException problem = new LoginAlreadyUsedException();
+ return create(
+ problem,
+ request,
+ HeaderUtil.createFailureAlert(applicationName, true, problem.getEntityName(), problem.getErrorKey(), problem.getMessage())
+ );
+ }
+
+ @ExceptionHandler
+ public ResponseEntity handleInvalidPasswordException(
+ com.mycompany.myapp.service.InvalidPasswordException ex,
+ NativeWebRequest request
+ ) {
+ return create(new InvalidPasswordException(), request);
+ }
+
+ @ExceptionHandler
+ public ResponseEntity handleBadRequestAlertException(BadRequestAlertException ex, NativeWebRequest request) {
+ return create(
+ ex,
+ request,
+ HeaderUtil.createFailureAlert(applicationName, true, ex.getEntityName(), ex.getErrorKey(), ex.getMessage())
+ );
+ }
+
+ @ExceptionHandler
+ public ResponseEntity handleConcurrencyFailure(ConcurrencyFailureException ex, NativeWebRequest request) {
+ Problem problem = Problem.builder().withStatus(Status.CONFLICT).with(MESSAGE_KEY, ErrorConstants.ERR_CONCURRENCY_FAILURE).build();
+ return create(ex, problem, request);
+ }
+
+ @Override
+ public ProblemBuilder prepare(final Throwable throwable, final StatusType status, final URI type) {
+ Collection activeProfiles = Arrays.asList(env.getActiveProfiles());
+
+ if (activeProfiles.contains(JHipsterConstants.SPRING_PROFILE_PRODUCTION)) {
+ if (throwable instanceof HttpMessageConversionException) {
+ return Problem
+ .builder()
+ .withType(type)
+ .withTitle(status.getReasonPhrase())
+ .withStatus(status)
+ .withDetail("Unable to convert http message")
+ .withCause(
+ Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null)
+ );
+ }
+ if (throwable instanceof DataAccessException) {
+ return Problem
+ .builder()
+ .withType(type)
+ .withTitle(status.getReasonPhrase())
+ .withStatus(status)
+ .withDetail("Failure during data access")
+ .withCause(
+ Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null)
+ );
+ }
+ if (containsPackageName(throwable.getMessage())) {
+ return Problem
+ .builder()
+ .withType(type)
+ .withTitle(status.getReasonPhrase())
+ .withStatus(status)
+ .withDetail("Unexpected runtime exception")
+ .withCause(
+ Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null)
+ );
+ }
+ }
+
+ return Problem
+ .builder()
+ .withType(type)
+ .withTitle(status.getReasonPhrase())
+ .withStatus(status)
+ .withDetail(throwable.getMessage())
+ .withCause(
+ Optional.ofNullable(throwable.getCause()).filter(cause -> isCausalChainsEnabled()).map(this::toProblem).orElse(null)
+ );
+ }
+
+ private boolean containsPackageName(String message) {
+ // This list is for sure not complete
+ return StringUtils.containsAny(message, "org.", "java.", "net.", "javax.", "com.", "io.", "de.", "com.mycompany.myapp");
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/FieldErrorVM.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/FieldErrorVM.java
new file mode 100644
index 000000000..4f50625f2
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/FieldErrorVM.java
@@ -0,0 +1,32 @@
+package com.mycompany.myapp.web.rest.errors;
+
+import java.io.Serializable;
+
+public class FieldErrorVM implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ private final String objectName;
+
+ private final String field;
+
+ private final String message;
+
+ public FieldErrorVM(String dto, String field, String message) {
+ this.objectName = dto;
+ this.field = field;
+ this.message = message;
+ }
+
+ public String getObjectName() {
+ return objectName;
+ }
+
+ public String getField() {
+ return field;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/InvalidPasswordException.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/InvalidPasswordException.java
new file mode 100644
index 000000000..770b4ad35
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/InvalidPasswordException.java
@@ -0,0 +1,13 @@
+package com.mycompany.myapp.web.rest.errors;
+
+import org.zalando.problem.AbstractThrowableProblem;
+import org.zalando.problem.Status;
+
+public class InvalidPasswordException extends AbstractThrowableProblem {
+
+ private static final long serialVersionUID = 1L;
+
+ public InvalidPasswordException() {
+ super(ErrorConstants.INVALID_PASSWORD_TYPE, "Incorrect password", Status.BAD_REQUEST);
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/LoginAlreadyUsedException.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/LoginAlreadyUsedException.java
new file mode 100644
index 000000000..a04bdc615
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/LoginAlreadyUsedException.java
@@ -0,0 +1,10 @@
+package com.mycompany.myapp.web.rest.errors;
+
+public class LoginAlreadyUsedException extends BadRequestAlertException {
+
+ private static final long serialVersionUID = 1L;
+
+ public LoginAlreadyUsedException() {
+ super(ErrorConstants.LOGIN_ALREADY_USED_TYPE, "Login name already used!", "userManagement", "userexists");
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/package-info.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/package-info.java
new file mode 100644
index 000000000..a62e9f2c2
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/errors/package-info.java
@@ -0,0 +1,6 @@
+/**
+ * Specific errors used with Zalando's "problem-spring-web" library.
+ *
+ * More information on https://github.com/zalando/problem-spring-web
+ */
+package com.mycompany.myapp.web.rest.errors;
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/package-info.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/package-info.java
new file mode 100644
index 000000000..2ed7b5f56
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * Spring MVC REST controllers.
+ */
+package com.mycompany.myapp.web.rest;
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/KeyAndPasswordVM.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/KeyAndPasswordVM.java
new file mode 100644
index 000000000..54bcc5921
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/KeyAndPasswordVM.java
@@ -0,0 +1,27 @@
+package com.mycompany.myapp.web.rest.vm;
+
+/**
+ * View Model object for storing the user's key and password.
+ */
+public class KeyAndPasswordVM {
+
+ private String key;
+
+ private String newPassword;
+
+ public String getKey() {
+ return key;
+ }
+
+ public void setKey(String key) {
+ this.key = key;
+ }
+
+ public String getNewPassword() {
+ return newPassword;
+ }
+
+ public void setNewPassword(String newPassword) {
+ this.newPassword = newPassword;
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/LoginVM.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/LoginVM.java
new file mode 100644
index 000000000..58cd6dee4
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/LoginVM.java
@@ -0,0 +1,53 @@
+package com.mycompany.myapp.web.rest.vm;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+
+/**
+ * View Model object for storing a user's credentials.
+ */
+public class LoginVM {
+
+ @NotNull
+ @Size(min = 1, max = 50)
+ private String username;
+
+ @NotNull
+ @Size(min = 4, max = 100)
+ private String password;
+
+ private boolean rememberMe;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(String username) {
+ this.username = username;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ public boolean isRememberMe() {
+ return rememberMe;
+ }
+
+ public void setRememberMe(boolean rememberMe) {
+ this.rememberMe = rememberMe;
+ }
+
+ // prettier-ignore
+ @Override
+ public String toString() {
+ return "LoginVM{" +
+ "username='" + username + '\'' +
+ ", rememberMe=" + rememberMe +
+ '}';
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/ManagedUserVM.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/ManagedUserVM.java
new file mode 100644
index 000000000..34275d5f3
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/ManagedUserVM.java
@@ -0,0 +1,35 @@
+package com.mycompany.myapp.web.rest.vm;
+
+import com.mycompany.myapp.service.dto.AdminUserDTO;
+import javax.validation.constraints.Size;
+
+/**
+ * View Model extending the AdminUserDTO, which is meant to be used in the user management UI.
+ */
+public class ManagedUserVM extends AdminUserDTO {
+
+ public static final int PASSWORD_MIN_LENGTH = 4;
+
+ public static final int PASSWORD_MAX_LENGTH = 100;
+
+ @Size(min = PASSWORD_MIN_LENGTH, max = PASSWORD_MAX_LENGTH)
+ private String password;
+
+ public ManagedUserVM() {
+ // Empty constructor needed for Jackson.
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(String password) {
+ this.password = password;
+ }
+
+ // prettier-ignore
+ @Override
+ public String toString() {
+ return "ManagedUserVM{" + super.toString() + "} ";
+ }
+}
diff --git a/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/package-info.java b/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/package-info.java
new file mode 100644
index 000000000..09642c8d7
--- /dev/null
+++ b/myApp/src/main/java/com/mycompany/myapp/web/rest/vm/package-info.java
@@ -0,0 +1,4 @@
+/**
+ * View Models used by Spring MVC REST controllers.
+ */
+package com.mycompany.myapp.web.rest.vm;
diff --git a/myApp/src/main/resources/.h2.server.properties b/myApp/src/main/resources/.h2.server.properties
new file mode 100644
index 000000000..18fed6cd1
--- /dev/null
+++ b/myApp/src/main/resources/.h2.server.properties
@@ -0,0 +1,6 @@
+#H2 Server Properties
+#Sun Jan 09 11:59:49 EST 2022
+0=JHipster H2 (Disk)|org.h2.Driver|jdbc\:h2\:file\:./target/h2db/db/myapp|myApp
+webSSL=false
+webAllowOthers=true
+webPort=8092
diff --git a/myApp/src/main/resources/banner.txt b/myApp/src/main/resources/banner.txt
new file mode 100644
index 000000000..c78ac6636
--- /dev/null
+++ b/myApp/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+
+ ${AnsiColor.GREEN} ██╗${AnsiColor.CYAN} ██╗ ██╗ ████████╗ ███████╗ ██████╗ ████████╗ ████████╗ ███████╗
+ ${AnsiColor.GREEN} ██║${AnsiColor.CYAN} ██║ ██║ ╚══██╔══╝ ██╔═══██╗ ██╔════╝ ╚══██╔══╝ ██╔═════╝ ██╔═══██╗
+ ${AnsiColor.GREEN} ██║${AnsiColor.CYAN} ████████║ ██║ ███████╔╝ ╚█████╗ ██║ ██████╗ ███████╔╝
+ ${AnsiColor.GREEN}██╗ ██║${AnsiColor.CYAN} ██╔═══██║ ██║ ██╔════╝ ╚═══██╗ ██║ ██╔═══╝ ██╔══██║
+ ${AnsiColor.GREEN}╚██████╔╝${AnsiColor.CYAN} ██║ ██║ ████████╗ ██║ ██████╔╝ ██║ ████████╗ ██║ ╚██╗
+ ${AnsiColor.GREEN} ╚═════╝ ${AnsiColor.CYAN} ╚═╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═════╝ ╚═╝ ╚═══════╝ ╚═╝ ╚═╝
+
+${AnsiColor.BRIGHT_BLUE}:: JHipster 🤓 :: Running Spring Boot ${spring-boot.version} ::
+:: https://www.jhipster.tech ::${AnsiColor.DEFAULT}
diff --git a/myApp/src/main/resources/config/application-dev.yml b/myApp/src/main/resources/config/application-dev.yml
new file mode 100644
index 000000000..517d033de
--- /dev/null
+++ b/myApp/src/main/resources/config/application-dev.yml
@@ -0,0 +1,121 @@
+# ===================================================================
+# Spring Boot configuration for the "dev" profile.
+#
+# This configuration overrides the application.yml file.
+#
+# More information on profiles: https://www.jhipster.tech/profiles/
+# More information on configuration properties: https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+# ===================================================================
+# Standard Spring Boot properties.
+# Full reference is available at:
+# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
+# ===================================================================
+logging:
+ level:
+ ROOT: DEBUG
+ tech.jhipster: DEBUG
+ org.hibernate.SQL: DEBUG
+ com.mycompany.myapp: DEBUG
+
+spring:
+ devtools:
+ restart:
+ enabled: true
+ additional-exclude: static/**,.h2.server.properties
+ livereload:
+ enabled: false # we use Webpack dev server + BrowserSync for livereload
+ jackson:
+ serialization:
+ indent-output: true
+ datasource:
+ type: com.zaxxer.hikari.HikariDataSource
+ url: jdbc:h2:file:./target/h2db/db/myapp;DB_CLOSE_DELAY=-1
+ username: myApp
+ password:
+ hikari:
+ poolName: Hikari
+ auto-commit: false
+ h2:
+ console:
+ # disable spring boot built-in h2-console since we start it manually with correct configuration
+ enabled: false
+ jpa:
+ database-platform: tech.jhipster.domain.util.FixedH2Dialect
+ liquibase:
+ # Remove 'faker' if you do not want the sample data to be loaded automatically
+ contexts: dev, faker
+ mail:
+ host: smtp.gmail.com
+ port: 587
+ username: zipcodebanking@gmail.com
+ password: Zipc0de#
+ protocol: smtp
+ properties.mail.smtp.auth: true
+ properties.mail.smtp.starttls.enable: true
+
+ messages:
+ cache-duration: PT1S # 1 second, see the ISO 8601 standard
+ thymeleaf:
+ cache: false
+ sleuth:
+ sampler:
+ probability: 1 # report 100% of traces
+ zipkin: # Use the "zipkin" Maven profile to have the Spring Cloud Zipkin dependencies
+ base-url: http://localhost:9411
+ enabled: false
+ locator:
+ discovery:
+ enabled: true
+
+server:
+ port: 8080
+
+# ===================================================================
+# JHipster specific properties
+#
+# Full reference is available at: https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+jhipster:
+ cache: # Cache configuration
+ ehcache: # Ehcache configuration
+ time-to-live-seconds: 3600 # By default objects stay 1 hour in the cache
+ max-entries: 100 # Number of objects in each cache entry
+ # CORS is only enabled by default with the "dev" profile
+ cors:
+ # Allow Ionic for JHipster by default (* no longer allowed in Spring Boot 2.4+)
+ allowed-origins: 'http://localhost:8100,https://localhost:8100,http://localhost:9000,https://localhost:9000,http://localhost:9060,https://localhost:9060'
+ allowed-methods: '*'
+ allowed-headers: '*'
+ exposed-headers: 'Authorization,Link,X-Total-Count,X-${jhipster.clientApp.name}-alert,X-${jhipster.clientApp.name}-error,X-${jhipster.clientApp.name}-params'
+ allow-credentials: true
+ max-age: 1800
+ security:
+ authentication:
+ jwt:
+ # This token must be encoded using Base64 and be at least 256 bits long (you can type `openssl rand -base64 64` on your command line to generate a 512 bits one)
+ base64-secret: YjEwZTA0MjIxN2I0MTA4ZWJmY2M1ZjliMDE3OTBjNDIzMjgxYjE5YzM1MDM1ZDM0Y2ZlZWNlYzRmY2ZmODk3OGMyMTRkZjBlZmZmMzM0YmUwMDMzZGNkNTE3YTk3MzU1Yzg5YjZiYWU2MTYwOTdjN2M2YWU0ZDkyM2M3NDM4OGY=
+ # Token is valid 24 hours
+ token-validity-in-seconds: 86400
+ token-validity-in-seconds-for-remember-me: 2592000
+ mail: # specific JHipster mail property, for standard properties see MailProperties
+ base-url: http://127.0.0.1:8080
+ logging:
+ use-json-format: false # By default, logs are not in Json format
+ logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration
+ enabled: false
+ host: localhost
+ port: 5000
+ queue-size: 512
+# ===================================================================
+# Application specific properties
+# Add your own application properties here, see the ApplicationProperties class
+# to have type-safe configuration, like in the JHipsterProperties above
+#
+# More documentation is available at:
+# https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+# application:
diff --git a/myApp/src/main/resources/config/application-prod.yml b/myApp/src/main/resources/config/application-prod.yml
new file mode 100644
index 000000000..a215beb22
--- /dev/null
+++ b/myApp/src/main/resources/config/application-prod.yml
@@ -0,0 +1,135 @@
+# ===================================================================
+# Spring Boot configuration for the "prod" profile.
+#
+# This configuration overrides the application.yml file.
+#
+# More information on profiles: https://www.jhipster.tech/profiles/
+# More information on configuration properties: https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+# ===================================================================
+# Standard Spring Boot properties.
+# Full reference is available at:
+# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
+# ===================================================================
+
+logging:
+ level:
+ ROOT: INFO
+ tech.jhipster: INFO
+ com.mycompany.myapp: INFO
+
+management:
+ metrics:
+ export:
+ prometheus:
+ enabled: false
+
+spring:
+ devtools:
+ restart:
+ enabled: false
+ livereload:
+ enabled: false
+ datasource:
+ type: com.zaxxer.hikari.HikariDataSource
+ url: jdbc:postgresql://localhost:5432/myApp
+ username: myApp
+ password:
+ hikari:
+ poolName: Hikari
+ auto-commit: false
+ jpa:
+ database-platform: tech.jhipster.domain.util.FixedPostgreSQL10Dialect
+ # Replace by 'prod, faker' to add the faker context and have sample data loaded in production
+ liquibase:
+ contexts: prod
+ mail:
+ host: localhost
+ port: 25
+ username:
+ password:
+ thymeleaf:
+ cache: true
+ sleuth:
+ sampler:
+ probability: 1 # report 100% of traces
+ zipkin: # Use the "zipkin" Maven profile to have the Spring Cloud Zipkin dependencies
+ base-url: http://localhost:9411
+ enabled: false
+ locator:
+ discovery:
+ enabled: true
+
+# ===================================================================
+# To enable TLS in production, generate a certificate using:
+# keytool -genkey -alias myapp -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650
+#
+# You can also use Let's Encrypt:
+# https://maximilian-boehm.com/hp2121/Create-a-Java-Keystore-JKS-from-Let-s-Encrypt-Certificates.htm
+#
+# Then, modify the server.ssl properties so your "server" configuration looks like:
+#
+# server:
+# port: 443
+# ssl:
+# key-store: classpath:config/tls/keystore.p12
+# key-store-password: password
+# key-store-type: PKCS12
+# key-alias: selfsigned
+# # The ciphers suite enforce the security by deactivating some old and deprecated SSL cipher, this list was tested against SSL Labs (https://www.ssllabs.com/ssltest/)
+# ciphers: TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 ,TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 ,TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,TLS_DHE_RSA_WITH_AES_128_CBC_SHA256,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_256_CBC_SHA256,TLS_DHE_RSA_WITH_AES_256_CBC_SHA,TLS_RSA_WITH_AES_128_GCM_SHA256,TLS_RSA_WITH_AES_256_GCM_SHA384,TLS_RSA_WITH_AES_128_CBC_SHA256,TLS_RSA_WITH_AES_256_CBC_SHA256,TLS_RSA_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_256_CBC_SHA,TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA,TLS_RSA_WITH_CAMELLIA_256_CBC_SHA,TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA,TLS_RSA_WITH_CAMELLIA_128_CBC_SHA
+# ===================================================================
+server:
+ port: 8080
+ shutdown: graceful # see https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-graceful-shutdown
+ compression:
+ enabled: true
+ mime-types: text/html,text/xml,text/plain,text/css,application/javascript,application/json,image/svg+xml
+ min-response-size: 1024
+
+# ===================================================================
+# JHipster specific properties
+#
+# Full reference is available at: https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+jhipster:
+ http:
+ cache: # Used by the CachingHttpHeadersFilter
+ timeToLiveInDays: 1461
+ cache: # Cache configuration
+ ehcache: # Ehcache configuration
+ time-to-live-seconds: 3600 # By default objects stay 1 hour in the cache
+ max-entries: 1000 # Number of objects in each cache entry
+ security:
+ authentication:
+ jwt:
+ # This token must be encoded using Base64 and be at least 256 bits long (you can type `openssl rand -base64 64` on your command line to generate a 512 bits one)
+ # As this is the PRODUCTION configuration, you MUST change the default key, and store it securely:
+ # - In the JHipster Registry (which includes a Spring Cloud Config server)
+ # - In a separate `application-prod.yml` file, in the same folder as your executable JAR file
+ # - In the `JHIPSTER_SECURITY_AUTHENTICATION_JWT_BASE64_SECRET` environment variable
+ base64-secret: YjEwZTA0MjIxN2I0MTA4ZWJmY2M1ZjliMDE3OTBjNDIzMjgxYjE5YzM1MDM1ZDM0Y2ZlZWNlYzRmY2ZmODk3OGMyMTRkZjBlZmZmMzM0YmUwMDMzZGNkNTE3YTk3MzU1Yzg5YjZiYWU2MTYwOTdjN2M2YWU0ZDkyM2M3NDM4OGY=
+ # Token is valid 24 hours
+ token-validity-in-seconds: 86400
+ token-validity-in-seconds-for-remember-me: 2592000
+ mail: # specific JHipster mail property, for standard properties see MailProperties
+ base-url: http://my-server-url-to-change # Modify according to your server's URL
+ logging:
+ use-json-format: false # By default, logs are not in Json format
+ logstash: # Forward logs to logstash over a socket, used by LoggingConfiguration
+ enabled: false
+ host: localhost
+ port: 5000
+ queue-size: 512
+# ===================================================================
+# Application specific properties
+# Add your own application properties here, see the ApplicationProperties class
+# to have type-safe configuration, like in the JHipsterProperties above
+#
+# More documentation is available at:
+# https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+# application:
diff --git a/myApp/src/main/resources/config/application-tls.yml b/myApp/src/main/resources/config/application-tls.yml
new file mode 100644
index 000000000..039f6f4a6
--- /dev/null
+++ b/myApp/src/main/resources/config/application-tls.yml
@@ -0,0 +1,19 @@
+# ===================================================================
+# Activate this profile to enable TLS and HTTP/2.
+#
+# JHipster has generated a self-signed certificate, which will be used to encrypt traffic.
+# As your browser will not understand this certificate, you will need to import it.
+#
+# Another (easiest) solution with Chrome is to enable the "allow-insecure-localhost" flag
+# at chrome://flags/#allow-insecure-localhost
+# ===================================================================
+server:
+ ssl:
+ key-store: classpath:config/tls/keystore.p12
+ key-store-password: password
+ key-store-type: PKCS12
+ key-alias: selfsigned
+ ciphers: TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+ enabled-protocols: TLSv1.2
+ http2:
+ enabled: true
diff --git a/myApp/src/main/resources/config/application.yml b/myApp/src/main/resources/config/application.yml
new file mode 100644
index 000000000..df37719c4
--- /dev/null
+++ b/myApp/src/main/resources/config/application.yml
@@ -0,0 +1,208 @@
+# ===================================================================
+# Spring Boot configuration.
+#
+# This configuration will be overridden by the Spring profile you use,
+# for example application-dev.yml if you use the "dev" profile.
+#
+# More information on profiles: https://www.jhipster.tech/profiles/
+# More information on configuration properties: https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+# ===================================================================
+# Standard Spring Boot properties.
+# Full reference is available at:
+# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
+# ===================================================================
+
+---
+# Conditionally disable springdoc on missing api-docs profile
+spring:
+ config:
+ activate:
+ on-profile: '!api-docs'
+springdoc:
+ api-docs:
+ enabled: false
+---
+management:
+ endpoints:
+ web:
+ base-path: /management
+ exposure:
+ include:
+ [
+ 'configprops',
+ 'env',
+ 'health',
+ 'info',
+ 'jhimetrics',
+ 'jhiopenapigroups',
+ 'logfile',
+ 'loggers',
+ 'prometheus',
+ 'threaddump',
+ 'caches',
+ 'liquibase',
+ ]
+ endpoint:
+ health:
+ show-details: when_authorized
+ roles: 'ROLE_ADMIN'
+ probes:
+ enabled: true
+ group:
+ liveness:
+ include: livenessState
+ readiness:
+ include: readinessState,db
+ jhimetrics:
+ enabled: true
+ info:
+ git:
+ mode: full
+ health:
+ mail:
+ enabled: false # When using the MailService, configure an SMTP server and set this to true
+ metrics:
+ export:
+ # Prometheus is the default metrics backend
+ prometheus:
+ enabled: true
+ step: 60
+ enable:
+ http: true
+ jvm: true
+ logback: true
+ process: true
+ system: true
+ distribution:
+ percentiles-histogram:
+ all: true
+ percentiles:
+ all: 0, 0.5, 0.75, 0.95, 0.99, 1.0
+ tags:
+ application: ${spring.application.name}
+ web:
+ server:
+ request:
+ autotime:
+ enabled: true
+
+spring:
+ application:
+ name: myApp
+ profiles:
+ # The commented value for `active` can be replaced with valid Spring profiles to load.
+ # Otherwise, it will be filled in by maven when building the JAR file
+ # Either way, it can be overridden by `--spring.profiles.active` value passed in the commandline or `-Dspring.profiles.active` set in `JAVA_OPTS`
+ active: #spring.profiles.active#
+ group:
+ dev:
+ - dev
+ - api-docs
+ # Uncomment to activate TLS for the dev profile
+ #- tls
+ jmx:
+ enabled: false
+ data:
+ jpa:
+ repositories:
+ bootstrap-mode: deferred
+ jpa:
+ open-in-view: false
+ properties:
+ hibernate.jdbc.time_zone: UTC
+ hibernate.id.new_generator_mappings: true
+ hibernate.connection.provider_disables_autocommit: true
+ hibernate.cache.use_second_level_cache: true
+ hibernate.cache.use_query_cache: false
+ hibernate.generate_statistics: false
+ # modify batch size as necessary
+ hibernate.jdbc.batch_size: 25
+ hibernate.order_inserts: true
+ hibernate.order_updates: true
+ hibernate.query.fail_on_pagination_over_collection_fetch: true
+ hibernate.query.in_clause_parameter_padding: true
+ hibernate:
+ ddl-auto: none
+ naming:
+ physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
+ implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
+ messages:
+ basename: i18n/messages
+ main:
+ allow-bean-definition-overriding: true
+ task:
+ execution:
+ thread-name-prefix: my-app-task-
+ pool:
+ core-size: 2
+ max-size: 50
+ queue-capacity: 10000
+ scheduling:
+ thread-name-prefix: my-app-scheduling-
+ pool:
+ size: 2
+ thymeleaf:
+ mode: HTML
+ output:
+ ansi:
+ console-available: true
+
+server:
+ servlet:
+ session:
+ cookie:
+ http-only: true
+
+springdoc:
+ show-actuator: true
+
+# Properties to be exposed on the /info management endpoint
+info:
+ # Comma separated list of profiles that will trigger the ribbon to show
+ display-ribbon-on-profiles: 'dev'
+
+# ===================================================================
+# JHipster specific properties
+#
+# Full reference is available at: https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+jhipster:
+ clientApp:
+ name: 'myApp'
+ # By default CORS is disabled. Uncomment to enable.
+ # cors:
+ # allowed-origins: "http://localhost:8100,http://localhost:9000"
+ # allowed-methods: "*"
+ # allowed-headers: "*"
+ # exposed-headers: "Authorization,Link,X-Total-Count,X-${jhipster.clientApp.name}-alert,X-${jhipster.clientApp.name}-error,X-${jhipster.clientApp.name}-params"
+ # allow-credentials: true
+ # max-age: 1800
+ mail:
+ from: zipcodebanking@gmail.com
+ api-docs:
+ default-include-pattern: ${server.servlet.context-path:}/api/**
+ management-include-pattern: ${server.servlet.context-path:}/management/**
+ title: My App API
+ description: My App API documentation
+ version: 0.0.1
+ terms-of-service-url:
+ contact-name:
+ contact-url:
+ contact-email:
+ license: unlicensed
+ license-url:
+ security:
+ content-security-policy: "default-src 'self'; frame-src 'self' data:; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://storage.googleapis.com; style-src 'self' https://fonts.googleapis.com 'unsafe-inline'; img-src 'self' data:; font-src 'self' https://fonts.gstatic.com data:"
+# ===================================================================
+# Application specific properties
+# Add your own application properties here, see the ApplicationProperties class
+# to have type-safe configuration, like in the JHipsterProperties above
+#
+# More documentation is available at:
+# https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+# application:
diff --git a/myApp/src/main/resources/config/bootstrap-prod.yml b/myApp/src/main/resources/config/bootstrap-prod.yml
new file mode 100644
index 000000000..1047df3ff
--- /dev/null
+++ b/myApp/src/main/resources/config/bootstrap-prod.yml
@@ -0,0 +1,6 @@
+# ===================================================================
+# Spring Cloud Config bootstrap configuration for the "prod" profile
+# ===================================================================
+
+spring:
+ cloud:
diff --git a/myApp/src/main/resources/config/bootstrap.yml b/myApp/src/main/resources/config/bootstrap.yml
new file mode 100644
index 000000000..670f7d327
--- /dev/null
+++ b/myApp/src/main/resources/config/bootstrap.yml
@@ -0,0 +1,14 @@
+# ===================================================================
+# Spring Cloud Config bootstrap configuration for the "dev" profile
+# In prod profile, properties will be overwritten by the ones defined in bootstrap-prod.yml
+# ===================================================================
+
+spring:
+ application:
+ name: myApp
+ profiles:
+ # The commented value for `active` can be replaced with valid Spring profiles to load.
+ # Otherwise, it will be filled in by maven when building the JAR file
+ # Either way, it can be overridden by `--spring.profiles.active` value passed in the commandline or `-Dspring.profiles.active` set in `JAVA_OPTS`
+ active: #spring.profiles.active#
+ cloud:
diff --git a/myApp/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml b/myApp/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml
new file mode 100644
index 000000000..1dd282e95
--- /dev/null
+++ b/myApp/src/main/resources/config/liquibase/changelog/00000000000000_initial_schema.xml
@@ -0,0 +1,121 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/myApp/src/main/resources/config/liquibase/data/authority.csv b/myApp/src/main/resources/config/liquibase/data/authority.csv
new file mode 100644
index 000000000..af5c6dfa1
--- /dev/null
+++ b/myApp/src/main/resources/config/liquibase/data/authority.csv
@@ -0,0 +1,3 @@
+name
+ROLE_ADMIN
+ROLE_USER
diff --git a/myApp/src/main/resources/config/liquibase/data/user.csv b/myApp/src/main/resources/config/liquibase/data/user.csv
new file mode 100644
index 000000000..fbc52da39
--- /dev/null
+++ b/myApp/src/main/resources/config/liquibase/data/user.csv
@@ -0,0 +1,3 @@
+id;login;password_hash;first_name;last_name;email;image_url;activated;lang_key;created_by;last_modified_by
+1;admin;$2a$10$gSAhZrxMllrbgj/kkK9UceBPpChGWJA7SYIb1Mqo.n5aNLq1/oRrC;Administrator;Administrator;admin@localhost;;true;en;system;system
+2;user;$2a$10$VEjxo0jq2YG9Rbk2HmX9S.k1uZBGYUHdUcid3g/vfiEl7lwWgOH/K;User;User;user@localhost;;true;en;system;system
diff --git a/myApp/src/main/resources/config/liquibase/data/user_authority.csv b/myApp/src/main/resources/config/liquibase/data/user_authority.csv
new file mode 100644
index 000000000..01dbdef7c
--- /dev/null
+++ b/myApp/src/main/resources/config/liquibase/data/user_authority.csv
@@ -0,0 +1,4 @@
+user_id;authority_name
+1;ROLE_ADMIN
+1;ROLE_USER
+2;ROLE_USER
diff --git a/myApp/src/main/resources/config/liquibase/master.xml b/myApp/src/main/resources/config/liquibase/master.xml
new file mode 100644
index 000000000..a1ea85794
--- /dev/null
+++ b/myApp/src/main/resources/config/liquibase/master.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/myApp/src/main/resources/config/tls/keystore.p12 b/myApp/src/main/resources/config/tls/keystore.p12
new file mode 100644
index 000000000..3ab2e8187
Binary files /dev/null and b/myApp/src/main/resources/config/tls/keystore.p12 differ
diff --git a/myApp/src/main/resources/i18n/messages.properties b/myApp/src/main/resources/i18n/messages.properties
new file mode 100644
index 000000000..e7ad392e2
--- /dev/null
+++ b/myApp/src/main/resources/i18n/messages.properties
@@ -0,0 +1,21 @@
+# Error page
+error.title=Your request cannot be processed
+error.subtitle=Sorry, an error has occurred.
+error.status=Status:
+error.message=Message:
+
+# Activation email
+email.activation.title=ZipCode Banking account activation is required
+email.activation.greeting=Dear {0}
+email.activation.text1=Your ZipCode Banking account has been created, please click on the URL below to activate it:
+email.activation.text2=Regards,
+email.signature=ZipCode Banking Team.
+
+# Creation email
+email.creation.text1=Your ZipCode Banking account has been created, please click on the URL below to access it:
+
+# Reset email
+email.reset.title=ZipCode Banking password reset
+email.reset.greeting=Dear {0}
+email.reset.text1=For your ZipCode Banking account a password reset was requested, please click on the URL below to reset it:
+email.reset.text2=Regards,
diff --git a/myApp/src/main/resources/i18n/messages_en.properties b/myApp/src/main/resources/i18n/messages_en.properties
new file mode 100644
index 000000000..cb7e4b2ca
--- /dev/null
+++ b/myApp/src/main/resources/i18n/messages_en.properties
@@ -0,0 +1,21 @@
+# Error page
+error.title=Your request cannot be processed
+error.subtitle=Sorry, an error has occurred.
+error.status=Status:
+error.message=Message:
+
+# Activation email
+email.activation.title=ZipCode Banking account activation
+email.activation.greeting=Dear {0}
+email.activation.text1=Your ZipCode Banking account has been created, please click on the URL below to activate it:
+email.activation.text2=Regards,
+email.signature=ZipCode Banking Team.
+
+# Creation email
+email.creation.text1=Your ZipCode Banking account has been created, please click on the URL below to access it:
+
+# Reset email
+email.reset.title=ZipCode Banking password reset
+email.reset.greeting=Dear {0}
+email.reset.text1=For your ZipCode Banking account a password reset was requested, please click on the URL below to reset it:
+email.reset.text2=Regards,
diff --git a/myApp/src/main/resources/logback-spring.xml b/myApp/src/main/resources/logback-spring.xml
new file mode 100644
index 000000000..e421f9a7a
--- /dev/null
+++ b/myApp/src/main/resources/logback-spring.xml
@@ -0,0 +1,72 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+
+
+
diff --git a/myApp/src/main/resources/templates/error.html b/myApp/src/main/resources/templates/error.html
new file mode 100644
index 000000000..690e85607
--- /dev/null
+++ b/myApp/src/main/resources/templates/error.html
@@ -0,0 +1,92 @@
+
+
+
+
+
+ Your request cannot be processed
+
+
+
+
+
Your request cannot be processed :(
+
+
Sorry, an error has occurred.
+
+
Status: (
)
+
+ Message:
+
+
+
+
diff --git a/myApp/src/main/resources/templates/mail/activationEmail.html b/myApp/src/main/resources/templates/mail/activationEmail.html
new file mode 100644
index 000000000..0bb53a288
--- /dev/null
+++ b/myApp/src/main/resources/templates/mail/activationEmail.html
@@ -0,0 +1,20 @@
+
+
+
+ JHipster activation
+
+
+
+
+ Dear
+ Your JHipster account has been created, please click on the URL below to activate it:
+
+ Activation link
+
+
+ Regards,
+
+ JHipster.
+
+
+
diff --git a/myApp/src/main/resources/templates/mail/creationEmail.html b/myApp/src/main/resources/templates/mail/creationEmail.html
new file mode 100644
index 000000000..4e528980e
--- /dev/null
+++ b/myApp/src/main/resources/templates/mail/creationEmail.html
@@ -0,0 +1,20 @@
+
+
+
+ JHipster creation
+
+
+
+
+ Dear
+ Your JHipster account has been created, please click on the URL below to access it:
+
+ Login link
+
+
+ Regards,
+
+ JHipster.
+
+
+
diff --git a/myApp/src/main/resources/templates/mail/passwordResetEmail.html b/myApp/src/main/resources/templates/mail/passwordResetEmail.html
new file mode 100644
index 000000000..290ca6dcc
--- /dev/null
+++ b/myApp/src/main/resources/templates/mail/passwordResetEmail.html
@@ -0,0 +1,22 @@
+
+
+
+ JHipster password reset
+
+
+
+
+ Dear
+
+ For your JHipster account a password reset was requested, please click on the URL below to reset it:
+
+
+ Login link
+
+
+ Regards,
+
+ JHipster.
+
+
+
diff --git a/myApp/src/main/webapp/404.html b/myApp/src/main/webapp/404.html
new file mode 100644
index 000000000..7569d7e21
--- /dev/null
+++ b/myApp/src/main/webapp/404.html
@@ -0,0 +1,58 @@
+
+
+
+
+ Page Not Found
+
+
+
+
+
+ Page Not Found
+ Sorry, but the page you were trying to view does not exist.
+
+
+
diff --git a/myApp/src/main/webapp/WEB-INF/web.xml b/myApp/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 000000000..f1611b515
--- /dev/null
+++ b/myApp/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,13 @@
+
+
+
+
+ html
+ text/html;charset=utf-8
+
+
+
diff --git a/myApp/src/main/webapp/app/_bootstrap-variables.scss b/myApp/src/main/webapp/app/_bootstrap-variables.scss
new file mode 100644
index 000000000..7a8fe8623
--- /dev/null
+++ b/myApp/src/main/webapp/app/_bootstrap-variables.scss
@@ -0,0 +1,6 @@
+/*
+* Bootstrap overrides https://v4-alpha.getbootstrap.com/getting-started/options/
+* All values defined in bootstrap source
+* https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss can be overwritten here
+* Make sure not to add !default to values here
+*/
diff --git a/myApp/src/main/webapp/app/app.scss b/myApp/src/main/webapp/app/app.scss
new file mode 100644
index 000000000..5ad77932d
--- /dev/null
+++ b/myApp/src/main/webapp/app/app.scss
@@ -0,0 +1,313 @@
+// Override Boostrap variables
+@import '~bootswatch/dist/cosmo/variables';
+// Import Bootstrap source files from node_modules
+@import 'node_modules/bootstrap/scss/bootstrap';
+@import '~bootswatch/dist/cosmo/bootswatch';
+body {
+ margin: 0;
+}
+
+a {
+ color: #533f03;
+ font-weight: bold;
+}
+
+* {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ &:after,
+ &::before {
+ -moz-box-sizing: border-box;
+ box-sizing: border-box;
+ }
+}
+
+.app-container {
+ box-sizing: border-box;
+ .view-container {
+ width: 100%;
+ height: calc(100% - 40px);
+ overflow-y: auto;
+ overflow-x: hidden;
+ padding: 1rem;
+ .card {
+ padding: 1rem;
+ }
+ .view-routes {
+ height: 100%;
+ > div {
+ height: 100%;
+ }
+ }
+ }
+}
+
+.fullscreen {
+ position: fixed;
+ top: 100px;
+ left: 0px;
+ width: 99% !important;
+ height: calc(100vh - 110px) !important;
+ margin: 5px;
+ z-index: 1000;
+ padding: 5px 25px 50px 25px !important;
+}
+
+/* ==========================================================================
+Browser Upgrade Prompt
+========================================================================== */
+
+.browserupgrade {
+ margin: 0.2em 0;
+ background: #ccc;
+ color: #000;
+ padding: 0.2em 0;
+}
+
+/* ==========================================================================
+Custom button styles
+========================================================================== */
+
+.icon-button > .btn {
+ background-color: transparent;
+ border-color: transparent;
+ padding: 0.5rem;
+ line-height: 1rem;
+ &:hover {
+ background-color: transparent;
+ border-color: transparent;
+ }
+ &:focus {
+ -webkit-box-shadow: none;
+ box-shadow: none;
+ }
+}
+
+/* ==========================================================================
+Generic styles
+========================================================================== */
+
+/* Temporary workaround for availity-reactstrap-validation */
+.invalid-feedback {
+ display: inline;
+}
+
+/* other generic styles */
+
+.title {
+ font-size: 1.25em;
+ margin: 1px 10px 1px 10px;
+}
+
+.description {
+ font-size: 0.9em;
+ margin: 1px 10px 1px 10px;
+}
+
+.shadow {
+ box-shadow: rgba(0, 0, 0, 0.12) 0px 1px 6px, rgba(0, 0, 0, 0.12) 0px 1px 4px;
+ border-radius: 2px;
+}
+
+.error {
+ color: white;
+ background-color: red;
+}
+
+.break {
+ white-space: normal;
+ word-break: break-all;
+}
+
+.break-word {
+ white-space: normal;
+ word-break: keep-all;
+}
+
+.preserve-space {
+ white-space: pre-wrap;
+}
+
+/* padding helpers */
+
+@mixin pad($size, $side) {
+ @if $size== '' {
+ @if $side== '' {
+ .pad {
+ padding: 10px !important;
+ }
+ } @else {
+ .pad {
+ padding-#{$side}: 10px !important;
+ }
+ }
+ } @else {
+ @if $side== '' {
+ .pad-#{$size} {
+ padding: #{$size}px !important;
+ }
+ } @else {
+ .pad-#{$side}-#{$size} {
+ padding-#{$side}: #{$size}px !important;
+ }
+ }
+ }
+}
+
+@include pad('', '');
+@include pad('2', '');
+@include pad('3', '');
+@include pad('5', '');
+@include pad('10', '');
+@include pad('20', '');
+@include pad('25', '');
+@include pad('30', '');
+@include pad('50', '');
+@include pad('75', '');
+@include pad('100', '');
+@include pad('4', 'top');
+@include pad('5', 'top');
+@include pad('10', 'top');
+@include pad('20', 'top');
+@include pad('25', 'top');
+@include pad('30', 'top');
+@include pad('50', 'top');
+@include pad('75', 'top');
+@include pad('100', 'top');
+@include pad('4', 'bottom');
+@include pad('5', 'bottom');
+@include pad('10', 'bottom');
+@include pad('20', 'bottom');
+@include pad('25', 'bottom');
+@include pad('30', 'bottom');
+@include pad('50', 'bottom');
+@include pad('75', 'bottom');
+@include pad('100', 'bottom');
+@include pad('5', 'right');
+@include pad('10', 'right');
+@include pad('20', 'right');
+@include pad('25', 'right');
+@include pad('30', 'right');
+@include pad('50', 'right');
+@include pad('75', 'right');
+@include pad('100', 'right');
+@include pad('5', 'left');
+@include pad('10', 'left');
+@include pad('20', 'left');
+@include pad('25', 'left');
+@include pad('30', 'left');
+@include pad('50', 'left');
+@include pad('75', 'left');
+@include pad('100', 'left');
+
+@mixin no-padding($side) {
+ @if $side== 'all' {
+ .no-padding {
+ padding: 0 !important;
+ }
+ } @else {
+ .no-padding-#{$side} {
+ padding-#{$side}: 0 !important;
+ }
+ }
+}
+
+@include no-padding('left');
+@include no-padding('right');
+@include no-padding('top');
+@include no-padding('bottom');
+@include no-padding('all');
+
+/* end of padding helpers */
+
+.no-margin {
+ margin: 0px;
+}
+@mixin voffset($size) {
+ @if $size== '' {
+ .voffset {
+ margin-top: 2px !important;
+ }
+ } @else {
+ .voffset-#{$size} {
+ margin-top: #{$size}px !important;
+ }
+ }
+}
+
+@include voffset('');
+@include voffset('5');
+@include voffset('10');
+@include voffset('15');
+@include voffset('30');
+@include voffset('40');
+@include voffset('60');
+@include voffset('80');
+@include voffset('100');
+@include voffset('150');
+
+.readonly {
+ background-color: #eee;
+ opacity: 1;
+}
+
+/* ==========================================================================
+make sure browsers use the pointer cursor for anchors, even with no href
+========================================================================== */
+
+a:hover {
+ cursor: pointer;
+}
+
+.hand {
+ cursor: pointer;
+}
+
+button.anchor-btn {
+ background: none;
+ border: none;
+ padding: 0;
+ align-items: initial;
+ text-align: initial;
+ width: 100%;
+}
+
+a.anchor-btn:hover {
+ text-decoration: none;
+}
+
+/* ==========================================================================
+Metrics and Health styles
+========================================================================== */
+
+#threadDump .popover,
+#healthCheck .popover {
+ top: inherit;
+ display: block;
+ font-size: 10px;
+ max-width: 1024px;
+}
+
+.thread-dump-modal-lock {
+ max-width: 450px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+#healthCheck .popover {
+ margin-left: -50px;
+}
+
+.health-details {
+ min-width: 400px;
+}
+
+/* bootstrap 3 input-group 100% width
+http://stackoverflow.com/questions/23436430/bootstrap-3-input-group-100-width */
+
+.width-min {
+ width: 1% !important;
+}
+
+/* jhipster-needle-scss-add-main JHipster will add new css style */
diff --git a/myApp/src/main/webapp/app/app.tsx b/myApp/src/main/webapp/app/app.tsx
new file mode 100644
index 000000000..6e3de5b15
--- /dev/null
+++ b/myApp/src/main/webapp/app/app.tsx
@@ -0,0 +1,66 @@
+import 'react-toastify/dist/ReactToastify.css';
+import './app.scss';
+import 'app/config/dayjs.ts';
+
+import React, { useEffect } from 'react';
+import { Card } from 'reactstrap';
+import { BrowserRouter as Router } from 'react-router-dom';
+import { ToastContainer, toast } from 'react-toastify';
+
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+import { getSession } from 'app/shared/reducers/authentication';
+import { getProfile } from 'app/shared/reducers/application-profile';
+import { setLocale } from 'app/shared/reducers/locale';
+import Header from 'app/shared/layout/header/header';
+import Footer from 'app/shared/layout/footer/footer';
+import { hasAnyAuthority } from 'app/shared/auth/private-route';
+import ErrorBoundary from 'app/shared/error/error-boundary';
+import { AUTHORITIES } from 'app/config/constants';
+import AppRoutes from 'app/routes';
+
+const baseHref = document.querySelector('base').getAttribute('href').replace(/\/$/, '');
+
+export const App = () => {
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ dispatch(getSession());
+ dispatch(getProfile());
+ }, []);
+
+ const currentLocale = useAppSelector(state => state.locale.currentLocale);
+ const isAuthenticated = useAppSelector(state => state.authentication.isAuthenticated);
+ const isAdmin = useAppSelector(state => hasAnyAuthority(state.authentication.account.authorities, [AUTHORITIES.ADMIN]));
+ const ribbonEnv = useAppSelector(state => state.applicationProfile.ribbonEnv);
+ const isInProduction = useAppSelector(state => state.applicationProfile.inProduction);
+ const isOpenAPIEnabled = useAppSelector(state => state.applicationProfile.isOpenAPIEnabled);
+
+ const paddingTop = '60px';
+ return (
+
+
+
+ );
+};
+
+export default App;
diff --git a/myApp/src/main/webapp/app/config/axios-interceptor.spec.ts b/myApp/src/main/webapp/app/config/axios-interceptor.spec.ts
new file mode 100644
index 000000000..5d6546bf5
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/axios-interceptor.spec.ts
@@ -0,0 +1,32 @@
+import axios from 'axios';
+import sinon from 'sinon';
+
+import setupAxiosInterceptors from './axios-interceptor';
+
+describe('Axios Interceptor', () => {
+ describe('setupAxiosInterceptors', () => {
+ const client = axios;
+ const onUnauthenticated = sinon.spy();
+ setupAxiosInterceptors(onUnauthenticated);
+
+ it('onRequestSuccess is called on fulfilled request', () => {
+ expect((client.interceptors.request as any).handlers[0].fulfilled({ data: 'foo', url: '/test' })).toMatchObject({
+ data: 'foo',
+ });
+ });
+ it('onResponseSuccess is called on fulfilled response', () => {
+ expect((client.interceptors.response as any).handlers[0].fulfilled({ data: 'foo' })).toEqual({ data: 'foo' });
+ });
+ it('onResponseError is called on rejected response', () => {
+ const rejectError = {
+ response: {
+ statusText: 'NotFound',
+ status: 403,
+ data: { message: 'Page not found' },
+ },
+ };
+ expect((client.interceptors.response as any).handlers[0].rejected(rejectError)).rejects.toEqual(rejectError);
+ expect(onUnauthenticated.calledOnce).toBe(true);
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/config/axios-interceptor.ts b/myApp/src/main/webapp/app/config/axios-interceptor.ts
new file mode 100644
index 000000000..f529b2799
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/axios-interceptor.ts
@@ -0,0 +1,28 @@
+import axios from 'axios';
+import { Storage } from 'react-jhipster';
+
+const TIMEOUT = 1 * 60 * 1000;
+axios.defaults.timeout = TIMEOUT;
+axios.defaults.baseURL = SERVER_API_URL;
+
+const setupAxiosInterceptors = onUnauthenticated => {
+ const onRequestSuccess = config => {
+ const token = Storage.local.get('jhi-authenticationToken') || Storage.session.get('jhi-authenticationToken');
+ if (token) {
+ config.headers.Authorization = `Bearer ${token}`;
+ }
+ return config;
+ };
+ const onResponseSuccess = response => response;
+ const onResponseError = err => {
+ const status = err.status || (err.response ? err.response.status : 0);
+ if (status === 403 || status === 401) {
+ onUnauthenticated();
+ }
+ return Promise.reject(err);
+ };
+ axios.interceptors.request.use(onRequestSuccess);
+ axios.interceptors.response.use(onResponseSuccess, onResponseError);
+};
+
+export default setupAxiosInterceptors;
diff --git a/myApp/src/main/webapp/app/config/constants.ts b/myApp/src/main/webapp/app/config/constants.ts
new file mode 100644
index 000000000..bd0e4c8dd
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/constants.ts
@@ -0,0 +1,15 @@
+export const AUTHORITIES = {
+ ADMIN: 'ROLE_ADMIN',
+ USER: 'ROLE_USER',
+};
+
+export const messages = {
+ DATA_ERROR_ALERT: 'Internal Error',
+};
+
+export const APP_DATE_FORMAT = 'DD/MM/YY HH:mm';
+export const APP_TIMESTAMP_FORMAT = 'DD/MM/YY HH:mm:ss';
+export const APP_LOCAL_DATE_FORMAT = 'DD/MM/YYYY';
+export const APP_LOCAL_DATETIME_FORMAT = 'YYYY-MM-DDTHH:mm';
+export const APP_WHOLE_NUMBER_FORMAT = '0,0';
+export const APP_TWO_DIGITS_AFTER_POINT_NUMBER_FORMAT = '0,0.[00]';
diff --git a/myApp/src/main/webapp/app/config/dayjs.ts b/myApp/src/main/webapp/app/config/dayjs.ts
new file mode 100644
index 000000000..9ae695d42
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/dayjs.ts
@@ -0,0 +1,12 @@
+import dayjs from 'dayjs';
+import customParseFormat from 'dayjs/plugin/customParseFormat';
+import duration from 'dayjs/plugin/duration';
+import relativeTime from 'dayjs/plugin/relativeTime';
+
+// jhipster-needle-i18n-language-dayjs-imports - JHipster will import languages from dayjs here
+import 'dayjs/locale/en';
+
+// DAYJS CONFIGURATION
+dayjs.extend(customParseFormat);
+dayjs.extend(duration);
+dayjs.extend(relativeTime);
diff --git a/myApp/src/main/webapp/app/config/error-middleware.ts b/myApp/src/main/webapp/app/config/error-middleware.ts
new file mode 100644
index 000000000..ecf1d5efd
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/error-middleware.ts
@@ -0,0 +1,29 @@
+const getErrorMessage = errorData => {
+ let message = errorData.message;
+ if (errorData.fieldErrors) {
+ errorData.fieldErrors.forEach(fErr => {
+ message += `\nfield: ${fErr.field}, Object: ${fErr.objectName}, message: ${fErr.message}\n`;
+ });
+ }
+ return message;
+};
+
+export default () => next => action => {
+ /**
+ *
+ * The error middleware serves to log error messages from dispatch
+ * It need not run in production
+ */
+ if (DEVELOPMENT) {
+ const { error } = action;
+ if (error) {
+ console.error(`${action.type} caught at middleware with reason: ${JSON.stringify(error.message)}.`);
+ if (error.response && error.response.data) {
+ const message = getErrorMessage(error.response.data);
+ console.error(`Actual cause: ${message}`);
+ }
+ }
+ }
+ // Dispatch initial action
+ return next(action);
+};
diff --git a/myApp/src/main/webapp/app/config/icon-loader.ts b/myApp/src/main/webapp/app/config/icon-loader.ts
new file mode 100644
index 000000000..e52a1faf5
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/icon-loader.ts
@@ -0,0 +1,73 @@
+import { faCogs } from '@fortawesome/free-solid-svg-icons/faCogs';
+import { faBan } from '@fortawesome/free-solid-svg-icons/faBan';
+import { faAsterisk } from '@fortawesome/free-solid-svg-icons/faAsterisk';
+import { faArrowLeft } from '@fortawesome/free-solid-svg-icons/faArrowLeft';
+import { faBell } from '@fortawesome/free-solid-svg-icons/faBell';
+import { faBook } from '@fortawesome/free-solid-svg-icons/faBook';
+import { faCloud } from '@fortawesome/free-solid-svg-icons/faCloud';
+import { faDatabase } from '@fortawesome/free-solid-svg-icons/faDatabase';
+import { faEye } from '@fortawesome/free-solid-svg-icons/faEye';
+import { faFlag } from '@fortawesome/free-solid-svg-icons/faFlag';
+import { faHeart } from '@fortawesome/free-solid-svg-icons/faHeart';
+import { faHome } from '@fortawesome/free-solid-svg-icons/faHome';
+import { faList } from '@fortawesome/free-solid-svg-icons/faList';
+import { faLock } from '@fortawesome/free-solid-svg-icons/faLock';
+import { faPencilAlt } from '@fortawesome/free-solid-svg-icons/faPencilAlt';
+import { faPlus } from '@fortawesome/free-solid-svg-icons/faPlus';
+import { faSave } from '@fortawesome/free-solid-svg-icons/faSave';
+import { faSearch } from '@fortawesome/free-solid-svg-icons/faSearch';
+import { faSort } from '@fortawesome/free-solid-svg-icons/faSort';
+import { faSync } from '@fortawesome/free-solid-svg-icons/faSync';
+import { faRoad } from '@fortawesome/free-solid-svg-icons/faRoad';
+import { faSignInAlt } from '@fortawesome/free-solid-svg-icons/faSignInAlt';
+import { faSignOutAlt } from '@fortawesome/free-solid-svg-icons/faSignOutAlt';
+import { faTachometerAlt } from '@fortawesome/free-solid-svg-icons/faTachometerAlt';
+import { faTasks } from '@fortawesome/free-solid-svg-icons/faTasks';
+import { faThList } from '@fortawesome/free-solid-svg-icons/faThList';
+import { faTimesCircle } from '@fortawesome/free-solid-svg-icons/faTimesCircle';
+import { faTrash } from '@fortawesome/free-solid-svg-icons/faTrash';
+import { faUser } from '@fortawesome/free-solid-svg-icons/faUser';
+import { faUserPlus } from '@fortawesome/free-solid-svg-icons/faUserPlus';
+import { faUsers } from '@fortawesome/free-solid-svg-icons/faUsers';
+import { faUsersCog } from '@fortawesome/free-solid-svg-icons/faUsersCog';
+import { faWrench } from '@fortawesome/free-solid-svg-icons/faWrench';
+
+import { library } from '@fortawesome/fontawesome-svg-core';
+
+export const loadIcons = () => {
+ library.add(
+ faArrowLeft,
+ faAsterisk,
+ faBan,
+ faBell,
+ faBook,
+ faCloud,
+ faCogs,
+ faDatabase,
+ faEye,
+ faFlag,
+ faHeart,
+ faHome,
+ faList,
+ faLock,
+ faPencilAlt,
+ faPlus,
+ faRoad,
+ faSave,
+ faSignInAlt,
+ faSignOutAlt,
+ faSearch,
+ faSort,
+ faSync,
+ faTachometerAlt,
+ faTasks,
+ faThList,
+ faTimesCircle,
+ faTrash,
+ faUser,
+ faUserPlus,
+ faUsers,
+ faUsersCog,
+ faWrench
+ );
+};
diff --git a/myApp/src/main/webapp/app/config/logger-middleware.ts b/myApp/src/main/webapp/app/config/logger-middleware.ts
new file mode 100644
index 000000000..013003e7e
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/logger-middleware.ts
@@ -0,0 +1,16 @@
+/* eslint no-console: off */
+export default () => next => action => {
+ if (DEVELOPMENT) {
+ const { type, payload, meta, error } = action;
+
+ console.groupCollapsed(type);
+ console.log('Payload:', payload);
+ if (error) {
+ console.log('Error:', error);
+ }
+ console.log('Meta:', meta);
+ console.groupEnd();
+ }
+
+ return next(action);
+};
diff --git a/myApp/src/main/webapp/app/config/notification-middleware.spec.ts b/myApp/src/main/webapp/app/config/notification-middleware.spec.ts
new file mode 100644
index 000000000..41877350c
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/notification-middleware.spec.ts
@@ -0,0 +1,248 @@
+import { createStore, applyMiddleware } from 'redux';
+import * as toastify from 'react-toastify'; // synthetic default import doesn't work here due to mocking.
+import sinon from 'sinon';
+import { TranslatorContext } from 'react-jhipster';
+
+import notificationMiddleware from './notification-middleware';
+
+describe('Notification Middleware', () => {
+ let store;
+
+ const SUCCESS_TYPE = 'SUCCESS/fulfilled';
+ const ERROR_TYPE = 'ERROR/rejected';
+
+ // Default action for use in local tests
+ const DEFAULT = {
+ type: SUCCESS_TYPE,
+ payload: 'foo',
+ };
+ const HEADER_SUCCESS = {
+ type: SUCCESS_TYPE,
+ payload: {
+ status: 201,
+ statusText: 'Created',
+ headers: { 'app-alert': 'foo.created', 'app-params': 'foo' },
+ },
+ };
+
+ const DEFAULT_ERROR = {
+ type: ERROR_TYPE,
+ error: new Error('foo'),
+ };
+ const VALIDATION_ERROR = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ response: {
+ data: {
+ type: 'https://www.jhipster.tech/problem/constraint-violation',
+ title: 'Method argument not valid',
+ status: 400,
+ path: '/api/foos',
+ message: 'error.validation',
+ fieldErrors: [{ objectName: 'foos', field: 'minField', message: 'Min' }],
+ },
+ status: 400,
+ statusText: 'Bad Request',
+ headers: { expires: '0' },
+ },
+ },
+ };
+ const HEADER_ERRORS = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ response: {
+ status: 400,
+ statusText: 'Bad Request',
+ headers: { 'app-error': 'foo.creation', 'app-params': 'foo' },
+ },
+ },
+ };
+ const NOT_FOUND_ERROR = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ response: {
+ data: {
+ status: 404,
+ message: 'Not found',
+ },
+ status: 404,
+ },
+ },
+ };
+ const NO_SERVER_ERROR = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ response: {
+ status: 0,
+ },
+ },
+ };
+ const GENERIC_ERROR = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ response: {
+ data: {
+ message: 'Error',
+ },
+ },
+ },
+ };
+ const LOGIN_REJECTED_ERROR = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ response: {
+ data: {
+ title: 'Unauthorized',
+ status: 401,
+ path: '/api/authenticate',
+ message: 'error.http.401',
+ },
+ status: 401,
+ },
+ },
+ };
+
+ const TITLE_ERROR = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ response: {
+ data: {
+ title: 'Incorrect password',
+ status: 400,
+ type: 'https://www.jhipster.tech/problem/invalid-password',
+ },
+ status: 400,
+ },
+ },
+ };
+
+ const STRING_DATA_ERROR = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ response: {
+ data: 'Incorrect password string',
+ status: 400,
+ },
+ },
+ };
+
+ const UNKNON_400_ERROR = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ response: {
+ status: 400,
+ },
+ },
+ };
+
+ const UNKNON_ERROR = {
+ type: ERROR_TYPE,
+ error: {
+ isAxiosError: true,
+ },
+ };
+
+ const makeStore = () => applyMiddleware(notificationMiddleware)(createStore)(() => null);
+
+ beforeAll(() => {
+ TranslatorContext.registerTranslations('en', {});
+ });
+
+ beforeEach(() => {
+ store = makeStore();
+ sinon.spy(toastify.toast, 'error');
+ sinon.spy(toastify.toast, 'success');
+ });
+
+ afterEach(() => {
+ (toastify.toast as any).error.restore();
+ (toastify.toast as any).success.restore();
+ });
+
+ it('should not trigger a toast message but should return action', () => {
+ expect(store.dispatch(DEFAULT).payload).toEqual('foo');
+ expect((toastify.toast as any).error.called).toEqual(false);
+ expect((toastify.toast as any).success.called).toEqual(false);
+ });
+
+ it('should trigger a success toast message for header alerts', () => {
+ expect(store.dispatch(HEADER_SUCCESS).payload.status).toEqual(201);
+ const toastMsg = (toastify.toast as any).success.getCall(0).args[0];
+ expect(toastMsg).toContain('foo.created');
+ });
+
+ it('should trigger an error toast message and return error', () => {
+ expect(store.dispatch(DEFAULT_ERROR).error.message).toEqual('foo');
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toEqual('foo');
+ });
+
+ it('should trigger an error toast message and return error for generic message', () => {
+ expect(store.dispatch(GENERIC_ERROR).error.response.data.message).toEqual('Error');
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toContain('Error');
+ });
+
+ it('should trigger an error toast message and return error for 400 response code', () => {
+ expect(store.dispatch(VALIDATION_ERROR).error.response.data.message).toEqual('error.validation');
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toContain('error.Size');
+ });
+
+ it('should trigger an error toast message and return error for 404 response code', () => {
+ expect(store.dispatch(NOT_FOUND_ERROR).error.response.data.message).toEqual('Not found');
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toContain('error.url.not.found');
+ });
+
+ it('should trigger an error toast message and return error for 0 response code', () => {
+ expect(store.dispatch(NO_SERVER_ERROR).error.response.status).toEqual(0);
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toContain('error.server.not.reachable');
+ });
+
+ it('should trigger an error toast message and return error for headers containing errors', () => {
+ expect(store.dispatch(HEADER_ERRORS).error.response.status).toEqual(400);
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toContain('foo.creation');
+ });
+
+ it('should not trigger an error toast message and return error for 401 response code', () => {
+ expect(store.dispatch(LOGIN_REJECTED_ERROR).error.response.status).toEqual(401);
+ expect((toastify.toast as any).error.called).toEqual(false);
+ expect((toastify.toast as any).success.called).toEqual(false);
+ });
+
+ it('should trigger an error toast message and return error for 400 response code', () => {
+ expect(store.dispatch(TITLE_ERROR).error.response.status).toEqual(400);
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toContain('Incorrect password');
+ });
+
+ it('should trigger an error toast message and return error for string in data', () => {
+ expect(store.dispatch(STRING_DATA_ERROR).error.response.status).toEqual(400);
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toContain('Incorrect password string');
+ });
+
+ it('should trigger an error toast message and return error for unknown 400 error', () => {
+ expect(store.dispatch(UNKNON_400_ERROR).error.response.status).toEqual(400);
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toContain('Unknown error!');
+ });
+
+ it('should trigger an error toast message and return error for unknown error', () => {
+ expect(store.dispatch(UNKNON_ERROR).error.isAxiosError).toEqual(true);
+ const toastMsg = (toastify.toast as any).error.getCall(0).args[0];
+ expect(toastMsg).toContain('Unknown error!');
+ });
+});
diff --git a/myApp/src/main/webapp/app/config/notification-middleware.ts b/myApp/src/main/webapp/app/config/notification-middleware.ts
new file mode 100644
index 000000000..916889b41
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/notification-middleware.ts
@@ -0,0 +1,106 @@
+import { translate } from 'react-jhipster';
+import { toast } from 'react-toastify';
+import { isFulfilledAction, isRejectedAction } from 'app/shared/reducers/reducer.utils';
+
+const addErrorAlert = (message, key?, data?) => {
+ key = key ? key : message;
+ toast.error(translate(key, data));
+};
+
+export default () => next => action => {
+ const { error, payload } = action;
+
+ /**
+ *
+ * The notification middleware serves to add success and error notifications
+ */
+ if (isFulfilledAction(action) && payload && payload.headers) {
+ const headers = payload?.headers;
+ let alert: string | null = null;
+ let alertParams: string | null = null;
+ headers &&
+ Object.entries(headers).forEach(([k, v]) => {
+ if (k.toLowerCase().endsWith('app-alert')) {
+ alert = v;
+ } else if (k.toLowerCase().endsWith('app-params')) {
+ alertParams = decodeURIComponent(v.replace(/\+/g, ' '));
+ }
+ });
+ if (alert) {
+ const alertParam = alertParams;
+ toast.success(translate(alert, { param: alertParam }));
+ }
+ }
+
+ if (isRejectedAction(action) && error && error.isAxiosError) {
+ if (error.response) {
+ const response = error.response;
+ const data = response.data;
+ if (
+ !(
+ response.status === 401 &&
+ (error.message === '' || (data && data.path && (data.path.includes('/api/account') || data.path.includes('/api/authenticate'))))
+ )
+ ) {
+ switch (response.status) {
+ // connection refused, server not reachable
+ case 0:
+ addErrorAlert('Server not reachable', 'error.server.not.reachable');
+ break;
+
+ case 400: {
+ let errorHeader: string | null = null;
+ let entityKey: string | null = null;
+ response?.headers &&
+ Object.entries(response.headers).forEach(([k, v]) => {
+ if (k.toLowerCase().endsWith('app-error')) {
+ errorHeader = v;
+ } else if (k.toLowerCase().endsWith('app-params')) {
+ entityKey = v;
+ }
+ });
+ if (errorHeader) {
+ const entityName = translate('global.menu.entities.' + entityKey);
+ addErrorAlert(errorHeader, errorHeader, { entityName });
+ } else if (data?.fieldErrors) {
+ const fieldErrors = data.fieldErrors;
+ for (const fieldError of fieldErrors) {
+ if (['Min', 'Max', 'DecimalMin', 'DecimalMax'].includes(fieldError.message)) {
+ fieldError.message = 'Size';
+ }
+ // convert 'something[14].other[4].id' to 'something[].other[].id' so translations can be written to it
+ const convertedField = fieldError.field.replace(/\[\d*\]/g, '[]');
+ const fieldName = translate(`myApp.${fieldError.objectName}.${convertedField}`);
+ addErrorAlert(`Error on field "${fieldName}"`, `error.${fieldError.message}`, { fieldName });
+ }
+ } else if (typeof data === 'string' && data !== '') {
+ addErrorAlert(data);
+ } else {
+ toast.error(data?.message || data?.error || data?.title || 'Unknown error!');
+ }
+ break;
+ }
+ case 404:
+ addErrorAlert('Not found', 'error.url.not.found');
+ break;
+
+ default:
+ if (typeof data === 'string' && data !== '') {
+ addErrorAlert(data);
+ } else {
+ toast.error(data?.message || data?.error || data?.title || 'Unknown error!');
+ }
+ }
+ }
+ } else if (error.config && error.config.url === 'api/account' && error.config.method === 'get') {
+ /* eslint-disable no-console */
+ console.log('Authentication Error: Trying to access url api/account with GET.');
+ } else {
+ toast.error(error.message || 'Unknown error!');
+ }
+ } else if (error) {
+ toast.error(error.message || 'Unknown error!');
+ }
+
+ return next(action);
+};
diff --git a/myApp/src/main/webapp/app/config/store.ts b/myApp/src/main/webapp/app/config/store.ts
new file mode 100644
index 000000000..966875459
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/store.ts
@@ -0,0 +1,30 @@
+import { AnyAction, configureStore, ThunkAction } from '@reduxjs/toolkit';
+import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
+
+import reducer from 'app/shared/reducers';
+import errorMiddleware from './error-middleware';
+import notificationMiddleware from './notification-middleware';
+import loggerMiddleware from './logger-middleware';
+import { loadingBarMiddleware } from 'react-redux-loading-bar';
+
+const store = configureStore({
+ reducer,
+ middleware: getDefaultMiddleware =>
+ getDefaultMiddleware({
+ serializableCheck: {
+ // Ignore these field paths in all actions
+ ignoredActionPaths: ['payload.config', 'payload.request', 'error', 'meta.arg'],
+ },
+ }).concat(errorMiddleware, notificationMiddleware, loadingBarMiddleware(), loggerMiddleware),
+});
+
+const getStore = () => store;
+
+export type IRootState = ReturnType;
+export type AppDispatch = typeof store.dispatch;
+
+export const useAppSelector: TypedUseSelectorHook = useSelector;
+export const useAppDispatch = () => useDispatch();
+export type AppThunk = ThunkAction;
+
+export default getStore;
diff --git a/myApp/src/main/webapp/app/config/translation.ts b/myApp/src/main/webapp/app/config/translation.ts
new file mode 100644
index 000000000..ba04d3b31
--- /dev/null
+++ b/myApp/src/main/webapp/app/config/translation.ts
@@ -0,0 +1,17 @@
+import { TranslatorContext, Storage } from 'react-jhipster';
+
+import { setLocale } from 'app/shared/reducers/locale';
+
+TranslatorContext.setDefaultLocale('en');
+TranslatorContext.setRenderInnerTextForMissingKeys(false);
+
+export const languages: any = {
+ en: { name: 'English' },
+ // jhipster-needle-i18n-language-key-pipe - JHipster will add/remove languages in this object
+};
+
+export const locales = Object.keys(languages).sort();
+
+export const registerLocale = store => {
+ store.dispatch(setLocale(Storage.session.get('locale', 'en')));
+};
diff --git a/myApp/src/main/webapp/app/entities/index.tsx b/myApp/src/main/webapp/app/entities/index.tsx
new file mode 100644
index 000000000..447b24d89
--- /dev/null
+++ b/myApp/src/main/webapp/app/entities/index.tsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import { Switch } from 'react-router-dom';
+
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
+
+/* jhipster-needle-add-route-import - JHipster will add routes here */
+
+const Routes = ({ match }) => (
+
+
+ {/* prettier-ignore */}
+ {/* jhipster-needle-add-route-path - JHipster will add routes here */}
+
+
+);
+
+export default Routes;
diff --git a/myApp/src/main/webapp/app/index.tsx b/myApp/src/main/webapp/app/index.tsx
new file mode 100644
index 000000000..bff475a89
--- /dev/null
+++ b/myApp/src/main/webapp/app/index.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import { Provider } from 'react-redux';
+import { bindActionCreators } from 'redux';
+
+import getStore from './config/store';
+import { registerLocale } from './config/translation';
+import setupAxiosInterceptors from './config/axios-interceptor';
+import { clearAuthentication } from './shared/reducers/authentication';
+import ErrorBoundary from './shared/error/error-boundary';
+import AppComponent from './app';
+import { loadIcons } from './config/icon-loader';
+
+const store = getStore();
+registerLocale(store);
+
+const actions = bindActionCreators({ clearAuthentication }, store.dispatch);
+setupAxiosInterceptors(() => actions.clearAuthentication('login.error.unauthorized'));
+
+loadIcons();
+
+const rootEl = document.getElementById('root');
+
+const render = Component =>
+ // eslint-disable-next-line react/no-render-return-value
+ ReactDOM.render(
+
+
+
+
+
+
+ ,
+ rootEl
+ );
+
+render(AppComponent);
diff --git a/myApp/src/main/webapp/app/modules/account/activate/activate.reducer.spec.ts b/myApp/src/main/webapp/app/modules/account/activate/activate.reducer.spec.ts
new file mode 100644
index 000000000..a8ca08833
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/activate/activate.reducer.spec.ts
@@ -0,0 +1,83 @@
+import thunk from 'redux-thunk';
+import axios from 'axios';
+import sinon from 'sinon';
+import configureStore from 'redux-mock-store';
+
+import activate, { activateAction, reset } from './activate.reducer';
+
+describe('Activate reducer tests', () => {
+ it('should return the initial state', () => {
+ expect(activate(undefined, { type: '' })).toMatchObject({
+ activationSuccess: false,
+ activationFailure: false,
+ });
+ });
+
+ it('should reset', () => {
+ expect(activate({ activationSuccess: true, activationFailure: false }, reset)).toMatchObject({
+ activationSuccess: false,
+ activationFailure: false,
+ });
+ });
+
+ it('should detect a success', () => {
+ expect(activate(undefined, { type: activateAction.fulfilled.type })).toMatchObject({
+ activationSuccess: true,
+ activationFailure: false,
+ });
+ });
+
+ it('should return the same state on request', () => {
+ expect(activate(undefined, { type: activateAction.pending.type })).toMatchObject({
+ activationSuccess: false,
+ activationFailure: false,
+ });
+ });
+
+ it('should detect a failure', () => {
+ expect(activate(undefined, { type: activateAction.rejected.type })).toMatchObject({
+ activationSuccess: false,
+ activationFailure: true,
+ });
+ });
+
+ it('should reset the state', () => {
+ const initialState = {
+ activationSuccess: false,
+ activationFailure: false,
+ };
+ expect(activate({ activationSuccess: true, activationFailure: true }, reset)).toEqual({
+ ...initialState,
+ });
+ });
+
+ describe('Actions', () => {
+ let store;
+
+ const resolvedObject = { value: 'whatever' };
+ beforeEach(() => {
+ const mockStore = configureStore([thunk]);
+ store = mockStore({});
+ axios.get = sinon.stub().returns(Promise.resolve(resolvedObject));
+ });
+
+ it('dispatches ACTIVATE_ACCOUNT_PENDING and ACTIVATE_ACCOUNT_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: activateAction.pending.type,
+ },
+ {
+ type: activateAction.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(activateAction(''));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ it('dispatches RESET actions', async () => {
+ await store.dispatch(reset());
+ expect(store.getActions()[0]).toMatchObject(reset());
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/modules/account/activate/activate.reducer.ts b/myApp/src/main/webapp/app/modules/account/activate/activate.reducer.ts
new file mode 100644
index 000000000..aa8ebeded
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/activate/activate.reducer.ts
@@ -0,0 +1,42 @@
+import axios from 'axios';
+import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
+
+import { serializeAxiosError } from 'app/shared/reducers/reducer.utils';
+
+const initialState = {
+ activationSuccess: false,
+ activationFailure: false,
+};
+
+export type ActivateState = Readonly;
+
+// Actions
+
+export const activateAction = createAsyncThunk('activate/activate_account', async (key: string) => axios.get(`api/activate?key=${key}`), {
+ serializeError: serializeAxiosError,
+});
+
+export const ActivateSlice = createSlice({
+ name: 'activate',
+ initialState: initialState as ActivateState,
+ reducers: {
+ reset() {
+ return initialState;
+ },
+ },
+ extraReducers(builder) {
+ builder
+ .addCase(activateAction.pending, () => initialState)
+ .addCase(activateAction.rejected, state => {
+ state.activationFailure = true;
+ })
+ .addCase(activateAction.fulfilled, state => {
+ state.activationSuccess = true;
+ });
+ },
+});
+
+export const { reset } = ActivateSlice.actions;
+
+// Reducer
+export default ActivateSlice.reducer;
diff --git a/myApp/src/main/webapp/app/modules/account/activate/activate.tsx b/myApp/src/main/webapp/app/modules/account/activate/activate.tsx
new file mode 100644
index 000000000..473a1de48
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/activate/activate.tsx
@@ -0,0 +1,56 @@
+import React, { useEffect } from 'react';
+import { Link, RouteComponentProps } from 'react-router-dom';
+import { Row, Col, Alert } from 'reactstrap';
+import { Translate, getUrlParameter } from 'react-jhipster';
+
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+import { activateAction, reset } from './activate.reducer';
+
+const successAlert = (
+
+
+ Your user account has been activated. Please
+
+
+ sign in
+
+ .
+
+);
+
+const failureAlert = (
+
+
+ Your user could not be activated. Please use the registration form to sign up.
+
+
+);
+
+export const ActivatePage = (props: RouteComponentProps<{ key: any }>) => {
+ const dispatch = useAppDispatch();
+ useEffect(() => {
+ const key = getUrlParameter('key', props.location.search);
+ dispatch(activateAction(key));
+ return () => {
+ dispatch(reset());
+ };
+ }, []);
+
+ const { activationSuccess, activationFailure } = useAppSelector(state => state.activate);
+
+ return (
+
+
+
+
+ Activation
+
+ {activationSuccess ? successAlert : undefined}
+ {activationFailure ? failureAlert : undefined}
+
+
+
+ );
+};
+
+export default ActivatePage;
diff --git a/myApp/src/main/webapp/app/modules/account/index.tsx b/myApp/src/main/webapp/app/modules/account/index.tsx
new file mode 100644
index 000000000..487446047
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/index.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+
+import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
+
+import Settings from './settings/settings';
+import Password from './password/password';
+
+const Routes = ({ match }) => (
+
+
+
+
+);
+
+export default Routes;
diff --git a/myApp/src/main/webapp/app/modules/account/password-reset/finish/password-reset-finish.tsx b/myApp/src/main/webapp/app/modules/account/password-reset/finish/password-reset-finish.tsx
new file mode 100644
index 000000000..a01ad6294
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/password-reset/finish/password-reset-finish.tsx
@@ -0,0 +1,86 @@
+import React, { useState, useEffect } from 'react';
+import { Col, Row, Button } from 'reactstrap';
+import { Translate, translate, getUrlParameter, ValidatedField, ValidatedForm } from 'react-jhipster';
+import { RouteComponentProps } from 'react-router-dom';
+import { toast } from 'react-toastify';
+
+import { handlePasswordResetFinish, reset } from '../password-reset.reducer';
+import PasswordStrengthBar from 'app/shared/layout/password/password-strength-bar';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+
+export const PasswordResetFinishPage = (props: RouteComponentProps<{ key: string }>) => {
+ const [password, setPassword] = useState('');
+ const [key] = useState(getUrlParameter('key', props.location.search));
+ const dispatch = useAppDispatch();
+
+ useEffect(
+ () => () => {
+ dispatch(reset());
+ },
+ []
+ );
+
+ const handleValidSubmit = ({ newPassword }) => dispatch(handlePasswordResetFinish({ key, newPassword }));
+
+ const updatePassword = event => setPassword(event.target.value);
+
+ const getResetForm = () => {
+ return (
+
+
+
+ v === password || translate('global.messages.error.dontmatch'),
+ }}
+ data-cy="confirmResetPassword"
+ />
+
+ Validate new password
+
+
+ );
+ };
+
+ const successMessage = useAppSelector(state => state.passwordReset.successMessage);
+
+ useEffect(() => {
+ if (successMessage) {
+ toast.success(translate(successMessage));
+ }
+ }, [successMessage]);
+
+ return (
+
+
+
+
+ Reset password
+
+ {key ? getResetForm() : null}
+
+
+
+ );
+};
+
+export default PasswordResetFinishPage;
diff --git a/myApp/src/main/webapp/app/modules/account/password-reset/init/password-reset-init.tsx b/myApp/src/main/webapp/app/modules/account/password-reset/init/password-reset-init.tsx
new file mode 100644
index 000000000..b0eb9cf8f
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/password-reset/init/password-reset-init.tsx
@@ -0,0 +1,67 @@
+import React, { useEffect } from 'react';
+import { Translate, translate, ValidatedField, ValidatedForm, isEmail } from 'react-jhipster';
+import { Button, Alert, Col, Row } from 'reactstrap';
+import { toast } from 'react-toastify';
+
+import { handlePasswordResetInit, reset } from '../password-reset.reducer';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+
+export const PasswordResetInit = () => {
+ const dispatch = useAppDispatch();
+
+ useEffect(
+ () => () => {
+ dispatch(reset());
+ },
+ []
+ );
+
+ const handleValidSubmit = ({ email }) => {
+ dispatch(handlePasswordResetInit(email));
+ };
+
+ const successMessage = useAppSelector(state => state.passwordReset.successMessage);
+
+ useEffect(() => {
+ if (successMessage) {
+ toast.success(translate(successMessage));
+ }
+ }, [successMessage]);
+
+ return (
+
+
+
+
+ Reset your password
+
+
+
+ Enter the email address you used to register
+
+
+
+ isEmail(v) || translate('global.messages.validate.email.invalid'),
+ }}
+ data-cy="emailResetPassword"
+ />
+
+ Reset password
+
+
+
+
+
+ );
+};
+
+export default PasswordResetInit;
diff --git a/myApp/src/main/webapp/app/modules/account/password-reset/password-reset.reducer.ts b/myApp/src/main/webapp/app/modules/account/password-reset/password-reset.reducer.ts
new file mode 100644
index 000000000..7e3358f53
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/password-reset/password-reset.reducer.ts
@@ -0,0 +1,67 @@
+import axios from 'axios';
+import { createAsyncThunk, createSlice, isPending, isRejected } from '@reduxjs/toolkit';
+
+import { serializeAxiosError } from 'app/shared/reducers/reducer.utils';
+
+const initialState = {
+ loading: false,
+ resetPasswordSuccess: false,
+ resetPasswordFailure: false,
+ successMessage: null,
+};
+
+export type PasswordResetState = Readonly;
+
+const apiUrl = 'api/account/reset-password';
+// Actions
+
+export const handlePasswordResetInit = createAsyncThunk(
+ 'passwordReset/reset_password_init',
+ // If the content-type isn't set that way, axios will try to encode the body and thus modify the data sent to the server.
+ async (mail: string) => axios.post(`${apiUrl}/init`, mail, { headers: { ['Content-Type']: 'text/plain' } }),
+ { serializeError: serializeAxiosError }
+);
+
+export const handlePasswordResetFinish = createAsyncThunk(
+ 'passwordReset/reset_password_finish',
+ async (data: { key: string; newPassword: string }) => axios.post(`${apiUrl}/finish`, data),
+ { serializeError: serializeAxiosError }
+);
+
+export const PasswordResetSlice = createSlice({
+ name: 'passwordReset',
+ initialState: initialState as PasswordResetState,
+ reducers: {
+ reset() {
+ return initialState;
+ },
+ },
+ extraReducers(builder) {
+ builder
+ .addCase(handlePasswordResetInit.fulfilled, () => ({
+ ...initialState,
+ loading: false,
+ resetPasswordSuccess: true,
+ successMessage: 'reset.request.messages.success',
+ }))
+ .addCase(handlePasswordResetFinish.fulfilled, () => ({
+ ...initialState,
+ loading: false,
+ resetPasswordSuccess: true,
+ successMessage: 'reset.finish.messages.success',
+ }))
+ .addMatcher(isPending(handlePasswordResetInit, handlePasswordResetFinish), state => {
+ state.loading = true;
+ })
+ .addMatcher(isRejected(handlePasswordResetInit, handlePasswordResetFinish), () => ({
+ ...initialState,
+ loading: false,
+ resetPasswordFailure: true,
+ }));
+ },
+});
+
+export const { reset } = PasswordResetSlice.actions;
+
+// Reducer
+export default PasswordResetSlice.reducer;
diff --git a/myApp/src/main/webapp/app/modules/account/password/password.reducer.spec.ts b/myApp/src/main/webapp/app/modules/account/password/password.reducer.spec.ts
new file mode 100644
index 000000000..305caf45b
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/password/password.reducer.spec.ts
@@ -0,0 +1,95 @@
+import thunk from 'redux-thunk';
+import axios from 'axios';
+import sinon from 'sinon';
+import configureStore from 'redux-mock-store';
+import { TranslatorContext } from 'react-jhipster';
+
+import password, { savePassword, reset } from './password.reducer';
+
+describe('Password reducer tests', () => {
+ beforeAll(() => {
+ TranslatorContext.registerTranslations('en', {});
+ });
+
+ describe('Common tests', () => {
+ it('should return the initial state', () => {
+ const toTest = password(undefined, { type: '' });
+ expect(toTest).toMatchObject({
+ loading: false,
+ errorMessage: null,
+ updateSuccess: false,
+ updateFailure: false,
+ });
+ });
+ });
+
+ describe('Password update', () => {
+ it('should detect a request', () => {
+ const toTest = password(undefined, { type: savePassword.pending.type });
+ expect(toTest).toMatchObject({
+ updateSuccess: false,
+ updateFailure: false,
+ loading: true,
+ });
+ });
+ it('should detect a success', () => {
+ const toTest = password(undefined, { type: savePassword.fulfilled.type });
+ expect(toTest).toMatchObject({
+ updateSuccess: true,
+ updateFailure: false,
+ loading: false,
+ });
+ });
+ it('should detect a failure', () => {
+ const toTest = password(undefined, { type: savePassword.rejected.type });
+ expect(toTest).toMatchObject({
+ updateSuccess: false,
+ updateFailure: true,
+ loading: false,
+ });
+ });
+
+ it('should reset the state', () => {
+ const initialState = {
+ loading: false,
+ errorMessage: null,
+ successMessage: null,
+ updateSuccess: false,
+ updateFailure: false,
+ };
+ expect(password({ ...initialState, loading: true }, reset)).toEqual({
+ ...initialState,
+ });
+ });
+ });
+
+ describe('Actions', () => {
+ let store;
+
+ const resolvedObject = { value: 'whatever' };
+ beforeEach(() => {
+ const mockStore = configureStore([thunk]);
+ store = mockStore({});
+ axios.post = sinon.stub().returns(Promise.resolve(resolvedObject));
+ });
+
+ it('dispatches UPDATE_PASSWORD_PENDING and UPDATE_PASSWORD_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: savePassword.pending.type,
+ },
+ {
+ type: savePassword.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(savePassword({ currentPassword: '', newPassword: '' }));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ it('dispatches RESET actions', async () => {
+ await store.dispatch(reset());
+ expect(store.getActions()[0]).toMatchObject(reset());
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/modules/account/password/password.reducer.ts b/myApp/src/main/webapp/app/modules/account/password/password.reducer.ts
new file mode 100644
index 000000000..7edce4f1d
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/password/password.reducer.ts
@@ -0,0 +1,64 @@
+import axios from 'axios';
+import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
+
+import { serializeAxiosError } from 'app/shared/reducers/reducer.utils';
+
+const initialState = {
+ loading: false,
+ errorMessage: null,
+ successMessage: null,
+ updateSuccess: false,
+ updateFailure: false,
+};
+
+export type PasswordState = Readonly;
+
+const apiUrl = 'api/account';
+
+interface IPassword {
+ currentPassword: string;
+ newPassword: string;
+}
+
+// Actions
+
+export const savePassword = createAsyncThunk(
+ 'password/update_password',
+ async (password: IPassword) => axios.post(`${apiUrl}/change-password`, password),
+ { serializeError: serializeAxiosError }
+);
+
+export const PasswordSlice = createSlice({
+ name: 'password',
+ initialState: initialState as PasswordState,
+ reducers: {
+ reset() {
+ return initialState;
+ },
+ },
+ extraReducers(builder) {
+ builder
+ .addCase(savePassword.pending, state => {
+ state.errorMessage = null;
+ state.updateSuccess = false;
+ state.loading = true;
+ })
+ .addCase(savePassword.rejected, state => {
+ state.loading = false;
+ state.updateSuccess = false;
+ state.updateFailure = true;
+ state.errorMessage = 'password.messages.error';
+ })
+ .addCase(savePassword.fulfilled, state => {
+ state.loading = false;
+ state.updateSuccess = true;
+ state.updateFailure = false;
+ state.successMessage = 'password.messages.success';
+ });
+ },
+});
+
+export const { reset } = PasswordSlice.actions;
+
+// Reducer
+export default PasswordSlice.reducer;
diff --git a/myApp/src/main/webapp/app/modules/account/password/password.tsx b/myApp/src/main/webapp/app/modules/account/password/password.tsx
new file mode 100644
index 000000000..0e2b86f9a
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/password/password.tsx
@@ -0,0 +1,98 @@
+import React, { useState, useEffect } from 'react';
+import { Translate, translate, ValidatedField, ValidatedForm } from 'react-jhipster';
+import { Row, Col, Button } from 'reactstrap';
+import { toast } from 'react-toastify';
+
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+import { getSession } from 'app/shared/reducers/authentication';
+import PasswordStrengthBar from 'app/shared/layout/password/password-strength-bar';
+import { savePassword, reset } from './password.reducer';
+
+export const PasswordPage = () => {
+ const [password, setPassword] = useState('');
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ dispatch(reset());
+ dispatch(getSession());
+ return () => {
+ dispatch(reset());
+ };
+ }, []);
+
+ const handleValidSubmit = ({ currentPassword, newPassword }) => {
+ dispatch(savePassword({ currentPassword, newPassword }));
+ };
+
+ const updatePassword = event => setPassword(event.target.value);
+
+ const account = useAppSelector(state => state.authentication.account);
+ const successMessage = useAppSelector(state => state.password.successMessage);
+ const errorMessage = useAppSelector(state => state.password.errorMessage);
+
+ useEffect(() => {
+ if (successMessage) {
+ toast.success(translate(successMessage));
+ } else if (errorMessage) {
+ toast.error(translate(errorMessage));
+ }
+ }, [successMessage, errorMessage]);
+
+ return (
+
+
+
+
+
+ Password for {account.login}
+
+
+
+
+
+
+ v === password || translate('global.messages.error.dontmatch'),
+ }}
+ data-cy="confirmPassword"
+ />
+
+ Save
+
+
+
+
+
+ );
+};
+
+export default PasswordPage;
diff --git a/myApp/src/main/webapp/app/modules/account/register/register.reducer.spec.ts b/myApp/src/main/webapp/app/modules/account/register/register.reducer.spec.ts
new file mode 100644
index 000000000..243024d52
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/register/register.reducer.spec.ts
@@ -0,0 +1,99 @@
+import thunk from 'redux-thunk';
+import axios from 'axios';
+import sinon from 'sinon';
+import configureStore from 'redux-mock-store';
+import { TranslatorContext } from 'react-jhipster';
+
+import register, { handleRegister, reset } from './register.reducer';
+
+describe('Creating account tests', () => {
+ const initialState = {
+ loading: false,
+ registrationSuccess: false,
+ registrationFailure: false,
+ errorMessage: null,
+ successMessage: null,
+ };
+
+ beforeAll(() => {
+ TranslatorContext.registerTranslations('en', {});
+ });
+
+ it('should return the initial state', () => {
+ expect(register(undefined, { type: '' })).toEqual({
+ ...initialState,
+ });
+ });
+
+ it('should detect a request', () => {
+ expect(register(undefined, { type: handleRegister.pending.type })).toEqual({
+ ...initialState,
+ loading: true,
+ });
+ });
+
+ it('should handle RESET', () => {
+ expect(
+ register({ loading: true, registrationSuccess: true, registrationFailure: true, errorMessage: '', successMessage: '' }, reset())
+ ).toEqual({
+ ...initialState,
+ });
+ });
+
+ it('should handle CREATE_ACCOUNT success', () => {
+ expect(
+ register(undefined, {
+ type: handleRegister.fulfilled.type,
+ payload: 'fake payload',
+ })
+ ).toEqual({
+ ...initialState,
+ registrationSuccess: true,
+ successMessage: 'register.messages.success',
+ });
+ });
+
+ it('should handle CREATE_ACCOUNT failure', () => {
+ const error = { message: 'fake error' };
+ expect(
+ register(undefined, {
+ type: handleRegister.rejected.type,
+ error,
+ })
+ ).toEqual({
+ ...initialState,
+ registrationFailure: true,
+ errorMessage: error.message,
+ });
+ });
+
+ describe('Actions', () => {
+ let store;
+
+ const resolvedObject = { value: 'whatever' };
+ beforeEach(() => {
+ const mockStore = configureStore([thunk]);
+ store = mockStore({});
+ axios.post = sinon.stub().returns(Promise.resolve(resolvedObject));
+ });
+
+ it('dispatches CREATE_ACCOUNT_PENDING and CREATE_ACCOUNT_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: handleRegister.pending.type,
+ },
+ {
+ type: handleRegister.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(handleRegister({ login: '', email: '', password: '' }));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ it('dispatches RESET actions', async () => {
+ await store.dispatch(reset());
+ expect(store.getActions()[0]).toMatchObject(reset());
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/modules/account/register/register.reducer.ts b/myApp/src/main/webapp/app/modules/account/register/register.reducer.ts
new file mode 100644
index 000000000..5e114b3c3
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/register/register.reducer.ts
@@ -0,0 +1,53 @@
+import axios from 'axios';
+import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
+
+import { serializeAxiosError } from 'app/shared/reducers/reducer.utils';
+
+const initialState = {
+ loading: false,
+ registrationSuccess: false,
+ registrationFailure: false,
+ errorMessage: null,
+ successMessage: null,
+};
+
+export type RegisterState = Readonly;
+
+// Actions
+
+export const handleRegister = createAsyncThunk(
+ 'register/create_account',
+ async (data: { login: string; email: string; password: string; langKey?: string }) => axios.post('api/register', data),
+ { serializeError: serializeAxiosError }
+);
+
+export const RegisterSlice = createSlice({
+ name: 'register',
+ initialState: initialState as RegisterState,
+ reducers: {
+ reset() {
+ return initialState;
+ },
+ },
+ extraReducers(builder) {
+ builder
+ .addCase(handleRegister.pending, state => {
+ state.loading = true;
+ })
+ .addCase(handleRegister.rejected, (state, action) => ({
+ ...initialState,
+ registrationFailure: true,
+ errorMessage: action.error.message,
+ }))
+ .addCase(handleRegister.fulfilled, () => ({
+ ...initialState,
+ registrationSuccess: true,
+ successMessage: 'register.messages.success',
+ }));
+ },
+});
+
+export const { reset } = RegisterSlice.actions;
+
+// Reducer
+export default RegisterSlice.reducer;
diff --git a/myApp/src/main/webapp/app/modules/account/register/register.tsx b/myApp/src/main/webapp/app/modules/account/register/register.tsx
new file mode 100644
index 000000000..8f87c3b5f
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/register/register.tsx
@@ -0,0 +1,130 @@
+import React, { useState, useEffect } from 'react';
+import { Translate, translate, ValidatedField, ValidatedForm, isEmail } from 'react-jhipster';
+import { Row, Col, Alert, Button } from 'reactstrap';
+import { toast } from 'react-toastify';
+
+import PasswordStrengthBar from 'app/shared/layout/password/password-strength-bar';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+import { handleRegister, reset } from './register.reducer';
+
+export const RegisterPage = () => {
+ const [password, setPassword] = useState('');
+ const dispatch = useAppDispatch();
+
+ useEffect(
+ () => () => {
+ dispatch(reset());
+ },
+ []
+ );
+
+ const currentLocale = useAppSelector(state => state.locale.currentLocale);
+
+ const handleValidSubmit = ({ username, email, firstPassword }) => {
+ dispatch(handleRegister({ login: username, email, password: firstPassword, langKey: currentLocale }));
+ };
+
+ const updatePassword = event => setPassword(event.target.value);
+
+ const successMessage = useAppSelector(state => state.register.successMessage);
+
+ useEffect(() => {
+ if (successMessage) {
+ toast.success(translate(successMessage));
+ }
+ }, [successMessage]);
+
+ return (
+
+
+
+
+ Registration
+
+
+
+
+
+
+
+ isEmail(v) || translate('global.messages.validate.email.invalid'),
+ }}
+ data-cy="email"
+ />
+
+
+ v === password || translate('global.messages.error.dontmatch'),
+ }}
+ data-cy="secondPassword"
+ />
+
+ Register
+
+
+
+
+
+ If you want to
+
+
+ sign in
+
+
+
+ , you can try the default accounts:
+ - Administrator (login="admin" and password="admin")
+ - User (login="user" and password="user").
+
+
+
+
+
+
+ );
+};
+
+export default RegisterPage;
diff --git a/myApp/src/main/webapp/app/modules/account/settings/settings.reducer.spec.ts b/myApp/src/main/webapp/app/modules/account/settings/settings.reducer.spec.ts
new file mode 100644
index 000000000..9f37b614b
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/settings/settings.reducer.spec.ts
@@ -0,0 +1,101 @@
+import configureStore from 'redux-mock-store';
+import thunk from 'redux-thunk';
+import axios from 'axios';
+import sinon from 'sinon';
+import { TranslatorContext } from 'react-jhipster';
+
+import account, { updateAccount, saveAccountSettings, reset } from './settings.reducer';
+import { getAccount } from 'app/shared/reducers/authentication';
+
+describe('Settings reducer tests', () => {
+ beforeAll(() => {
+ TranslatorContext.registerTranslations('en', {});
+ });
+
+ describe('Common tests', () => {
+ it('should return the initial state', () => {
+ const toTest = account(undefined, { type: '' });
+ expect(toTest).toMatchObject({
+ loading: false,
+ errorMessage: null,
+ updateSuccess: false,
+ updateFailure: false,
+ });
+ });
+ });
+
+ describe('Settings update', () => {
+ it('should detect a request', () => {
+ const toTest = account(undefined, { type: updateAccount.pending.type });
+ expect(toTest).toMatchObject({
+ updateSuccess: false,
+ updateFailure: false,
+ loading: true,
+ });
+ });
+ it('should detect a success', () => {
+ const toTest = account(undefined, { type: updateAccount.fulfilled.type });
+ expect(toTest).toMatchObject({
+ updateSuccess: true,
+ updateFailure: false,
+ loading: false,
+ });
+ });
+ it('should detect a failure', () => {
+ const toTest = account(undefined, { type: updateAccount.rejected.type });
+ expect(toTest).toMatchObject({
+ updateSuccess: false,
+ updateFailure: true,
+ loading: false,
+ });
+ });
+
+ it('should reset the state', () => {
+ const initialState = {
+ loading: false,
+ errorMessage: null,
+ successMessage: null,
+ updateSuccess: false,
+ updateFailure: false,
+ };
+ expect(account({ ...initialState, loading: true }, reset())).toEqual({
+ ...initialState,
+ });
+ });
+ });
+
+ describe('Actions', () => {
+ let store;
+
+ const resolvedObject = { value: 'whatever' };
+ beforeEach(() => {
+ const mockStore = configureStore([thunk]);
+ store = mockStore({ authentication: { account: { langKey: 'en' } } });
+ axios.get = sinon.stub().returns(Promise.resolve(resolvedObject));
+ axios.post = sinon.stub().returns(Promise.resolve(resolvedObject));
+ });
+
+ it('dispatches UPDATE_ACCOUNT_PENDING and UPDATE_ACCOUNT_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: updateAccount.pending.type,
+ },
+ {
+ type: updateAccount.fulfilled.type,
+ payload: resolvedObject,
+ },
+ {
+ type: getAccount.pending.type,
+ },
+ ];
+ await store.dispatch(saveAccountSettings({}));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ expect(store.getActions()[2]).toMatchObject(expectedActions[2]);
+ });
+ it('dispatches RESET actions', async () => {
+ await store.dispatch(reset());
+ expect(store.getActions()[0]).toMatchObject(reset());
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/modules/account/settings/settings.reducer.ts b/myApp/src/main/webapp/app/modules/account/settings/settings.reducer.ts
new file mode 100644
index 000000000..00e07d537
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/settings/settings.reducer.ts
@@ -0,0 +1,67 @@
+import axios from 'axios';
+import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
+import { Storage } from 'react-jhipster';
+import { getSession } from 'app/shared/reducers/authentication';
+import { AppThunk } from 'app/config/store';
+import { serializeAxiosError } from 'app/shared/reducers/reducer.utils';
+
+const initialState = {
+ loading: false,
+ errorMessage: null,
+ successMessage: null,
+ updateSuccess: false,
+ updateFailure: false,
+};
+
+export type SettingsState = Readonly;
+
+// Actions
+const apiUrl = 'api/account';
+
+export const saveAccountSettings: (account: any) => AppThunk = account => async dispatch => {
+ await dispatch(updateAccount(account));
+
+ if (Storage.session.get(`locale`)) {
+ Storage.session.remove(`locale`);
+ }
+
+ dispatch(getSession());
+};
+
+export const updateAccount = createAsyncThunk('settings/update_account', async (account: any) => axios.post(apiUrl, account), {
+ serializeError: serializeAxiosError,
+});
+
+export const SettingsSlice = createSlice({
+ name: 'settings',
+ initialState: initialState as SettingsState,
+ reducers: {
+ reset() {
+ return initialState;
+ },
+ },
+ extraReducers(builder) {
+ builder
+ .addCase(updateAccount.pending, state => {
+ state.loading = true;
+ state.errorMessage = null;
+ state.updateSuccess = false;
+ })
+ .addCase(updateAccount.rejected, state => {
+ state.loading = false;
+ state.updateSuccess = false;
+ state.updateFailure = true;
+ })
+ .addCase(updateAccount.fulfilled, state => {
+ state.loading = false;
+ state.updateSuccess = true;
+ state.updateFailure = false;
+ state.successMessage = 'settings.messages.success';
+ });
+ },
+});
+
+export const { reset } = SettingsSlice.actions;
+
+// Reducer
+export default SettingsSlice.reducer;
diff --git a/myApp/src/main/webapp/app/modules/account/settings/settings.tsx b/myApp/src/main/webapp/app/modules/account/settings/settings.tsx
new file mode 100644
index 000000000..35e9aa27e
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/account/settings/settings.tsx
@@ -0,0 +1,102 @@
+import React, { useEffect } from 'react';
+import { Button, Col, Row } from 'reactstrap';
+import { Translate, translate, ValidatedField, ValidatedForm, isEmail } from 'react-jhipster';
+import { toast } from 'react-toastify';
+
+import { locales, languages } from 'app/config/translation';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+import { getSession } from 'app/shared/reducers/authentication';
+import { saveAccountSettings, reset } from './settings.reducer';
+
+export const SettingsPage = () => {
+ const dispatch = useAppDispatch();
+ const account = useAppSelector(state => state.authentication.account);
+ const successMessage = useAppSelector(state => state.settings.successMessage);
+
+ useEffect(() => {
+ dispatch(getSession());
+ return () => {
+ dispatch(reset());
+ };
+ }, []);
+
+ useEffect(() => {
+ if (successMessage) {
+ toast.success(translate(successMessage));
+ }
+ }, [successMessage]);
+
+ const handleValidSubmit = values => {
+ dispatch(
+ saveAccountSettings({
+ ...account,
+ ...values,
+ })
+ );
+ };
+
+ return (
+
+
+
+
+
+ User settings for {account.login}
+
+
+
+
+
+ isEmail(v) || translate('global.messages.validate.email.invalid'),
+ }}
+ data-cy="email"
+ />
+
+ {locales.map(locale => (
+
+ {languages[locale].name}
+
+ ))}
+
+
+ Save
+
+
+
+
+
+ );
+};
+
+export default SettingsPage;
diff --git a/myApp/src/main/webapp/app/modules/administration/administration.reducer.spec.ts b/myApp/src/main/webapp/app/modules/administration/administration.reducer.spec.ts
new file mode 100644
index 000000000..9103caa70
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/administration.reducer.spec.ts
@@ -0,0 +1,282 @@
+import configureStore from 'redux-mock-store';
+import axios from 'axios';
+import thunk from 'redux-thunk';
+import sinon from 'sinon';
+
+import administration, {
+ getSystemHealth,
+ getSystemMetrics,
+ getSystemThreadDump,
+ getLoggers,
+ changeLogLevel,
+ getConfigurations,
+ getEnv,
+ setLoggers,
+} from './administration.reducer';
+
+describe('Administration reducer tests', () => {
+ function isEmpty(element): boolean {
+ if (element instanceof Array) {
+ return element.length === 0;
+ }
+ return Object.keys(element).length === 0;
+ }
+
+ function testInitialState(state) {
+ expect(state).toMatchObject({
+ loading: false,
+ errorMessage: null,
+ totalItems: 0,
+ });
+ expect(isEmpty(state.logs.loggers));
+ expect(isEmpty(state.threadDump));
+ }
+
+ function testMultipleTypes(types, payload, testFunction, error?) {
+ types.forEach(e => {
+ testFunction(administration(undefined, { type: e, payload, error }));
+ });
+ }
+
+ describe('Common', () => {
+ it('should return the initial state', () => {
+ testInitialState(administration(undefined, { type: '' }));
+ });
+ });
+
+ describe('Requests', () => {
+ it('should set state to loading', () => {
+ testMultipleTypes(
+ [
+ getLoggers.pending.type,
+ getSystemHealth.pending.type,
+ getSystemMetrics.pending.type,
+ getSystemThreadDump.pending.type,
+ getConfigurations.pending.type,
+ getEnv.pending.type,
+ ],
+ {},
+ state => {
+ expect(state).toMatchObject({
+ errorMessage: null,
+ loading: true,
+ });
+ }
+ );
+ });
+ });
+
+ describe('Failures', () => {
+ it('should set state to failed and put an error message in errorMessage', () => {
+ testMultipleTypes(
+ [
+ getLoggers.rejected.type,
+ getSystemHealth.rejected.type,
+ getSystemMetrics.rejected.type,
+ getSystemThreadDump.rejected.type,
+ getConfigurations.rejected.type,
+ getEnv.rejected.type,
+ ],
+ 'something happened',
+ state => {
+ expect(state).toMatchObject({
+ loading: false,
+ errorMessage: 'error',
+ });
+ },
+ {
+ message: 'error',
+ }
+ );
+ });
+ });
+
+ describe('Success', () => {
+ it('should update state according to a successful fetch logs request', () => {
+ const payload = {
+ data: {
+ loggers: {
+ main: {
+ effectiveLevel: 'WARN',
+ },
+ },
+ },
+ };
+ const toTest = administration(undefined, { type: getLoggers.fulfilled.type, payload });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ logs: payload.data,
+ });
+ });
+
+ it('should update state according to a successful fetch health request', () => {
+ const payload = { data: { status: 'UP' } };
+ const toTest = administration(undefined, { type: getSystemHealth.fulfilled.type, payload });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ health: payload.data,
+ });
+ });
+
+ it('should update state according to a successful fetch metrics request', () => {
+ const payload = { data: { version: '3.1.3', gauges: {} } };
+ const toTest = administration(undefined, { type: getSystemMetrics.fulfilled.type, payload });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ metrics: payload.data,
+ });
+ });
+
+ it('should update state according to a successful fetch thread dump request', () => {
+ const payload = { data: [{ threadName: 'hz.gateway.cached.thread-6', threadId: 9266 }] };
+ const toTest = administration(undefined, { type: getSystemThreadDump.fulfilled.type, payload });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ threadDump: payload.data,
+ });
+ });
+
+ it('should update state according to a successful fetch configurations request', () => {
+ const payload = { data: { contexts: { jhipster: { beans: {} } } } };
+ const toTest = administration(undefined, { type: getConfigurations.fulfilled.type, payload });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ configuration: {
+ configProps: payload.data,
+ env: {},
+ },
+ });
+ });
+
+ it('should update state according to a successful fetch env request', () => {
+ const payload = { data: { activeProfiles: ['api-docs', 'dev'] } };
+ const toTest = administration(undefined, { type: getEnv.fulfilled.type, payload });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ configuration: {
+ configProps: {},
+ env: payload.data,
+ },
+ });
+ });
+ });
+ describe('Actions', () => {
+ let store;
+
+ const resolvedObject = { value: 'whatever' };
+ beforeEach(() => {
+ const mockStore = configureStore([thunk]);
+ store = mockStore({});
+ axios.get = sinon.stub().returns(Promise.resolve(resolvedObject));
+ axios.post = sinon.stub().returns(Promise.resolve(resolvedObject));
+ });
+ it('dispatches FETCH_HEALTH_PENDING and FETCH_HEALTH_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getSystemHealth.pending.type,
+ },
+ {
+ type: getSystemHealth.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getSystemHealth());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ it('dispatches FETCH_METRICS_PENDING and FETCH_METRICS_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getSystemMetrics.pending.type,
+ },
+ {
+ type: getSystemMetrics.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getSystemMetrics());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ it('dispatches FETCH_THREAD_DUMP_PENDING and FETCH_THREAD_DUMP_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getSystemThreadDump.pending.type,
+ },
+ {
+ type: getSystemThreadDump.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getSystemThreadDump());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ it('dispatches FETCH_LOGS_PENDING and FETCH_LOGS_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getLoggers.pending.type,
+ },
+ {
+ type: getLoggers.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getLoggers());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ it('dispatches FETCH_LOGS_CHANGE_LEVEL_PENDING and FETCH_LOGS_CHANGE_LEVEL_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: setLoggers.pending.type,
+ },
+ {
+ type: setLoggers.fulfilled.type,
+ payload: resolvedObject,
+ },
+ {
+ type: getLoggers.pending.type,
+ },
+ ];
+ await store.dispatch(changeLogLevel('ROOT', 'DEBUG'));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ expect(store.getActions()[2]).toMatchObject(expectedActions[2]);
+ });
+ it('dispatches FETCH_CONFIGURATIONS_PENDING and FETCH_CONFIGURATIONS_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getConfigurations.pending.type,
+ },
+ {
+ type: getConfigurations.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getConfigurations());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ it('dispatches FETCH_ENV_PENDING and FETCH_ENV_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getEnv.pending.type,
+ },
+ {
+ type: getEnv.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getEnv());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/modules/administration/administration.reducer.ts b/myApp/src/main/webapp/app/modules/administration/administration.reducer.ts
new file mode 100644
index 000000000..3cab111a3
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/administration.reducer.ts
@@ -0,0 +1,125 @@
+import axios from 'axios';
+import { createAsyncThunk, createSlice, isPending, isRejected } from '@reduxjs/toolkit';
+
+import { serializeAxiosError } from 'app/shared/reducers/reducer.utils';
+import { AppThunk } from 'app/config/store';
+
+const initialState = {
+ loading: false,
+ errorMessage: null,
+ logs: {
+ loggers: [] as any[],
+ },
+ health: {} as any,
+ metrics: {} as any,
+ threadDump: [],
+ configuration: {
+ configProps: {} as any,
+ env: {} as any,
+ },
+ totalItems: 0,
+};
+
+export type AdministrationState = Readonly;
+
+// Actions
+
+export const getSystemHealth = createAsyncThunk('administration/fetch_health', async () => axios.get('management/health'), {
+ serializeError: serializeAxiosError,
+});
+
+export const getSystemMetrics = createAsyncThunk('administration/fetch_metrics', async () => axios.get('management/jhimetrics'), {
+ serializeError: serializeAxiosError,
+});
+
+export const getSystemThreadDump = createAsyncThunk(
+ 'administration/fetch_thread_dump',
+ async () => axios.get('management/threaddump'),
+ {
+ serializeError: serializeAxiosError,
+ }
+);
+
+export const getLoggers = createAsyncThunk('administration/fetch_logs', async () => axios.get('management/loggers'), {
+ serializeError: serializeAxiosError,
+});
+
+export const setLoggers = createAsyncThunk(
+ 'administration/fetch_logs_change_level',
+ async ({ name, configuredLevel }: any) => axios.post(`management/loggers/${name}`, { configuredLevel }),
+ {
+ serializeError: serializeAxiosError,
+ }
+);
+
+export const changeLogLevel: (name, configuredLevel) => AppThunk = (name, configuredLevel) => async dispatch => {
+ await dispatch(setLoggers({ name, configuredLevel }));
+ dispatch(getLoggers());
+};
+
+export const getConfigurations = createAsyncThunk(
+ 'administration/fetch_configurations',
+ async () => axios.get('management/configprops'),
+ {
+ serializeError: serializeAxiosError,
+ }
+);
+
+export const getEnv = createAsyncThunk('administration/fetch_env', async () => axios.get('management/env'), {
+ serializeError: serializeAxiosError,
+});
+
+export const AdministrationSlice = createSlice({
+ name: 'administration',
+ initialState: initialState as AdministrationState,
+ reducers: {},
+ extraReducers(builder) {
+ builder
+ .addCase(getSystemHealth.fulfilled, (state, action) => {
+ state.loading = false;
+ state.health = action.payload.data;
+ })
+ .addCase(getSystemMetrics.fulfilled, (state, action) => {
+ state.loading = false;
+ state.metrics = action.payload.data;
+ })
+ .addCase(getSystemThreadDump.fulfilled, (state, action) => {
+ state.loading = false;
+ state.threadDump = action.payload.data;
+ })
+ .addCase(getLoggers.fulfilled, (state, action) => {
+ state.loading = false;
+ state.logs = {
+ loggers: action.payload.data.loggers,
+ };
+ })
+ .addCase(getConfigurations.fulfilled, (state, action) => {
+ state.loading = false;
+ state.configuration = {
+ ...state.configuration,
+ configProps: action.payload.data,
+ };
+ })
+ .addCase(getEnv.fulfilled, (state, action) => {
+ state.loading = false;
+ state.configuration = {
+ ...state.configuration,
+ env: action.payload.data,
+ };
+ })
+ .addMatcher(isPending(getSystemHealth, getSystemMetrics, getSystemThreadDump, getLoggers, getConfigurations, getEnv), state => {
+ state.errorMessage = null;
+ state.loading = true;
+ })
+ .addMatcher(
+ isRejected(getSystemHealth, getSystemMetrics, getSystemThreadDump, getLoggers, getConfigurations, getEnv),
+ (state, action) => {
+ state.errorMessage = action.error.message;
+ state.loading = false;
+ }
+ );
+ },
+});
+
+// Reducer
+export default AdministrationSlice.reducer;
diff --git a/myApp/src/main/webapp/app/modules/administration/configuration/configuration.tsx b/myApp/src/main/webapp/app/modules/administration/configuration/configuration.tsx
new file mode 100644
index 000000000..34f1cdc4c
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/configuration/configuration.tsx
@@ -0,0 +1,116 @@
+import React, { useState, useEffect } from 'react';
+import { Table, Input, Row, Col, Badge } from 'reactstrap';
+import { Translate } from 'react-jhipster';
+
+import { getConfigurations, getEnv } from '../administration.reducer';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+
+export const ConfigurationPage = () => {
+ const [filter, setFilter] = useState('');
+ const [reversePrefix, setReversePrefix] = useState(false);
+ const [reverseProperties, setReverseProperties] = useState(false);
+ const dispatch = useAppDispatch();
+
+ const configuration = useAppSelector(state => state.administration.configuration);
+
+ useEffect(() => {
+ dispatch(getConfigurations());
+ dispatch(getEnv());
+ }, []);
+
+ const changeFilter = evt => setFilter(evt.target.value);
+
+ const envFilterFn = configProp => configProp.toUpperCase().includes(filter.toUpperCase());
+
+ const propsFilterFn = configProp => configProp.prefix.toUpperCase().includes(filter.toUpperCase());
+
+ const changeReversePrefix = () => setReversePrefix(!reversePrefix);
+
+ const changeReverseProperties = () => setReverseProperties(!reverseProperties);
+
+ const getContextList = contexts =>
+ Object.values(contexts)
+ .map((v: any) => v.beans)
+ .reduce((acc, e) => ({ ...acc, ...e }));
+
+ const configProps = configuration?.configProps ?? {};
+
+ const env = configuration?.env ?? {};
+
+ return (
+
+
+ Configuration
+
+
+ Filter
+ {' '}
+
+
Spring configuration
+
+
+
+
+ Prefix
+
+
+ Properties
+
+
+
+
+ {configProps.contexts
+ ? Object.values(getContextList(configProps.contexts))
+ .filter(propsFilterFn)
+ .map((property: any, propIndex) => (
+
+ {property['prefix']}
+
+ {Object.keys(property['properties']).map((propKey, index) => (
+
+ {propKey}
+
+ {JSON.stringify(property['properties'][propKey])}
+
+
+ ))}
+
+
+ ))
+ : null}
+
+
+ {env.propertySources
+ ? env.propertySources.map((envKey, envIndex) => (
+
+
+ {envKey.name}
+
+
+
+
+ Property
+ Value
+
+
+
+ {Object.keys(envKey.properties)
+ .filter(envFilterFn)
+ .map((propKey, propIndex) => (
+
+ {propKey}
+
+ {envKey.properties[propKey].value}
+
+
+ ))}
+
+
+
+ ))
+ : null}
+
+ );
+};
+
+export default ConfigurationPage;
diff --git a/myApp/src/main/webapp/app/modules/administration/docs/docs.scss b/myApp/src/main/webapp/app/modules/administration/docs/docs.scss
new file mode 100644
index 000000000..b5edede95
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/docs/docs.scss
@@ -0,0 +1,3 @@
+iframe {
+ background: white;
+}
diff --git a/myApp/src/main/webapp/app/modules/administration/docs/docs.tsx b/myApp/src/main/webapp/app/modules/administration/docs/docs.tsx
new file mode 100644
index 000000000..37c5e1bc4
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/docs/docs.tsx
@@ -0,0 +1,19 @@
+import './docs.scss';
+
+import React from 'react';
+
+const DocsPage = () => (
+
+
+
+);
+
+export default DocsPage;
diff --git a/myApp/src/main/webapp/app/modules/administration/health/health-modal.tsx b/myApp/src/main/webapp/app/modules/administration/health/health-modal.tsx
new file mode 100644
index 000000000..b15da3a24
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/health/health-modal.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { Table, Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
+
+const formatDiskSpaceOutput = rawValue => {
+ // Should display storage space in an human readable unit
+ const val = rawValue / 1073741824;
+ if (val > 1) {
+ // Value
+ return val.toFixed(2) + ' GB';
+ }
+ return (rawValue / 1048576).toFixed(2) + ' MB';
+};
+
+const HealthModal = ({ handleClose, healthObject, showModal }) => {
+ const data = healthObject.details || {};
+ return (
+
+ {healthObject.name}
+
+
+
+
+ Name
+ Value
+
+
+
+ {Object.keys(data).map((key, index) => (
+
+ {key}
+ {healthObject.name === 'diskSpace' ? formatDiskSpaceOutput(data[key]) : JSON.stringify(data[key])}
+
+ ))}
+
+
+
+
+
+ Close
+
+
+
+ );
+};
+
+export default HealthModal;
diff --git a/myApp/src/main/webapp/app/modules/administration/health/health.tsx b/myApp/src/main/webapp/app/modules/administration/health/health.tsx
new file mode 100644
index 000000000..bb03b8bc1
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/health/health.tsx
@@ -0,0 +1,92 @@
+import React, { useState, useEffect } from 'react';
+import { Translate } from 'react-jhipster';
+import { Table, Badge, Col, Row, Button } from 'reactstrap';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+import HealthModal from './health-modal';
+import { getSystemHealth } from '../administration.reducer';
+
+export const HealthPage = () => {
+ const [healthObject, setHealthObject] = useState({});
+ const [showModal, setShowModal] = useState(false);
+ const dispatch = useAppDispatch();
+
+ const health = useAppSelector(state => state.administration.health);
+ const isFetching = useAppSelector(state => state.administration.loading);
+
+ useEffect(() => {
+ dispatch(getSystemHealth());
+ }, []);
+
+ const fetchSystemHealth = () => {
+ if (!isFetching) {
+ dispatch(getSystemHealth());
+ }
+ };
+
+ const getSystemHealthInfo = (name, healthObj) => () => {
+ setShowModal(true);
+ setHealthObject({ ...healthObj, name });
+ };
+
+ const getBadgeType = (status: string) => (status !== 'UP' ? 'danger' : 'success');
+
+ const handleClose = () => setShowModal(false);
+
+ const renderModal = () => ;
+
+ const data = (health || {}).components || {};
+
+ return (
+
+
+ Health Checks
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+
+ Service Name
+ Status
+ Details
+
+
+
+ {Object.keys(data).map((configPropKey, configPropIndex) =>
+ configPropKey !== 'status' ? (
+
+ {configPropKey}
+
+ {data[configPropKey].status}
+
+
+ {data[configPropKey].details ? (
+
+
+
+ ) : null}
+
+
+ ) : null
+ )}
+
+
+
+
+ {renderModal()}
+
+ );
+};
+
+export default HealthPage;
diff --git a/myApp/src/main/webapp/app/modules/administration/index.tsx b/myApp/src/main/webapp/app/modules/administration/index.tsx
new file mode 100644
index 000000000..dccf47ef9
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/index.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+
+import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
+import UserManagement from './user-management';
+import Logs from './logs/logs';
+import Health from './health/health';
+import Metrics from './metrics/metrics';
+import Configuration from './configuration/configuration';
+import Docs from './docs/docs';
+
+const Routes = ({ match }) => (
+
+
+
+
+
+
+
+
+);
+
+export default Routes;
diff --git a/myApp/src/main/webapp/app/modules/administration/logs/logs.tsx b/myApp/src/main/webapp/app/modules/administration/logs/logs.tsx
new file mode 100644
index 000000000..fa659c31c
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/logs/logs.tsx
@@ -0,0 +1,116 @@
+import React, { useState, useEffect } from 'react';
+import { Translate } from 'react-jhipster';
+
+import { getLoggers, changeLogLevel } from '../administration.reducer';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+
+export const LogsPage = () => {
+ const [filter, setFilter] = useState('');
+ const logs = useAppSelector(state => state.administration.logs);
+ const isFetching = useAppSelector(state => state.administration.loading);
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ dispatch(getLoggers());
+ }, []);
+
+ const changeLevel = (loggerName, level) => () => dispatch(changeLogLevel(loggerName, level));
+
+ const changeFilter = evt => setFilter(evt.target.value);
+
+ const getClassName = (level, check, className) => (level === check ? `btn btn-sm btn-${className}` : 'btn btn-sm btn-light');
+
+ const filterFn = l => l.name.toUpperCase().includes(filter.toUpperCase());
+
+ const loggers = logs ? Object.entries(logs.loggers).map(e => ({ name: e[0], level: e[1].effectiveLevel })) : [];
+
+ return (
+
+
+ Logs
+
+
+
+ There are {loggers.length.toString()} loggers.
+
+
+
+
+ Filter
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+ Level
+
+
+
+
+
+ {loggers.filter(filterFn).map((logger, i) => (
+
+
+ {logger.name}
+
+
+
+ TRACE
+
+
+ DEBUG
+
+
+ INFO
+
+
+ WARN
+
+
+ ERROR
+
+
+ OFF
+
+
+
+ ))}
+
+
+
+ );
+};
+
+export default LogsPage;
diff --git a/myApp/src/main/webapp/app/modules/administration/metrics/metrics.tsx b/myApp/src/main/webapp/app/modules/administration/metrics/metrics.tsx
new file mode 100644
index 000000000..2708df4ef
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/metrics/metrics.tsx
@@ -0,0 +1,118 @@
+import React, { useEffect } from 'react';
+import { Button, Col, Row } from 'reactstrap';
+import {
+ CacheMetrics,
+ DatasourceMetrics,
+ GarbageCollectorMetrics,
+ HttpRequestMetrics,
+ JvmMemory,
+ JvmThreads,
+ EndpointsRequestsMetrics,
+ SystemMetrics,
+ Translate,
+} from 'react-jhipster';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+import { APP_TIMESTAMP_FORMAT, APP_TWO_DIGITS_AFTER_POINT_NUMBER_FORMAT, APP_WHOLE_NUMBER_FORMAT } from 'app/config/constants';
+import { getSystemMetrics, getSystemThreadDump } from '../administration.reducer';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+
+export const MetricsPage = () => {
+ const dispatch = useAppDispatch();
+ const metrics = useAppSelector(state => state.administration.metrics);
+ const isFetching = useAppSelector(state => state.administration.loading);
+ const threadDump = useAppSelector(state => state.administration.threadDump);
+
+ useEffect(() => {
+ dispatch(getSystemMetrics());
+ dispatch(getSystemThreadDump());
+ }, []);
+
+ const getMetrics = () => {
+ if (!isFetching) {
+ dispatch(getSystemMetrics());
+ dispatch(getSystemThreadDump());
+ }
+ };
+
+ return (
+
+
+ Application Metrics
+
+
+
+
+
+
+ Refresh
+
+
+
+
+
+
+
+ JVM Metrics
+
+ {metrics?.jvm ? : ''}
+ {threadDump ? : ''}
+
+ {metrics?.processMetrics ? (
+
+ ) : (
+ ''
+ )}
+
+
+
+
+
+ {metrics?.garbageCollector ? (
+
+ ) : (
+ ''
+ )}
+ {metrics && metrics['http.server.requests'] ? (
+
+ ) : (
+ ''
+ )}
+ {metrics?.services ? (
+
+ ) : (
+ ''
+ )}
+
+ {metrics?.cache ? (
+
+
+
+
+
+ ) : (
+ ''
+ )}
+
+ {metrics?.databases && JSON.stringify(metrics.databases) !== '{}' ? (
+
+
+
+
+
+ ) : (
+ ''
+ )}
+
+ );
+};
+
+export default MetricsPage;
diff --git a/myApp/src/main/webapp/app/modules/administration/user-management/index.tsx b/myApp/src/main/webapp/app/modules/administration/user-management/index.tsx
new file mode 100644
index 000000000..3b5d6a93f
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/user-management/index.tsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { Switch } from 'react-router-dom';
+
+import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
+import UserManagement from './user-management';
+import UserManagementDetail from './user-management-detail';
+import UserManagementUpdate from './user-management-update';
+import UserManagementDeleteDialog from './user-management-delete-dialog';
+
+const Routes = ({ match }) => (
+ <>
+
+
+
+
+
+
+
+ >
+);
+
+export default Routes;
diff --git a/myApp/src/main/webapp/app/modules/administration/user-management/user-management-delete-dialog.tsx b/myApp/src/main/webapp/app/modules/administration/user-management/user-management-delete-dialog.tsx
new file mode 100644
index 000000000..514f067b2
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/user-management/user-management-delete-dialog.tsx
@@ -0,0 +1,55 @@
+import React, { useEffect } from 'react';
+import { RouteComponentProps } from 'react-router-dom';
+import { Modal, ModalHeader, ModalBody, ModalFooter, Button } from 'reactstrap';
+import { Translate } from 'react-jhipster';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+import { getUser, deleteUser } from './user-management.reducer';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+
+export const UserManagementDeleteDialog = (props: RouteComponentProps<{ login: string }>) => {
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ dispatch(getUser(props.match.params.login));
+ }, []);
+
+ const handleClose = event => {
+ event.stopPropagation();
+ props.history.push('/admin/user-management');
+ };
+
+ const user = useAppSelector(state => state.userManagement.user);
+
+ const confirmDelete = event => {
+ dispatch(deleteUser(user.login));
+ handleClose(event);
+ };
+
+ return (
+
+
+ Confirm delete operation
+
+
+
+ Are you sure you want to delete this User?
+
+
+
+
+
+
+ Cancel
+
+
+
+
+ Delete
+
+
+
+ );
+};
+
+export default UserManagementDeleteDialog;
diff --git a/myApp/src/main/webapp/app/modules/administration/user-management/user-management-detail.tsx b/myApp/src/main/webapp/app/modules/administration/user-management/user-management-detail.tsx
new file mode 100644
index 000000000..f4d679fde
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/user-management/user-management-detail.tsx
@@ -0,0 +1,105 @@
+import React, { useEffect } from 'react';
+import { Link, RouteComponentProps } from 'react-router-dom';
+import { Button, Row, Badge } from 'reactstrap';
+import { Translate, TextFormat } from 'react-jhipster';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+import { APP_DATE_FORMAT } from 'app/config/constants';
+import { languages } from 'app/config/translation';
+import { getUser } from './user-management.reducer';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+
+export const UserManagementDetail = (props: RouteComponentProps<{ login: string }>) => {
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ dispatch(getUser(props.match.params.login));
+ }, []);
+
+ const user = useAppSelector(state => state.userManagement.user);
+
+ return (
+
+
+ User [{user.login} ]
+
+
+
+
+ Login
+
+
+ {user.login}
+ {user.activated ? (
+
+ Activated
+
+ ) : (
+
+ Deactivated
+
+ )}
+
+
+ First Name
+
+ {user.firstName}
+
+ Last Name
+
+ {user.lastName}
+
+ Email
+
+ {user.email}
+
+ Lang Key
+
+ {user.langKey ? languages[user.langKey].name : undefined}
+
+ Created By
+
+ {user.createdBy}
+
+ Created Date
+
+ {user.createdDate ? : null}
+
+ Last Modified By
+
+ {user.lastModifiedBy}
+
+ Last Modified Date
+
+
+ {user.lastModifiedDate ? (
+
+ ) : null}
+
+
+ Profiles
+
+
+
+ {user.authorities
+ ? user.authorities.map((authority, i) => (
+
+ {authority}
+
+ ))
+ : null}
+
+
+
+
+
+ {' '}
+
+ Back
+
+
+
+ );
+};
+
+export default UserManagementDetail;
diff --git a/myApp/src/main/webapp/app/modules/administration/user-management/user-management-update.tsx b/myApp/src/main/webapp/app/modules/administration/user-management/user-management-update.tsx
new file mode 100644
index 000000000..912fc0655
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/user-management/user-management-update.tsx
@@ -0,0 +1,181 @@
+import React, { useState, useEffect } from 'react';
+import { Link, RouteComponentProps } from 'react-router-dom';
+import { Button, Row, Col, FormText } from 'reactstrap';
+import { Translate, translate, ValidatedField, ValidatedForm, isEmail } from 'react-jhipster';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+import { locales, languages } from 'app/config/translation';
+import { getUser, getRoles, updateUser, createUser, reset } from './user-management.reducer';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+
+export const UserManagementUpdate = (props: RouteComponentProps<{ login: string }>) => {
+ const [isNew] = useState(!props.match.params || !props.match.params.login);
+ const dispatch = useAppDispatch();
+
+ useEffect(() => {
+ if (isNew) {
+ dispatch(reset());
+ } else {
+ dispatch(getUser(props.match.params.login));
+ }
+ dispatch(getRoles());
+ return () => {
+ dispatch(reset());
+ };
+ }, [props.match.params.login]);
+
+ const handleClose = () => {
+ props.history.push('/admin/user-management');
+ };
+
+ const saveUser = values => {
+ if (isNew) {
+ dispatch(createUser(values));
+ } else {
+ dispatch(updateUser(values));
+ }
+ handleClose();
+ };
+
+ const isInvalid = false;
+ const user = useAppSelector(state => state.userManagement.user);
+ const loading = useAppSelector(state => state.userManagement.loading);
+ const updating = useAppSelector(state => state.userManagement.updating);
+ const authorities = useAppSelector(state => state.userManagement.authorities);
+
+ return (
+
+
+
+
+ Create or edit a User
+
+
+
+
+
+ {loading ? (
+ Loading...
+ ) : (
+
+ {user.id ? (
+
+ ) : null}
+
+
+
+ This field cannot be longer than 50 characters.
+ isEmail(v) || translate('global.messages.validate.email.invalid'),
+ }}
+ />
+
+
+ {locales.map(locale => (
+
+ {languages[locale].name}
+
+ ))}
+
+
+ {authorities.map(role => (
+
+ {role}
+
+ ))}
+
+
+
+
+
+ Back
+
+
+
+
+
+
+ Save
+
+
+ )}
+
+
+
+ );
+};
+
+export default UserManagementUpdate;
diff --git a/myApp/src/main/webapp/app/modules/administration/user-management/user-management.reducer.spec.ts b/myApp/src/main/webapp/app/modules/administration/user-management/user-management.reducer.spec.ts
new file mode 100644
index 000000000..5cdf30853
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/user-management/user-management.reducer.spec.ts
@@ -0,0 +1,347 @@
+import configureStore from 'redux-mock-store';
+import axios from 'axios';
+import thunk from 'redux-thunk';
+import sinon from 'sinon';
+
+import userManagement, {
+ getUsers,
+ getUsersAsAdmin,
+ getRoles,
+ getUser,
+ createUser,
+ updateUser,
+ deleteUser,
+ reset,
+} from './user-management.reducer';
+import { defaultValue } from 'app/shared/model/user.model';
+import { AUTHORITIES } from 'app/config/constants';
+
+describe('User management reducer tests', () => {
+ const username = process.env.E2E_USERNAME ?? 'admin';
+
+ function isEmpty(element): boolean {
+ if (element instanceof Array) {
+ return element.length === 0;
+ } else {
+ return Object.keys(element).length === 0;
+ }
+ }
+
+ function testInitialState(state) {
+ expect(state).toMatchObject({
+ loading: false,
+ errorMessage: null,
+ updating: false,
+ updateSuccess: false,
+ totalItems: 0,
+ });
+ expect(isEmpty(state.users));
+ expect(isEmpty(state.authorities));
+ expect(isEmpty(state.user));
+ }
+
+ function testMultipleTypes(types, payload, testFunction, error?) {
+ types.forEach(e => {
+ testFunction(userManagement(undefined, { type: e, payload, error }));
+ });
+ }
+
+ describe('Common', () => {
+ it('should return the initial state', () => {
+ testInitialState(userManagement(undefined, { type: 'unknown' }));
+ });
+ });
+
+ describe('Requests', () => {
+ it('should not modify the current state', () => {
+ testInitialState(userManagement(undefined, { type: getRoles.pending.type }));
+ });
+
+ it('should set state to loading', () => {
+ testMultipleTypes([getUsers.pending.type, getUsersAsAdmin.pending.type, getUser.pending.type], {}, state => {
+ expect(state).toMatchObject({
+ errorMessage: null,
+ updateSuccess: false,
+ loading: true,
+ });
+ });
+ });
+
+ it('should set state to updating', () => {
+ testMultipleTypes([createUser.pending.type, updateUser.pending.type, deleteUser.pending.type], {}, state => {
+ expect(state).toMatchObject({
+ errorMessage: null,
+ updateSuccess: false,
+ updating: true,
+ });
+ });
+ });
+ });
+
+ describe('Failures', () => {
+ it('should set state to failed and put an error message in errorMessage', () => {
+ testMultipleTypes(
+ [
+ getUsersAsAdmin.rejected.type,
+ getUsers.rejected.type,
+ getUser.rejected.type,
+ getRoles.rejected.type,
+ createUser.rejected.type,
+ updateUser.rejected.type,
+ deleteUser.rejected.type,
+ ],
+ { message: 'something happened' },
+ state => {
+ expect(state).toMatchObject({
+ loading: false,
+ updating: false,
+ updateSuccess: false,
+ errorMessage: 'error happened',
+ });
+ },
+ { message: 'error happened' }
+ );
+ });
+ });
+
+ describe('Success', () => {
+ it('should update state according to a successful fetch users request', () => {
+ const headers = { ['x-total-count']: 42 };
+ const payload = { data: 'some handsome users', headers };
+ const toTest = userManagement(undefined, { type: getUsers.fulfilled.type, payload });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ users: payload.data,
+ totalItems: headers['x-total-count'],
+ });
+ });
+
+ it('should update state according to a successful fetch user request', () => {
+ const payload = { data: 'some handsome user' };
+ const toTest = userManagement(undefined, { type: getUser.fulfilled.type, payload });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ user: payload.data,
+ });
+ });
+
+ it('should update state according to a successful fetch role request', () => {
+ const payload = { data: [AUTHORITIES.ADMIN] };
+ const toTest = userManagement(undefined, { type: getRoles.fulfilled.type, payload });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ authorities: payload.data,
+ });
+ });
+
+ it('should set state to successful update', () => {
+ testMultipleTypes([createUser.fulfilled.type, updateUser.fulfilled.type], { data: 'some handsome user' }, types => {
+ expect(types).toMatchObject({
+ updating: false,
+ updateSuccess: true,
+ user: 'some handsome user',
+ });
+ });
+ });
+
+ it('should set state to successful update with an empty user', () => {
+ const toTest = userManagement(undefined, { type: deleteUser.fulfilled.type });
+
+ expect(toTest).toMatchObject({
+ updating: false,
+ updateSuccess: true,
+ });
+ expect(isEmpty(toTest.user));
+ });
+ });
+
+ describe('Reset', () => {
+ it('should reset the state', () => {
+ const initialState = {
+ loading: false,
+ errorMessage: null,
+ users: [],
+ authorities: [] as any[],
+ user: defaultValue,
+ updating: false,
+ updateSuccess: false,
+ totalItems: 0,
+ };
+ const initialStateNew = {
+ ...initialState,
+ loading: true,
+ };
+ expect(userManagement(initialStateNew, reset)).toEqual(initialState);
+ });
+ });
+
+ describe('Actions', () => {
+ let store;
+
+ const resolvedObject = { value: 'whatever' };
+ beforeEach(() => {
+ const mockStore = configureStore([thunk]);
+ store = mockStore({});
+ axios.get = sinon.stub().returns(Promise.resolve(resolvedObject));
+ axios.put = sinon.stub().returns(Promise.resolve(resolvedObject));
+ axios.post = sinon.stub().returns(Promise.resolve(resolvedObject));
+ axios.delete = sinon.stub().returns(Promise.resolve(resolvedObject));
+ });
+
+ it('dispatches FETCH_USERS_AS_ADMIN_PENDING and FETCH_USERS_AS_ADMIN_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getUsersAsAdmin.pending.type,
+ },
+ {
+ type: getUsersAsAdmin.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getUsersAsAdmin({}));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+
+ it('dispatches FETCH_USERS_AS_ADMIN_PENDING and FETCH_USERS_AS_ADMIN_FULFILLED actions with pagination options', async () => {
+ const expectedActions = [
+ {
+ type: getUsersAsAdmin.pending.type,
+ },
+ {
+ type: getUsersAsAdmin.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getUsersAsAdmin({ page: 1, size: 20, sort: 'id,desc' }));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+
+ it('dispatches FETCH_USERS_PENDING and FETCH_USERS_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getUsers.pending.type,
+ },
+ {
+ type: getUsers.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getUsers({}));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+
+ it('dispatches FETCH_USERS_PENDING and FETCH_USERS_FULFILLED actions with pagination options', async () => {
+ const expectedActions = [
+ {
+ type: getUsers.pending.type,
+ },
+ {
+ type: getUsers.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getUsers({ page: 1, size: 20, sort: 'id,desc' }));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+
+ it('dispatches FETCH_ROLES_PENDING and FETCH_ROLES_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getRoles.pending.type,
+ },
+ {
+ type: getRoles.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getRoles());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+
+ it('dispatches FETCH_USER_PENDING and FETCH_USER_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getUser.pending.type,
+ },
+ {
+ type: getUser.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getUser(username));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+
+ it('dispatches CREATE_USER_PENDING and CREATE_USER_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: createUser.pending.type,
+ },
+ {
+ type: getUsersAsAdmin.pending.type,
+ },
+ {
+ type: createUser.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(createUser({}));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ expect(store.getActions()[2]).toMatchObject(expectedActions[2]);
+ });
+
+ it('dispatches UPDATE_USER_PENDING and UPDATE_USER_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: updateUser.pending.type,
+ },
+ {
+ type: getUsersAsAdmin.pending.type,
+ },
+ {
+ type: updateUser.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(updateUser({ login: username }));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ expect(store.getActions()[2]).toMatchObject(expectedActions[2]);
+ });
+
+ it('dispatches DELETE_USER_PENDING and DELETE_USER_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: deleteUser.pending.type,
+ },
+ {
+ type: getUsersAsAdmin.pending.type,
+ },
+ {
+ type: deleteUser.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(deleteUser(username));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ expect(store.getActions()[2]).toMatchObject(expectedActions[2]);
+ });
+
+ it('dispatches RESET actions', async () => {
+ const expectedActions = [reset()];
+ await store.dispatch(reset());
+ expect(store.getActions()).toEqual(expectedActions);
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/modules/administration/user-management/user-management.reducer.ts b/myApp/src/main/webapp/app/modules/administration/user-management/user-management.reducer.ts
new file mode 100644
index 000000000..9b4ce6509
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/user-management/user-management.reducer.ts
@@ -0,0 +1,134 @@
+import axios from 'axios';
+import { createAsyncThunk, createSlice, isFulfilled, isPending, isRejected } from '@reduxjs/toolkit';
+
+import { IUser, defaultValue } from 'app/shared/model/user.model';
+import { IQueryParams, serializeAxiosError } from 'app/shared/reducers/reducer.utils';
+
+const initialState = {
+ loading: false,
+ errorMessage: null,
+ users: [] as ReadonlyArray,
+ authorities: [] as any[],
+ user: defaultValue,
+ updating: false,
+ updateSuccess: false,
+ totalItems: 0,
+};
+
+const apiUrl = 'api/users';
+const adminUrl = 'api/admin/users';
+
+// Async Actions
+
+export const getUsers = createAsyncThunk('userManagement/fetch_users', async ({ page, size, sort }: IQueryParams) => {
+ const requestUrl = `${apiUrl}${sort ? `?page=${page}&size=${size}&sort=${sort}` : ''}`;
+ return axios.get(requestUrl);
+});
+
+export const getUsersAsAdmin = createAsyncThunk('userManagement/fetch_users_as_admin', async ({ page, size, sort }: IQueryParams) => {
+ const requestUrl = `${adminUrl}${sort ? `?page=${page}&size=${size}&sort=${sort}` : ''}`;
+ return axios.get(requestUrl);
+});
+
+export const getRoles = createAsyncThunk('userManagement/fetch_roles', async () => {
+ return axios.get(`api/authorities`);
+});
+
+export const getUser = createAsyncThunk(
+ 'userManagement/fetch_user',
+ async (id: string) => {
+ const requestUrl = `${adminUrl}/${id}`;
+ return axios.get(requestUrl);
+ },
+ { serializeError: serializeAxiosError }
+);
+
+export const createUser = createAsyncThunk(
+ 'userManagement/create_user',
+ async (user: IUser, thunkAPI) => {
+ const result = await axios.post(adminUrl, user);
+ thunkAPI.dispatch(getUsersAsAdmin({}));
+ return result;
+ },
+ { serializeError: serializeAxiosError }
+);
+
+export const updateUser = createAsyncThunk(
+ 'userManagement/update_user',
+ async (user: IUser, thunkAPI) => {
+ const result = await axios.put(adminUrl, user);
+ thunkAPI.dispatch(getUsersAsAdmin({}));
+ return result;
+ },
+ { serializeError: serializeAxiosError }
+);
+
+export const deleteUser = createAsyncThunk(
+ 'userManagement/delete_user',
+ async (id: string, thunkAPI) => {
+ const requestUrl = `${adminUrl}/${id}`;
+ const result = await axios.delete(requestUrl);
+ thunkAPI.dispatch(getUsersAsAdmin({}));
+ return result;
+ },
+ { serializeError: serializeAxiosError }
+);
+
+export type UserManagementState = Readonly;
+
+export const UserManagementSlice = createSlice({
+ name: 'userManagement',
+ initialState: initialState as UserManagementState,
+ reducers: {
+ reset() {
+ return initialState;
+ },
+ },
+ extraReducers(builder) {
+ builder
+ .addCase(getRoles.fulfilled, (state, action) => {
+ state.authorities = action.payload.data;
+ })
+ .addCase(getUser.fulfilled, (state, action) => {
+ state.loading = false;
+ state.user = action.payload.data;
+ })
+ .addCase(deleteUser.fulfilled, state => {
+ state.updating = false;
+ state.updateSuccess = true;
+ state.user = defaultValue;
+ })
+ .addMatcher(isFulfilled(getUsers, getUsersAsAdmin), (state, action) => {
+ state.loading = false;
+ state.users = action.payload.data;
+ state.totalItems = parseInt(action.payload.headers['x-total-count'], 10);
+ })
+ .addMatcher(isFulfilled(createUser, updateUser), (state, action) => {
+ state.updating = false;
+ state.loading = false;
+ state.updateSuccess = true;
+ state.user = action.payload.data;
+ })
+ .addMatcher(isPending(getUsers, getUsersAsAdmin, getUser), state => {
+ state.errorMessage = null;
+ state.updateSuccess = false;
+ state.loading = true;
+ })
+ .addMatcher(isPending(createUser, updateUser, deleteUser), state => {
+ state.errorMessage = null;
+ state.updateSuccess = false;
+ state.updating = true;
+ })
+ .addMatcher(isRejected(getUsers, getUsersAsAdmin, getUser, getRoles, createUser, updateUser, deleteUser), (state, action) => {
+ state.loading = false;
+ state.updating = false;
+ state.updateSuccess = false;
+ state.errorMessage = action.error.message;
+ });
+ },
+});
+
+export const { reset } = UserManagementSlice.actions;
+
+// Reducer
+export default UserManagementSlice.reducer;
diff --git a/myApp/src/main/webapp/app/modules/administration/user-management/user-management.tsx b/myApp/src/main/webapp/app/modules/administration/user-management/user-management.tsx
new file mode 100644
index 000000000..8fd63a86a
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/administration/user-management/user-management.tsx
@@ -0,0 +1,230 @@
+import React, { useState, useEffect } from 'react';
+import { Link, RouteComponentProps } from 'react-router-dom';
+import { Button, Table, Badge } from 'reactstrap';
+import { Translate, TextFormat, JhiPagination, JhiItemCount, getSortState } from 'react-jhipster';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+import { APP_DATE_FORMAT } from 'app/config/constants';
+import { ASC, DESC, ITEMS_PER_PAGE, SORT } from 'app/shared/util/pagination.constants';
+import { overridePaginationStateWithQueryParams } from 'app/shared/util/entity-utils';
+import { getUsersAsAdmin, updateUser } from './user-management.reducer';
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+
+export const UserManagement = (props: RouteComponentProps) => {
+ const dispatch = useAppDispatch();
+
+ const [pagination, setPagination] = useState(
+ overridePaginationStateWithQueryParams(getSortState(props.location, ITEMS_PER_PAGE, 'id'), props.location.search)
+ );
+
+ const getUsersFromProps = () => {
+ dispatch(
+ getUsersAsAdmin({
+ page: pagination.activePage - 1,
+ size: pagination.itemsPerPage,
+ sort: `${pagination.sort},${pagination.order}`,
+ })
+ );
+ const endURL = `?page=${pagination.activePage}&sort=${pagination.sort},${pagination.order}`;
+ if (props.location.search !== endURL) {
+ props.history.push(`${props.location.pathname}${endURL}`);
+ }
+ };
+
+ useEffect(() => {
+ getUsersFromProps();
+ }, [pagination.activePage, pagination.order, pagination.sort]);
+
+ useEffect(() => {
+ const params = new URLSearchParams(props.location.search);
+ const page = params.get('page');
+ const sortParam = params.get(SORT);
+ if (page && sortParam) {
+ const sortSplit = sortParam.split(',');
+ setPagination({
+ ...pagination,
+ activePage: +page,
+ sort: sortSplit[0],
+ order: sortSplit[1],
+ });
+ }
+ }, [props.location.search]);
+
+ const sort = p => () =>
+ setPagination({
+ ...pagination,
+ order: pagination.order === ASC ? DESC : ASC,
+ sort: p,
+ });
+
+ const handlePagination = currentPage =>
+ setPagination({
+ ...pagination,
+ activePage: currentPage,
+ });
+
+ const handleSyncList = () => {
+ getUsersFromProps();
+ };
+
+ const toggleActive = user => () =>
+ dispatch(
+ updateUser({
+ ...user,
+ activated: !user.activated,
+ })
+ );
+
+ const { match } = props;
+ const account = useAppSelector(state => state.authentication.account);
+ const users = useAppSelector(state => state.userManagement.users);
+ const totalItems = useAppSelector(state => state.userManagement.totalItems);
+ const loading = useAppSelector(state => state.userManagement.loading);
+
+ return (
+
+
+ Users
+
+
+ {' '}
+ Refresh List
+
+
+ Create a new user
+
+
+
+
+
+
+
+ ID
+
+
+
+ Login
+
+
+
+ Email
+
+
+
+
+ Lang Key
+
+
+
+ Profiles
+
+
+ Created Date
+
+
+
+ Last Modified By
+
+
+
+ Last Modified Date
+
+
+
+
+
+
+ {users.map((user, i) => (
+
+
+
+ {user.id}
+
+
+ {user.login}
+ {user.email}
+
+ {user.activated ? (
+
+ Activated
+
+ ) : (
+
+ Deactivated
+
+ )}
+
+ {user.langKey}
+
+ {user.authorities
+ ? user.authorities.map((authority, j) => (
+
+ {authority}
+
+ ))
+ : null}
+
+
+ {user.createdDate ? : null}
+
+ {user.lastModifiedBy}
+
+ {user.lastModifiedDate ? (
+
+ ) : null}
+
+
+
+
+ {' '}
+
+ View
+
+
+
+ {' '}
+
+ Edit
+
+
+
+ {' '}
+
+ Delete
+
+
+
+
+
+ ))}
+
+
+ {totalItems ? (
+
0 ? '' : 'd-none'}>
+
+
+
+
+
+
+
+ ) : (
+ ''
+ )}
+
+ );
+};
+
+export default UserManagement;
diff --git a/myApp/src/main/webapp/app/modules/home/home.scss b/myApp/src/main/webapp/app/modules/home/home.scss
new file mode 100644
index 000000000..985c83c51
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/home/home.scss
@@ -0,0 +1,10 @@
+/* ==========================================================================
+Main page styles
+========================================================================== */
+.hipster {
+ display: inline-block;
+ width: 100%;
+ height: 497px;
+ background: url('../../../content/images/jhipster_family_member_1.svg') no-repeat center top;
+ background-size: contain;
+}
diff --git a/myApp/src/main/webapp/app/modules/home/home.tsx b/myApp/src/main/webapp/app/modules/home/home.tsx
new file mode 100644
index 000000000..74b132357
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/home/home.tsx
@@ -0,0 +1,100 @@
+import './home.scss';
+
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Translate } from 'react-jhipster';
+import { Row, Col, Alert } from 'reactstrap';
+
+import { useAppSelector } from 'app/config/store';
+
+export const Home = () => {
+ const account = useAppSelector(state => state.authentication.account);
+
+ return (
+
+
+
+
+
+
+ Welcome, Java 7.2 Hipster!
+
+
+ This is your homepage
+
+ {account?.login ? (
+
+
+
+ You are logged in as user {account.login}.
+
+
+
+ ) : (
+
+
+ If you want to
+
+
+ sign in
+
+
+ , you can try the default accounts:
+ - Administrator (login="admin" and password="admin")
+ - User (login="user" and password="user").
+
+
+
+
+ You do not have an account yet?
+
+ Register a new account
+
+
+
+ )}
+
+ If you have any question on JHipster:
+
+
+
+
+
+ If you like JHipster, do not forget to give us a star on {' '}
+
+ GitHub
+
+ !
+
+
+
+ );
+};
+
+export default Home;
diff --git a/myApp/src/main/webapp/app/modules/login/login-modal.tsx b/myApp/src/main/webapp/app/modules/login/login-modal.tsx
new file mode 100644
index 000000000..d6d752389
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/login/login-modal.tsx
@@ -0,0 +1,107 @@
+import React from 'react';
+import { Translate, translate, ValidatedField } from 'react-jhipster';
+import { Button, Modal, ModalHeader, ModalBody, ModalFooter, Alert, Row, Col, Form } from 'reactstrap';
+import { Link } from 'react-router-dom';
+import { useForm } from 'react-hook-form';
+
+export interface ILoginModalProps {
+ showModal: boolean;
+ loginError: boolean;
+ handleLogin: (username: string, password: string, rememberMe: boolean) => void;
+ handleClose: () => void;
+}
+
+const LoginModal = (props: ILoginModalProps) => {
+ const login = ({ username, password, rememberMe }) => {
+ props.handleLogin(username, password, rememberMe);
+ };
+
+ const {
+ handleSubmit,
+ register,
+ formState: { errors, touchedFields },
+ } = useForm({ mode: 'onTouched' });
+
+ const { loginError, handleClose } = props;
+
+ return (
+
+
+
+ );
+};
+
+export default LoginModal;
diff --git a/myApp/src/main/webapp/app/modules/login/login.tsx b/myApp/src/main/webapp/app/modules/login/login.tsx
new file mode 100644
index 000000000..a928bb6d4
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/login/login.tsx
@@ -0,0 +1,34 @@
+import React, { useState, useEffect } from 'react';
+import { Redirect, RouteComponentProps } from 'react-router-dom';
+
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+import { login } from 'app/shared/reducers/authentication';
+import LoginModal from './login-modal';
+
+export const Login = (props: RouteComponentProps) => {
+ const dispatch = useAppDispatch();
+ const isAuthenticated = useAppSelector(state => state.authentication.isAuthenticated);
+ const loginError = useAppSelector(state => state.authentication.loginError);
+ const showModalLogin = useAppSelector(state => state.authentication.showModalLogin);
+ const [showModal, setShowModal] = useState(showModalLogin);
+
+ useEffect(() => {
+ setShowModal(true);
+ }, []);
+
+ const handleLogin = (username, password, rememberMe = false) => dispatch(login(username, password, rememberMe));
+
+ const handleClose = () => {
+ setShowModal(false);
+ props.history.push('/');
+ };
+
+ const { location } = props;
+ const { from } = (location.state as any) || { from: { pathname: '/', search: location.search } };
+ if (isAuthenticated) {
+ return ;
+ }
+ return ;
+};
+
+export default Login;
diff --git a/myApp/src/main/webapp/app/modules/login/logout.tsx b/myApp/src/main/webapp/app/modules/login/logout.tsx
new file mode 100644
index 000000000..e675f71d6
--- /dev/null
+++ b/myApp/src/main/webapp/app/modules/login/logout.tsx
@@ -0,0 +1,24 @@
+import React, { useLayoutEffect } from 'react';
+
+import { useAppDispatch, useAppSelector } from 'app/config/store';
+import { logout } from 'app/shared/reducers/authentication';
+
+export const Logout = () => {
+ const logoutUrl = useAppSelector(state => state.authentication.logoutUrl);
+ const dispatch = useAppDispatch();
+
+ useLayoutEffect(() => {
+ dispatch(logout());
+ if (logoutUrl) {
+ window.location.href = logoutUrl;
+ }
+ });
+
+ return (
+
+
Logged out successfully!
+
+ );
+};
+
+export default Logout;
diff --git a/myApp/src/main/webapp/app/routes.tsx b/myApp/src/main/webapp/app/routes.tsx
new file mode 100644
index 000000000..647a37ed9
--- /dev/null
+++ b/myApp/src/main/webapp/app/routes.tsx
@@ -0,0 +1,48 @@
+import React from 'react';
+import { Switch } from 'react-router-dom';
+import Loadable from 'react-loadable';
+
+import Login from 'app/modules/login/login';
+import Register from 'app/modules/account/register/register';
+import Activate from 'app/modules/account/activate/activate';
+import PasswordResetInit from 'app/modules/account/password-reset/init/password-reset-init';
+import PasswordResetFinish from 'app/modules/account/password-reset/finish/password-reset-finish';
+import Logout from 'app/modules/login/logout';
+import Home from 'app/modules/home/home';
+import Entities from 'app/entities';
+import PrivateRoute from 'app/shared/auth/private-route';
+import ErrorBoundaryRoute from 'app/shared/error/error-boundary-route';
+import PageNotFound from 'app/shared/error/page-not-found';
+import { AUTHORITIES } from 'app/config/constants';
+
+const Account = Loadable({
+ loader: () => import(/* webpackChunkName: "account" */ 'app/modules/account'),
+ loading: () => loading ...
,
+});
+
+const Admin = Loadable({
+ loader: () => import(/* webpackChunkName: "administration" */ 'app/modules/administration'),
+ loading: () => loading ...
,
+});
+
+const Routes = () => {
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ );
+};
+
+export default Routes;
diff --git a/myApp/src/main/webapp/app/setup-tests.ts b/myApp/src/main/webapp/app/setup-tests.ts
new file mode 100644
index 000000000..1390499d4
--- /dev/null
+++ b/myApp/src/main/webapp/app/setup-tests.ts
@@ -0,0 +1,3 @@
+import { loadIcons } from './config/icon-loader';
+
+loadIcons();
diff --git a/myApp/src/main/webapp/app/shared/DurationFormat.tsx b/myApp/src/main/webapp/app/shared/DurationFormat.tsx
new file mode 100644
index 000000000..3dbc162fa
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/DurationFormat.tsx
@@ -0,0 +1,28 @@
+import * as React from 'react';
+import { TranslatorContext } from 'react-jhipster';
+import dayjs from 'dayjs';
+
+export interface IDurationFormat {
+ value: any;
+ blankOnInvalid?: boolean;
+ locale?: string;
+}
+
+export const DurationFormat = ({ value, blankOnInvalid, locale }: IDurationFormat) => {
+ if (blankOnInvalid && !value) {
+ return null;
+ }
+
+ if (!locale) {
+ locale = TranslatorContext.context.locale;
+ }
+
+ return (
+
+ {dayjs
+ .duration(value)
+ .locale(locale || 'en')
+ .humanize()}
+
+ );
+};
diff --git a/myApp/src/main/webapp/app/shared/auth/private-route.spec.tsx b/myApp/src/main/webapp/app/shared/auth/private-route.spec.tsx
new file mode 100644
index 000000000..ebf51574c
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/auth/private-route.spec.tsx
@@ -0,0 +1,124 @@
+import React from 'react';
+import { Router } from 'react-router-dom';
+import { createMemoryHistory } from 'history';
+import { render } from '@testing-library/react';
+import { TranslatorContext } from 'react-jhipster';
+import configureStore from 'redux-mock-store';
+import thunk from 'redux-thunk';
+import { Provider } from 'react-redux';
+
+import { AUTHORITIES } from 'app/config/constants';
+import { PrivateRouteComponent, hasAnyAuthority } from './private-route';
+
+const TestComp = () => Test
;
+
+describe('private-route component', () => {
+ beforeAll(() => {
+ TranslatorContext.registerTranslations('en', {
+ 'error.http.403': 'You are not authorized to access this page.',
+ });
+ });
+
+ const mockStore = configureStore([thunk]);
+ const wrapper = (Elem: JSX.Element, authentication) => {
+ const store = mockStore({ authentication });
+ return render({Elem} );
+ };
+
+ // All tests will go here
+ it('Should throw error when no component is provided', () => {
+ const originalError = console.error;
+ console.error = jest.fn();
+ expect(() =>
+ wrapper( , {
+ isAuthenticated: true,
+ sessionHasBeenFetched: true,
+ account: {
+ authorities: [],
+ },
+ })
+ ).toThrow(Error);
+ console.error = originalError;
+ });
+
+ it('Should render an error message when the user has no authorities', () => {
+ const history = createMemoryHistory();
+ const { container } = wrapper(
+
+
+ ,
+ {
+ isAuthenticated: true,
+ sessionHasBeenFetched: true,
+ account: {
+ authorities: [],
+ },
+ }
+ );
+ expect(container.innerHTML).toEqual(
+ 'You are not authorized to access this page.
'
+ );
+ });
+
+ it('Should render a route for the component provided when authenticated', () => {
+ const history = createMemoryHistory();
+ const { container } = wrapper(
+
+
+ ,
+ {
+ isAuthenticated: true,
+ sessionHasBeenFetched: true,
+ account: {
+ authorities: ['ADMIN'],
+ },
+ }
+ );
+ expect(container.innerHTML).toEqual('Test
');
+ });
+
+ it('Should render a redirect to login when not authenticated', () => {
+ const history = createMemoryHistory();
+ const { container } = wrapper(
+
+
+ ,
+ {
+ isAuthenticated: false,
+ sessionHasBeenFetched: true,
+ account: {
+ authorities: ['ADMIN'],
+ },
+ }
+ );
+ expect(container.innerHTML).not.toEqual('Test
');
+ });
+});
+
+describe('hasAnyAuthority', () => {
+ // All tests will go here
+ it('Should return false when authorities is invalid', () => {
+ expect(hasAnyAuthority(undefined, undefined)).toEqual(false);
+ expect(hasAnyAuthority(null, [])).toEqual(false);
+ expect(hasAnyAuthority([], [])).toEqual(false);
+ expect(hasAnyAuthority([], [AUTHORITIES.USER])).toEqual(false);
+ });
+
+ it('Should return true when authorities is valid and hasAnyAuthorities is empty', () => {
+ expect(hasAnyAuthority([AUTHORITIES.USER], [])).toEqual(true);
+ });
+
+ it('Should return true when authorities is valid and hasAnyAuthorities contains an authority', () => {
+ expect(hasAnyAuthority([AUTHORITIES.USER], [AUTHORITIES.USER])).toEqual(true);
+ expect(hasAnyAuthority([AUTHORITIES.USER, AUTHORITIES.ADMIN], [AUTHORITIES.USER])).toEqual(true);
+ expect(hasAnyAuthority([AUTHORITIES.USER, AUTHORITIES.ADMIN], [AUTHORITIES.USER, AUTHORITIES.ADMIN])).toEqual(true);
+ expect(hasAnyAuthority([AUTHORITIES.USER, AUTHORITIES.ADMIN], [AUTHORITIES.USER, 'ROLEADMIN'])).toEqual(true);
+ expect(hasAnyAuthority([AUTHORITIES.USER, AUTHORITIES.ADMIN], [AUTHORITIES.ADMIN])).toEqual(true);
+ });
+
+ it('Should return false when authorities is valid and hasAnyAuthorities does not contain an authority', () => {
+ expect(hasAnyAuthority([AUTHORITIES.USER], [AUTHORITIES.ADMIN])).toEqual(false);
+ expect(hasAnyAuthority([AUTHORITIES.USER, AUTHORITIES.ADMIN], ['ROLE_USERSS'])).toEqual(false);
+ expect(hasAnyAuthority([AUTHORITIES.USER, AUTHORITIES.ADMIN], ['ROLEUSER', 'ROLEADMIN'])).toEqual(false);
+ });
+});
diff --git a/myApp/src/main/webapp/app/shared/auth/private-route.tsx b/myApp/src/main/webapp/app/shared/auth/private-route.tsx
new file mode 100644
index 000000000..ca80668b3
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/auth/private-route.tsx
@@ -0,0 +1,68 @@
+import React from 'react';
+import { Route, Redirect, RouteProps } from 'react-router-dom';
+import { Translate } from 'react-jhipster';
+import { useAppSelector } from 'app/config/store';
+import ErrorBoundary from 'app/shared/error/error-boundary';
+
+interface IOwnProps extends RouteProps {
+ hasAnyAuthorities?: string[];
+}
+
+export const PrivateRouteComponent = ({ component: Component, hasAnyAuthorities = [], ...rest }: IOwnProps) => {
+ const isAuthenticated = useAppSelector(state => state.authentication.isAuthenticated);
+ const sessionHasBeenFetched = useAppSelector(state => state.authentication.sessionHasBeenFetched);
+ const account = useAppSelector(state => state.authentication.account);
+ const isAuthorized = hasAnyAuthority(account.authorities, hasAnyAuthorities);
+
+ const checkAuthorities = props =>
+ isAuthorized ? (
+
+
+
+ ) : (
+
+
+ You are not authorized to access this page.
+
+
+ );
+
+ const renderRedirect = props => {
+ if (!sessionHasBeenFetched) {
+ return
;
+ } else {
+ return isAuthenticated ? (
+ checkAuthorities(props)
+ ) : (
+
+ );
+ }
+ };
+
+ if (!Component) throw new Error(`A component needs to be specified for private route for path ${(rest as any).path}`);
+
+ return ;
+};
+
+export const hasAnyAuthority = (authorities: string[], hasAnyAuthorities: string[]) => {
+ if (authorities && authorities.length !== 0) {
+ if (hasAnyAuthorities.length === 0) {
+ return true;
+ }
+ return hasAnyAuthorities.some(auth => authorities.includes(auth));
+ }
+ return false;
+};
+
+/**
+ * A route wrapped in an authentication check so that routing happens only when you are authenticated.
+ * Accepts same props as React router Route.
+ * The route also checks for authorization if hasAnyAuthorities is specified.
+ */
+export default PrivateRouteComponent;
diff --git a/myApp/src/main/webapp/app/shared/error/error-boundary-route.spec.tsx b/myApp/src/main/webapp/app/shared/error/error-boundary-route.spec.tsx
new file mode 100644
index 000000000..ebe2b0355
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/error/error-boundary-route.spec.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { Router } from 'react-router-dom';
+import { createMemoryHistory } from 'history';
+import { render } from '@testing-library/react';
+
+import ErrorBoundaryRoute from './error-boundary-route';
+
+const ErrorComp = () => {
+ throw new Error('test');
+};
+
+describe('error-boundary-route component', () => {
+ beforeEach(() => {
+ // ignore console and jsdom errors
+ jest.spyOn((window as any)._virtualConsole, 'emit').mockImplementation(() => false);
+ jest.spyOn((window as any).console, 'error').mockImplementation(() => false);
+ });
+
+ // All tests will go here
+ it('Should throw error when no component is provided', () => {
+ expect(() => render( )).toThrow(Error);
+ });
+
+ it('Should render fallback component when an uncaught error is thrown from component', () => {
+ const history = createMemoryHistory();
+ const { container } = render(
+
+
+
+ );
+ expect(container.innerHTML).toEqual('
An unexpected error has occurred.
');
+ });
+});
diff --git a/myApp/src/main/webapp/app/shared/error/error-boundary-route.tsx b/myApp/src/main/webapp/app/shared/error/error-boundary-route.tsx
new file mode 100644
index 000000000..a8442b064
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/error/error-boundary-route.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Route, RouteProps } from 'react-router-dom';
+import ErrorBoundary from 'app/shared/error/error-boundary';
+
+export const ErrorBoundaryRoute = ({ component: Component, ...rest }: RouteProps) => {
+ const encloseInErrorBoundary = props => (
+
+
+
+ );
+
+ if (!Component) throw new Error(`A component needs to be specified for path ${(rest as any).path}`);
+
+ return ;
+};
+
+export default ErrorBoundaryRoute;
diff --git a/myApp/src/main/webapp/app/shared/error/error-boundary.spec.tsx b/myApp/src/main/webapp/app/shared/error/error-boundary.spec.tsx
new file mode 100644
index 000000000..91f9994a8
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/error/error-boundary.spec.tsx
@@ -0,0 +1,30 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+
+import ErrorBoundary from 'app/shared/error/error-boundary';
+
+const ErrorComp = () => {
+ throw new Error('test');
+};
+
+describe('error component', () => {
+ beforeEach(() => {
+ // ignore console and jsdom errors
+ jest.spyOn((window as any)._virtualConsole, 'emit').mockImplementation(() => false);
+ jest.spyOn((window as any).console, 'error').mockImplementation(() => false);
+ });
+
+ it('Should throw an error when componnet is not enclosed in Error Boundary', () => {
+ expect(() => render( )).toThrow(Error);
+ });
+
+ it('Should call Error Boundary componentDidCatch method', () => {
+ const spy = jest.spyOn(ErrorBoundary.prototype, 'componentDidCatch');
+ render(
+
+
+
+ );
+ expect(spy).toHaveBeenCalled();
+ });
+});
diff --git a/myApp/src/main/webapp/app/shared/error/error-boundary.tsx b/myApp/src/main/webapp/app/shared/error/error-boundary.tsx
new file mode 100644
index 000000000..77830f358
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/error/error-boundary.tsx
@@ -0,0 +1,43 @@
+import React from 'react';
+
+interface IErrorBoundaryProps {
+ readonly children: JSX.Element | JSX.Element[];
+}
+
+interface IErrorBoundaryState {
+ readonly error: any;
+ readonly errorInfo: any;
+}
+
+class ErrorBoundary extends React.Component {
+ readonly state: IErrorBoundaryState = { error: undefined, errorInfo: undefined };
+
+ componentDidCatch(error, errorInfo) {
+ this.setState({
+ error,
+ errorInfo,
+ });
+ }
+
+ render() {
+ const { error, errorInfo } = this.state;
+ if (errorInfo) {
+ const errorDetails = DEVELOPMENT ? (
+
+ {error && error.toString()}
+
+ {errorInfo.componentStack}
+
+ ) : undefined;
+ return (
+
+
An unexpected error has occurred.
+ {errorDetails}
+
+ );
+ }
+ return this.props.children;
+ }
+}
+
+export default ErrorBoundary;
diff --git a/myApp/src/main/webapp/app/shared/error/page-not-found.tsx b/myApp/src/main/webapp/app/shared/error/page-not-found.tsx
new file mode 100644
index 000000000..8a415715a
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/error/page-not-found.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import { Translate } from 'react-jhipster';
+import { Alert } from 'reactstrap';
+
+class PageNotFound extends React.Component {
+ render() {
+ return (
+
+
+ The page does not exist.
+
+
+ );
+ }
+}
+
+export default PageNotFound;
diff --git a/myApp/src/main/webapp/app/shared/layout/footer/footer.scss b/myApp/src/main/webapp/app/shared/layout/footer/footer.scss
new file mode 100644
index 000000000..d1bb630b7
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/footer/footer.scss
@@ -0,0 +1,3 @@
+.footer {
+ height: 50px;
+}
diff --git a/myApp/src/main/webapp/app/shared/layout/footer/footer.tsx b/myApp/src/main/webapp/app/shared/layout/footer/footer.tsx
new file mode 100644
index 000000000..136735c58
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/footer/footer.tsx
@@ -0,0 +1,19 @@
+import './footer.scss';
+
+import React from 'react';
+import { Translate } from 'react-jhipster';
+import { Col, Row } from 'reactstrap';
+
+const Footer = () => (
+
+
+
+
+ Your footer
+
+
+
+
+);
+
+export default Footer;
diff --git a/myApp/src/main/webapp/app/shared/layout/header/header-components.tsx b/myApp/src/main/webapp/app/shared/layout/header/header-components.tsx
new file mode 100644
index 000000000..4671211b3
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/header/header-components.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { Translate } from 'react-jhipster';
+
+import { NavItem, NavLink, NavbarBrand } from 'reactstrap';
+import { NavLink as Link } from 'react-router-dom';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+export const BrandIcon = props => (
+
+
+
+);
+
+export const Brand = () => (
+
+
+
+ ZipCode Banking
+
+ {VERSION}
+
+);
+
+export const Home = () => (
+
+
+
+
+ Home
+
+
+
+);
diff --git a/myApp/src/main/webapp/app/shared/layout/header/header.scss b/myApp/src/main/webapp/app/shared/layout/header/header.scss
new file mode 100644
index 000000000..1b6c9a177
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/header/header.scss
@@ -0,0 +1,84 @@
+$header-color: #fff;
+$header-color-secondary: #bbb;
+$header-color-hover: darken($header-color, 20%);
+
+/* ==========================================================================
+Developement Ribbon
+========================================================================== */
+.ribbon {
+ background-color: rgba(170, 0, 0, 0.5);
+ left: -3.5em;
+ -moz-transform: rotate(-45deg);
+ -ms-transform: rotate(-45deg);
+ -o-transform: rotate(-45deg);
+ -webkit-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+ overflow: hidden;
+ position: absolute;
+ top: 30px;
+ white-space: nowrap;
+ width: 15em;
+ z-index: 99999;
+ pointer-events: none;
+ opacity: 0.75;
+ a {
+ color: #fff;
+ display: block;
+ font-weight: 400;
+ margin: 1px 0;
+ padding: 10px 50px;
+ text-align: center;
+ text-decoration: none;
+ text-shadow: 0 0 5px #444;
+ pointer-events: none;
+ }
+}
+
+/* ==========================================================================
+Navbar styles
+========================================================================== */
+.navbar-brand {
+ overflow: hidden;
+}
+
+.jh-navbar .navbar-nav .nav-link {
+ padding-right: 0;
+ padding-left: 0;
+}
+
+.navbar-version {
+ font-size: 10px;
+ color: $header-color-secondary;
+ padding: 0 0 0 10px;
+}
+
+.brand-logo {
+ &:hover {
+ text-decoration: none;
+ }
+ .brand-icon {
+ height: 35px;
+ width: auto;
+ display: inline-block;
+ img {
+ height: 45px;
+ }
+ }
+}
+
+.brand-title {
+ font-size: 24px;
+ color: $header-color;
+ &:hover {
+ color: $header-color-hover;
+ text-decoration: none;
+ }
+}
+
+.loading-bar {
+ height: 3px;
+ background-color: #009cd8;
+ position: absolute;
+ top: 0px;
+ z-index: 1031;
+}
diff --git a/myApp/src/main/webapp/app/shared/layout/header/header.spec.tsx b/myApp/src/main/webapp/app/shared/layout/header/header.spec.tsx
new file mode 100644
index 000000000..e14e55348
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/header/header.spec.tsx
@@ -0,0 +1,112 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import { Provider } from 'react-redux';
+import { Router } from 'react-router-dom';
+import { createMemoryHistory } from 'history';
+
+import initStore from 'app/config/store';
+import Header from './header';
+
+describe('Header', () => {
+ let mountedWrapper;
+ const devProps = {
+ isAuthenticated: true,
+ isAdmin: true,
+ currentLocale: 'en',
+ ribbonEnv: 'dev',
+ isInProduction: false,
+ isOpenAPIEnabled: true,
+ };
+ const prodProps = {
+ ...devProps,
+ ribbonEnv: 'prod',
+ isInProduction: true,
+ isOpenAPIEnabled: false,
+ };
+ const userProps = {
+ ...prodProps,
+ isAdmin: false,
+ };
+ const guestProps = {
+ ...prodProps,
+ isAdmin: false,
+ isAuthenticated: false,
+ };
+
+ const wrapper = (props = devProps) => {
+ if (!mountedWrapper) {
+ const store = initStore();
+ const history = createMemoryHistory();
+ const { container } = render(
+
+
+
+
+
+ );
+ mountedWrapper = container.innerHTML;
+ }
+ return mountedWrapper;
+ };
+
+ beforeEach(() => {
+ mountedWrapper = undefined;
+ });
+
+ // All tests will go here
+ it('Renders a Header component in dev profile with LoadingBar, Navbar, Nav and dev ribbon.', () => {
+ const html = wrapper();
+
+ // Find Navbar component
+ expect(html).toContain('navbar');
+ // Find AdminMenu component
+ expect(html).toContain('admin-menu');
+ // Find EntitiesMenu component
+ expect(html).toContain('entity-menu');
+ // Find AccountMenu component
+ expect(html).toContain('account-menu');
+ // Ribbon
+ expect(html).toContain('ribbon');
+ });
+
+ it('Renders a Header component in prod profile with LoadingBar, Navbar, Nav.', () => {
+ const html = wrapper(prodProps);
+
+ // Find Navbar component
+ expect(html).toContain('navbar');
+ // Find AdminMenu component
+ expect(html).toContain('admin-menu');
+ // Find EntitiesMenu component
+ expect(html).toContain('entity-menu');
+ // Find AccountMenu component
+ expect(html).toContain('account-menu');
+ // No Ribbon
+ expect(html).not.toContain('ribbon');
+ });
+
+ it('Renders a Header component in prod profile with logged in User', () => {
+ const html = wrapper(userProps);
+
+ // Find Navbar component
+ expect(html).toContain('navbar');
+ // Not find AdminMenu component
+ expect(html).not.toContain('admin-menu');
+ // Find EntitiesMenu component
+ expect(html).toContain('entity-menu');
+ // Find AccountMenu component
+ expect(html).toContain('account-menu');
+ });
+
+ it('Renders a Header component in prod profile with no logged in User', () => {
+ const html = wrapper(guestProps);
+
+ // Find Navbar component
+ expect(html).toContain('navbar');
+ // Not find AdminMenu component
+ expect(html).not.toContain('admin-menu');
+ // Not find EntitiesMenu component
+ expect(html).not.toContain('entity-menu');
+ // Find AccountMenu component
+ expect(html).toContain('account-menu');
+ });
+});
diff --git a/myApp/src/main/webapp/app/shared/layout/header/header.tsx b/myApp/src/main/webapp/app/shared/layout/header/header.tsx
new file mode 100644
index 000000000..67fdc3c72
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/header/header.tsx
@@ -0,0 +1,69 @@
+import './header.scss';
+
+import React, { useState } from 'react';
+import { Translate, Storage } from 'react-jhipster';
+import { Navbar, Nav, NavbarToggler, Collapse } from 'reactstrap';
+import LoadingBar from 'react-redux-loading-bar';
+
+import { Home, Brand } from './header-components';
+import { AdminMenu, EntitiesMenu, AccountMenu, LocaleMenu } from '../menus';
+import { useAppDispatch } from 'app/config/store';
+import { setLocale } from 'app/shared/reducers/locale';
+
+export interface IHeaderProps {
+ isAuthenticated: boolean;
+ isAdmin: boolean;
+ ribbonEnv: string;
+ isInProduction: boolean;
+ isOpenAPIEnabled: boolean;
+ currentLocale: string;
+}
+
+const Header = (props: IHeaderProps) => {
+ const [menuOpen, setMenuOpen] = useState(false);
+
+ const dispatch = useAppDispatch();
+
+ const handleLocaleChange = event => {
+ const langKey = event.target.value;
+ Storage.session.set('locale', langKey);
+ dispatch(setLocale(langKey));
+ };
+
+ const renderDevRibbon = () =>
+ props.isInProduction === false ? (
+
+ ) : null;
+
+ const toggleMenu = () => setMenuOpen(!menuOpen);
+
+ /* jhipster-needle-add-element-to-menu - JHipster will add new menu items here */
+
+ return (
+
+ );
+};
+
+export default Header;
diff --git a/myApp/src/main/webapp/app/shared/layout/menus/account.spec.tsx b/myApp/src/main/webapp/app/shared/layout/menus/account.spec.tsx
new file mode 100644
index 000000000..ba3342d24
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/menus/account.spec.tsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+import { Router } from 'react-router-dom';
+import { createMemoryHistory } from 'history';
+
+import { AccountMenu } from './account';
+
+describe('AccountMenu', () => {
+ let mountedWrapper;
+
+ const authenticatedWrapper = () => {
+ if (!mountedWrapper) {
+ const history = createMemoryHistory();
+ const { container } = render(
+
+
+
+ );
+ mountedWrapper = container.innerHTML;
+ }
+ return mountedWrapper;
+ };
+ const guestWrapper = () => {
+ if (!mountedWrapper) {
+ const history = createMemoryHistory();
+ const { container } = (mountedWrapper = render(
+
+
+
+ ));
+ mountedWrapper = container.innerHTML;
+ }
+ return mountedWrapper;
+ };
+
+ beforeEach(() => {
+ mountedWrapper = undefined;
+ });
+
+ // All tests will go here
+
+ it('Renders a authenticated AccountMenu component', () => {
+ const html = authenticatedWrapper();
+
+ expect(html).not.toContain('/login');
+ expect(html).toContain('/logout');
+ });
+
+ it('Renders a guest AccountMenu component', () => {
+ const html = guestWrapper();
+
+ expect(html).toContain('/login');
+ expect(html).not.toContain('/logout');
+ });
+});
diff --git a/myApp/src/main/webapp/app/shared/layout/menus/account.tsx b/myApp/src/main/webapp/app/shared/layout/menus/account.tsx
new file mode 100644
index 000000000..183ace769
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/menus/account.tsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import MenuItem from 'app/shared/layout/menus/menu-item';
+import { Translate, translate } from 'react-jhipster';
+import { NavDropdown } from './menu-components';
+
+const accountMenuItemsAuthenticated = () => (
+ <>
+
+ Settings
+
+
+ Password
+
+
+ Sign out
+
+ >
+);
+
+const accountMenuItems = () => (
+ <>
+
+ Sign in
+
+
+ Register
+
+ >
+);
+
+export const AccountMenu = ({ isAuthenticated = false }) => (
+
+);
+
+export default AccountMenu;
diff --git a/myApp/src/main/webapp/app/shared/layout/menus/admin.tsx b/myApp/src/main/webapp/app/shared/layout/menus/admin.tsx
new file mode 100644
index 000000000..88cdf35dd
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/menus/admin.tsx
@@ -0,0 +1,50 @@
+import React from 'react';
+import MenuItem from 'app/shared/layout/menus/menu-item';
+import { DropdownItem } from 'reactstrap';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { NavDropdown } from './menu-components';
+import { Translate, translate } from 'react-jhipster';
+
+const adminMenuItems = () => (
+ <>
+
+ User management
+
+
+ Metrics
+
+
+ Health
+
+
+ Configuration
+
+
+ Logs
+
+ {/* jhipster-needle-add-element-to-admin-menu - JHipster will add entities to the admin menu here */}
+ >
+);
+
+const openAPIItem = () => (
+
+ API
+
+);
+
+const databaseItem = () => (
+
+ Database
+
+);
+
+export const AdminMenu = ({ showOpenAPI, showDatabase }) => (
+
+);
+
+export default AdminMenu;
diff --git a/myApp/src/main/webapp/app/shared/layout/menus/entities.tsx b/myApp/src/main/webapp/app/shared/layout/menus/entities.tsx
new file mode 100644
index 000000000..382e3e6ea
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/menus/entities.tsx
@@ -0,0 +1,17 @@
+import React from 'react';
+import MenuItem from 'app/shared/layout/menus/menu-item';
+import { Translate, translate } from 'react-jhipster';
+import { NavDropdown } from './menu-components';
+
+export const EntitiesMenu = props => (
+
+);
diff --git a/myApp/src/main/webapp/app/shared/layout/menus/index.ts b/myApp/src/main/webapp/app/shared/layout/menus/index.ts
new file mode 100644
index 000000000..74f0c7d02
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/menus/index.ts
@@ -0,0 +1,4 @@
+export * from './account';
+export * from './admin';
+export * from './locale';
+export * from './entities';
diff --git a/myApp/src/main/webapp/app/shared/layout/menus/locale.tsx b/myApp/src/main/webapp/app/shared/layout/menus/locale.tsx
new file mode 100644
index 000000000..92acb5870
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/menus/locale.tsx
@@ -0,0 +1,15 @@
+import React from 'react';
+import { DropdownItem } from 'reactstrap';
+import { NavDropdown } from './menu-components';
+import { locales, languages } from 'app/config/translation';
+
+export const LocaleMenu = ({ currentLocale, onClick }: { currentLocale: string; onClick: (event: any) => void }) =>
+ Object.keys(languages).length > 1 ? (
+
+ {locales.map(locale => (
+
+ {languages[locale].name}
+
+ ))}
+
+ ) : null;
diff --git a/myApp/src/main/webapp/app/shared/layout/menus/menu-components.tsx b/myApp/src/main/webapp/app/shared/layout/menus/menu-components.tsx
new file mode 100644
index 000000000..9d17eac1f
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/menus/menu-components.tsx
@@ -0,0 +1,16 @@
+import React from 'react';
+
+import { UncontrolledDropdown, DropdownToggle, DropdownMenu } from 'reactstrap';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+
+export const NavDropdown = props => (
+
+
+
+ {props.name}
+
+
+ {props.children}
+
+
+);
diff --git a/myApp/src/main/webapp/app/shared/layout/menus/menu-item.tsx b/myApp/src/main/webapp/app/shared/layout/menus/menu-item.tsx
new file mode 100644
index 000000000..50a63f4ea
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/menus/menu-item.tsx
@@ -0,0 +1,24 @@
+import React from 'react';
+import { DropdownItem } from 'reactstrap';
+import { NavLink as Link } from 'react-router-dom';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { IconProp } from '@fortawesome/fontawesome-svg-core';
+
+export interface IMenuItem {
+ icon: IconProp;
+ to: string;
+ id?: string;
+ 'data-cy'?: string;
+}
+
+export default class MenuItem extends React.Component {
+ render() {
+ const { to, icon, id, children } = this.props;
+
+ return (
+
+ {children}
+
+ );
+ }
+}
diff --git a/myApp/src/main/webapp/app/shared/layout/password/password-strength-bar.scss b/myApp/src/main/webapp/app/shared/layout/password/password-strength-bar.scss
new file mode 100644
index 000000000..67ce4687a
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/password/password-strength-bar.scss
@@ -0,0 +1,23 @@
+/* ==========================================================================
+start Password strength bar style
+========================================================================== */
+ul#strength {
+ display: inline;
+ list-style: none;
+ margin: 0;
+ margin-left: 15px;
+ padding: 0;
+ vertical-align: 2px;
+}
+
+.point {
+ background: #ddd;
+ border-radius: 2px;
+ display: inline-block;
+ height: 5px;
+ margin-right: 1px;
+ width: 20px;
+ &:last-child {
+ margin: 0 !important;
+ }
+}
diff --git a/myApp/src/main/webapp/app/shared/layout/password/password-strength-bar.tsx b/myApp/src/main/webapp/app/shared/layout/password/password-strength-bar.tsx
new file mode 100644
index 000000000..b457f1dc1
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/layout/password/password-strength-bar.tsx
@@ -0,0 +1,76 @@
+import './password-strength-bar.scss';
+
+import React from 'react';
+import { Translate } from 'react-jhipster';
+
+export interface IPasswordStrengthBarProps {
+ password: string;
+}
+
+export const PasswordStrengthBar = ({ password }: IPasswordStrengthBarProps) => {
+ const colors = ['#F00', '#F90', '#FF0', '#9F0', '#0F0'];
+
+ const measureStrength = (p: string): number => {
+ let force = 0;
+ const regex = /[$-/:-?{-~!"^_`[\]]/g;
+ const flags = {
+ lowerLetters: /[a-z]+/.test(p),
+ upperLetters: /[A-Z]+/.test(p),
+ numbers: /[0-9]+/.test(p),
+ symbols: regex.test(p),
+ };
+
+ const passedMatches = Object.values(flags).filter((isMatchedFlag: boolean) => !!isMatchedFlag).length;
+
+ force += 2 * p.length + (p.length >= 10 ? 1 : 0);
+ force += passedMatches * 10;
+
+ // penalty (short password)
+ force = p.length <= 6 ? Math.min(force, 10) : force;
+
+ // penalty (poor variety of characters)
+ force = passedMatches === 1 ? Math.min(force, 10) : force;
+ force = passedMatches === 2 ? Math.min(force, 20) : force;
+ force = passedMatches === 3 ? Math.min(force, 40) : force;
+
+ return force;
+ };
+
+ const getColor = (s: number): any => {
+ let idx = 0;
+ if (s > 10) {
+ if (s <= 20) {
+ idx = 1;
+ } else if (s <= 30) {
+ idx = 2;
+ } else if (s <= 40) {
+ idx = 3;
+ } else {
+ idx = 4;
+ }
+ }
+ return { idx: idx + 1, col: colors[idx] };
+ };
+
+ const getPoints = force => {
+ const pts = [] as any[];
+ for (let i = 0; i < 5; i++) {
+ pts.push( );
+ }
+ return pts;
+ };
+
+ const strength = getColor(measureStrength(password));
+ const points = getPoints(strength);
+
+ return (
+
+
+ Password strength:
+
+
+
+ );
+};
+
+export default PasswordStrengthBar;
diff --git a/myApp/src/main/webapp/app/shared/model/user.model.ts b/myApp/src/main/webapp/app/shared/model/user.model.ts
new file mode 100644
index 000000000..b64d02b80
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/model/user.model.ts
@@ -0,0 +1,31 @@
+export interface IUser {
+ id?: any;
+ login?: string;
+ firstName?: string;
+ lastName?: string;
+ email?: string;
+ activated?: boolean;
+ langKey?: string;
+ authorities?: any[];
+ createdBy?: string;
+ createdDate?: Date | null;
+ lastModifiedBy?: string;
+ lastModifiedDate?: Date | null;
+ password?: string;
+}
+
+export const defaultValue: Readonly = {
+ id: '',
+ login: '',
+ firstName: '',
+ lastName: '',
+ email: '',
+ activated: true,
+ langKey: '',
+ authorities: [],
+ createdBy: '',
+ createdDate: null,
+ lastModifiedBy: '',
+ lastModifiedDate: null,
+ password: '',
+};
diff --git a/myApp/src/main/webapp/app/shared/reducers/application-profile.spec.ts b/myApp/src/main/webapp/app/shared/reducers/application-profile.spec.ts
new file mode 100644
index 000000000..8150db444
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/reducers/application-profile.spec.ts
@@ -0,0 +1,76 @@
+import thunk from 'redux-thunk';
+import axios from 'axios';
+import sinon from 'sinon';
+import configureStore from 'redux-mock-store';
+
+import profile, { getProfile } from './application-profile';
+
+describe('Profile reducer tests', () => {
+ const initialState = {
+ ribbonEnv: '',
+ inProduction: true,
+ isOpenAPIEnabled: false,
+ };
+ describe('Common tests', () => {
+ it('should return the initial state', () => {
+ const toTest = profile(undefined, { type: '' });
+ expect(toTest).toEqual(initialState);
+ });
+
+ it('should return the right payload in prod', () => {
+ const payload = {
+ data: {
+ 'display-ribbon-on-profiles': 'awesome ribbon stuff',
+ activeProfiles: ['prod'],
+ },
+ };
+
+ expect(profile(undefined, { type: getProfile.fulfilled.type, payload })).toEqual({
+ ribbonEnv: 'awesome ribbon stuff',
+ inProduction: true,
+ isOpenAPIEnabled: false,
+ });
+ });
+
+ it('should return the right payload in dev with OpenAPI enabled', () => {
+ const payload = {
+ data: {
+ 'display-ribbon-on-profiles': 'awesome ribbon stuff',
+ activeProfiles: ['api-docs', 'dev'],
+ },
+ };
+
+ expect(profile(undefined, { type: getProfile.fulfilled.type, payload })).toEqual({
+ ribbonEnv: 'awesome ribbon stuff',
+ inProduction: false,
+ isOpenAPIEnabled: true,
+ });
+ });
+ });
+
+ describe('Actions', () => {
+ let store;
+
+ const resolvedObject = { value: 'whatever' };
+ beforeEach(() => {
+ const mockStore = configureStore([thunk]);
+ store = mockStore({});
+ axios.get = sinon.stub().returns(Promise.resolve(resolvedObject));
+ });
+
+ it('dispatches GET_SESSION_PENDING and GET_SESSION_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getProfile.pending.type,
+ },
+ {
+ type: getProfile.fulfilled.type,
+ payload: resolvedObject,
+ },
+ ];
+ await store.dispatch(getProfile());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/shared/reducers/application-profile.ts b/myApp/src/main/webapp/app/shared/reducers/application-profile.ts
new file mode 100644
index 000000000..a624fdf18
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/reducers/application-profile.ts
@@ -0,0 +1,33 @@
+import axios from 'axios';
+
+import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
+import { serializeAxiosError } from './reducer.utils';
+
+const initialState = {
+ ribbonEnv: '',
+ inProduction: true,
+ isOpenAPIEnabled: false,
+};
+
+export type ApplicationProfileState = Readonly;
+
+export const getProfile = createAsyncThunk('applicationProfile/get_profile', async () => axios.get('management/info'), {
+ serializeError: serializeAxiosError,
+});
+
+export const ApplicationProfileSlice = createSlice({
+ name: 'applicationProfile',
+ initialState: initialState as ApplicationProfileState,
+ reducers: {},
+ extraReducers(builder) {
+ builder.addCase(getProfile.fulfilled, (state, action) => {
+ const { data } = action.payload;
+ state.ribbonEnv = data['display-ribbon-on-profiles'];
+ state.inProduction = data.activeProfiles.includes('prod');
+ state.isOpenAPIEnabled = data.activeProfiles.includes('api-docs');
+ });
+ },
+});
+
+// Reducer
+export default ApplicationProfileSlice.reducer;
diff --git a/myApp/src/main/webapp/app/shared/reducers/authentication.spec.ts b/myApp/src/main/webapp/app/shared/reducers/authentication.spec.ts
new file mode 100644
index 000000000..dcd480b02
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/reducers/authentication.spec.ts
@@ -0,0 +1,244 @@
+import thunk from 'redux-thunk';
+import axios from 'axios';
+import sinon from 'sinon';
+import { Storage } from 'react-jhipster';
+import configureStore from 'redux-mock-store';
+
+import authentication, {
+ getSession,
+ getAccount,
+ authenticate,
+ login,
+ clearAuthentication,
+ logout,
+ logoutSession,
+ clearAuthToken,
+ authError,
+ clearAuth,
+ initialState,
+} from 'app/shared/reducers/authentication';
+import { updateLocale } from 'app/shared/reducers/locale';
+
+describe('Authentication reducer tests', () => {
+ function isAccountEmpty(state): boolean {
+ return Object.keys(state.account).length === 0;
+ }
+
+ describe('Common tests', () => {
+ it('should return the initial state', () => {
+ const toTest = authentication(undefined, { type: '' });
+ expect(toTest).toMatchObject({
+ loading: false,
+ isAuthenticated: false,
+ errorMessage: null, // Errors returned from server side
+ loginSuccess: false,
+ loginError: false, // Errors returned from server side
+ showModalLogin: false,
+ redirectMessage: null,
+ });
+ expect(isAccountEmpty(toTest));
+ });
+ });
+
+ describe('Requests', () => {
+ it('should detect a request', () => {
+ expect(authentication(undefined, { type: authenticate.pending.type })).toMatchObject({
+ loading: true,
+ });
+ expect(authentication(undefined, { type: getAccount.pending.type })).toMatchObject({
+ loading: true,
+ });
+ });
+ });
+
+ describe('Success', () => {
+ it('should detect a success on login', () => {
+ const toTest = authentication(undefined, { type: authenticate.fulfilled.type });
+ expect(toTest).toMatchObject({
+ loading: false,
+ loginError: false,
+ loginSuccess: true,
+ showModalLogin: false,
+ });
+ });
+
+ it('should detect a success on get session and be authenticated', () => {
+ const payload = { data: { activated: true } };
+ const toTest = authentication(undefined, { type: getAccount.fulfilled.type, payload });
+ expect(toTest).toMatchObject({
+ isAuthenticated: true,
+ loading: false,
+ account: payload.data,
+ });
+ });
+
+ it('should detect a success on get session and not be authenticated', () => {
+ const payload = { data: { activated: false } };
+ const toTest = authentication(undefined, { type: getAccount.fulfilled.type, payload });
+ expect(toTest).toMatchObject({
+ isAuthenticated: false,
+ loading: false,
+ account: payload.data,
+ });
+ });
+ });
+
+ describe('Failure', () => {
+ it('should detect a failure on login', () => {
+ const error = { message: 'Something happened.' };
+ const toTest = authentication(undefined, { type: authenticate.rejected.type, error });
+
+ expect(toTest).toMatchObject({
+ errorMessage: error.message,
+ showModalLogin: true,
+ loginError: true,
+ });
+ expect(isAccountEmpty(toTest));
+ });
+
+ it('should detect a failure', () => {
+ const error = { message: 'Something happened.' };
+ const toTest = authentication(undefined, { type: getAccount.rejected.type, error });
+
+ expect(toTest).toMatchObject({
+ loading: false,
+ isAuthenticated: false,
+ showModalLogin: true,
+ errorMessage: error.message,
+ });
+ expect(isAccountEmpty(toTest));
+ });
+ });
+
+ describe('Other cases', () => {
+ it('should properly reset the current state when a logout is requested', () => {
+ const toTest = authentication(undefined, logoutSession());
+ expect(toTest).toMatchObject({
+ loading: false,
+ isAuthenticated: false,
+ loginSuccess: false,
+ loginError: false,
+ showModalLogin: true,
+ errorMessage: null,
+ redirectMessage: null,
+ });
+ expect(isAccountEmpty(toTest));
+ });
+
+ it('should properly define an error message and change the current state to display the login modal', () => {
+ const message = 'redirect me please';
+ const toTest = authentication(undefined, authError(message));
+ expect(toTest).toMatchObject({
+ loading: false,
+ isAuthenticated: false,
+ loginSuccess: false,
+ loginError: false,
+ showModalLogin: true,
+ errorMessage: null,
+ redirectMessage: message,
+ });
+ expect(isAccountEmpty(toTest));
+ });
+
+ it('should clear authentication', () => {
+ const toTest = authentication({ ...initialState, isAuthenticated: true }, clearAuth());
+ expect(toTest).toMatchObject({
+ loading: false,
+ showModalLogin: true,
+ isAuthenticated: false,
+ });
+ });
+ });
+
+ describe('Actions', () => {
+ let store;
+
+ const resolvedObject = { value: 'whatever' };
+ beforeEach(() => {
+ const mockStore = configureStore([thunk]);
+ store = mockStore({ authentication: { account: { langKey: 'en' } } });
+ axios.get = sinon.stub().returns(Promise.resolve(resolvedObject));
+ });
+
+ it('dispatches GET_SESSION_PENDING and GET_SESSION_FULFILLED actions', async () => {
+ const expectedActions = [
+ {
+ type: getAccount.pending.type,
+ },
+ {
+ type: getAccount.fulfilled.type,
+ payload: resolvedObject,
+ },
+ updateLocale('en'),
+ ];
+ await store.dispatch(getSession());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ expect(store.getActions()[2]).toMatchObject(expectedActions[2]);
+ });
+
+ it('dispatches LOGOUT actions', async () => {
+ const expectedActions = [logoutSession()];
+ await store.dispatch(logout());
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ });
+
+ it('dispatches CLEAR_AUTH actions', async () => {
+ const expectedActions = [authError('message'), clearAuth()];
+ await store.dispatch(clearAuthentication('message'));
+ expect(store.getActions()).toEqual(expectedActions);
+ });
+
+ it('dispatches LOGIN, GET_SESSION and SET_LOCALE success and request actions', async () => {
+ const loginResponse = { headers: { authorization: 'auth' } };
+ axios.post = sinon.stub().returns(Promise.resolve(loginResponse));
+ const expectedActions = [
+ {
+ type: authenticate.pending.type,
+ },
+ {
+ type: authenticate.fulfilled.type,
+ payload: loginResponse,
+ },
+ {
+ type: getAccount.pending.type,
+ },
+ ];
+ await store.dispatch(login('test', 'test'));
+ expect(store.getActions()[0]).toMatchObject(expectedActions[0]);
+ expect(store.getActions()[1]).toMatchObject(expectedActions[1]);
+ expect(store.getActions()[2]).toMatchObject(expectedActions[2]);
+ });
+ });
+ describe('clearAuthToken', () => {
+ let store;
+ beforeEach(() => {
+ const mockStore = configureStore([thunk]);
+ store = mockStore({ authentication: { account: { langKey: 'en' } } });
+ });
+ it('clears the session token on clearAuthToken', async () => {
+ const AUTH_TOKEN_KEY = 'jhi-authenticationToken';
+ const loginResponse = { headers: { authorization: 'Bearer TestToken' } };
+ axios.post = sinon.stub().returns(Promise.resolve(loginResponse));
+
+ await store.dispatch(login('test', 'test'));
+ expect(Storage.session.get(AUTH_TOKEN_KEY)).toBe('TestToken');
+ expect(Storage.local.get(AUTH_TOKEN_KEY)).toBe(undefined);
+ clearAuthToken();
+ expect(Storage.session.get(AUTH_TOKEN_KEY)).toBe(undefined);
+ expect(Storage.local.get(AUTH_TOKEN_KEY)).toBe(undefined);
+ });
+ it('clears the local storage token on clearAuthToken', async () => {
+ const AUTH_TOKEN_KEY = 'jhi-authenticationToken';
+ const loginResponse = { headers: { authorization: 'Bearer TestToken' } };
+ axios.post = sinon.stub().returns(Promise.resolve(loginResponse));
+
+ await store.dispatch(login('user', 'user', true));
+ expect(Storage.session.get(AUTH_TOKEN_KEY)).toBe(undefined);
+ expect(Storage.local.get(AUTH_TOKEN_KEY)).toBe('TestToken');
+ clearAuthToken();
+ expect(Storage.session.get(AUTH_TOKEN_KEY)).toBe(undefined);
+ expect(Storage.local.get(AUTH_TOKEN_KEY)).toBe(undefined);
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/shared/reducers/authentication.ts b/myApp/src/main/webapp/app/shared/reducers/authentication.ts
new file mode 100644
index 000000000..3a5f26d40
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/reducers/authentication.ts
@@ -0,0 +1,164 @@
+import axios, { AxiosResponse } from 'axios';
+import { Storage } from 'react-jhipster';
+import { createAsyncThunk, createSlice } from '@reduxjs/toolkit';
+import { serializeAxiosError } from './reducer.utils';
+
+import { AppThunk } from 'app/config/store';
+import { setLocale } from 'app/shared/reducers/locale';
+
+const AUTH_TOKEN_KEY = 'jhi-authenticationToken';
+
+export const initialState = {
+ loading: false,
+ isAuthenticated: false,
+ loginSuccess: false,
+ loginError: false, // Errors returned from server side
+ showModalLogin: false,
+ account: {} as any,
+ errorMessage: null as unknown as string, // Errors returned from server side
+ redirectMessage: null as unknown as string,
+ sessionHasBeenFetched: false,
+ logoutUrl: null as unknown as string,
+};
+
+export type AuthenticationState = Readonly;
+
+// Actions
+
+export const getSession = (): AppThunk => async (dispatch, getState) => {
+ await dispatch(getAccount());
+
+ const { account } = getState().authentication;
+ if (account && account.langKey) {
+ const langKey = Storage.session.get('locale', account.langKey);
+ dispatch(setLocale(langKey));
+ }
+};
+
+export const getAccount = createAsyncThunk('authentication/get_account', async () => axios.get('api/account'), {
+ serializeError: serializeAxiosError,
+});
+
+interface IAuthParams {
+ username: string;
+ password: string;
+ rememberMe?: boolean;
+}
+
+export const authenticate = createAsyncThunk(
+ 'authentication/login',
+ async (auth: IAuthParams) => axios.post('api/authenticate', auth),
+ {
+ serializeError: serializeAxiosError,
+ }
+);
+
+export const login: (username: string, password: string, rememberMe?: boolean) => AppThunk =
+ (username, password, rememberMe = false) =>
+ async dispatch => {
+ const result = await dispatch(authenticate({ username, password, rememberMe }));
+ const response = result.payload as AxiosResponse;
+ const bearerToken = response?.headers?.authorization;
+ if (bearerToken && bearerToken.slice(0, 7) === 'Bearer ') {
+ const jwt = bearerToken.slice(7, bearerToken.length);
+ if (rememberMe) {
+ Storage.local.set(AUTH_TOKEN_KEY, jwt);
+ } else {
+ Storage.session.set(AUTH_TOKEN_KEY, jwt);
+ }
+ }
+ dispatch(getSession());
+ };
+
+export const clearAuthToken = () => {
+ if (Storage.local.get(AUTH_TOKEN_KEY)) {
+ Storage.local.remove(AUTH_TOKEN_KEY);
+ }
+ if (Storage.session.get(AUTH_TOKEN_KEY)) {
+ Storage.session.remove(AUTH_TOKEN_KEY);
+ }
+};
+
+export const logout: () => AppThunk = () => dispatch => {
+ clearAuthToken();
+ dispatch(logoutSession());
+};
+
+export const clearAuthentication = messageKey => dispatch => {
+ clearAuthToken();
+ dispatch(authError(messageKey));
+ dispatch(clearAuth());
+};
+
+export const AuthenticationSlice = createSlice({
+ name: 'authentication',
+ initialState: initialState as AuthenticationState,
+ reducers: {
+ logoutSession() {
+ return {
+ ...initialState,
+ showModalLogin: true,
+ };
+ },
+ authError(state, action) {
+ return {
+ ...state,
+ showModalLogin: true,
+ redirectMessage: action.payload,
+ };
+ },
+ clearAuth(state) {
+ return {
+ ...state,
+ loading: false,
+ showModalLogin: true,
+ isAuthenticated: false,
+ };
+ },
+ },
+ extraReducers(builder) {
+ builder
+ .addCase(authenticate.rejected, (state, action) => ({
+ ...initialState,
+ errorMessage: action.error.message,
+ showModalLogin: true,
+ loginError: true,
+ }))
+ .addCase(authenticate.fulfilled, state => ({
+ ...state,
+ loading: false,
+ loginError: false,
+ showModalLogin: false,
+ loginSuccess: true,
+ }))
+ .addCase(getAccount.rejected, (state, action) => ({
+ ...state,
+ loading: false,
+ isAuthenticated: false,
+ sessionHasBeenFetched: true,
+ showModalLogin: true,
+ errorMessage: action.error.message,
+ }))
+ .addCase(getAccount.fulfilled, (state, action) => {
+ const isAuthenticated = action.payload && action.payload.data && action.payload.data.activated;
+ return {
+ ...state,
+ isAuthenticated,
+ loading: false,
+ sessionHasBeenFetched: true,
+ account: action.payload.data,
+ };
+ })
+ .addCase(authenticate.pending, state => {
+ state.loading = true;
+ })
+ .addCase(getAccount.pending, state => {
+ state.loading = true;
+ });
+ },
+});
+
+export const { logoutSession, authError, clearAuth } = AuthenticationSlice.actions;
+
+// Reducer
+export default AuthenticationSlice.reducer;
diff --git a/myApp/src/main/webapp/app/shared/reducers/index.ts b/myApp/src/main/webapp/app/shared/reducers/index.ts
new file mode 100644
index 000000000..0da21fba4
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/reducers/index.ts
@@ -0,0 +1,31 @@
+import { loadingBarReducer as loadingBar } from 'react-redux-loading-bar';
+
+import locale from './locale';
+import authentication from './authentication';
+import applicationProfile from './application-profile';
+
+import administration from 'app/modules/administration/administration.reducer';
+import userManagement from 'app/modules/administration/user-management/user-management.reducer';
+import register from 'app/modules/account/register/register.reducer';
+import activate from 'app/modules/account/activate/activate.reducer';
+import password from 'app/modules/account/password/password.reducer';
+import settings from 'app/modules/account/settings/settings.reducer';
+import passwordReset from 'app/modules/account/password-reset/password-reset.reducer';
+/* jhipster-needle-add-reducer-import - JHipster will add reducer here */
+
+const rootReducer = {
+ authentication,
+ locale,
+ applicationProfile,
+ administration,
+ userManagement,
+ register,
+ activate,
+ passwordReset,
+ password,
+ settings,
+ /* jhipster-needle-add-reducer-combine - JHipster will add reducer here */
+ loadingBar,
+};
+
+export default rootReducer;
diff --git a/myApp/src/main/webapp/app/shared/reducers/locale.spec.ts b/myApp/src/main/webapp/app/shared/reducers/locale.spec.ts
new file mode 100644
index 000000000..3783a334a
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/reducers/locale.spec.ts
@@ -0,0 +1,55 @@
+import axios from 'axios';
+import sinon from 'sinon';
+import configureStore from 'redux-mock-store';
+import thunk from 'redux-thunk';
+import { TranslatorContext } from 'react-jhipster';
+
+import locale, { setLocale, updateLocale } from 'app/shared/reducers/locale';
+
+describe('Locale reducer tests', () => {
+ it('should return the initial state', () => {
+ const localeState = locale(undefined, { type: '' });
+ expect(localeState).toMatchObject({
+ currentLocale: '',
+ });
+ });
+
+ it('should correctly set the first time locale', () => {
+ const localeState = locale(undefined, updateLocale('en'));
+ expect(localeState).toMatchObject({
+ currentLocale: 'en',
+ });
+ expect(TranslatorContext.context.locale).toEqual('en');
+ });
+
+ it('should correctly detect update in current locale state', () => {
+ TranslatorContext.setLocale('en');
+ expect(TranslatorContext.context.locale).toEqual('en');
+ const localeState = locale({ currentLocale: 'en' }, updateLocale('es'));
+ expect(localeState).toMatchObject({
+ currentLocale: 'es',
+ });
+ expect(TranslatorContext.context.locale).toEqual('es');
+ });
+
+ describe('Locale actions', () => {
+ let store;
+ beforeEach(() => {
+ store = configureStore([thunk])({});
+ axios.get = sinon.stub().returns(Promise.resolve({ key: 'value' }));
+ });
+
+ it('dispatches SET_LOCALE action for default locale', async () => {
+ TranslatorContext.setDefaultLocale('en');
+ const defaultLocale = TranslatorContext.context.defaultLocale;
+ expect(Object.keys(TranslatorContext.context.translations)).not.toContainEqual(defaultLocale);
+
+ const expectedActions = [updateLocale(defaultLocale)];
+
+ await store.dispatch(setLocale(defaultLocale));
+ expect(store.getActions()).toEqual(expectedActions);
+ expect(TranslatorContext.context.translations).toBeDefined();
+ expect(Object.keys(TranslatorContext.context.translations)).toContainEqual(defaultLocale);
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/shared/reducers/locale.ts b/myApp/src/main/webapp/app/shared/reducers/locale.ts
new file mode 100644
index 000000000..eec88e2de
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/reducers/locale.ts
@@ -0,0 +1,40 @@
+import axios from 'axios';
+import dayjs from 'dayjs';
+import { createSlice } from '@reduxjs/toolkit';
+
+import { AppThunk } from 'app/config/store';
+import { TranslatorContext } from 'react-jhipster';
+
+const initialState = {
+ currentLocale: '',
+};
+
+export type LocaleState = Readonly;
+
+export const setLocale: (locale: string) => AppThunk = locale => async dispatch => {
+ if (!Object.keys(TranslatorContext.context.translations).includes(locale)) {
+ const response = await axios.get(`i18n/${locale}.json?_=${I18N_HASH}`, { baseURL: '' });
+ TranslatorContext.registerTranslations(locale, response.data);
+ }
+ dispatch(updateLocale(locale));
+};
+
+export const LocaleSlice = createSlice({
+ name: 'locale',
+ initialState: initialState as LocaleState,
+ reducers: {
+ updateLocale(state, action) {
+ const currentLocale = action.payload;
+ if (state.currentLocale !== currentLocale) {
+ dayjs.locale(currentLocale);
+ TranslatorContext.setLocale(currentLocale);
+ }
+ state.currentLocale = currentLocale;
+ },
+ },
+});
+
+export const { updateLocale } = LocaleSlice.actions;
+
+// Reducer
+export default LocaleSlice.reducer;
diff --git a/myApp/src/main/webapp/app/shared/reducers/reducer.utils.ts b/myApp/src/main/webapp/app/shared/reducers/reducer.utils.ts
new file mode 100644
index 000000000..db3c87b59
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/reducers/reducer.utils.ts
@@ -0,0 +1,127 @@
+import {
+ AnyAction,
+ AsyncThunk,
+ ActionReducerMapBuilder,
+ createSlice,
+ SerializedError,
+ SliceCaseReducers,
+ ValidateSliceCaseReducers,
+} from '@reduxjs/toolkit';
+import { AxiosError } from 'axios';
+
+/**
+ * Model for redux actions with pagination
+ */
+export type IQueryParams = { query?: string; page?: number; size?: number; sort?: string };
+
+/**
+ * Useful types for working with actions
+ */
+type GenericAsyncThunk = AsyncThunk;
+export type PendingAction = ReturnType;
+export type RejectedAction = ReturnType;
+export type FulfilledAction = ReturnType;
+
+/**
+ * Check if the async action type is rejected
+ */
+export function isRejectedAction(action: AnyAction) {
+ return action.type.endsWith('/rejected');
+}
+
+/**
+ * Check if the async action type is pending
+ */
+export function isPendingAction(action: AnyAction) {
+ return action.type.endsWith('/pending');
+}
+
+/**
+ * Check if the async action type is completed
+ */
+export function isFulfilledAction(action: AnyAction) {
+ return action.type.endsWith('/fulfilled');
+}
+
+const commonErrorProperties: Array = ['name', 'message', 'stack', 'code'];
+
+/**
+ * serialize function used for async action errors,
+ * since the default function from Redux Toolkit strips useful info from axios errors
+ */
+export const serializeAxiosError = (value: any): AxiosError | SerializedError => {
+ if (typeof value === 'object' && value !== null) {
+ if (value.isAxiosError) {
+ return value;
+ } else {
+ const simpleError: SerializedError = {};
+ for (const property of commonErrorProperties) {
+ if (typeof value[property] === 'string') {
+ simpleError[property] = value[property];
+ }
+ }
+
+ return simpleError;
+ }
+ }
+ return { message: String(value) };
+};
+
+export interface EntityState {
+ loading: boolean;
+ errorMessage: string | null;
+ entities: ReadonlyArray;
+ entity: T;
+ links?: any;
+ updating: boolean;
+ totalItems?: number;
+ updateSuccess: boolean;
+}
+
+/**
+ * A wrapper on top of createSlice from Redux Toolkit to extract
+ * common reducers and matchers used by entities
+ */
+export const createEntitySlice = >>({
+ name = '',
+ initialState,
+ reducers,
+ extraReducers,
+ skipRejectionHandling,
+}: {
+ name: string;
+ initialState: EntityState;
+ reducers?: ValidateSliceCaseReducers, Reducers>;
+ extraReducers?: (builder: ActionReducerMapBuilder>) => void;
+ skipRejectionHandling?: boolean;
+}) => {
+ return createSlice({
+ name,
+ initialState,
+ reducers: {
+ /**
+ * Reset the entity state to initial state
+ */
+ reset() {
+ return initialState;
+ },
+ ...reducers,
+ },
+ extraReducers(builder) {
+ extraReducers(builder);
+ /*
+ * Common rejection logic is handled here.
+ * If you want to add your own rejcetion logic, pass `skipRejectionHandling: true`
+ * while calling `createEntitySlice`
+ * */
+ if (!skipRejectionHandling) {
+ builder.addMatcher(isRejectedAction, (state, action) => {
+ state.loading = false;
+ state.updating = false;
+ state.updateSuccess = false;
+ state.errorMessage = action.error.message;
+ });
+ }
+ },
+ });
+};
diff --git a/myApp/src/main/webapp/app/shared/util/date-utils.ts b/myApp/src/main/webapp/app/shared/util/date-utils.ts
new file mode 100644
index 000000000..b4dd41f75
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/util/date-utils.ts
@@ -0,0 +1,9 @@
+import dayjs from 'dayjs';
+
+import { APP_LOCAL_DATETIME_FORMAT } from 'app/config/constants';
+
+export const convertDateTimeFromServer = date => (date ? dayjs(date).format(APP_LOCAL_DATETIME_FORMAT) : null);
+
+export const convertDateTimeToServer = date => (date ? dayjs(date).toDate() : null);
+
+export const displayDefaultDateTime = () => dayjs().startOf('day').format(APP_LOCAL_DATETIME_FORMAT);
diff --git a/myApp/src/main/webapp/app/shared/util/entity-utils.spec.ts b/myApp/src/main/webapp/app/shared/util/entity-utils.spec.ts
new file mode 100644
index 000000000..a8777d4e3
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/util/entity-utils.spec.ts
@@ -0,0 +1,56 @@
+import { cleanEntity, mapIdList } from './entity-utils';
+
+describe('Entity utils', () => {
+ describe('cleanEntity', () => {
+ it('should not remove fields with an id', () => {
+ const entityA = {
+ a: {
+ id: 5,
+ },
+ };
+ const entityB = {
+ a: {
+ id: '5',
+ },
+ };
+
+ expect(cleanEntity({ ...entityA })).toEqual(entityA);
+ expect(cleanEntity({ ...entityB })).toEqual(entityB);
+ });
+
+ it('should remove fields with an empty id', () => {
+ const entity = {
+ a: {
+ id: '',
+ },
+ };
+
+ expect(cleanEntity({ ...entity })).toEqual({});
+ });
+
+ it('should not remove fields that are not objects', () => {
+ const entity = {
+ a: '',
+ b: 5,
+ c: [],
+ d: '5',
+ };
+
+ expect(cleanEntity({ ...entity })).toEqual(entity);
+ });
+ });
+
+ describe('mapIdList', () => {
+ it("should map ids no matter the element's type", () => {
+ const ids = ['jhipster', '', 1, { key: 'value' }];
+
+ expect(mapIdList(ids)).toEqual([{ id: 'jhipster' }, { id: 1 }, { id: { key: 'value' } }]);
+ });
+
+ it('should return an empty array', () => {
+ const ids = [];
+
+ expect(mapIdList(ids)).toEqual([]);
+ });
+ });
+});
diff --git a/myApp/src/main/webapp/app/shared/util/entity-utils.ts b/myApp/src/main/webapp/app/shared/util/entity-utils.ts
new file mode 100644
index 000000000..0ae07b8cb
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/util/entity-utils.ts
@@ -0,0 +1,36 @@
+import pick from 'lodash/pick';
+import { IPaginationBaseState } from 'react-jhipster';
+
+/**
+ * Removes fields with an 'id' field that equals ''.
+ * This function was created to prevent entities to be sent to
+ * the server with an empty id and thus resulting in a 500.
+ *
+ * @param entity Object to clean.
+ */
+export const cleanEntity = entity => {
+ const keysToKeep = Object.keys(entity).filter(k => !(entity[k] instanceof Object) || (entity[k]['id'] !== '' && entity[k]['id'] !== -1));
+
+ return pick(entity, keysToKeep);
+};
+
+/**
+ * Simply map a list of element to a list a object with the element as id.
+ *
+ * @param idList Elements to map.
+ * @returns The list of objects with mapped ids.
+ */
+export const mapIdList = (idList: ReadonlyArray) => idList.filter((id: any) => id !== '').map((id: any) => ({ id }));
+
+export const overridePaginationStateWithQueryParams = (paginationBaseState: IPaginationBaseState, locationSearch: string) => {
+ const params = new URLSearchParams(locationSearch);
+ const page = params.get('page');
+ const sort = params.get('sort');
+ if (page && sort) {
+ const sortSplit = sort.split(',');
+ paginationBaseState.activePage = +page;
+ paginationBaseState.sort = sortSplit[0];
+ paginationBaseState.order = sortSplit[1];
+ }
+ return paginationBaseState;
+};
diff --git a/myApp/src/main/webapp/app/shared/util/pagination.constants.ts b/myApp/src/main/webapp/app/shared/util/pagination.constants.ts
new file mode 100644
index 000000000..d1fa55c4a
--- /dev/null
+++ b/myApp/src/main/webapp/app/shared/util/pagination.constants.ts
@@ -0,0 +1,4 @@
+export const ITEMS_PER_PAGE = 20;
+export const ASC = 'asc';
+export const DESC = 'desc';
+export const SORT = 'sort';
diff --git a/myApp/src/main/webapp/app/typings.d.ts b/myApp/src/main/webapp/app/typings.d.ts
new file mode 100644
index 000000000..cc89f6c8c
--- /dev/null
+++ b/myApp/src/main/webapp/app/typings.d.ts
@@ -0,0 +1,9 @@
+declare const VERSION: string;
+declare const SERVER_API_URL: string;
+declare const DEVELOPMENT: string;
+declare const I18N_HASH: string;
+
+declare module '*.json' {
+ const value: any;
+ export default value;
+}
diff --git a/myApp/src/main/webapp/content/css/loading.css b/myApp/src/main/webapp/content/css/loading.css
new file mode 100644
index 000000000..b2c662687
--- /dev/null
+++ b/myApp/src/main/webapp/content/css/loading.css
@@ -0,0 +1,152 @@
+@keyframes lds-pacman-1 {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 50% {
+ -webkit-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+ }
+ 100% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+}
+@-webkit-keyframes lds-pacman-1 {
+ 0% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+ 50% {
+ -webkit-transform: rotate(-45deg);
+ transform: rotate(-45deg);
+ }
+ 100% {
+ -webkit-transform: rotate(0deg);
+ transform: rotate(0deg);
+ }
+}
+@keyframes lds-pacman-2 {
+ 0% {
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+ }
+ 50% {
+ -webkit-transform: rotate(225deg);
+ transform: rotate(225deg);
+ }
+ 100% {
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+ }
+}
+@-webkit-keyframes lds-pacman-2 {
+ 0% {
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+ }
+ 50% {
+ -webkit-transform: rotate(225deg);
+ transform: rotate(225deg);
+ }
+ 100% {
+ -webkit-transform: rotate(180deg);
+ transform: rotate(180deg);
+ }
+}
+@keyframes lds-pacman-3 {
+ 0% {
+ -webkit-transform: translate(190px, 0);
+ transform: translate(190px, 0);
+ opacity: 0;
+ }
+ 20% {
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translate(70px, 0);
+ transform: translate(70px, 0);
+ opacity: 1;
+ }
+}
+@-webkit-keyframes lds-pacman-3 {
+ 0% {
+ -webkit-transform: translate(190px, 0);
+ transform: translate(190px, 0);
+ opacity: 0;
+ }
+ 20% {
+ opacity: 1;
+ }
+ 100% {
+ -webkit-transform: translate(70px, 0);
+ transform: translate(70px, 0);
+ opacity: 1;
+ }
+}
+
+.app-loading {
+ font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+ position: relative;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ top: 10em;
+}
+.app-loading p {
+ display: block;
+ font-size: 1.17em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: normal;
+}
+
+.app-loading .lds-pacman {
+ position: relative;
+ margin: auto;
+ width: 200px !important;
+ height: 200px !important;
+ -webkit-transform: translate(-100px, -100px) scale(1) translate(100px, 100px);
+ transform: translate(-100px, -100px) scale(1) translate(100px, 100px);
+}
+.app-loading .lds-pacman > div:nth-child(2) div {
+ position: absolute;
+ top: 40px;
+ left: 40px;
+ width: 120px;
+ height: 60px;
+ border-radius: 120px 120px 0 0;
+ background: #bbcedd;
+ -webkit-animation: lds-pacman-1 1s linear infinite;
+ animation: lds-pacman-1 1s linear infinite;
+ -webkit-transform-origin: 60px 60px;
+ transform-origin: 60px 60px;
+}
+.app-loading .lds-pacman > div:nth-child(2) div:nth-child(2) {
+ -webkit-animation: lds-pacman-2 1s linear infinite;
+ animation: lds-pacman-2 1s linear infinite;
+}
+.app-loading .lds-pacman > div:nth-child(1) div {
+ position: absolute;
+ top: 97px;
+ left: -8px;
+ width: 24px;
+ height: 10px;
+ background-image: url('../images/logo-jhipster.png');
+ background-size: contain;
+ -webkit-animation: lds-pacman-3 1s linear infinite;
+ animation: lds-pacman-3 1.5s linear infinite;
+}
+.app-loading .lds-pacman > div:nth-child(1) div:nth-child(1) {
+ -webkit-animation-delay: -0.67s;
+ animation-delay: -1s;
+}
+.app-loading .lds-pacman > div:nth-child(1) div:nth-child(2) {
+ -webkit-animation-delay: -0.33s;
+ animation-delay: -0.5s;
+}
+.app-loading .lds-pacman > div:nth-child(1) div:nth-child(3) {
+ -webkit-animation-delay: 0s;
+ animation-delay: 0s;
+}
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_0.svg b/myApp/src/main/webapp/content/images/jhipster_family_member_0.svg
new file mode 100644
index 000000000..d6df83ceb
--- /dev/null
+++ b/myApp/src/main/webapp/content/images/jhipster_family_member_0.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-192.png b/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-192.png
new file mode 100644
index 000000000..6d90ab36d
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-192.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-256.png b/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-256.png
new file mode 100644
index 000000000..8e99bfe66
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-256.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-384.png b/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-384.png
new file mode 100644
index 000000000..c7ca46022
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-384.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-512.png b/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-512.png
new file mode 100644
index 000000000..7e0b8436e
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_0_head-512.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_1.svg b/myApp/src/main/webapp/content/images/jhipster_family_member_1.svg
new file mode 100644
index 000000000..e3a0f3db9
--- /dev/null
+++ b/myApp/src/main/webapp/content/images/jhipster_family_member_1.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-192.png b/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-192.png
new file mode 100644
index 000000000..ac5f2a00a
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-192.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-256.png b/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-256.png
new file mode 100644
index 000000000..443822e8e
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-256.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-384.png b/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-384.png
new file mode 100644
index 000000000..4a5e9fe47
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-384.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-512.png b/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-512.png
new file mode 100644
index 000000000..66c625c10
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_1_head-512.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_2.svg b/myApp/src/main/webapp/content/images/jhipster_family_member_2.svg
new file mode 100644
index 000000000..51c6a5a98
--- /dev/null
+++ b/myApp/src/main/webapp/content/images/jhipster_family_member_2.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-192.png b/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-192.png
new file mode 100644
index 000000000..24baf78ce
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-192.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-256.png b/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-256.png
new file mode 100644
index 000000000..7b25f52f9
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-256.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-384.png b/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-384.png
new file mode 100644
index 000000000..e89e120c2
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-384.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-512.png b/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-512.png
new file mode 100644
index 000000000..3c0e6cb9a
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_2_head-512.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_3.svg b/myApp/src/main/webapp/content/images/jhipster_family_member_3.svg
new file mode 100644
index 000000000..cc0d01f1e
--- /dev/null
+++ b/myApp/src/main/webapp/content/images/jhipster_family_member_3.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-192.png b/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-192.png
new file mode 100644
index 000000000..b1e4fb3c8
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-192.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-256.png b/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-256.png
new file mode 100644
index 000000000..aa058c7a0
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-256.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-384.png b/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-384.png
new file mode 100644
index 000000000..1d10bd5da
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-384.png differ
diff --git a/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-512.png b/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-512.png
new file mode 100644
index 000000000..e719f1df8
Binary files /dev/null and b/myApp/src/main/webapp/content/images/jhipster_family_member_3_head-512.png differ
diff --git a/myApp/src/main/webapp/content/images/logo-jhipster.png b/myApp/src/main/webapp/content/images/logo-jhipster.png
new file mode 100644
index 000000000..6a005bf5e
Binary files /dev/null and b/myApp/src/main/webapp/content/images/logo-jhipster.png differ
diff --git a/myApp/src/main/webapp/content/images/zipcode.png b/myApp/src/main/webapp/content/images/zipcode.png
new file mode 100644
index 000000000..9bf15b4d6
Binary files /dev/null and b/myApp/src/main/webapp/content/images/zipcode.png differ
diff --git a/myApp/src/main/webapp/favicon.ico b/myApp/src/main/webapp/favicon.ico
new file mode 100644
index 000000000..4179874f5
Binary files /dev/null and b/myApp/src/main/webapp/favicon.ico differ
diff --git a/myApp/src/main/webapp/i18n/en/activate.json b/myApp/src/main/webapp/i18n/en/activate.json
new file mode 100644
index 000000000..058bd497f
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/activate.json
@@ -0,0 +1,9 @@
+{
+ "activate": {
+ "title": "Activation",
+ "messages": {
+ "success": "Your user account has been activated. Please ",
+ "error": "Your user could not be activated. Please use the registration form to sign up."
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/configuration.json b/myApp/src/main/webapp/i18n/en/configuration.json
new file mode 100644
index 000000000..09c9a1af0
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/configuration.json
@@ -0,0 +1,10 @@
+{
+ "configuration": {
+ "title": "Configuration",
+ "filter": "Filter (by prefix)",
+ "table": {
+ "prefix": "Prefix",
+ "properties": "Properties"
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/error.json b/myApp/src/main/webapp/i18n/en/error.json
new file mode 100644
index 000000000..d25756327
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/error.json
@@ -0,0 +1,14 @@
+{
+ "error": {
+ "title": "Error page!",
+ "http": {
+ "400": "Bad request.",
+ "403": "You are not authorized to access this page.",
+ "404": "The page does not exist.",
+ "405": "The HTTP verb you used is not supported for this URL.",
+ "500": "Internal server error."
+ },
+ "concurrencyFailure": "Another user modified this data at the same time as you. Your changes were rejected.",
+ "validation": "Validation error on the server."
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/global.json b/myApp/src/main/webapp/i18n/en/global.json
new file mode 100644
index 000000000..1f964a63a
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/global.json
@@ -0,0 +1,141 @@
+{
+ "global": {
+ "title": "",
+ "browsehappy": "You are using an outdated browser. Please upgrade your browser to improve your experience.",
+ "menu": {
+ "home": "Home",
+ "jhipster-needle-menu-add-element": "JHipster will add additional menu entries here (do not translate!)",
+ "entities": {
+ "main": "Entities",
+ "jhipster-needle-menu-add-entry": "JHipster will add additional entities here (do not translate!)"
+ },
+ "account": {
+ "main": "Account",
+ "settings": "Settings",
+ "password": "Password",
+ "sessions": "Sessions",
+ "login": "Sign in",
+ "logout": "Sign out",
+ "register": "Register"
+ },
+ "admin": {
+ "main": "Administration",
+ "userManagement": "User management",
+ "tracker": "User tracker",
+ "metrics": "Metrics",
+ "health": "Health",
+ "configuration": "Configuration",
+ "logs": "Logs",
+ "apidocs": "API",
+ "database": "Database",
+ "jhipster-needle-menu-add-admin-element": "JHipster will add additional menu entries here (do not translate!)"
+ },
+ "language": "Language"
+ },
+ "form": {
+ "username.label": "Username",
+ "username.placeholder": "Your username",
+ "currentpassword.label": "Current password",
+ "currentpassword.placeholder": "Current password",
+ "newpassword.label": "New password",
+ "newpassword.placeholder": "New password",
+ "confirmpassword.label": "New password confirmation",
+ "confirmpassword.placeholder": "Confirm the new password",
+ "email.label": "Email",
+ "email.placeholder": "Your email"
+ },
+ "messages": {
+ "info": {
+ "authenticated": {
+ "prefix": "If you want to ",
+ "link": "sign in",
+ "suffix": ", you can try the default accounts: - Administrator (login=\"admin\" and password=\"admin\") - User (login=\"user\" and password=\"user\")."
+ },
+ "register": {
+ "noaccount": "You don't have an account yet?",
+ "link": "Register a new account"
+ }
+ },
+ "error": {
+ "dontmatch": "The password and its confirmation do not match!"
+ },
+ "validate": {
+ "newpassword": {
+ "required": "Your password is required.",
+ "minlength": "Your password is required to be at least 4 characters.",
+ "maxlength": "Your password cannot be longer than 50 characters.",
+ "strength": "Password strength:"
+ },
+ "confirmpassword": {
+ "required": "Your confirmation password is required.",
+ "minlength": "Your confirmation password is required to be at least 4 characters.",
+ "maxlength": "Your confirmation password cannot be longer than 50 characters."
+ },
+ "email": {
+ "required": "Your email is required.",
+ "invalid": "Your email is invalid.",
+ "minlength": "Your email is required to be at least 5 characters.",
+ "maxlength": "Your email cannot be longer than 50 characters."
+ }
+ }
+ },
+ "field": {
+ "id": "ID"
+ },
+ "ribbon": {
+ "dev": "Development"
+ },
+ "item-count": "Showing {{first}} - {{second}} of {{total}} items."
+ },
+ "entity": {
+ "action": {
+ "addblob": "Add blob",
+ "addimage": "Add image",
+ "back": "Back",
+ "cancel": "Cancel",
+ "delete": "Delete",
+ "edit": "Edit",
+ "open": "Open",
+ "save": "Save",
+ "view": "View"
+ },
+ "detail": {
+ "field": "Field",
+ "value": "Value"
+ },
+ "delete": {
+ "title": "Confirm delete operation"
+ },
+ "validation": {
+ "required": "This field is required.",
+ "minlength": "This field is required to be at least {{ min }} characters.",
+ "maxlength": "This field cannot be longer than {{ max }} characters.",
+ "min": "This field should be at least {{ min }}.",
+ "max": "This field cannot be more than {{ max }}.",
+ "minbytes": "This field should be at least {{ min }} bytes.",
+ "maxbytes": "This field cannot be more than {{ max }} bytes.",
+ "pattern": "This field should follow pattern for {{ pattern }}.",
+ "number": "This field should be a number.",
+ "datetimelocal": "This field should be a date and time.",
+ "patternLogin": "This field can only contain letters, digits and e-mail addresses."
+ }
+ },
+ "error": {
+ "internalServerError": "Internal server error",
+ "server.not.reachable": "Server not reachable",
+ "url.not.found": "Not found",
+ "NotNull": "Field {{ fieldName }} cannot be empty!",
+ "Size": "Field {{ fieldName }} does not meet min/max size requirements!",
+ "userexists": "Login name already used!",
+ "emailexists": "Email is already in use!",
+ "idexists": "A new {{ entityName }} cannot already have an ID",
+ "idnull": "Invalid ID",
+ "idinvalid": "Invalid ID",
+ "idnotfound": "ID cannot be found",
+ "file": {
+ "could.not.extract": "Could not extract file",
+ "not.image": "File was expected to be an image but was found to be \"{{ fileType }}\""
+ }
+ },
+ "footer": "This is your footer"
+}
diff --git a/myApp/src/main/webapp/i18n/en/health.json b/myApp/src/main/webapp/i18n/en/health.json
new file mode 100644
index 000000000..10f40f00a
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/health.json
@@ -0,0 +1,31 @@
+{
+ "health": {
+ "title": "Health Checks",
+ "refresh.button": "Refresh",
+ "stacktrace": "Stacktrace",
+ "details": {
+ "details": "Details",
+ "properties": "Properties",
+ "name": "Name",
+ "value": "Value",
+ "error": "Error"
+ },
+ "indicator": {
+ "diskSpace": "Disk space",
+ "mail": "Email",
+ "livenessState": "Liveness state",
+ "readinessState": "Readiness state",
+ "ping": "Application",
+ "db": "Database"
+ },
+ "table": {
+ "service": "Service name",
+ "status": "Status"
+ },
+ "status": {
+ "UNKNOWN": "UNKNOWN",
+ "UP": "UP",
+ "DOWN": "DOWN"
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/home.json b/myApp/src/main/webapp/i18n/en/home.json
new file mode 100644
index 000000000..b6525c40b
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/home.json
@@ -0,0 +1,19 @@
+{
+ "home": {
+ "title": "Welcome, Java 7.2 Hipster!",
+ "subtitle": "This is your homepage",
+ "logged": {
+ "message": "You are logged in as user \"{{username}}\"."
+ },
+ "question": "If you have any question on JHipster:",
+ "link": {
+ "homepage": "JHipster homepage",
+ "stackoverflow": "JHipster on Stack Overflow",
+ "bugtracker": "JHipster bug tracker",
+ "chat": "JHipster public chat room",
+ "follow": "follow @jhipster on Twitter"
+ },
+ "like": "If you like JHipster, don't forget to give us a star on",
+ "github": "GitHub"
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/login.json b/myApp/src/main/webapp/i18n/en/login.json
new file mode 100644
index 000000000..466795880
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/login.json
@@ -0,0 +1,19 @@
+{
+ "login": {
+ "title": "Sign in",
+ "form": {
+ "password": "Password",
+ "password.placeholder": "Your password",
+ "rememberme": "Remember me",
+ "button": "Sign in"
+ },
+ "messages": {
+ "error": {
+ "authentication": "Failed to sign in! Please check your credentials and try again."
+ }
+ },
+ "password": {
+ "forgot": "Did you forget your password?"
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/logs.json b/myApp/src/main/webapp/i18n/en/logs.json
new file mode 100644
index 000000000..8ee0ba5a2
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/logs.json
@@ -0,0 +1,11 @@
+{
+ "logs": {
+ "title": "Logs",
+ "nbloggers": "There are {{ total }} loggers.",
+ "filter": "Filter",
+ "table": {
+ "name": "Name",
+ "level": "Level"
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/metrics.json b/myApp/src/main/webapp/i18n/en/metrics.json
new file mode 100644
index 000000000..c514dee72
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/metrics.json
@@ -0,0 +1,102 @@
+{
+ "metrics": {
+ "title": "Application Metrics",
+ "refresh.button": "Refresh",
+ "updating": "Updating...",
+ "jvm": {
+ "title": "JVM Metrics",
+ "memory": {
+ "title": "Memory",
+ "total": "Total Memory",
+ "heap": "Heap Memory",
+ "nonheap": "Non-Heap Memory"
+ },
+ "threads": {
+ "title": "Threads",
+ "all": "All",
+ "runnable": "Runnable",
+ "timedwaiting": "Timed waiting",
+ "waiting": "Waiting",
+ "blocked": "Blocked",
+ "dump": {
+ "title": "Threads dump",
+ "id": "Id: ",
+ "blockedtime": "Blocked Time",
+ "blockedcount": "Blocked Count",
+ "waitedtime": "Waited Time",
+ "waitedcount": "Waited Count",
+ "lockname": "Lock name",
+ "stacktrace": "Stacktrace",
+ "show": "Show Stacktrace",
+ "hide": "Hide Stacktrace"
+ }
+ },
+ "gc": {
+ "title": "Garbage collections",
+ "marksweepcount": "Mark Sweep count",
+ "marksweeptime": "Mark Sweep time",
+ "scavengecount": "Scavenge count",
+ "scavengetime": "Scavenge time"
+ },
+ "http": {
+ "title": "HTTP requests (time in millisecond)",
+ "active": "Active requests:",
+ "total": "Total requests:",
+ "table": {
+ "code": "Code",
+ "count": "Count",
+ "mean": "Mean",
+ "average": "Average",
+ "max": "Max"
+ },
+ "code": {
+ "ok": "Ok",
+ "notfound": "Not found",
+ "servererror": "Server Error"
+ }
+ }
+ },
+ "servicesstats": {
+ "title": "Services statistics (time in millisecond)",
+ "table": {
+ "name": "Service name",
+ "count": "Count",
+ "mean": "Mean",
+ "min": "Min",
+ "max": "Max",
+ "p50": "p50",
+ "p75": "p75",
+ "p95": "p95",
+ "p99": "p99"
+ }
+ },
+ "cache": {
+ "title": "Cache statistics",
+ "cachename": "Cache name",
+ "hits": "Cache Hits",
+ "misses": "Cache Misses",
+ "gets": "Cache Gets",
+ "puts": "Cache Puts",
+ "removals": "Cache Removals",
+ "evictions": "Cache Evictions",
+ "hitPercent": "Cache Hit %",
+ "missPercent": "Cache Miss %",
+ "averageGetTime": "Average get time (µs)",
+ "averagePutTime": "Average put time (µs)",
+ "averageRemoveTime": "Average remove time (µs)"
+ },
+ "datasource": {
+ "usage": "Connection Pool Usage",
+ "title": "DataSource statistics (time in millisecond)",
+ "name": "Pool usage",
+ "count": "Count",
+ "mean": "Mean",
+ "min": "Min",
+ "max": "Max",
+ "p50": "p50",
+ "p75": "p75",
+ "p95": "p95",
+ "p99": "p99"
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/password.json b/myApp/src/main/webapp/i18n/en/password.json
new file mode 100644
index 000000000..fc9b6c946
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/password.json
@@ -0,0 +1,12 @@
+{
+ "password": {
+ "title": "Password for [{{username}} ]",
+ "form": {
+ "button": "Save"
+ },
+ "messages": {
+ "error": "An error has occurred! The password could not be changed.",
+ "success": "Password changed! "
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/register.json b/myApp/src/main/webapp/i18n/en/register.json
new file mode 100644
index 000000000..1a0aeecfc
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/register.json
@@ -0,0 +1,24 @@
+{
+ "register": {
+ "title": "Registration",
+ "form": {
+ "button": "Register"
+ },
+ "messages": {
+ "validate": {
+ "login": {
+ "required": "Your username is required.",
+ "minlength": "Your username is required to be at least 1 character.",
+ "maxlength": "Your username cannot be longer than 50 characters.",
+ "pattern": "Your username is invalid."
+ }
+ },
+ "success": "Registration saved! Please check your email for confirmation.",
+ "error": {
+ "fail": "Registration failed! Please try again later.",
+ "userexists": "Login name already registered! Please choose another one.",
+ "emailexists": "Email is already in use! Please choose another one."
+ }
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/reset.json b/myApp/src/main/webapp/i18n/en/reset.json
new file mode 100644
index 000000000..4c35e9a2c
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/reset.json
@@ -0,0 +1,26 @@
+{
+ "reset": {
+ "request": {
+ "title": "Reset your password",
+ "form": {
+ "button": "Reset password"
+ },
+ "messages": {
+ "info": "Enter the email address you used to register",
+ "success": "Check your emails for details on how to reset your password."
+ }
+ },
+ "finish": {
+ "title": "Reset password",
+ "form": {
+ "button": "Validate new password"
+ },
+ "messages": {
+ "info": "Choose a new password",
+ "success": "Your password has been reset. Please ",
+ "keymissing": "The reset key is missing.",
+ "error": "Your password couldn't be reset. Remember a password request is only valid for 24 hours."
+ }
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/sessions.json b/myApp/src/main/webapp/i18n/en/sessions.json
new file mode 100644
index 000000000..38bf44f70
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/sessions.json
@@ -0,0 +1,15 @@
+{
+ "sessions": {
+ "title": "Active sessions for [{{username}} ]",
+ "table": {
+ "ipaddress": "IP address",
+ "useragent": "User Agent",
+ "date": "Date",
+ "button": "Invalidate"
+ },
+ "messages": {
+ "success": "Session invalidated! ",
+ "error": "An error has occurred! The session could not be invalidated."
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/settings.json b/myApp/src/main/webapp/i18n/en/settings.json
new file mode 100644
index 000000000..508c037c3
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/settings.json
@@ -0,0 +1,32 @@
+{
+ "settings": {
+ "title": "User settings for [{{username}} ]",
+ "form": {
+ "firstname": "First Name",
+ "firstname.placeholder": "Your first name",
+ "lastname": "Last Name",
+ "lastname.placeholder": "Your last name",
+ "language": "Language",
+ "button": "Save"
+ },
+ "messages": {
+ "error": {
+ "fail": "An error has occurred! Settings could not be saved.",
+ "emailexists": "Email is already in use! Please choose another one."
+ },
+ "success": "Settings saved! ",
+ "validate": {
+ "firstname": {
+ "required": "Your first name is required.",
+ "minlength": "Your first name is required to be at least 1 character",
+ "maxlength": "Your first name cannot be longer than 50 characters"
+ },
+ "lastname": {
+ "required": "Your last name is required.",
+ "minlength": "Your last name is required to be at least 1 character",
+ "maxlength": "Your last name cannot be longer than 50 characters"
+ }
+ }
+ }
+ }
+}
diff --git a/myApp/src/main/webapp/i18n/en/user-management.json b/myApp/src/main/webapp/i18n/en/user-management.json
new file mode 100644
index 000000000..52b56a1aa
--- /dev/null
+++ b/myApp/src/main/webapp/i18n/en/user-management.json
@@ -0,0 +1,31 @@
+{
+ "userManagement": {
+ "home": {
+ "title": "Users",
+ "refreshListLabel": "Refresh list",
+ "createLabel": "Create a new user",
+ "createOrEditLabel": "Create or edit a user"
+ },
+ "created": "A new user is created with identifier {{ param }}",
+ "updated": "A user is updated with identifier {{ param }}",
+ "deleted": "A user is deleted with identifier {{ param }}",
+ "delete": {
+ "question": "Are you sure you want to delete user {{ login }}?"
+ },
+ "detail": {
+ "title": "User"
+ },
+ "login": "Login",
+ "firstName": "First name",
+ "lastName": "Last name",
+ "email": "Email",
+ "activated": "Activated",
+ "deactivated": "Deactivated",
+ "profiles": "Profiles",
+ "langKey": "Language",
+ "createdBy": "Created by",
+ "createdDate": "Created date",
+ "lastModifiedBy": "Modified by",
+ "lastModifiedDate": "Modified date"
+ }
+}
diff --git a/myApp/src/main/webapp/index.html b/myApp/src/main/webapp/index.html
new file mode 100644
index 000000000..48a225671
--- /dev/null
+++ b/myApp/src/main/webapp/index.html
@@ -0,0 +1,139 @@
+
+
+
+
+
+ myApp
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
An error has occurred :-(
+
Usual error causes
+
+
+ You started the application from an IDE and you didn't run npm start
or
+ npm run webapp:build
.
+
+
+ You had a network error while running npm install
. If you are behind a corporate proxy, it is
+ likely that this error was caused by your proxy. Have a look at the JHipster error logs, you will probably have the cause of
+ the error.
+
+
+ You installed a Node.js version that doesn't work with JHipster: please use an LTS (long-term support) version, as it's the
+ only version we support.
+
+
+
Building the client side code again
+
If you want to go fast, run ./mvnw
to build and run everything.
+
If you want to have more control, so you can debug your issue more easily, you should follow the following steps:
+
+ Install npm dependencies with the command npm install
+
+ Build the client with the command npm run webapp:build
or
+ npm start
+
+ Start the server with ./mvnw
or using your IDE
+
+
+
Getting more help
+
+
If you have a question on how to use JHipster
+
+ Go to Stack Overflow with the
+ "jhipster" tag.
+
+
+
If you have a bug or a feature request
+
+ First read our
+ contributing guidelines .
+
+
+ Then, fill a ticket on our
+ bug tracker , we'll be happy to resolve your issue!
+
+
+
If you want to chat with contributors and other users
+
+ Join our chat room on
+ Gitter.im . Please note
+ that this is a public chat room, and that we expect you to respect other people and write in a correct English language!
+
+
+
+
+
+
+ You must enable JavaScript to view this page.
+
+
+
+
+
+
diff --git a/myApp/src/main/webapp/manifest.webapp b/myApp/src/main/webapp/manifest.webapp
new file mode 100644
index 000000000..29e7e7c51
--- /dev/null
+++ b/myApp/src/main/webapp/manifest.webapp
@@ -0,0 +1,31 @@
+{
+ "name": "MyApp",
+ "short_name": "MyApp",
+ "icons": [
+ {
+ "src": "./content/images/jhipster_family_member_1_head-192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "./content/images/jhipster_family_member_1_head-256.png",
+ "sizes": "256x256",
+ "type": "image/png"
+ },
+ {
+ "src": "./content/images/jhipster_family_member_1_head-384.png",
+ "sizes": "384x384",
+ "type": "image/png"
+ },
+ {
+ "src": "./content/images/jhipster_family_member_1_head-512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#000000",
+ "background_color": "#e0e0e0",
+ "start_url": ".",
+ "display": "standalone",
+ "orientation": "portrait"
+}
diff --git a/myApp/src/main/webapp/robots.txt b/myApp/src/main/webapp/robots.txt
new file mode 100644
index 000000000..361ff600c
--- /dev/null
+++ b/myApp/src/main/webapp/robots.txt
@@ -0,0 +1,10 @@
+# robotstxt.org/
+
+User-agent: *
+Disallow: /api/account
+Disallow: /api/account/change-password
+Disallow: /api/account/sessions
+Disallow: /api/logs/
+Disallow: /api/users/
+Disallow: /management/
+Disallow: /v3/api-docs/
diff --git a/myApp/src/main/webapp/swagger-ui/dist/images/throbber.gif b/myApp/src/main/webapp/swagger-ui/dist/images/throbber.gif
new file mode 100644
index 000000000..063938892
Binary files /dev/null and b/myApp/src/main/webapp/swagger-ui/dist/images/throbber.gif differ
diff --git a/myApp/src/main/webapp/swagger-ui/index.html b/myApp/src/main/webapp/swagger-ui/index.html
new file mode 100644
index 000000000..9e8bb5801
--- /dev/null
+++ b/myApp/src/main/webapp/swagger-ui/index.html
@@ -0,0 +1,126 @@
+
+
+
+
+ myApp - Swagger UI
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/myApp/src/test/java/com/mycompany/myapp/ArchTest.java b/myApp/src/test/java/com/mycompany/myapp/ArchTest.java
new file mode 100644
index 000000000..cde5471d3
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/ArchTest.java
@@ -0,0 +1,29 @@
+package com.mycompany.myapp;
+
+import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses;
+
+import com.tngtech.archunit.core.domain.JavaClasses;
+import com.tngtech.archunit.core.importer.ClassFileImporter;
+import com.tngtech.archunit.core.importer.ImportOption;
+import org.junit.jupiter.api.Test;
+
+class ArchTest {
+
+ @Test
+ void servicesAndRepositoriesShouldNotDependOnWebLayer() {
+ JavaClasses importedClasses = new ClassFileImporter()
+ .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_TESTS)
+ .importPackages("com.mycompany.myapp");
+
+ noClasses()
+ .that()
+ .resideInAnyPackage("com.mycompany.myapp.service..")
+ .or()
+ .resideInAnyPackage("com.mycompany.myapp.repository..")
+ .should()
+ .dependOnClassesThat()
+ .resideInAnyPackage("..com.mycompany.myapp.web..")
+ .because("Services and repositories should not depend on web layer")
+ .check(importedClasses);
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/IntegrationTest.java b/myApp/src/test/java/com/mycompany/myapp/IntegrationTest.java
new file mode 100644
index 000000000..ffe4feb21
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/IntegrationTest.java
@@ -0,0 +1,17 @@
+package com.mycompany.myapp;
+
+import com.mycompany.myapp.MyApp;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.springframework.boot.test.context.SpringBootTest;
+
+/**
+ * Base composite annotation for integration tests.
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@SpringBootTest(classes = MyApp.class)
+public @interface IntegrationTest {
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/config/NoOpMailConfiguration.java b/myApp/src/test/java/com/mycompany/myapp/config/NoOpMailConfiguration.java
new file mode 100644
index 000000000..7fe573cba
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/config/NoOpMailConfiguration.java
@@ -0,0 +1,25 @@
+package com.mycompany.myapp.config;
+
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.mock;
+
+import com.mycompany.myapp.service.MailService;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class NoOpMailConfiguration {
+
+ private final MailService mockMailService;
+
+ public NoOpMailConfiguration() {
+ mockMailService = mock(MailService.class);
+ doNothing().when(mockMailService).sendActivationEmail(any());
+ }
+
+ @Bean
+ public MailService mailService() {
+ return mockMailService;
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/config/StaticResourcesWebConfigurerTest.java b/myApp/src/test/java/com/mycompany/myapp/config/StaticResourcesWebConfigurerTest.java
new file mode 100644
index 000000000..ac385d21f
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/config/StaticResourcesWebConfigurerTest.java
@@ -0,0 +1,76 @@
+package com.mycompany.myapp.config;
+
+import static com.mycompany.myapp.config.StaticResourcesWebConfiguration.*;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.*;
+
+import java.util.concurrent.TimeUnit;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.CacheControl;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.web.context.WebApplicationContext;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import tech.jhipster.config.JHipsterDefaults;
+import tech.jhipster.config.JHipsterProperties;
+
+class StaticResourcesWebConfigurerTest {
+
+ public static final int MAX_AGE_TEST = 5;
+ public StaticResourcesWebConfiguration staticResourcesWebConfiguration;
+ private ResourceHandlerRegistry resourceHandlerRegistry;
+ private MockServletContext servletContext;
+ private WebApplicationContext applicationContext;
+ private JHipsterProperties props;
+
+ @BeforeEach
+ void setUp() {
+ servletContext = spy(new MockServletContext());
+ applicationContext = mock(WebApplicationContext.class);
+ resourceHandlerRegistry = spy(new ResourceHandlerRegistry(applicationContext, servletContext));
+ props = new JHipsterProperties();
+ staticResourcesWebConfiguration = spy(new StaticResourcesWebConfiguration(props));
+ }
+
+ @Test
+ void shouldAppendResourceHandlerAndInitializeIt() {
+ staticResourcesWebConfiguration.addResourceHandlers(resourceHandlerRegistry);
+
+ verify(resourceHandlerRegistry, times(1)).addResourceHandler(RESOURCE_PATHS);
+ verify(staticResourcesWebConfiguration, times(1)).initializeResourceHandler(any(ResourceHandlerRegistration.class));
+ for (String testingPath : RESOURCE_PATHS) {
+ assertThat(resourceHandlerRegistry.hasMappingForPattern(testingPath)).isTrue();
+ }
+ }
+
+ @Test
+ void shouldInitializeResourceHandlerWithCacheControlAndLocations() {
+ CacheControl ccExpected = CacheControl.maxAge(5, TimeUnit.DAYS).cachePublic();
+ when(staticResourcesWebConfiguration.getCacheControl()).thenReturn(ccExpected);
+ ResourceHandlerRegistration resourceHandlerRegistration = spy(new ResourceHandlerRegistration(RESOURCE_PATHS));
+
+ staticResourcesWebConfiguration.initializeResourceHandler(resourceHandlerRegistration);
+
+ verify(staticResourcesWebConfiguration, times(1)).getCacheControl();
+ verify(resourceHandlerRegistration, times(1)).setCacheControl(ccExpected);
+ verify(resourceHandlerRegistration, times(1)).addResourceLocations(RESOURCE_LOCATIONS);
+ }
+
+ @Test
+ void shouldCreateCacheControlBasedOnJhipsterDefaultProperties() {
+ CacheControl cacheExpected = CacheControl.maxAge(JHipsterDefaults.Http.Cache.timeToLiveInDays, TimeUnit.DAYS).cachePublic();
+ assertThat(staticResourcesWebConfiguration.getCacheControl())
+ .extracting(CacheControl::getHeaderValue)
+ .isEqualTo(cacheExpected.getHeaderValue());
+ }
+
+ @Test
+ void shouldCreateCacheControlWithSpecificConfigurationInProperties() {
+ props.getHttp().getCache().setTimeToLiveInDays(MAX_AGE_TEST);
+ CacheControl cacheExpected = CacheControl.maxAge(MAX_AGE_TEST, TimeUnit.DAYS).cachePublic();
+ assertThat(staticResourcesWebConfiguration.getCacheControl())
+ .extracting(CacheControl::getHeaderValue)
+ .isEqualTo(cacheExpected.getHeaderValue());
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/config/WebConfigurerTest.java b/myApp/src/test/java/com/mycompany/myapp/config/WebConfigurerTest.java
new file mode 100644
index 000000000..5902035a0
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/config/WebConfigurerTest.java
@@ -0,0 +1,150 @@
+package com.mycompany.myapp.config;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatCode;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.Mockito.*;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import java.io.File;
+import java.util.*;
+import javax.servlet.*;
+import org.h2.server.web.WebServlet;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.web.embedded.undertow.UndertowServletWebServerFactory;
+import org.springframework.http.HttpHeaders;
+import org.springframework.mock.env.MockEnvironment;
+import org.springframework.mock.web.MockServletContext;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import tech.jhipster.config.JHipsterConstants;
+import tech.jhipster.config.JHipsterProperties;
+
+/**
+ * Unit tests for the {@link WebConfigurer} class.
+ */
+class WebConfigurerTest {
+
+ private WebConfigurer webConfigurer;
+
+ private MockServletContext servletContext;
+
+ private MockEnvironment env;
+
+ private JHipsterProperties props;
+
+ @BeforeEach
+ public void setup() {
+ servletContext = spy(new MockServletContext());
+ doReturn(mock(FilterRegistration.Dynamic.class)).when(servletContext).addFilter(anyString(), any(Filter.class));
+ doReturn(mock(ServletRegistration.Dynamic.class)).when(servletContext).addServlet(anyString(), any(Servlet.class));
+
+ env = new MockEnvironment();
+ props = new JHipsterProperties();
+
+ webConfigurer = new WebConfigurer(env, props);
+ }
+
+ @Test
+ void shouldStartUpProdServletContext() throws ServletException {
+ env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION);
+
+ assertThatCode(() -> webConfigurer.onStartup(servletContext)).doesNotThrowAnyException();
+ verify(servletContext, never()).addServlet(eq("H2Console"), any(WebServlet.class));
+ }
+
+ @Test
+ void shouldStartUpDevServletContext() throws ServletException {
+ env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_DEVELOPMENT);
+
+ assertThatCode(() -> webConfigurer.onStartup(servletContext)).doesNotThrowAnyException();
+ verify(servletContext).addServlet(eq("H2Console"), any(WebServlet.class));
+ }
+
+ @Test
+ void shouldCustomizeServletContainer() {
+ env.setActiveProfiles(JHipsterConstants.SPRING_PROFILE_PRODUCTION);
+ UndertowServletWebServerFactory container = new UndertowServletWebServerFactory();
+ webConfigurer.customize(container);
+ assertThat(container.getMimeMappings().get("abs")).isEqualTo("audio/x-mpeg");
+ assertThat(container.getMimeMappings().get("html")).isEqualTo("text/html");
+ assertThat(container.getMimeMappings().get("json")).isEqualTo("application/json");
+ if (container.getDocumentRoot() != null) {
+ assertThat(container.getDocumentRoot()).isEqualTo(new File("target/classes/static/"));
+ }
+ }
+
+ @Test
+ void shouldCorsFilterOnApiPath() throws Exception {
+ props.getCors().setAllowedOrigins(Collections.singletonList("other.domain.com"));
+ props.getCors().setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
+ props.getCors().setAllowedHeaders(Collections.singletonList("*"));
+ props.getCors().setMaxAge(1800L);
+ props.getCors().setAllowCredentials(true);
+
+ MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()).addFilters(webConfigurer.corsFilter()).build();
+
+ mockMvc
+ .perform(
+ options("/api/test-cors")
+ .header(HttpHeaders.ORIGIN, "other.domain.com")
+ .header(HttpHeaders.ACCESS_CONTROL_REQUEST_METHOD, "POST")
+ )
+ .andExpect(status().isOk())
+ .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "other.domain.com"))
+ .andExpect(header().string(HttpHeaders.VARY, "Origin"))
+ .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET,POST,PUT,DELETE"))
+ .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS, "true"))
+ .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_MAX_AGE, "1800"));
+
+ mockMvc
+ .perform(get("/api/test-cors").header(HttpHeaders.ORIGIN, "other.domain.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, "other.domain.com"));
+ }
+
+ @Test
+ void shouldCorsFilterOnOtherPath() throws Exception {
+ props.getCors().setAllowedOrigins(Collections.singletonList("*"));
+ props.getCors().setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE"));
+ props.getCors().setAllowedHeaders(Collections.singletonList("*"));
+ props.getCors().setMaxAge(1800L);
+ props.getCors().setAllowCredentials(true);
+
+ MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()).addFilters(webConfigurer.corsFilter()).build();
+
+ mockMvc
+ .perform(get("/test/test-cors").header(HttpHeaders.ORIGIN, "other.domain.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN));
+ }
+
+ @Test
+ void shouldCorsFilterDeactivatedForNullAllowedOrigins() throws Exception {
+ props.getCors().setAllowedOrigins(null);
+
+ MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()).addFilters(webConfigurer.corsFilter()).build();
+
+ mockMvc
+ .perform(get("/api/test-cors").header(HttpHeaders.ORIGIN, "other.domain.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN));
+ }
+
+ @Test
+ void shouldCorsFilterDeactivatedForEmptyAllowedOrigins() throws Exception {
+ props.getCors().setAllowedOrigins(new ArrayList<>());
+
+ MockMvc mockMvc = MockMvcBuilders.standaloneSetup(new WebConfigurerTestController()).addFilters(webConfigurer.corsFilter()).build();
+
+ mockMvc
+ .perform(get("/api/test-cors").header(HttpHeaders.ORIGIN, "other.domain.com"))
+ .andExpect(status().isOk())
+ .andExpect(header().doesNotExist(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN));
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/config/WebConfigurerTestController.java b/myApp/src/test/java/com/mycompany/myapp/config/WebConfigurerTestController.java
new file mode 100644
index 000000000..9bd7bec01
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/config/WebConfigurerTestController.java
@@ -0,0 +1,14 @@
+package com.mycompany.myapp.config;
+
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+public class WebConfigurerTestController {
+
+ @GetMapping("/api/test-cors")
+ public void testCorsOnApiPath() {}
+
+ @GetMapping("/test/test-cors")
+ public void testCorsOnOtherPath() {}
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/config/timezone/HibernateTimeZoneIT.java b/myApp/src/test/java/com/mycompany/myapp/config/timezone/HibernateTimeZoneIT.java
new file mode 100644
index 000000000..8bb1d2a5f
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/config/timezone/HibernateTimeZoneIT.java
@@ -0,0 +1,162 @@
+package com.mycompany.myapp.config.timezone;
+
+import static java.lang.String.format;
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.mycompany.myapp.IntegrationTest;
+import com.mycompany.myapp.repository.timezone.DateTimeWrapper;
+import com.mycompany.myapp.repository.timezone.DateTimeWrapperRepository;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.support.rowset.SqlRowSet;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests for the ZoneId Hibernate configuration.
+ */
+@IntegrationTest
+class HibernateTimeZoneIT {
+
+ @Autowired
+ private DateTimeWrapperRepository dateTimeWrapperRepository;
+
+ @Autowired
+ private JdbcTemplate jdbcTemplate;
+
+ @Value("${spring.jpa.properties.hibernate.jdbc.time_zone:UTC}")
+ private String zoneId;
+
+ private DateTimeWrapper dateTimeWrapper;
+ private DateTimeFormatter dateTimeFormatter;
+ private DateTimeFormatter timeFormatter;
+ private DateTimeFormatter dateFormatter;
+
+ @BeforeEach
+ public void setup() {
+ dateTimeWrapper = new DateTimeWrapper();
+ dateTimeWrapper.setInstant(Instant.parse("2014-11-12T05:50:00.0Z"));
+ dateTimeWrapper.setLocalDateTime(LocalDateTime.parse("2014-11-12T07:50:00.0"));
+ dateTimeWrapper.setOffsetDateTime(OffsetDateTime.parse("2011-12-14T08:30:00.0Z"));
+ dateTimeWrapper.setZonedDateTime(ZonedDateTime.parse("2011-12-14T08:30:00.0Z"));
+ dateTimeWrapper.setLocalTime(LocalTime.parse("14:30:00"));
+ dateTimeWrapper.setOffsetTime(OffsetTime.parse("14:30:00+02:00"));
+ dateTimeWrapper.setLocalDate(LocalDate.parse("2016-09-10"));
+
+ dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S").withZone(ZoneId.of(zoneId));
+
+ timeFormatter = DateTimeFormatter.ofPattern("HH:mm:ss").withZone(ZoneId.of(zoneId));
+
+ dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+ }
+
+ @Test
+ @Transactional
+ void storeInstantWithZoneIdConfigShouldBeStoredOnGMTTimeZone() {
+ dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper);
+
+ String request = generateSqlRequest("instant", dateTimeWrapper.getId());
+ SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request);
+ String expectedValue = dateTimeFormatter.format(dateTimeWrapper.getInstant());
+
+ assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue);
+ }
+
+ @Test
+ @Transactional
+ void storeLocalDateTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZone() {
+ dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper);
+
+ String request = generateSqlRequest("local_date_time", dateTimeWrapper.getId());
+ SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request);
+ String expectedValue = dateTimeWrapper.getLocalDateTime().atZone(ZoneId.systemDefault()).format(dateTimeFormatter);
+
+ assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue);
+ }
+
+ @Test
+ @Transactional
+ void storeOffsetDateTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZone() {
+ dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper);
+
+ String request = generateSqlRequest("offset_date_time", dateTimeWrapper.getId());
+ SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request);
+ String expectedValue = dateTimeWrapper.getOffsetDateTime().format(dateTimeFormatter);
+
+ assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue);
+ }
+
+ @Test
+ @Transactional
+ void storeZoneDateTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZone() {
+ dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper);
+
+ String request = generateSqlRequest("zoned_date_time", dateTimeWrapper.getId());
+ SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request);
+ String expectedValue = dateTimeWrapper.getZonedDateTime().format(dateTimeFormatter);
+
+ assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue);
+ }
+
+ @Test
+ @Transactional
+ void storeLocalTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZoneAccordingToHis1stJan1970Value() {
+ dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper);
+
+ String request = generateSqlRequest("local_time", dateTimeWrapper.getId());
+ SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request);
+ String expectedValue = dateTimeWrapper
+ .getLocalTime()
+ .atDate(LocalDate.of(1970, Month.JANUARY, 1))
+ .atZone(ZoneId.systemDefault())
+ .format(timeFormatter);
+
+ assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue);
+ }
+
+ @Test
+ @Transactional
+ void storeOffsetTimeWithZoneIdConfigShouldBeStoredOnGMTTimeZoneAccordingToHis1stJan1970Value() {
+ dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper);
+
+ String request = generateSqlRequest("offset_time", dateTimeWrapper.getId());
+ SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request);
+ String expectedValue = dateTimeWrapper
+ .getOffsetTime()
+ .toLocalTime()
+ .atDate(LocalDate.of(1970, Month.JANUARY, 1))
+ .atZone(ZoneId.systemDefault())
+ .format(timeFormatter);
+
+ assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue);
+ }
+
+ @Test
+ @Transactional
+ void storeLocalDateWithZoneIdConfigShouldBeStoredWithoutTransformation() {
+ dateTimeWrapperRepository.saveAndFlush(dateTimeWrapper);
+
+ String request = generateSqlRequest("local_date", dateTimeWrapper.getId());
+ SqlRowSet resultSet = jdbcTemplate.queryForRowSet(request);
+ String expectedValue = dateTimeWrapper.getLocalDate().format(dateFormatter);
+
+ assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(resultSet, expectedValue);
+ }
+
+ private String generateSqlRequest(String fieldName, long id) {
+ return format("SELECT %s FROM jhi_date_time_wrapper where id=%d", fieldName, id);
+ }
+
+ private void assertThatDateStoredValueIsEqualToInsertDateValueOnGMTTimeZone(SqlRowSet sqlRowSet, String expectedValue) {
+ while (sqlRowSet.next()) {
+ String dbValue = sqlRowSet.getString(1);
+
+ assertThat(dbValue).isNotNull();
+ assertThat(dbValue).isEqualTo(expectedValue);
+ }
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/management/SecurityMetersServiceTests.java b/myApp/src/test/java/com/mycompany/myapp/management/SecurityMetersServiceTests.java
new file mode 100644
index 000000000..b8746f1cd
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/management/SecurityMetersServiceTests.java
@@ -0,0 +1,70 @@
+package com.mycompany.myapp.management;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import java.util.Collection;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+class SecurityMetersServiceTests {
+
+ private static final String INVALID_TOKENS_METER_EXPECTED_NAME = "security.authentication.invalid-tokens";
+
+ private MeterRegistry meterRegistry;
+
+ private SecurityMetersService securityMetersService;
+
+ @BeforeEach
+ public void setup() {
+ meterRegistry = new SimpleMeterRegistry();
+
+ securityMetersService = new SecurityMetersService(meterRegistry);
+ }
+
+ @Test
+ void testInvalidTokensCountersByCauseAreCreated() {
+ meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).counter();
+
+ meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "expired").counter();
+
+ meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "unsupported").counter();
+
+ meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "invalid-signature").counter();
+
+ meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter();
+
+ Collection counters = meterRegistry.find(INVALID_TOKENS_METER_EXPECTED_NAME).counters();
+
+ assertThat(counters).hasSize(4);
+ }
+
+ @Test
+ void testCountMethodsShouldBeBoundToCorrectCounters() {
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "expired").counter().count()).isZero();
+
+ securityMetersService.trackTokenExpired();
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "expired").counter().count()).isEqualTo(1);
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "unsupported").counter().count()).isZero();
+
+ securityMetersService.trackTokenUnsupported();
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "unsupported").counter().count()).isEqualTo(1);
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "invalid-signature").counter().count()).isZero();
+
+ securityMetersService.trackTokenInvalidSignature();
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "invalid-signature").counter().count()).isEqualTo(1);
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count()).isZero();
+
+ securityMetersService.trackTokenMalformed();
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count()).isEqualTo(1);
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/repository/timezone/DateTimeWrapper.java b/myApp/src/test/java/com/mycompany/myapp/repository/timezone/DateTimeWrapper.java
new file mode 100644
index 000000000..c4e2aac5b
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/repository/timezone/DateTimeWrapper.java
@@ -0,0 +1,133 @@
+package com.mycompany.myapp.repository.timezone;
+
+import java.io.Serializable;
+import java.time.*;
+import java.util.Objects;
+import javax.persistence.*;
+
+@Entity
+@Table(name = "jhi_date_time_wrapper")
+public class DateTimeWrapper implements Serializable {
+
+ private static final long serialVersionUID = 1L;
+
+ @Id
+ @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequenceGenerator")
+ @SequenceGenerator(name = "sequenceGenerator")
+ private Long id;
+
+ @Column(name = "instant")
+ private Instant instant;
+
+ @Column(name = "local_date_time")
+ private LocalDateTime localDateTime;
+
+ @Column(name = "offset_date_time")
+ private OffsetDateTime offsetDateTime;
+
+ @Column(name = "zoned_date_time")
+ private ZonedDateTime zonedDateTime;
+
+ @Column(name = "local_time")
+ private LocalTime localTime;
+
+ @Column(name = "offset_time")
+ private OffsetTime offsetTime;
+
+ @Column(name = "local_date")
+ private LocalDate localDate;
+
+ public Long getId() {
+ return id;
+ }
+
+ public void setId(Long id) {
+ this.id = id;
+ }
+
+ public Instant getInstant() {
+ return instant;
+ }
+
+ public void setInstant(Instant instant) {
+ this.instant = instant;
+ }
+
+ public LocalDateTime getLocalDateTime() {
+ return localDateTime;
+ }
+
+ public void setLocalDateTime(LocalDateTime localDateTime) {
+ this.localDateTime = localDateTime;
+ }
+
+ public OffsetDateTime getOffsetDateTime() {
+ return offsetDateTime;
+ }
+
+ public void setOffsetDateTime(OffsetDateTime offsetDateTime) {
+ this.offsetDateTime = offsetDateTime;
+ }
+
+ public ZonedDateTime getZonedDateTime() {
+ return zonedDateTime;
+ }
+
+ public void setZonedDateTime(ZonedDateTime zonedDateTime) {
+ this.zonedDateTime = zonedDateTime;
+ }
+
+ public LocalTime getLocalTime() {
+ return localTime;
+ }
+
+ public void setLocalTime(LocalTime localTime) {
+ this.localTime = localTime;
+ }
+
+ public OffsetTime getOffsetTime() {
+ return offsetTime;
+ }
+
+ public void setOffsetTime(OffsetTime offsetTime) {
+ this.offsetTime = offsetTime;
+ }
+
+ public LocalDate getLocalDate() {
+ return localDate;
+ }
+
+ public void setLocalDate(LocalDate localDate) {
+ this.localDate = localDate;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ DateTimeWrapper dateTimeWrapper = (DateTimeWrapper) o;
+ return !(dateTimeWrapper.getId() == null || getId() == null) && Objects.equals(getId(), dateTimeWrapper.getId());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hashCode(getId());
+ }
+
+ // prettier-ignore
+ @Override
+ public String toString() {
+ return "TimeZoneTest{" +
+ "id=" + id +
+ ", instant=" + instant +
+ ", localDateTime=" + localDateTime +
+ ", offsetDateTime=" + offsetDateTime +
+ ", zonedDateTime=" + zonedDateTime +
+ '}';
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/repository/timezone/DateTimeWrapperRepository.java b/myApp/src/test/java/com/mycompany/myapp/repository/timezone/DateTimeWrapperRepository.java
new file mode 100644
index 000000000..f59d62aa0
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/repository/timezone/DateTimeWrapperRepository.java
@@ -0,0 +1,10 @@
+package com.mycompany.myapp.repository.timezone;
+
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.stereotype.Repository;
+
+/**
+ * Spring Data JPA repository for the {@link DateTimeWrapper} entity.
+ */
+@Repository
+public interface DateTimeWrapperRepository extends JpaRepository {}
diff --git a/myApp/src/test/java/com/mycompany/myapp/security/DomainUserDetailsServiceIT.java b/myApp/src/test/java/com/mycompany/myapp/security/DomainUserDetailsServiceIT.java
new file mode 100644
index 000000000..bf1aa8466
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/security/DomainUserDetailsServiceIT.java
@@ -0,0 +1,111 @@
+package com.mycompany.myapp.security;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
+
+import com.mycompany.myapp.IntegrationTest;
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.UserRepository;
+import java.util.Locale;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integrations tests for {@link DomainUserDetailsService}.
+ */
+@Transactional
+@IntegrationTest
+class DomainUserDetailsServiceIT {
+
+ private static final String USER_ONE_LOGIN = "test-user-one";
+ private static final String USER_ONE_EMAIL = "test-user-one@localhost";
+ private static final String USER_TWO_LOGIN = "test-user-two";
+ private static final String USER_TWO_EMAIL = "test-user-two@localhost";
+ private static final String USER_THREE_LOGIN = "test-user-three";
+ private static final String USER_THREE_EMAIL = "test-user-three@localhost";
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private UserDetailsService domainUserDetailsService;
+
+ @BeforeEach
+ public void init() {
+ User userOne = new User();
+ userOne.setLogin(USER_ONE_LOGIN);
+ userOne.setPassword(RandomStringUtils.random(60));
+ userOne.setActivated(true);
+ userOne.setEmail(USER_ONE_EMAIL);
+ userOne.setFirstName("userOne");
+ userOne.setLastName("doe");
+ userOne.setLangKey("en");
+ userRepository.save(userOne);
+
+ User userTwo = new User();
+ userTwo.setLogin(USER_TWO_LOGIN);
+ userTwo.setPassword(RandomStringUtils.random(60));
+ userTwo.setActivated(true);
+ userTwo.setEmail(USER_TWO_EMAIL);
+ userTwo.setFirstName("userTwo");
+ userTwo.setLastName("doe");
+ userTwo.setLangKey("en");
+ userRepository.save(userTwo);
+
+ User userThree = new User();
+ userThree.setLogin(USER_THREE_LOGIN);
+ userThree.setPassword(RandomStringUtils.random(60));
+ userThree.setActivated(false);
+ userThree.setEmail(USER_THREE_EMAIL);
+ userThree.setFirstName("userThree");
+ userThree.setLastName("doe");
+ userThree.setLangKey("en");
+ userRepository.save(userThree);
+ }
+
+ @Test
+ void assertThatUserCanBeFoundByLogin() {
+ UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_LOGIN);
+ assertThat(userDetails).isNotNull();
+ assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN);
+ }
+
+ @Test
+ void assertThatUserCanBeFoundByLoginIgnoreCase() {
+ UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_LOGIN.toUpperCase(Locale.ENGLISH));
+ assertThat(userDetails).isNotNull();
+ assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN);
+ }
+
+ @Test
+ void assertThatUserCanBeFoundByEmail() {
+ UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_TWO_EMAIL);
+ assertThat(userDetails).isNotNull();
+ assertThat(userDetails.getUsername()).isEqualTo(USER_TWO_LOGIN);
+ }
+
+ @Test
+ void assertThatUserCanBeFoundByEmailIgnoreCase() {
+ UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_TWO_EMAIL.toUpperCase(Locale.ENGLISH));
+ assertThat(userDetails).isNotNull();
+ assertThat(userDetails.getUsername()).isEqualTo(USER_TWO_LOGIN);
+ }
+
+ @Test
+ void assertThatEmailIsPrioritizedOverLogin() {
+ UserDetails userDetails = domainUserDetailsService.loadUserByUsername(USER_ONE_EMAIL);
+ assertThat(userDetails).isNotNull();
+ assertThat(userDetails.getUsername()).isEqualTo(USER_ONE_LOGIN);
+ }
+
+ @Test
+ void assertThatUserNotActivatedExceptionIsThrownForNotActivatedUsers() {
+ assertThatExceptionOfType(UserNotActivatedException.class)
+ .isThrownBy(() -> domainUserDetailsService.loadUserByUsername(USER_THREE_LOGIN));
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/security/SecurityUtilsUnitTest.java b/myApp/src/test/java/com/mycompany/myapp/security/SecurityUtilsUnitTest.java
new file mode 100644
index 000000000..dfcb26061
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/security/SecurityUtilsUnitTest.java
@@ -0,0 +1,101 @@
+package com.mycompany.myapp.security;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Optional;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+
+/**
+ * Test class for the {@link SecurityUtils} utility class.
+ */
+class SecurityUtilsUnitTest {
+
+ @BeforeEach
+ @AfterEach
+ void cleanup() {
+ SecurityContextHolder.clearContext();
+ }
+
+ @Test
+ void testGetCurrentUserLogin() {
+ SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
+ securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin"));
+ SecurityContextHolder.setContext(securityContext);
+ Optional login = SecurityUtils.getCurrentUserLogin();
+ assertThat(login).contains("admin");
+ }
+
+ @Test
+ void testGetCurrentUserJWT() {
+ SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
+ securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "token"));
+ SecurityContextHolder.setContext(securityContext);
+ Optional jwt = SecurityUtils.getCurrentUserJWT();
+ assertThat(jwt).contains("token");
+ }
+
+ @Test
+ void testIsAuthenticated() {
+ SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
+ securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("admin", "admin"));
+ SecurityContextHolder.setContext(securityContext);
+ boolean isAuthenticated = SecurityUtils.isAuthenticated();
+ assertThat(isAuthenticated).isTrue();
+ }
+
+ @Test
+ void testAnonymousIsNotAuthenticated() {
+ SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
+ Collection authorities = new ArrayList<>();
+ authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
+ securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities));
+ SecurityContextHolder.setContext(securityContext);
+ boolean isAuthenticated = SecurityUtils.isAuthenticated();
+ assertThat(isAuthenticated).isFalse();
+ }
+
+ @Test
+ void testHasCurrentUserThisAuthority() {
+ SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
+ Collection authorities = new ArrayList<>();
+ authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER));
+ securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("user", "user", authorities));
+ SecurityContextHolder.setContext(securityContext);
+
+ assertThat(SecurityUtils.hasCurrentUserThisAuthority(AuthoritiesConstants.USER)).isTrue();
+ assertThat(SecurityUtils.hasCurrentUserThisAuthority(AuthoritiesConstants.ADMIN)).isFalse();
+ }
+
+ @Test
+ void testHasCurrentUserAnyOfAuthorities() {
+ SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
+ Collection authorities = new ArrayList<>();
+ authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER));
+ securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("user", "user", authorities));
+ SecurityContextHolder.setContext(securityContext);
+
+ assertThat(SecurityUtils.hasCurrentUserAnyOfAuthorities(AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN)).isTrue();
+ assertThat(SecurityUtils.hasCurrentUserAnyOfAuthorities(AuthoritiesConstants.ANONYMOUS, AuthoritiesConstants.ADMIN)).isFalse();
+ }
+
+ @Test
+ void testHasCurrentUserNoneOfAuthorities() {
+ SecurityContext securityContext = SecurityContextHolder.createEmptyContext();
+ Collection authorities = new ArrayList<>();
+ authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.USER));
+ securityContext.setAuthentication(new UsernamePasswordAuthenticationToken("user", "user", authorities));
+ SecurityContextHolder.setContext(securityContext);
+
+ assertThat(SecurityUtils.hasCurrentUserNoneOfAuthorities(AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN)).isFalse();
+ assertThat(SecurityUtils.hasCurrentUserNoneOfAuthorities(AuthoritiesConstants.ANONYMOUS, AuthoritiesConstants.ADMIN)).isTrue();
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/security/jwt/JWTFilterTest.java b/myApp/src/test/java/com/mycompany/myapp/security/jwt/JWTFilterTest.java
new file mode 100644
index 000000000..2e6b14f90
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/security/jwt/JWTFilterTest.java
@@ -0,0 +1,117 @@
+package com.mycompany.myapp.security.jwt;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.mycompany.myapp.management.SecurityMetersService;
+import com.mycompany.myapp.security.AuthoritiesConstants;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.security.Keys;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import java.util.Collections;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.HttpStatus;
+import org.springframework.mock.web.MockFilterChain;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.mock.web.MockHttpServletResponse;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.test.util.ReflectionTestUtils;
+import tech.jhipster.config.JHipsterProperties;
+
+class JWTFilterTest {
+
+ private TokenProvider tokenProvider;
+
+ private JWTFilter jwtFilter;
+
+ @BeforeEach
+ public void setup() {
+ JHipsterProperties jHipsterProperties = new JHipsterProperties();
+ String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8";
+ jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret);
+
+ SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry());
+
+ tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
+ ReflectionTestUtils.setField(tokenProvider, "key", Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret)));
+
+ ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", 60000);
+ jwtFilter = new JWTFilter(tokenProvider);
+ SecurityContextHolder.getContext().setAuthentication(null);
+ }
+
+ @Test
+ void testJWTFilter() throws Exception {
+ UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
+ "test-user",
+ "test-password",
+ Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.USER))
+ );
+ String jwt = tokenProvider.createToken(authentication, false);
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt);
+ request.setRequestURI("/api/test");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ MockFilterChain filterChain = new MockFilterChain();
+ jwtFilter.doFilter(request, response, filterChain);
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ assertThat(SecurityContextHolder.getContext().getAuthentication().getName()).isEqualTo("test-user");
+ assertThat(SecurityContextHolder.getContext().getAuthentication().getCredentials()).hasToString(jwt);
+ }
+
+ @Test
+ void testJWTFilterInvalidToken() throws Exception {
+ String jwt = "wrong_jwt";
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer " + jwt);
+ request.setRequestURI("/api/test");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ MockFilterChain filterChain = new MockFilterChain();
+ jwtFilter.doFilter(request, response, filterChain);
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+ }
+
+ @Test
+ void testJWTFilterMissingAuthorization() throws Exception {
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.setRequestURI("/api/test");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ MockFilterChain filterChain = new MockFilterChain();
+ jwtFilter.doFilter(request, response, filterChain);
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+ }
+
+ @Test
+ void testJWTFilterMissingToken() throws Exception {
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Bearer ");
+ request.setRequestURI("/api/test");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ MockFilterChain filterChain = new MockFilterChain();
+ jwtFilter.doFilter(request, response, filterChain);
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+ }
+
+ @Test
+ void testJWTFilterWrongScheme() throws Exception {
+ UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
+ "test-user",
+ "test-password",
+ Collections.singletonList(new SimpleGrantedAuthority(AuthoritiesConstants.USER))
+ );
+ String jwt = tokenProvider.createToken(authentication, false);
+ MockHttpServletRequest request = new MockHttpServletRequest();
+ request.addHeader(JWTFilter.AUTHORIZATION_HEADER, "Basic " + jwt);
+ request.setRequestURI("/api/test");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ MockFilterChain filterChain = new MockFilterChain();
+ jwtFilter.doFilter(request, response, filterChain);
+ assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
+ assertThat(SecurityContextHolder.getContext().getAuthentication()).isNull();
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/security/jwt/TokenProviderSecurityMetersTests.java b/myApp/src/test/java/com/mycompany/myapp/security/jwt/TokenProviderSecurityMetersTests.java
new file mode 100644
index 000000000..21915a230
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/security/jwt/TokenProviderSecurityMetersTests.java
@@ -0,0 +1,158 @@
+package com.mycompany.myapp.security.jwt;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.mycompany.myapp.management.SecurityMetersService;
+import com.mycompany.myapp.security.AuthoritiesConstants;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.security.Keys;
+import io.micrometer.core.instrument.Counter;
+import io.micrometer.core.instrument.MeterRegistry;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import java.security.Key;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.test.util.ReflectionTestUtils;
+import tech.jhipster.config.JHipsterProperties;
+
+class TokenProviderSecurityMetersTests {
+
+ private static final long ONE_MINUTE = 60000;
+ private static final String INVALID_TOKENS_METER_EXPECTED_NAME = "security.authentication.invalid-tokens";
+
+ private MeterRegistry meterRegistry;
+
+ private TokenProvider tokenProvider;
+
+ @BeforeEach
+ public void setup() {
+ JHipsterProperties jHipsterProperties = new JHipsterProperties();
+ String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8";
+ jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret);
+
+ meterRegistry = new SimpleMeterRegistry();
+
+ SecurityMetersService securityMetersService = new SecurityMetersService(meterRegistry);
+
+ tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
+ Key key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret));
+
+ ReflectionTestUtils.setField(tokenProvider, "key", key);
+ ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", ONE_MINUTE);
+ }
+
+ @Test
+ void testValidTokenShouldNotCountAnything() {
+ Collection counters = meterRegistry.find(INVALID_TOKENS_METER_EXPECTED_NAME).counters();
+
+ assertThat(aggregate(counters)).isZero();
+
+ String validToken = createValidToken();
+
+ tokenProvider.validateToken(validToken);
+
+ assertThat(aggregate(counters)).isZero();
+ }
+
+ @Test
+ void testTokenExpiredCount() {
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "expired").counter().count()).isZero();
+
+ String expiredToken = createExpiredToken();
+
+ tokenProvider.validateToken(expiredToken);
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "expired").counter().count()).isEqualTo(1);
+ }
+
+ @Test
+ void testTokenUnsupportedCount() {
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "unsupported").counter().count()).isZero();
+
+ String unsupportedToken = createUnsupportedToken();
+
+ tokenProvider.validateToken(unsupportedToken);
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "unsupported").counter().count()).isEqualTo(1);
+ }
+
+ @Test
+ void testTokenSignatureInvalidCount() {
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "invalid-signature").counter().count()).isZero();
+
+ String tokenWithDifferentSignature = createTokenWithDifferentSignature();
+
+ tokenProvider.validateToken(tokenWithDifferentSignature);
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "invalid-signature").counter().count()).isEqualTo(1);
+ }
+
+ @Test
+ void testTokenMalformedCount() {
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count()).isZero();
+
+ String malformedToken = createMalformedToken();
+
+ tokenProvider.validateToken(malformedToken);
+
+ assertThat(meterRegistry.get(INVALID_TOKENS_METER_EXPECTED_NAME).tag("cause", "malformed").counter().count()).isEqualTo(1);
+ }
+
+ private String createValidToken() {
+ Authentication authentication = createAuthentication();
+
+ return tokenProvider.createToken(authentication, false);
+ }
+
+ private String createExpiredToken() {
+ ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", -ONE_MINUTE);
+
+ Authentication authentication = createAuthentication();
+
+ return tokenProvider.createToken(authentication, false);
+ }
+
+ private Authentication createAuthentication() {
+ Collection authorities = new ArrayList<>();
+ authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
+ return new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities);
+ }
+
+ private String createUnsupportedToken() {
+ Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key");
+
+ return Jwts.builder().setPayload("payload").signWith(key, SignatureAlgorithm.HS256).compact();
+ }
+
+ private String createMalformedToken() {
+ String validToken = createValidToken();
+
+ return "X" + validToken;
+ }
+
+ private String createTokenWithDifferentSignature() {
+ Key otherKey = Keys.hmacShaKeyFor(
+ Decoders.BASE64.decode("Xfd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8")
+ );
+
+ return Jwts
+ .builder()
+ .setSubject("anonymous")
+ .signWith(otherKey, SignatureAlgorithm.HS512)
+ .setExpiration(new Date(new Date().getTime() + ONE_MINUTE))
+ .compact();
+ }
+
+ private double aggregate(Collection counters) {
+ return counters.stream().mapToDouble(Counter::count).sum();
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/security/jwt/TokenProviderTest.java b/myApp/src/test/java/com/mycompany/myapp/security/jwt/TokenProviderTest.java
new file mode 100644
index 000000000..b4f8059d9
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/security/jwt/TokenProviderTest.java
@@ -0,0 +1,141 @@
+package com.mycompany.myapp.security.jwt;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.mycompany.myapp.management.SecurityMetersService;
+import com.mycompany.myapp.security.AuthoritiesConstants;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+import io.jsonwebtoken.io.Decoders;
+import io.jsonwebtoken.security.Keys;
+import io.micrometer.core.instrument.simple.SimpleMeterRegistry;
+import java.nio.charset.StandardCharsets;
+import java.security.Key;
+import java.util.*;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.test.util.ReflectionTestUtils;
+import tech.jhipster.config.JHipsterProperties;
+
+class TokenProviderTest {
+
+ private static final long ONE_MINUTE = 60000;
+
+ private Key key;
+ private TokenProvider tokenProvider;
+
+ @BeforeEach
+ public void setup() {
+ JHipsterProperties jHipsterProperties = new JHipsterProperties();
+ String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8";
+ jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret);
+
+ SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry());
+
+ tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
+ key = Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret));
+
+ ReflectionTestUtils.setField(tokenProvider, "key", key);
+ ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", ONE_MINUTE);
+ }
+
+ @Test
+ void testReturnFalseWhenJWThasInvalidSignature() {
+ boolean isTokenValid = tokenProvider.validateToken(createTokenWithDifferentSignature());
+
+ assertThat(isTokenValid).isFalse();
+ }
+
+ @Test
+ void testReturnFalseWhenJWTisMalformed() {
+ Authentication authentication = createAuthentication();
+ String token = tokenProvider.createToken(authentication, false);
+ String invalidToken = token.substring(1);
+ boolean isTokenValid = tokenProvider.validateToken(invalidToken);
+
+ assertThat(isTokenValid).isFalse();
+ }
+
+ @Test
+ void testReturnFalseWhenJWTisExpired() {
+ ReflectionTestUtils.setField(tokenProvider, "tokenValidityInMilliseconds", -ONE_MINUTE);
+
+ Authentication authentication = createAuthentication();
+ String token = tokenProvider.createToken(authentication, false);
+
+ boolean isTokenValid = tokenProvider.validateToken(token);
+
+ assertThat(isTokenValid).isFalse();
+ }
+
+ @Test
+ void testReturnFalseWhenJWTisUnsupported() {
+ String unsupportedToken = createUnsupportedToken();
+
+ boolean isTokenValid = tokenProvider.validateToken(unsupportedToken);
+
+ assertThat(isTokenValid).isFalse();
+ }
+
+ @Test
+ void testReturnFalseWhenJWTisInvalid() {
+ boolean isTokenValid = tokenProvider.validateToken("");
+
+ assertThat(isTokenValid).isFalse();
+ }
+
+ @Test
+ void testKeyIsSetFromSecretWhenSecretIsNotEmpty() {
+ final String secret = "NwskoUmKHZtzGRKJKVjsJF7BtQMMxNWi";
+ JHipsterProperties jHipsterProperties = new JHipsterProperties();
+ jHipsterProperties.getSecurity().getAuthentication().getJwt().setSecret(secret);
+
+ SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry());
+
+ TokenProvider tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
+
+ Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key");
+ assertThat(key).isNotNull().isEqualTo(Keys.hmacShaKeyFor(secret.getBytes(StandardCharsets.UTF_8)));
+ }
+
+ @Test
+ void testKeyIsSetFromBase64SecretWhenSecretIsEmpty() {
+ final String base64Secret = "fd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8";
+ JHipsterProperties jHipsterProperties = new JHipsterProperties();
+ jHipsterProperties.getSecurity().getAuthentication().getJwt().setBase64Secret(base64Secret);
+
+ SecurityMetersService securityMetersService = new SecurityMetersService(new SimpleMeterRegistry());
+
+ TokenProvider tokenProvider = new TokenProvider(jHipsterProperties, securityMetersService);
+
+ Key key = (Key) ReflectionTestUtils.getField(tokenProvider, "key");
+ assertThat(key).isNotNull().isEqualTo(Keys.hmacShaKeyFor(Decoders.BASE64.decode(base64Secret)));
+ }
+
+ private Authentication createAuthentication() {
+ Collection authorities = new ArrayList<>();
+ authorities.add(new SimpleGrantedAuthority(AuthoritiesConstants.ANONYMOUS));
+ return new UsernamePasswordAuthenticationToken("anonymous", "anonymous", authorities);
+ }
+
+ private String createUnsupportedToken() {
+ return Jwts.builder().setPayload("payload").signWith(key, SignatureAlgorithm.HS512).compact();
+ }
+
+ private String createTokenWithDifferentSignature() {
+ Key otherKey = Keys.hmacShaKeyFor(
+ Decoders.BASE64.decode("Xfd54a45s65fds737b9aafcb3412e07ed99b267f33413274720ddbb7f6c5e64e9f14075f2d7ed041592f0b7657baf8")
+ );
+
+ return Jwts
+ .builder()
+ .setSubject("anonymous")
+ .signWith(otherKey, SignatureAlgorithm.HS512)
+ .setExpiration(new Date(new Date().getTime() + ONE_MINUTE))
+ .compact();
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/service/MailServiceIT.java b/myApp/src/test/java/com/mycompany/myapp/service/MailServiceIT.java
new file mode 100644
index 000000000..1288125f1
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/service/MailServiceIT.java
@@ -0,0 +1,244 @@
+package com.mycompany.myapp.service;
+
+import static org.assertj.core.api.Assertions.*;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.*;
+
+import com.mycompany.myapp.IntegrationTest;
+import com.mycompany.myapp.config.Constants;
+import com.mycompany.myapp.domain.User;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
+import java.net.URI;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.mail.Multipart;
+import javax.mail.internet.MimeBodyPart;
+import javax.mail.internet.MimeMessage;
+import javax.mail.internet.MimeMultipart;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
+import org.mockito.MockitoAnnotations;
+import org.mockito.Spy;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.MessageSource;
+import org.springframework.mail.MailSendException;
+import org.springframework.mail.javamail.JavaMailSenderImpl;
+import org.thymeleaf.spring5.SpringTemplateEngine;
+import tech.jhipster.config.JHipsterProperties;
+
+/**
+ * Integration tests for {@link MailService}.
+ */
+@IntegrationTest
+class MailServiceIT {
+
+ private static final String[] languages = {
+ "en",
+ // jhipster-needle-i18n-language-constant - JHipster will add/remove languages in this array
+ };
+ private static final Pattern PATTERN_LOCALE_3 = Pattern.compile("([a-z]{2})-([a-zA-Z]{4})-([a-z]{2})");
+ private static final Pattern PATTERN_LOCALE_2 = Pattern.compile("([a-z]{2})-([a-z]{2})");
+
+ @Autowired
+ private JHipsterProperties jHipsterProperties;
+
+ @Autowired
+ private MessageSource messageSource;
+
+ @Autowired
+ private SpringTemplateEngine templateEngine;
+
+ @Spy
+ private JavaMailSenderImpl javaMailSender;
+
+ @Captor
+ private ArgumentCaptor messageCaptor;
+
+ private MailService mailService;
+
+ @BeforeEach
+ public void setup() {
+ MockitoAnnotations.openMocks(this);
+ doNothing().when(javaMailSender).send(any(MimeMessage.class));
+ mailService = new MailService(jHipsterProperties, javaMailSender, messageSource, templateEngine);
+ }
+
+ @Test
+ void testSendEmail() throws Exception {
+ mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, false);
+ verify(javaMailSender).send(messageCaptor.capture());
+ MimeMessage message = messageCaptor.getValue();
+ assertThat(message.getSubject()).isEqualTo("testSubject");
+ assertThat(message.getAllRecipients()[0]).hasToString("john.doe@example.com");
+ assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom());
+ assertThat(message.getContent()).isInstanceOf(String.class);
+ assertThat(message.getContent()).hasToString("testContent");
+ assertThat(message.getDataHandler().getContentType()).isEqualTo("text/plain; charset=UTF-8");
+ }
+
+ @Test
+ void testSendHtmlEmail() throws Exception {
+ mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, true);
+ verify(javaMailSender).send(messageCaptor.capture());
+ MimeMessage message = messageCaptor.getValue();
+ assertThat(message.getSubject()).isEqualTo("testSubject");
+ assertThat(message.getAllRecipients()[0]).hasToString("john.doe@example.com");
+ assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom());
+ assertThat(message.getContent()).isInstanceOf(String.class);
+ assertThat(message.getContent()).hasToString("testContent");
+ assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8");
+ }
+
+ @Test
+ void testSendMultipartEmail() throws Exception {
+ mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", true, false);
+ verify(javaMailSender).send(messageCaptor.capture());
+ MimeMessage message = messageCaptor.getValue();
+ MimeMultipart mp = (MimeMultipart) message.getContent();
+ MimeBodyPart part = (MimeBodyPart) ((MimeMultipart) mp.getBodyPart(0).getContent()).getBodyPart(0);
+ ByteArrayOutputStream aos = new ByteArrayOutputStream();
+ part.writeTo(aos);
+ assertThat(message.getSubject()).isEqualTo("testSubject");
+ assertThat(message.getAllRecipients()[0]).hasToString("john.doe@example.com");
+ assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom());
+ assertThat(message.getContent()).isInstanceOf(Multipart.class);
+ assertThat(aos).hasToString("\r\ntestContent");
+ assertThat(part.getDataHandler().getContentType()).isEqualTo("text/plain; charset=UTF-8");
+ }
+
+ @Test
+ void testSendMultipartHtmlEmail() throws Exception {
+ mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", true, true);
+ verify(javaMailSender).send(messageCaptor.capture());
+ MimeMessage message = messageCaptor.getValue();
+ MimeMultipart mp = (MimeMultipart) message.getContent();
+ MimeBodyPart part = (MimeBodyPart) ((MimeMultipart) mp.getBodyPart(0).getContent()).getBodyPart(0);
+ ByteArrayOutputStream aos = new ByteArrayOutputStream();
+ part.writeTo(aos);
+ assertThat(message.getSubject()).isEqualTo("testSubject");
+ assertThat(message.getAllRecipients()[0]).hasToString("john.doe@example.com");
+ assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom());
+ assertThat(message.getContent()).isInstanceOf(Multipart.class);
+ assertThat(aos).hasToString("\r\ntestContent");
+ assertThat(part.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8");
+ }
+
+ @Test
+ void testSendEmailFromTemplate() throws Exception {
+ User user = new User();
+ user.setLogin("john");
+ user.setEmail("john.doe@example.com");
+ user.setLangKey("en");
+ mailService.sendEmailFromTemplate(user, "mail/testEmail", "email.test.title");
+ verify(javaMailSender).send(messageCaptor.capture());
+ MimeMessage message = messageCaptor.getValue();
+ assertThat(message.getSubject()).isEqualTo("test title");
+ assertThat(message.getAllRecipients()[0]).hasToString(user.getEmail());
+ assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom());
+ assertThat(message.getContent().toString()).isEqualToNormalizingNewlines("test title, http://127.0.0.1:8080, john\n");
+ assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8");
+ }
+
+ @Test
+ void testSendActivationEmail() throws Exception {
+ User user = new User();
+ user.setLangKey(Constants.DEFAULT_LANGUAGE);
+ user.setLogin("john");
+ user.setEmail("john.doe@example.com");
+ mailService.sendActivationEmail(user);
+ verify(javaMailSender).send(messageCaptor.capture());
+ MimeMessage message = messageCaptor.getValue();
+ assertThat(message.getAllRecipients()[0]).hasToString(user.getEmail());
+ assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom());
+ assertThat(message.getContent().toString()).isNotEmpty();
+ assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8");
+ }
+
+ @Test
+ void testCreationEmail() throws Exception {
+ User user = new User();
+ user.setLangKey(Constants.DEFAULT_LANGUAGE);
+ user.setLogin("john");
+ user.setEmail("john.doe@example.com");
+ mailService.sendCreationEmail(user);
+ verify(javaMailSender).send(messageCaptor.capture());
+ MimeMessage message = messageCaptor.getValue();
+ assertThat(message.getAllRecipients()[0]).hasToString(user.getEmail());
+ assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom());
+ assertThat(message.getContent().toString()).isNotEmpty();
+ assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8");
+ }
+
+ @Test
+ void testSendPasswordResetMail() throws Exception {
+ User user = new User();
+ user.setLangKey(Constants.DEFAULT_LANGUAGE);
+ user.setLogin("john");
+ user.setEmail("john.doe@example.com");
+ mailService.sendPasswordResetMail(user);
+ verify(javaMailSender).send(messageCaptor.capture());
+ MimeMessage message = messageCaptor.getValue();
+ assertThat(message.getAllRecipients()[0]).hasToString(user.getEmail());
+ assertThat(message.getFrom()[0]).hasToString(jHipsterProperties.getMail().getFrom());
+ assertThat(message.getContent().toString()).isNotEmpty();
+ assertThat(message.getDataHandler().getContentType()).isEqualTo("text/html;charset=UTF-8");
+ }
+
+ @Test
+ void testSendEmailWithException() {
+ doThrow(MailSendException.class).when(javaMailSender).send(any(MimeMessage.class));
+ try {
+ mailService.sendEmail("john.doe@example.com", "testSubject", "testContent", false, false);
+ } catch (Exception e) {
+ fail("Exception shouldn't have been thrown");
+ }
+ }
+
+ @Test
+ void testSendLocalizedEmailForAllSupportedLanguages() throws Exception {
+ User user = new User();
+ user.setLogin("john");
+ user.setEmail("john.doe@example.com");
+ for (String langKey : languages) {
+ user.setLangKey(langKey);
+ mailService.sendEmailFromTemplate(user, "mail/testEmail", "email.test.title");
+ verify(javaMailSender, atLeastOnce()).send(messageCaptor.capture());
+ MimeMessage message = messageCaptor.getValue();
+
+ String propertyFilePath = "i18n/messages_" + getJavaLocale(langKey) + ".properties";
+ URL resource = this.getClass().getClassLoader().getResource(propertyFilePath);
+ File file = new File(new URI(resource.getFile()).getPath());
+ Properties properties = new Properties();
+ properties.load(new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8")));
+
+ String emailTitle = (String) properties.get("email.test.title");
+ assertThat(message.getSubject()).isEqualTo(emailTitle);
+ assertThat(message.getContent().toString())
+ .isEqualToNormalizingNewlines("" + emailTitle + ", http://127.0.0.1:8080, john\n");
+ }
+ }
+
+ /**
+ * Convert a lang key to the Java locale.
+ */
+ private String getJavaLocale(String langKey) {
+ String javaLangKey = langKey;
+ Matcher matcher2 = PATTERN_LOCALE_2.matcher(langKey);
+ if (matcher2.matches()) {
+ javaLangKey = matcher2.group(1) + "_" + matcher2.group(2).toUpperCase();
+ }
+ Matcher matcher3 = PATTERN_LOCALE_3.matcher(langKey);
+ if (matcher3.matches()) {
+ javaLangKey = matcher3.group(1) + "_" + matcher3.group(2) + "_" + matcher3.group(3).toUpperCase();
+ }
+ return javaLangKey;
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/service/UserServiceIT.java b/myApp/src/test/java/com/mycompany/myapp/service/UserServiceIT.java
new file mode 100644
index 000000000..6e1f366d9
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/service/UserServiceIT.java
@@ -0,0 +1,185 @@
+package com.mycompany.myapp.service;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.when;
+
+import com.mycompany.myapp.IntegrationTest;
+import com.mycompany.myapp.config.Constants;
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.UserRepository;
+import com.mycompany.myapp.service.dto.AdminUserDTO;
+import java.time.Instant;
+import java.time.LocalDateTime;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
+import java.util.Optional;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.mock.mockito.MockBean;
+import org.springframework.data.auditing.AuditingHandler;
+import org.springframework.data.auditing.DateTimeProvider;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.transaction.annotation.Transactional;
+import tech.jhipster.security.RandomUtil;
+
+/**
+ * Integration tests for {@link UserService}.
+ */
+@IntegrationTest
+@Transactional
+class UserServiceIT {
+
+ private static final String DEFAULT_LOGIN = "johndoe";
+
+ private static final String DEFAULT_EMAIL = "johndoe@localhost";
+
+ private static final String DEFAULT_FIRSTNAME = "john";
+
+ private static final String DEFAULT_LASTNAME = "doe";
+
+ private static final String DEFAULT_IMAGEURL = "http://placehold.it/50x50";
+
+ private static final String DEFAULT_LANGKEY = "dummy";
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private AuditingHandler auditingHandler;
+
+ @MockBean
+ private DateTimeProvider dateTimeProvider;
+
+ private User user;
+
+ @BeforeEach
+ public void init() {
+ user = new User();
+ user.setLogin(DEFAULT_LOGIN);
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(true);
+ user.setEmail(DEFAULT_EMAIL);
+ user.setFirstName(DEFAULT_FIRSTNAME);
+ user.setLastName(DEFAULT_LASTNAME);
+ user.setImageUrl(DEFAULT_IMAGEURL);
+ user.setLangKey(DEFAULT_LANGKEY);
+
+ when(dateTimeProvider.getNow()).thenReturn(Optional.of(LocalDateTime.now()));
+ auditingHandler.setDateTimeProvider(dateTimeProvider);
+ }
+
+ @Test
+ @Transactional
+ void assertThatUserMustExistToResetPassword() {
+ userRepository.saveAndFlush(user);
+ Optional maybeUser = userService.requestPasswordReset("invalid.login@localhost");
+ assertThat(maybeUser).isNotPresent();
+
+ maybeUser = userService.requestPasswordReset(user.getEmail());
+ assertThat(maybeUser).isPresent();
+ assertThat(maybeUser.orElse(null).getEmail()).isEqualTo(user.getEmail());
+ assertThat(maybeUser.orElse(null).getResetDate()).isNotNull();
+ assertThat(maybeUser.orElse(null).getResetKey()).isNotNull();
+ }
+
+ @Test
+ @Transactional
+ void assertThatOnlyActivatedUserCanRequestPasswordReset() {
+ user.setActivated(false);
+ userRepository.saveAndFlush(user);
+
+ Optional maybeUser = userService.requestPasswordReset(user.getLogin());
+ assertThat(maybeUser).isNotPresent();
+ userRepository.delete(user);
+ }
+
+ @Test
+ @Transactional
+ void assertThatResetKeyMustNotBeOlderThan24Hours() {
+ Instant daysAgo = Instant.now().minus(25, ChronoUnit.HOURS);
+ String resetKey = RandomUtil.generateResetKey();
+ user.setActivated(true);
+ user.setResetDate(daysAgo);
+ user.setResetKey(resetKey);
+ userRepository.saveAndFlush(user);
+
+ Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey());
+ assertThat(maybeUser).isNotPresent();
+ userRepository.delete(user);
+ }
+
+ @Test
+ @Transactional
+ void assertThatResetKeyMustBeValid() {
+ Instant daysAgo = Instant.now().minus(25, ChronoUnit.HOURS);
+ user.setActivated(true);
+ user.setResetDate(daysAgo);
+ user.setResetKey("1234");
+ userRepository.saveAndFlush(user);
+
+ Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey());
+ assertThat(maybeUser).isNotPresent();
+ userRepository.delete(user);
+ }
+
+ @Test
+ @Transactional
+ void assertThatUserCanResetPassword() {
+ String oldPassword = user.getPassword();
+ Instant daysAgo = Instant.now().minus(2, ChronoUnit.HOURS);
+ String resetKey = RandomUtil.generateResetKey();
+ user.setActivated(true);
+ user.setResetDate(daysAgo);
+ user.setResetKey(resetKey);
+ userRepository.saveAndFlush(user);
+
+ Optional maybeUser = userService.completePasswordReset("johndoe2", user.getResetKey());
+ assertThat(maybeUser).isPresent();
+ assertThat(maybeUser.orElse(null).getResetDate()).isNull();
+ assertThat(maybeUser.orElse(null).getResetKey()).isNull();
+ assertThat(maybeUser.orElse(null).getPassword()).isNotEqualTo(oldPassword);
+
+ userRepository.delete(user);
+ }
+
+ @Test
+ @Transactional
+ void assertThatNotActivatedUsersWithNotNullActivationKeyCreatedBefore3DaysAreDeleted() {
+ Instant now = Instant.now();
+ when(dateTimeProvider.getNow()).thenReturn(Optional.of(now.minus(4, ChronoUnit.DAYS)));
+ user.setActivated(false);
+ user.setActivationKey(RandomStringUtils.random(20));
+ User dbUser = userRepository.saveAndFlush(user);
+ dbUser.setCreatedDate(now.minus(4, ChronoUnit.DAYS));
+ userRepository.saveAndFlush(user);
+ Instant threeDaysAgo = now.minus(3, ChronoUnit.DAYS);
+ List users = userRepository.findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(threeDaysAgo);
+ assertThat(users).isNotEmpty();
+ userService.removeNotActivatedUsers();
+ users = userRepository.findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(threeDaysAgo);
+ assertThat(users).isEmpty();
+ }
+
+ @Test
+ @Transactional
+ void assertThatNotActivatedUsersWithNullActivationKeyCreatedBefore3DaysAreNotDeleted() {
+ Instant now = Instant.now();
+ when(dateTimeProvider.getNow()).thenReturn(Optional.of(now.minus(4, ChronoUnit.DAYS)));
+ user.setActivated(false);
+ User dbUser = userRepository.saveAndFlush(user);
+ dbUser.setCreatedDate(now.minus(4, ChronoUnit.DAYS));
+ userRepository.saveAndFlush(user);
+ Instant threeDaysAgo = now.minus(3, ChronoUnit.DAYS);
+ List users = userRepository.findAllByActivatedIsFalseAndActivationKeyIsNotNullAndCreatedDateBefore(threeDaysAgo);
+ assertThat(users).isEmpty();
+ userService.removeNotActivatedUsers();
+ Optional maybeDbUser = userRepository.findById(dbUser.getId());
+ assertThat(maybeDbUser).contains(dbUser);
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/service/mapper/UserMapperTest.java b/myApp/src/test/java/com/mycompany/myapp/service/mapper/UserMapperTest.java
new file mode 100644
index 000000000..2bce9983e
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/service/mapper/UserMapperTest.java
@@ -0,0 +1,132 @@
+package com.mycompany.myapp.service.mapper;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.service.dto.AdminUserDTO;
+import com.mycompany.myapp.service.dto.UserDTO;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Unit tests for {@link UserMapper}.
+ */
+class UserMapperTest {
+
+ private static final String DEFAULT_LOGIN = "johndoe";
+ private static final Long DEFAULT_ID = 1L;
+
+ private UserMapper userMapper;
+ private User user;
+ private AdminUserDTO userDto;
+
+ @BeforeEach
+ public void init() {
+ userMapper = new UserMapper();
+ user = new User();
+ user.setLogin(DEFAULT_LOGIN);
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(true);
+ user.setEmail("johndoe@localhost");
+ user.setFirstName("john");
+ user.setLastName("doe");
+ user.setImageUrl("image_url");
+ user.setLangKey("en");
+
+ userDto = new AdminUserDTO(user);
+ }
+
+ @Test
+ void usersToUserDTOsShouldMapOnlyNonNullUsers() {
+ List users = new ArrayList<>();
+ users.add(user);
+ users.add(null);
+
+ List userDTOS = userMapper.usersToUserDTOs(users);
+
+ assertThat(userDTOS).isNotEmpty().size().isEqualTo(1);
+ }
+
+ @Test
+ void userDTOsToUsersShouldMapOnlyNonNullUsers() {
+ List usersDto = new ArrayList<>();
+ usersDto.add(userDto);
+ usersDto.add(null);
+
+ List users = userMapper.userDTOsToUsers(usersDto);
+
+ assertThat(users).isNotEmpty().size().isEqualTo(1);
+ }
+
+ @Test
+ void userDTOsToUsersWithAuthoritiesStringShouldMapToUsersWithAuthoritiesDomain() {
+ Set authoritiesAsString = new HashSet<>();
+ authoritiesAsString.add("ADMIN");
+ userDto.setAuthorities(authoritiesAsString);
+
+ List usersDto = new ArrayList<>();
+ usersDto.add(userDto);
+
+ List users = userMapper.userDTOsToUsers(usersDto);
+
+ assertThat(users).isNotEmpty().size().isEqualTo(1);
+ assertThat(users.get(0).getAuthorities()).isNotNull();
+ assertThat(users.get(0).getAuthorities()).isNotEmpty();
+ assertThat(users.get(0).getAuthorities().iterator().next().getName()).isEqualTo("ADMIN");
+ }
+
+ @Test
+ void userDTOsToUsersMapWithNullAuthoritiesStringShouldReturnUserWithEmptyAuthorities() {
+ userDto.setAuthorities(null);
+
+ List usersDto = new ArrayList<>();
+ usersDto.add(userDto);
+
+ List users = userMapper.userDTOsToUsers(usersDto);
+
+ assertThat(users).isNotEmpty().size().isEqualTo(1);
+ assertThat(users.get(0).getAuthorities()).isNotNull();
+ assertThat(users.get(0).getAuthorities()).isEmpty();
+ }
+
+ @Test
+ void userDTOToUserMapWithAuthoritiesStringShouldReturnUserWithAuthorities() {
+ Set authoritiesAsString = new HashSet<>();
+ authoritiesAsString.add("ADMIN");
+ userDto.setAuthorities(authoritiesAsString);
+
+ User user = userMapper.userDTOToUser(userDto);
+
+ assertThat(user).isNotNull();
+ assertThat(user.getAuthorities()).isNotNull();
+ assertThat(user.getAuthorities()).isNotEmpty();
+ assertThat(user.getAuthorities().iterator().next().getName()).isEqualTo("ADMIN");
+ }
+
+ @Test
+ void userDTOToUserMapWithNullAuthoritiesStringShouldReturnUserWithEmptyAuthorities() {
+ userDto.setAuthorities(null);
+
+ User user = userMapper.userDTOToUser(userDto);
+
+ assertThat(user).isNotNull();
+ assertThat(user.getAuthorities()).isNotNull();
+ assertThat(user.getAuthorities()).isEmpty();
+ }
+
+ @Test
+ void userDTOToUserMapWithNullUserShouldReturnNull() {
+ assertThat(userMapper.userDTOToUser(null)).isNull();
+ }
+
+ @Test
+ void testUserFromId() {
+ assertThat(userMapper.userFromId(DEFAULT_ID).getId()).isEqualTo(DEFAULT_ID);
+ assertThat(userMapper.userFromId(null)).isNull();
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/web/rest/AccountResourceIT.java b/myApp/src/test/java/com/mycompany/myapp/web/rest/AccountResourceIT.java
new file mode 100644
index 000000000..31a2559e5
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/web/rest/AccountResourceIT.java
@@ -0,0 +1,760 @@
+package com.mycompany.myapp.web.rest;
+
+import static com.mycompany.myapp.web.rest.AccountResourceIT.TEST_USER_LOGIN;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import com.mycompany.myapp.IntegrationTest;
+import com.mycompany.myapp.config.Constants;
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.AuthorityRepository;
+import com.mycompany.myapp.repository.UserRepository;
+import com.mycompany.myapp.security.AuthoritiesConstants;
+import com.mycompany.myapp.service.UserService;
+import com.mycompany.myapp.service.dto.AdminUserDTO;
+import com.mycompany.myapp.service.dto.PasswordChangeDTO;
+import com.mycompany.myapp.service.dto.UserDTO;
+import com.mycompany.myapp.web.rest.vm.KeyAndPasswordVM;
+import com.mycompany.myapp.web.rest.vm.ManagedUserVM;
+import java.time.Instant;
+import java.util.*;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.http.MediaType;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests for the {@link AccountResource} REST controller.
+ */
+@AutoConfigureMockMvc
+@WithMockUser(value = TEST_USER_LOGIN)
+@IntegrationTest
+class AccountResourceIT {
+
+ static final String TEST_USER_LOGIN = "test";
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private AuthorityRepository authorityRepository;
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private MockMvc restAccountMockMvc;
+
+ @Test
+ @WithUnauthenticatedMockUser
+ void testNonAuthenticatedUser() throws Exception {
+ restAccountMockMvc
+ .perform(get("/api/authenticate").accept(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andExpect(content().string(""));
+ }
+
+ @Test
+ void testAuthenticatedUser() throws Exception {
+ restAccountMockMvc
+ .perform(
+ get("/api/authenticate")
+ .with(request -> {
+ request.setRemoteUser(TEST_USER_LOGIN);
+ return request;
+ })
+ .accept(MediaType.APPLICATION_JSON)
+ )
+ .andExpect(status().isOk())
+ .andExpect(content().string(TEST_USER_LOGIN));
+ }
+
+ @Test
+ void testGetExistingAccount() throws Exception {
+ Set authorities = new HashSet<>();
+ authorities.add(AuthoritiesConstants.ADMIN);
+
+ AdminUserDTO user = new AdminUserDTO();
+ user.setLogin(TEST_USER_LOGIN);
+ user.setFirstName("john");
+ user.setLastName("doe");
+ user.setEmail("john.doe@jhipster.com");
+ user.setImageUrl("http://placehold.it/50x50");
+ user.setLangKey("en");
+ user.setAuthorities(authorities);
+ userService.createUser(user);
+
+ restAccountMockMvc
+ .perform(get("/api/account").accept(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
+ .andExpect(jsonPath("$.login").value(TEST_USER_LOGIN))
+ .andExpect(jsonPath("$.firstName").value("john"))
+ .andExpect(jsonPath("$.lastName").value("doe"))
+ .andExpect(jsonPath("$.email").value("john.doe@jhipster.com"))
+ .andExpect(jsonPath("$.imageUrl").value("http://placehold.it/50x50"))
+ .andExpect(jsonPath("$.langKey").value("en"))
+ .andExpect(jsonPath("$.authorities").value(AuthoritiesConstants.ADMIN));
+ }
+
+ @Test
+ void testGetUnknownAccount() throws Exception {
+ restAccountMockMvc
+ .perform(get("/api/account").accept(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(status().isInternalServerError());
+ }
+
+ @Test
+ @Transactional
+ void testRegisterValid() throws Exception {
+ ManagedUserVM validUser = new ManagedUserVM();
+ validUser.setLogin("test-register-valid");
+ validUser.setPassword("password");
+ validUser.setFirstName("Alice");
+ validUser.setLastName("Test");
+ validUser.setEmail("test-register-valid@example.com");
+ validUser.setImageUrl("http://placehold.it/50x50");
+ validUser.setLangKey(Constants.DEFAULT_LANGUAGE);
+ validUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+ assertThat(userRepository.findOneByLogin("test-register-valid")).isEmpty();
+
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(validUser)))
+ .andExpect(status().isCreated());
+
+ assertThat(userRepository.findOneByLogin("test-register-valid")).isPresent();
+ }
+
+ @Test
+ @Transactional
+ void testRegisterInvalidLogin() throws Exception {
+ ManagedUserVM invalidUser = new ManagedUserVM();
+ invalidUser.setLogin("funky-log(n"); // <-- invalid
+ invalidUser.setPassword("password");
+ invalidUser.setFirstName("Funky");
+ invalidUser.setLastName("One");
+ invalidUser.setEmail("funky@example.com");
+ invalidUser.setActivated(true);
+ invalidUser.setImageUrl("http://placehold.it/50x50");
+ invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE);
+ invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(invalidUser)))
+ .andExpect(status().isBadRequest());
+
+ Optional user = userRepository.findOneByEmailIgnoreCase("funky@example.com");
+ assertThat(user).isEmpty();
+ }
+
+ @Test
+ @Transactional
+ void testRegisterInvalidEmail() throws Exception {
+ ManagedUserVM invalidUser = new ManagedUserVM();
+ invalidUser.setLogin("bob");
+ invalidUser.setPassword("password");
+ invalidUser.setFirstName("Bob");
+ invalidUser.setLastName("Green");
+ invalidUser.setEmail("invalid"); // <-- invalid
+ invalidUser.setActivated(true);
+ invalidUser.setImageUrl("http://placehold.it/50x50");
+ invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE);
+ invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(invalidUser)))
+ .andExpect(status().isBadRequest());
+
+ Optional user = userRepository.findOneByLogin("bob");
+ assertThat(user).isEmpty();
+ }
+
+ @Test
+ @Transactional
+ void testRegisterInvalidPassword() throws Exception {
+ ManagedUserVM invalidUser = new ManagedUserVM();
+ invalidUser.setLogin("bob");
+ invalidUser.setPassword("123"); // password with only 3 digits
+ invalidUser.setFirstName("Bob");
+ invalidUser.setLastName("Green");
+ invalidUser.setEmail("bob@example.com");
+ invalidUser.setActivated(true);
+ invalidUser.setImageUrl("http://placehold.it/50x50");
+ invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE);
+ invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(invalidUser)))
+ .andExpect(status().isBadRequest());
+
+ Optional user = userRepository.findOneByLogin("bob");
+ assertThat(user).isEmpty();
+ }
+
+ @Test
+ @Transactional
+ void testRegisterNullPassword() throws Exception {
+ ManagedUserVM invalidUser = new ManagedUserVM();
+ invalidUser.setLogin("bob");
+ invalidUser.setPassword(null); // invalid null password
+ invalidUser.setFirstName("Bob");
+ invalidUser.setLastName("Green");
+ invalidUser.setEmail("bob@example.com");
+ invalidUser.setActivated(true);
+ invalidUser.setImageUrl("http://placehold.it/50x50");
+ invalidUser.setLangKey(Constants.DEFAULT_LANGUAGE);
+ invalidUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(invalidUser)))
+ .andExpect(status().isBadRequest());
+
+ Optional user = userRepository.findOneByLogin("bob");
+ assertThat(user).isEmpty();
+ }
+
+ @Test
+ @Transactional
+ void testRegisterDuplicateLogin() throws Exception {
+ // First registration
+ ManagedUserVM firstUser = new ManagedUserVM();
+ firstUser.setLogin("alice");
+ firstUser.setPassword("password");
+ firstUser.setFirstName("Alice");
+ firstUser.setLastName("Something");
+ firstUser.setEmail("alice@example.com");
+ firstUser.setImageUrl("http://placehold.it/50x50");
+ firstUser.setLangKey(Constants.DEFAULT_LANGUAGE);
+ firstUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ // Duplicate login, different email
+ ManagedUserVM secondUser = new ManagedUserVM();
+ secondUser.setLogin(firstUser.getLogin());
+ secondUser.setPassword(firstUser.getPassword());
+ secondUser.setFirstName(firstUser.getFirstName());
+ secondUser.setLastName(firstUser.getLastName());
+ secondUser.setEmail("alice2@example.com");
+ secondUser.setImageUrl(firstUser.getImageUrl());
+ secondUser.setLangKey(firstUser.getLangKey());
+ secondUser.setCreatedBy(firstUser.getCreatedBy());
+ secondUser.setCreatedDate(firstUser.getCreatedDate());
+ secondUser.setLastModifiedBy(firstUser.getLastModifiedBy());
+ secondUser.setLastModifiedDate(firstUser.getLastModifiedDate());
+ secondUser.setAuthorities(new HashSet<>(firstUser.getAuthorities()));
+
+ // First user
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(firstUser)))
+ .andExpect(status().isCreated());
+
+ // Second (non activated) user
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(secondUser)))
+ .andExpect(status().isCreated());
+
+ Optional testUser = userRepository.findOneByEmailIgnoreCase("alice2@example.com");
+ assertThat(testUser).isPresent();
+ testUser.get().setActivated(true);
+ userRepository.save(testUser.get());
+
+ // Second (already activated) user
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(secondUser)))
+ .andExpect(status().is4xxClientError());
+ }
+
+ @Test
+ @Transactional
+ void testRegisterDuplicateEmail() throws Exception {
+ // First user
+ ManagedUserVM firstUser = new ManagedUserVM();
+ firstUser.setLogin("test-register-duplicate-email");
+ firstUser.setPassword("password");
+ firstUser.setFirstName("Alice");
+ firstUser.setLastName("Test");
+ firstUser.setEmail("test-register-duplicate-email@example.com");
+ firstUser.setImageUrl("http://placehold.it/50x50");
+ firstUser.setLangKey(Constants.DEFAULT_LANGUAGE);
+ firstUser.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ // Register first user
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(firstUser)))
+ .andExpect(status().isCreated());
+
+ Optional testUser1 = userRepository.findOneByLogin("test-register-duplicate-email");
+ assertThat(testUser1).isPresent();
+
+ // Duplicate email, different login
+ ManagedUserVM secondUser = new ManagedUserVM();
+ secondUser.setLogin("test-register-duplicate-email-2");
+ secondUser.setPassword(firstUser.getPassword());
+ secondUser.setFirstName(firstUser.getFirstName());
+ secondUser.setLastName(firstUser.getLastName());
+ secondUser.setEmail(firstUser.getEmail());
+ secondUser.setImageUrl(firstUser.getImageUrl());
+ secondUser.setLangKey(firstUser.getLangKey());
+ secondUser.setAuthorities(new HashSet<>(firstUser.getAuthorities()));
+
+ // Register second (non activated) user
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(secondUser)))
+ .andExpect(status().isCreated());
+
+ Optional testUser2 = userRepository.findOneByLogin("test-register-duplicate-email");
+ assertThat(testUser2).isEmpty();
+
+ Optional testUser3 = userRepository.findOneByLogin("test-register-duplicate-email-2");
+ assertThat(testUser3).isPresent();
+
+ // Duplicate email - with uppercase email address
+ ManagedUserVM userWithUpperCaseEmail = new ManagedUserVM();
+ userWithUpperCaseEmail.setId(firstUser.getId());
+ userWithUpperCaseEmail.setLogin("test-register-duplicate-email-3");
+ userWithUpperCaseEmail.setPassword(firstUser.getPassword());
+ userWithUpperCaseEmail.setFirstName(firstUser.getFirstName());
+ userWithUpperCaseEmail.setLastName(firstUser.getLastName());
+ userWithUpperCaseEmail.setEmail("TEST-register-duplicate-email@example.com");
+ userWithUpperCaseEmail.setImageUrl(firstUser.getImageUrl());
+ userWithUpperCaseEmail.setLangKey(firstUser.getLangKey());
+ userWithUpperCaseEmail.setAuthorities(new HashSet<>(firstUser.getAuthorities()));
+
+ // Register third (not activated) user
+ restAccountMockMvc
+ .perform(
+ post("/api/register")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(TestUtil.convertObjectToJsonBytes(userWithUpperCaseEmail))
+ )
+ .andExpect(status().isCreated());
+
+ Optional testUser4 = userRepository.findOneByLogin("test-register-duplicate-email-3");
+ assertThat(testUser4).isPresent();
+ assertThat(testUser4.get().getEmail()).isEqualTo("test-register-duplicate-email@example.com");
+
+ testUser4.get().setActivated(true);
+ userService.updateUser((new AdminUserDTO(testUser4.get())));
+
+ // Register 4th (already activated) user
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(secondUser)))
+ .andExpect(status().is4xxClientError());
+ }
+
+ @Test
+ @Transactional
+ void testRegisterAdminIsIgnored() throws Exception {
+ ManagedUserVM validUser = new ManagedUserVM();
+ validUser.setLogin("badguy");
+ validUser.setPassword("password");
+ validUser.setFirstName("Bad");
+ validUser.setLastName("Guy");
+ validUser.setEmail("badguy@example.com");
+ validUser.setActivated(true);
+ validUser.setImageUrl("http://placehold.it/50x50");
+ validUser.setLangKey(Constants.DEFAULT_LANGUAGE);
+ validUser.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN));
+
+ restAccountMockMvc
+ .perform(post("/api/register").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(validUser)))
+ .andExpect(status().isCreated());
+
+ Optional userDup = userRepository.findOneWithAuthoritiesByLogin("badguy");
+ assertThat(userDup).isPresent();
+ assertThat(userDup.get().getAuthorities())
+ .hasSize(1)
+ .containsExactly(authorityRepository.findById(AuthoritiesConstants.USER).get());
+ }
+
+ @Test
+ @Transactional
+ void testActivateAccount() throws Exception {
+ final String activationKey = "some activation key";
+ User user = new User();
+ user.setLogin("activate-account");
+ user.setEmail("activate-account@example.com");
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(false);
+ user.setActivationKey(activationKey);
+
+ userRepository.saveAndFlush(user);
+
+ restAccountMockMvc.perform(get("/api/activate?key={activationKey}", activationKey)).andExpect(status().isOk());
+
+ user = userRepository.findOneByLogin(user.getLogin()).orElse(null);
+ assertThat(user.isActivated()).isTrue();
+ }
+
+ @Test
+ @Transactional
+ void testActivateAccountWithWrongKey() throws Exception {
+ restAccountMockMvc.perform(get("/api/activate?key=wrongActivationKey")).andExpect(status().isInternalServerError());
+ }
+
+ @Test
+ @Transactional
+ @WithMockUser("save-account")
+ void testSaveAccount() throws Exception {
+ User user = new User();
+ user.setLogin("save-account");
+ user.setEmail("save-account@example.com");
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(true);
+ userRepository.saveAndFlush(user);
+
+ AdminUserDTO userDTO = new AdminUserDTO();
+ userDTO.setLogin("not-used");
+ userDTO.setFirstName("firstname");
+ userDTO.setLastName("lastname");
+ userDTO.setEmail("save-account@example.com");
+ userDTO.setActivated(false);
+ userDTO.setImageUrl("http://placehold.it/50x50");
+ userDTO.setLangKey(Constants.DEFAULT_LANGUAGE);
+ userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN));
+
+ restAccountMockMvc
+ .perform(post("/api/account").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(userDTO)))
+ .andExpect(status().isOk());
+
+ User updatedUser = userRepository.findOneWithAuthoritiesByLogin(user.getLogin()).orElse(null);
+ assertThat(updatedUser.getFirstName()).isEqualTo(userDTO.getFirstName());
+ assertThat(updatedUser.getLastName()).isEqualTo(userDTO.getLastName());
+ assertThat(updatedUser.getEmail()).isEqualTo(userDTO.getEmail());
+ assertThat(updatedUser.getLangKey()).isEqualTo(userDTO.getLangKey());
+ assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword());
+ assertThat(updatedUser.getImageUrl()).isEqualTo(userDTO.getImageUrl());
+ assertThat(updatedUser.isActivated()).isTrue();
+ assertThat(updatedUser.getAuthorities()).isEmpty();
+ }
+
+ @Test
+ @Transactional
+ @WithMockUser("save-invalid-email")
+ void testSaveInvalidEmail() throws Exception {
+ User user = new User();
+ user.setLogin("save-invalid-email");
+ user.setEmail("save-invalid-email@example.com");
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(true);
+
+ userRepository.saveAndFlush(user);
+
+ AdminUserDTO userDTO = new AdminUserDTO();
+ userDTO.setLogin("not-used");
+ userDTO.setFirstName("firstname");
+ userDTO.setLastName("lastname");
+ userDTO.setEmail("invalid email");
+ userDTO.setActivated(false);
+ userDTO.setImageUrl("http://placehold.it/50x50");
+ userDTO.setLangKey(Constants.DEFAULT_LANGUAGE);
+ userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN));
+
+ restAccountMockMvc
+ .perform(post("/api/account").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(userDTO)))
+ .andExpect(status().isBadRequest());
+
+ assertThat(userRepository.findOneByEmailIgnoreCase("invalid email")).isNotPresent();
+ }
+
+ @Test
+ @Transactional
+ @WithMockUser("save-existing-email")
+ void testSaveExistingEmail() throws Exception {
+ User user = new User();
+ user.setLogin("save-existing-email");
+ user.setEmail("save-existing-email@example.com");
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(true);
+ userRepository.saveAndFlush(user);
+
+ User anotherUser = new User();
+ anotherUser.setLogin("save-existing-email2");
+ anotherUser.setEmail("save-existing-email2@example.com");
+ anotherUser.setPassword(RandomStringUtils.random(60));
+ anotherUser.setActivated(true);
+
+ userRepository.saveAndFlush(anotherUser);
+
+ AdminUserDTO userDTO = new AdminUserDTO();
+ userDTO.setLogin("not-used");
+ userDTO.setFirstName("firstname");
+ userDTO.setLastName("lastname");
+ userDTO.setEmail("save-existing-email2@example.com");
+ userDTO.setActivated(false);
+ userDTO.setImageUrl("http://placehold.it/50x50");
+ userDTO.setLangKey(Constants.DEFAULT_LANGUAGE);
+ userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN));
+
+ restAccountMockMvc
+ .perform(post("/api/account").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(userDTO)))
+ .andExpect(status().isBadRequest());
+
+ User updatedUser = userRepository.findOneByLogin("save-existing-email").orElse(null);
+ assertThat(updatedUser.getEmail()).isEqualTo("save-existing-email@example.com");
+ }
+
+ @Test
+ @Transactional
+ @WithMockUser("save-existing-email-and-login")
+ void testSaveExistingEmailAndLogin() throws Exception {
+ User user = new User();
+ user.setLogin("save-existing-email-and-login");
+ user.setEmail("save-existing-email-and-login@example.com");
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(true);
+ userRepository.saveAndFlush(user);
+
+ AdminUserDTO userDTO = new AdminUserDTO();
+ userDTO.setLogin("not-used");
+ userDTO.setFirstName("firstname");
+ userDTO.setLastName("lastname");
+ userDTO.setEmail("save-existing-email-and-login@example.com");
+ userDTO.setActivated(false);
+ userDTO.setImageUrl("http://placehold.it/50x50");
+ userDTO.setLangKey(Constants.DEFAULT_LANGUAGE);
+ userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.ADMIN));
+
+ restAccountMockMvc
+ .perform(post("/api/account").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(userDTO)))
+ .andExpect(status().isOk());
+
+ User updatedUser = userRepository.findOneByLogin("save-existing-email-and-login").orElse(null);
+ assertThat(updatedUser.getEmail()).isEqualTo("save-existing-email-and-login@example.com");
+ }
+
+ @Test
+ @Transactional
+ @WithMockUser("change-password-wrong-existing-password")
+ void testChangePasswordWrongExistingPassword() throws Exception {
+ User user = new User();
+ String currentPassword = RandomStringUtils.random(60);
+ user.setPassword(passwordEncoder.encode(currentPassword));
+ user.setLogin("change-password-wrong-existing-password");
+ user.setEmail("change-password-wrong-existing-password@example.com");
+ userRepository.saveAndFlush(user);
+
+ restAccountMockMvc
+ .perform(
+ post("/api/account/change-password")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO("1" + currentPassword, "new password")))
+ )
+ .andExpect(status().isBadRequest());
+
+ User updatedUser = userRepository.findOneByLogin("change-password-wrong-existing-password").orElse(null);
+ assertThat(passwordEncoder.matches("new password", updatedUser.getPassword())).isFalse();
+ assertThat(passwordEncoder.matches(currentPassword, updatedUser.getPassword())).isTrue();
+ }
+
+ @Test
+ @Transactional
+ @WithMockUser("change-password")
+ void testChangePassword() throws Exception {
+ User user = new User();
+ String currentPassword = RandomStringUtils.random(60);
+ user.setPassword(passwordEncoder.encode(currentPassword));
+ user.setLogin("change-password");
+ user.setEmail("change-password@example.com");
+ userRepository.saveAndFlush(user);
+
+ restAccountMockMvc
+ .perform(
+ post("/api/account/change-password")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, "new password")))
+ )
+ .andExpect(status().isOk());
+
+ User updatedUser = userRepository.findOneByLogin("change-password").orElse(null);
+ assertThat(passwordEncoder.matches("new password", updatedUser.getPassword())).isTrue();
+ }
+
+ @Test
+ @Transactional
+ @WithMockUser("change-password-too-small")
+ void testChangePasswordTooSmall() throws Exception {
+ User user = new User();
+ String currentPassword = RandomStringUtils.random(60);
+ user.setPassword(passwordEncoder.encode(currentPassword));
+ user.setLogin("change-password-too-small");
+ user.setEmail("change-password-too-small@example.com");
+ userRepository.saveAndFlush(user);
+
+ String newPassword = RandomStringUtils.random(ManagedUserVM.PASSWORD_MIN_LENGTH - 1);
+
+ restAccountMockMvc
+ .perform(
+ post("/api/account/change-password")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, newPassword)))
+ )
+ .andExpect(status().isBadRequest());
+
+ User updatedUser = userRepository.findOneByLogin("change-password-too-small").orElse(null);
+ assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword());
+ }
+
+ @Test
+ @Transactional
+ @WithMockUser("change-password-too-long")
+ void testChangePasswordTooLong() throws Exception {
+ User user = new User();
+ String currentPassword = RandomStringUtils.random(60);
+ user.setPassword(passwordEncoder.encode(currentPassword));
+ user.setLogin("change-password-too-long");
+ user.setEmail("change-password-too-long@example.com");
+ userRepository.saveAndFlush(user);
+
+ String newPassword = RandomStringUtils.random(ManagedUserVM.PASSWORD_MAX_LENGTH + 1);
+
+ restAccountMockMvc
+ .perform(
+ post("/api/account/change-password")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, newPassword)))
+ )
+ .andExpect(status().isBadRequest());
+
+ User updatedUser = userRepository.findOneByLogin("change-password-too-long").orElse(null);
+ assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword());
+ }
+
+ @Test
+ @Transactional
+ @WithMockUser("change-password-empty")
+ void testChangePasswordEmpty() throws Exception {
+ User user = new User();
+ String currentPassword = RandomStringUtils.random(60);
+ user.setPassword(passwordEncoder.encode(currentPassword));
+ user.setLogin("change-password-empty");
+ user.setEmail("change-password-empty@example.com");
+ userRepository.saveAndFlush(user);
+
+ restAccountMockMvc
+ .perform(
+ post("/api/account/change-password")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(TestUtil.convertObjectToJsonBytes(new PasswordChangeDTO(currentPassword, "")))
+ )
+ .andExpect(status().isBadRequest());
+
+ User updatedUser = userRepository.findOneByLogin("change-password-empty").orElse(null);
+ assertThat(updatedUser.getPassword()).isEqualTo(user.getPassword());
+ }
+
+ @Test
+ @Transactional
+ void testRequestPasswordReset() throws Exception {
+ User user = new User();
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(true);
+ user.setLogin("password-reset");
+ user.setEmail("password-reset@example.com");
+ userRepository.saveAndFlush(user);
+
+ restAccountMockMvc
+ .perform(post("/api/account/reset-password/init").content("password-reset@example.com"))
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ @Transactional
+ void testRequestPasswordResetUpperCaseEmail() throws Exception {
+ User user = new User();
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(true);
+ user.setLogin("password-reset-upper-case");
+ user.setEmail("password-reset-upper-case@example.com");
+ userRepository.saveAndFlush(user);
+
+ restAccountMockMvc
+ .perform(post("/api/account/reset-password/init").content("password-reset-upper-case@EXAMPLE.COM"))
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ void testRequestPasswordResetWrongEmail() throws Exception {
+ restAccountMockMvc
+ .perform(post("/api/account/reset-password/init").content("password-reset-wrong-email@example.com"))
+ .andExpect(status().isOk());
+ }
+
+ @Test
+ @Transactional
+ void testFinishPasswordReset() throws Exception {
+ User user = new User();
+ user.setPassword(RandomStringUtils.random(60));
+ user.setLogin("finish-password-reset");
+ user.setEmail("finish-password-reset@example.com");
+ user.setResetDate(Instant.now().plusSeconds(60));
+ user.setResetKey("reset key");
+ userRepository.saveAndFlush(user);
+
+ KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM();
+ keyAndPassword.setKey(user.getResetKey());
+ keyAndPassword.setNewPassword("new password");
+
+ restAccountMockMvc
+ .perform(
+ post("/api/account/reset-password/finish")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(TestUtil.convertObjectToJsonBytes(keyAndPassword))
+ )
+ .andExpect(status().isOk());
+
+ User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null);
+ assertThat(passwordEncoder.matches(keyAndPassword.getNewPassword(), updatedUser.getPassword())).isTrue();
+ }
+
+ @Test
+ @Transactional
+ void testFinishPasswordResetTooSmall() throws Exception {
+ User user = new User();
+ user.setPassword(RandomStringUtils.random(60));
+ user.setLogin("finish-password-reset-too-small");
+ user.setEmail("finish-password-reset-too-small@example.com");
+ user.setResetDate(Instant.now().plusSeconds(60));
+ user.setResetKey("reset key too small");
+ userRepository.saveAndFlush(user);
+
+ KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM();
+ keyAndPassword.setKey(user.getResetKey());
+ keyAndPassword.setNewPassword("foo");
+
+ restAccountMockMvc
+ .perform(
+ post("/api/account/reset-password/finish")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(TestUtil.convertObjectToJsonBytes(keyAndPassword))
+ )
+ .andExpect(status().isBadRequest());
+
+ User updatedUser = userRepository.findOneByLogin(user.getLogin()).orElse(null);
+ assertThat(passwordEncoder.matches(keyAndPassword.getNewPassword(), updatedUser.getPassword())).isFalse();
+ }
+
+ @Test
+ @Transactional
+ void testFinishPasswordResetWrongKey() throws Exception {
+ KeyAndPasswordVM keyAndPassword = new KeyAndPasswordVM();
+ keyAndPassword.setKey("wrong reset key");
+ keyAndPassword.setNewPassword("new password");
+
+ restAccountMockMvc
+ .perform(
+ post("/api/account/reset-password/finish")
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(TestUtil.convertObjectToJsonBytes(keyAndPassword))
+ )
+ .andExpect(status().isInternalServerError());
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/web/rest/ClientForwardControllerTest.java b/myApp/src/test/java/com/mycompany/myapp/web/rest/ClientForwardControllerTest.java
new file mode 100644
index 000000000..bb2f46255
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/web/rest/ClientForwardControllerTest.java
@@ -0,0 +1,68 @@
+package com.mycompany.myapp.web.rest;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.forwardedUrl;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.http.MediaType;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.ResultActions;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * Unit tests for the {@link ClientForwardController} REST controller.
+ */
+class ClientForwardControllerTest {
+
+ private MockMvc restMockMvc;
+
+ @BeforeEach
+ public void setup() {
+ ClientForwardController clientForwardController = new ClientForwardController();
+ this.restMockMvc = MockMvcBuilders.standaloneSetup(clientForwardController, new TestController()).build();
+ }
+
+ @Test
+ void getBackendEndpoint() throws Exception {
+ restMockMvc
+ .perform(get("/test"))
+ .andExpect(status().isOk())
+ .andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_PLAIN_VALUE))
+ .andExpect(content().string("test"));
+ }
+
+ @Test
+ void getClientEndpoint() throws Exception {
+ ResultActions perform = restMockMvc.perform(get("/non-existant-mapping"));
+ perform.andExpect(status().isOk()).andExpect(forwardedUrl("/"));
+ }
+
+ @Test
+ void getNestedClientEndpoint() throws Exception {
+ restMockMvc.perform(get("/admin/user-management")).andExpect(status().isOk()).andExpect(forwardedUrl("/"));
+ }
+
+ @Test
+ void getUnmappedDottedEndpoint() throws Exception {
+ restMockMvc.perform(get("/foo.js")).andExpect(status().isNotFound());
+ }
+
+ @Test
+ void getUnmappedNestedDottedEndpoint() throws Exception {
+ restMockMvc.perform(get("/foo/bar.js")).andExpect(status().isNotFound());
+ }
+
+ @RestController
+ public static class TestController {
+
+ @RequestMapping(value = "/test")
+ public String test() {
+ return "test";
+ }
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/web/rest/PublicUserResourceIT.java b/myApp/src/test/java/com/mycompany/myapp/web/rest/PublicUserResourceIT.java
new file mode 100644
index 000000000..ca9bcb4df
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/web/rest/PublicUserResourceIT.java
@@ -0,0 +1,99 @@
+package com.mycompany.myapp.web.rest;
+
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasItems;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import com.mycompany.myapp.IntegrationTest;
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.UserRepository;
+import com.mycompany.myapp.security.AuthoritiesConstants;
+import javax.persistence.EntityManager;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.cache.CacheManager;
+import org.springframework.http.MediaType;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests for the {@link UserResource} REST controller.
+ */
+@AutoConfigureMockMvc
+@WithMockUser(authorities = AuthoritiesConstants.ADMIN)
+@IntegrationTest
+class PublicUserResourceIT {
+
+ private static final String DEFAULT_LOGIN = "johndoe";
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private EntityManager em;
+
+ @Autowired
+ private CacheManager cacheManager;
+
+ @Autowired
+ private MockMvc restUserMockMvc;
+
+ private User user;
+
+ @BeforeEach
+ public void setup() {
+ cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).clear();
+ cacheManager.getCache(UserRepository.USERS_BY_EMAIL_CACHE).clear();
+ }
+
+ @BeforeEach
+ public void initTest() {
+ user = UserResourceIT.initTestUser(userRepository, em);
+ }
+
+ @Test
+ @Transactional
+ void getAllPublicUsers() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+
+ // Get all the users
+ restUserMockMvc
+ .perform(get("/api/users?sort=id,desc").accept(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
+ .andExpect(jsonPath("$.[*].login").value(hasItem(DEFAULT_LOGIN)))
+ .andExpect(jsonPath("$.[*].email").doesNotExist())
+ .andExpect(jsonPath("$.[*].imageUrl").doesNotExist())
+ .andExpect(jsonPath("$.[*].langKey").doesNotExist());
+ }
+
+ @Test
+ @Transactional
+ void getAllAuthorities() throws Exception {
+ restUserMockMvc
+ .perform(get("/api/authorities").accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
+ .andExpect(jsonPath("$").isArray())
+ .andExpect(jsonPath("$").value(hasItems(AuthoritiesConstants.USER, AuthoritiesConstants.ADMIN)));
+ }
+
+ @Test
+ @Transactional
+ void getAllUsersSortedByParameters() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+
+ restUserMockMvc.perform(get("/api/users?sort=resetKey,desc").accept(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest());
+ restUserMockMvc.perform(get("/api/users?sort=password,desc").accept(MediaType.APPLICATION_JSON)).andExpect(status().isBadRequest());
+ restUserMockMvc
+ .perform(get("/api/users?sort=resetKey,id,desc").accept(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest());
+ restUserMockMvc.perform(get("/api/users?sort=id,desc").accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk());
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/web/rest/TestUtil.java b/myApp/src/test/java/com/mycompany/myapp/web/rest/TestUtil.java
new file mode 100644
index 000000000..11e20d06a
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/web/rest/TestUtil.java
@@ -0,0 +1,206 @@
+package com.mycompany.myapp.web.rest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import java.io.IOException;
+import java.math.BigDecimal;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeParseException;
+import java.util.List;
+import javax.persistence.EntityManager;
+import javax.persistence.TypedQuery;
+import javax.persistence.criteria.CriteriaBuilder;
+import javax.persistence.criteria.CriteriaQuery;
+import javax.persistence.criteria.Root;
+import org.hamcrest.Description;
+import org.hamcrest.TypeSafeDiagnosingMatcher;
+import org.hamcrest.TypeSafeMatcher;
+import org.springframework.format.datetime.standard.DateTimeFormatterRegistrar;
+import org.springframework.format.support.DefaultFormattingConversionService;
+import org.springframework.format.support.FormattingConversionService;
+
+/**
+ * Utility class for testing REST controllers.
+ */
+public final class TestUtil {
+
+ private static final ObjectMapper mapper = createObjectMapper();
+
+ private static ObjectMapper createObjectMapper() {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
+ mapper.setSerializationInclusion(JsonInclude.Include.NON_EMPTY);
+ mapper.registerModule(new JavaTimeModule());
+ return mapper;
+ }
+
+ /**
+ * Convert an object to JSON byte array.
+ *
+ * @param object the object to convert.
+ * @return the JSON byte array.
+ * @throws IOException
+ */
+ public static byte[] convertObjectToJsonBytes(Object object) throws IOException {
+ return mapper.writeValueAsBytes(object);
+ }
+
+ /**
+ * Create a byte array with a specific size filled with specified data.
+ *
+ * @param size the size of the byte array.
+ * @param data the data to put in the byte array.
+ * @return the JSON byte array.
+ */
+ public static byte[] createByteArray(int size, String data) {
+ byte[] byteArray = new byte[size];
+ for (int i = 0; i < size; i++) {
+ byteArray[i] = Byte.parseByte(data, 2);
+ }
+ return byteArray;
+ }
+
+ /**
+ * A matcher that tests that the examined string represents the same instant as the reference datetime.
+ */
+ public static class ZonedDateTimeMatcher extends TypeSafeDiagnosingMatcher {
+
+ private final ZonedDateTime date;
+
+ public ZonedDateTimeMatcher(ZonedDateTime date) {
+ this.date = date;
+ }
+
+ @Override
+ protected boolean matchesSafely(String item, Description mismatchDescription) {
+ try {
+ if (!date.isEqual(ZonedDateTime.parse(item))) {
+ mismatchDescription.appendText("was ").appendValue(item);
+ return false;
+ }
+ return true;
+ } catch (DateTimeParseException e) {
+ mismatchDescription.appendText("was ").appendValue(item).appendText(", which could not be parsed as a ZonedDateTime");
+ return false;
+ }
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("a String representing the same Instant as ").appendValue(date);
+ }
+ }
+
+ /**
+ * Creates a matcher that matches when the examined string represents the same instant as the reference datetime.
+ *
+ * @param date the reference datetime against which the examined string is checked.
+ */
+ public static ZonedDateTimeMatcher sameInstant(ZonedDateTime date) {
+ return new ZonedDateTimeMatcher(date);
+ }
+
+ /**
+ * A matcher that tests that the examined number represents the same value - it can be Long, Double, etc - as the reference BigDecimal.
+ */
+ public static class NumberMatcher extends TypeSafeMatcher {
+
+ final BigDecimal value;
+
+ public NumberMatcher(BigDecimal value) {
+ this.value = value;
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("a numeric value is ").appendValue(value);
+ }
+
+ @Override
+ protected boolean matchesSafely(Number item) {
+ BigDecimal bigDecimal = asDecimal(item);
+ return bigDecimal != null && value.compareTo(bigDecimal) == 0;
+ }
+
+ private static BigDecimal asDecimal(Number item) {
+ if (item == null) {
+ return null;
+ }
+ if (item instanceof BigDecimal) {
+ return (BigDecimal) item;
+ } else if (item instanceof Long) {
+ return BigDecimal.valueOf((Long) item);
+ } else if (item instanceof Integer) {
+ return BigDecimal.valueOf((Integer) item);
+ } else if (item instanceof Double) {
+ return BigDecimal.valueOf((Double) item);
+ } else if (item instanceof Float) {
+ return BigDecimal.valueOf((Float) item);
+ } else {
+ return BigDecimal.valueOf(item.doubleValue());
+ }
+ }
+ }
+
+ /**
+ * Creates a matcher that matches when the examined number represents the same value as the reference BigDecimal.
+ *
+ * @param number the reference BigDecimal against which the examined number is checked.
+ */
+ public static NumberMatcher sameNumber(BigDecimal number) {
+ return new NumberMatcher(number);
+ }
+
+ /**
+ * Verifies the equals/hashcode contract on the domain object.
+ */
+ public static void equalsVerifier(Class clazz) throws Exception {
+ T domainObject1 = clazz.getConstructor().newInstance();
+ assertThat(domainObject1.toString()).isNotNull();
+ assertThat(domainObject1).isEqualTo(domainObject1);
+ assertThat(domainObject1).hasSameHashCodeAs(domainObject1);
+ // Test with an instance of another class
+ Object testOtherObject = new Object();
+ assertThat(domainObject1).isNotEqualTo(testOtherObject);
+ assertThat(domainObject1).isNotEqualTo(null);
+ // Test with an instance of the same class
+ T domainObject2 = clazz.getConstructor().newInstance();
+ assertThat(domainObject1).isNotEqualTo(domainObject2);
+ // HashCodes are equals because the objects are not persisted yet
+ assertThat(domainObject1).hasSameHashCodeAs(domainObject2);
+ }
+
+ /**
+ * Create a {@link FormattingConversionService} which use ISO date format, instead of the localized one.
+ * @return the {@link FormattingConversionService}.
+ */
+ public static FormattingConversionService createFormattingConversionService() {
+ DefaultFormattingConversionService dfcs = new DefaultFormattingConversionService();
+ DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
+ registrar.setUseIsoFormat(true);
+ registrar.registerFormatters(dfcs);
+ return dfcs;
+ }
+
+ /**
+ * Makes a an executes a query to the EntityManager finding all stored objects.
+ * @param The type of objects to be searched
+ * @param em The instance of the EntityManager
+ * @param clss The class type to be searched
+ * @return A list of all found objects
+ */
+ public static List findAll(EntityManager em, Class clss) {
+ CriteriaBuilder cb = em.getCriteriaBuilder();
+ CriteriaQuery cq = cb.createQuery(clss);
+ Root rootEntry = cq.from(clss);
+ CriteriaQuery all = cq.select(rootEntry);
+ TypedQuery allQuery = em.createQuery(all);
+ return allQuery.getResultList();
+ }
+
+ private TestUtil() {}
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/web/rest/UserJWTControllerIT.java b/myApp/src/test/java/com/mycompany/myapp/web/rest/UserJWTControllerIT.java
new file mode 100644
index 000000000..ed46992df
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/web/rest/UserJWTControllerIT.java
@@ -0,0 +1,98 @@
+package com.mycompany.myapp.web.rest;
+
+import static org.hamcrest.Matchers.emptyString;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+import static org.hamcrest.Matchers.nullValue;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import com.mycompany.myapp.IntegrationTest;
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.UserRepository;
+import com.mycompany.myapp.web.rest.vm.LoginVM;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.http.MediaType;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests for the {@link UserJWTController} REST controller.
+ */
+@AutoConfigureMockMvc
+@IntegrationTest
+class UserJWTControllerIT {
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private PasswordEncoder passwordEncoder;
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ @Transactional
+ void testAuthorize() throws Exception {
+ User user = new User();
+ user.setLogin("user-jwt-controller");
+ user.setEmail("user-jwt-controller@example.com");
+ user.setActivated(true);
+ user.setPassword(passwordEncoder.encode("test"));
+
+ userRepository.saveAndFlush(user);
+
+ LoginVM login = new LoginVM();
+ login.setUsername("user-jwt-controller");
+ login.setPassword("test");
+ mockMvc
+ .perform(post("/api/authenticate").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(login)))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.id_token").isString())
+ .andExpect(jsonPath("$.id_token").isNotEmpty())
+ .andExpect(header().string("Authorization", not(nullValue())))
+ .andExpect(header().string("Authorization", not(is(emptyString()))));
+ }
+
+ @Test
+ @Transactional
+ void testAuthorizeWithRememberMe() throws Exception {
+ User user = new User();
+ user.setLogin("user-jwt-controller-remember-me");
+ user.setEmail("user-jwt-controller-remember-me@example.com");
+ user.setActivated(true);
+ user.setPassword(passwordEncoder.encode("test"));
+
+ userRepository.saveAndFlush(user);
+
+ LoginVM login = new LoginVM();
+ login.setUsername("user-jwt-controller-remember-me");
+ login.setPassword("test");
+ login.setRememberMe(true);
+ mockMvc
+ .perform(post("/api/authenticate").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(login)))
+ .andExpect(status().isOk())
+ .andExpect(jsonPath("$.id_token").isString())
+ .andExpect(jsonPath("$.id_token").isNotEmpty())
+ .andExpect(header().string("Authorization", not(nullValue())))
+ .andExpect(header().string("Authorization", not(is(emptyString()))));
+ }
+
+ @Test
+ void testAuthorizeFails() throws Exception {
+ LoginVM login = new LoginVM();
+ login.setUsername("wrong-user");
+ login.setPassword("wrong password");
+ mockMvc
+ .perform(post("/api/authenticate").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(login)))
+ .andExpect(status().isUnauthorized())
+ .andExpect(jsonPath("$.id_token").doesNotExist())
+ .andExpect(header().doesNotExist("Authorization"));
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/web/rest/UserResourceIT.java b/myApp/src/test/java/com/mycompany/myapp/web/rest/UserResourceIT.java
new file mode 100644
index 000000000..1ecfb0e8a
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/web/rest/UserResourceIT.java
@@ -0,0 +1,583 @@
+package com.mycompany.myapp.web.rest;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.hasItem;
+import static org.hamcrest.Matchers.hasItems;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
+
+import com.mycompany.myapp.IntegrationTest;
+import com.mycompany.myapp.domain.Authority;
+import com.mycompany.myapp.domain.User;
+import com.mycompany.myapp.repository.UserRepository;
+import com.mycompany.myapp.security.AuthoritiesConstants;
+import com.mycompany.myapp.service.dto.AdminUserDTO;
+import com.mycompany.myapp.service.dto.UserDTO;
+import com.mycompany.myapp.service.mapper.UserMapper;
+import com.mycompany.myapp.web.rest.vm.ManagedUserVM;
+import java.time.Instant;
+import java.util.*;
+import java.util.function.Consumer;
+import javax.persistence.EntityManager;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.cache.CacheManager;
+import org.springframework.http.MediaType;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Integration tests for the {@link UserResource} REST controller.
+ */
+@AutoConfigureMockMvc
+@WithMockUser(authorities = AuthoritiesConstants.ADMIN)
+@IntegrationTest
+class UserResourceIT {
+
+ private static final String DEFAULT_LOGIN = "johndoe";
+ private static final String UPDATED_LOGIN = "jhipster";
+
+ private static final Long DEFAULT_ID = 1L;
+
+ private static final String DEFAULT_PASSWORD = "passjohndoe";
+ private static final String UPDATED_PASSWORD = "passjhipster";
+
+ private static final String DEFAULT_EMAIL = "johndoe@localhost";
+ private static final String UPDATED_EMAIL = "jhipster@localhost";
+
+ private static final String DEFAULT_FIRSTNAME = "john";
+ private static final String UPDATED_FIRSTNAME = "jhipsterFirstName";
+
+ private static final String DEFAULT_LASTNAME = "doe";
+ private static final String UPDATED_LASTNAME = "jhipsterLastName";
+
+ private static final String DEFAULT_IMAGEURL = "http://placehold.it/50x50";
+ private static final String UPDATED_IMAGEURL = "http://placehold.it/40x40";
+
+ private static final String DEFAULT_LANGKEY = "en";
+ private static final String UPDATED_LANGKEY = "fr";
+
+ @Autowired
+ private UserRepository userRepository;
+
+ @Autowired
+ private UserMapper userMapper;
+
+ @Autowired
+ private EntityManager em;
+
+ @Autowired
+ private CacheManager cacheManager;
+
+ @Autowired
+ private MockMvc restUserMockMvc;
+
+ private User user;
+
+ @BeforeEach
+ public void setup() {
+ cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).clear();
+ cacheManager.getCache(UserRepository.USERS_BY_EMAIL_CACHE).clear();
+ }
+
+ /**
+ * Create a User.
+ *
+ * This is a static method, as tests for other entities might also need it,
+ * if they test an entity which has a required relationship to the User entity.
+ */
+ public static User createEntity(EntityManager em) {
+ User user = new User();
+ user.setLogin(DEFAULT_LOGIN + RandomStringUtils.randomAlphabetic(5));
+ user.setPassword(RandomStringUtils.random(60));
+ user.setActivated(true);
+ user.setEmail(RandomStringUtils.randomAlphabetic(5) + DEFAULT_EMAIL);
+ user.setFirstName(DEFAULT_FIRSTNAME);
+ user.setLastName(DEFAULT_LASTNAME);
+ user.setImageUrl(DEFAULT_IMAGEURL);
+ user.setLangKey(DEFAULT_LANGKEY);
+ return user;
+ }
+
+ /**
+ * Setups the database with one user.
+ */
+ public static User initTestUser(UserRepository userRepository, EntityManager em) {
+ User user = createEntity(em);
+ user.setLogin(DEFAULT_LOGIN);
+ user.setEmail(DEFAULT_EMAIL);
+ return user;
+ }
+
+ @BeforeEach
+ public void initTest() {
+ user = initTestUser(userRepository, em);
+ }
+
+ @Test
+ @Transactional
+ void createUser() throws Exception {
+ int databaseSizeBeforeCreate = userRepository.findAll().size();
+
+ // Create the User
+ ManagedUserVM managedUserVM = new ManagedUserVM();
+ managedUserVM.setLogin(DEFAULT_LOGIN);
+ managedUserVM.setPassword(DEFAULT_PASSWORD);
+ managedUserVM.setFirstName(DEFAULT_FIRSTNAME);
+ managedUserVM.setLastName(DEFAULT_LASTNAME);
+ managedUserVM.setEmail(DEFAULT_EMAIL);
+ managedUserVM.setActivated(true);
+ managedUserVM.setImageUrl(DEFAULT_IMAGEURL);
+ managedUserVM.setLangKey(DEFAULT_LANGKEY);
+ managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ restUserMockMvc
+ .perform(
+ post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM))
+ )
+ .andExpect(status().isCreated());
+
+ // Validate the User in the database
+ assertPersistedUsers(users -> {
+ assertThat(users).hasSize(databaseSizeBeforeCreate + 1);
+ User testUser = users.get(users.size() - 1);
+ assertThat(testUser.getLogin()).isEqualTo(DEFAULT_LOGIN);
+ assertThat(testUser.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME);
+ assertThat(testUser.getLastName()).isEqualTo(DEFAULT_LASTNAME);
+ assertThat(testUser.getEmail()).isEqualTo(DEFAULT_EMAIL);
+ assertThat(testUser.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL);
+ assertThat(testUser.getLangKey()).isEqualTo(DEFAULT_LANGKEY);
+ });
+ }
+
+ @Test
+ @Transactional
+ void createUserWithExistingId() throws Exception {
+ int databaseSizeBeforeCreate = userRepository.findAll().size();
+
+ ManagedUserVM managedUserVM = new ManagedUserVM();
+ managedUserVM.setId(DEFAULT_ID);
+ managedUserVM.setLogin(DEFAULT_LOGIN);
+ managedUserVM.setPassword(DEFAULT_PASSWORD);
+ managedUserVM.setFirstName(DEFAULT_FIRSTNAME);
+ managedUserVM.setLastName(DEFAULT_LASTNAME);
+ managedUserVM.setEmail(DEFAULT_EMAIL);
+ managedUserVM.setActivated(true);
+ managedUserVM.setImageUrl(DEFAULT_IMAGEURL);
+ managedUserVM.setLangKey(DEFAULT_LANGKEY);
+ managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ // An entity with an existing ID cannot be created, so this API call must fail
+ restUserMockMvc
+ .perform(
+ post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM))
+ )
+ .andExpect(status().isBadRequest());
+
+ // Validate the User in the database
+ assertPersistedUsers(users -> assertThat(users).hasSize(databaseSizeBeforeCreate));
+ }
+
+ @Test
+ @Transactional
+ void createUserWithExistingLogin() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+ int databaseSizeBeforeCreate = userRepository.findAll().size();
+
+ ManagedUserVM managedUserVM = new ManagedUserVM();
+ managedUserVM.setLogin(DEFAULT_LOGIN); // this login should already be used
+ managedUserVM.setPassword(DEFAULT_PASSWORD);
+ managedUserVM.setFirstName(DEFAULT_FIRSTNAME);
+ managedUserVM.setLastName(DEFAULT_LASTNAME);
+ managedUserVM.setEmail("anothermail@localhost");
+ managedUserVM.setActivated(true);
+ managedUserVM.setImageUrl(DEFAULT_IMAGEURL);
+ managedUserVM.setLangKey(DEFAULT_LANGKEY);
+ managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ // Create the User
+ restUserMockMvc
+ .perform(
+ post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM))
+ )
+ .andExpect(status().isBadRequest());
+
+ // Validate the User in the database
+ assertPersistedUsers(users -> assertThat(users).hasSize(databaseSizeBeforeCreate));
+ }
+
+ @Test
+ @Transactional
+ void createUserWithExistingEmail() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+ int databaseSizeBeforeCreate = userRepository.findAll().size();
+
+ ManagedUserVM managedUserVM = new ManagedUserVM();
+ managedUserVM.setLogin("anotherlogin");
+ managedUserVM.setPassword(DEFAULT_PASSWORD);
+ managedUserVM.setFirstName(DEFAULT_FIRSTNAME);
+ managedUserVM.setLastName(DEFAULT_LASTNAME);
+ managedUserVM.setEmail(DEFAULT_EMAIL); // this email should already be used
+ managedUserVM.setActivated(true);
+ managedUserVM.setImageUrl(DEFAULT_IMAGEURL);
+ managedUserVM.setLangKey(DEFAULT_LANGKEY);
+ managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ // Create the User
+ restUserMockMvc
+ .perform(
+ post("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM))
+ )
+ .andExpect(status().isBadRequest());
+
+ // Validate the User in the database
+ assertPersistedUsers(users -> assertThat(users).hasSize(databaseSizeBeforeCreate));
+ }
+
+ @Test
+ @Transactional
+ void getAllUsers() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+
+ // Get all the users
+ restUserMockMvc
+ .perform(get("/api/admin/users?sort=id,desc").accept(MediaType.APPLICATION_JSON))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
+ .andExpect(jsonPath("$.[*].login").value(hasItem(DEFAULT_LOGIN)))
+ .andExpect(jsonPath("$.[*].firstName").value(hasItem(DEFAULT_FIRSTNAME)))
+ .andExpect(jsonPath("$.[*].lastName").value(hasItem(DEFAULT_LASTNAME)))
+ .andExpect(jsonPath("$.[*].email").value(hasItem(DEFAULT_EMAIL)))
+ .andExpect(jsonPath("$.[*].imageUrl").value(hasItem(DEFAULT_IMAGEURL)))
+ .andExpect(jsonPath("$.[*].langKey").value(hasItem(DEFAULT_LANGKEY)));
+ }
+
+ @Test
+ @Transactional
+ void getUser() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+
+ assertThat(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).get(user.getLogin())).isNull();
+
+ // Get the user
+ restUserMockMvc
+ .perform(get("/api/admin/users/{login}", user.getLogin()))
+ .andExpect(status().isOk())
+ .andExpect(content().contentType(MediaType.APPLICATION_JSON_VALUE))
+ .andExpect(jsonPath("$.login").value(user.getLogin()))
+ .andExpect(jsonPath("$.firstName").value(DEFAULT_FIRSTNAME))
+ .andExpect(jsonPath("$.lastName").value(DEFAULT_LASTNAME))
+ .andExpect(jsonPath("$.email").value(DEFAULT_EMAIL))
+ .andExpect(jsonPath("$.imageUrl").value(DEFAULT_IMAGEURL))
+ .andExpect(jsonPath("$.langKey").value(DEFAULT_LANGKEY));
+
+ assertThat(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).get(user.getLogin())).isNotNull();
+ }
+
+ @Test
+ @Transactional
+ void getNonExistingUser() throws Exception {
+ restUserMockMvc.perform(get("/api/admin/users/unknown")).andExpect(status().isNotFound());
+ }
+
+ @Test
+ @Transactional
+ void updateUser() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+ int databaseSizeBeforeUpdate = userRepository.findAll().size();
+
+ // Update the user
+ User updatedUser = userRepository.findById(user.getId()).get();
+
+ ManagedUserVM managedUserVM = new ManagedUserVM();
+ managedUserVM.setId(updatedUser.getId());
+ managedUserVM.setLogin(updatedUser.getLogin());
+ managedUserVM.setPassword(UPDATED_PASSWORD);
+ managedUserVM.setFirstName(UPDATED_FIRSTNAME);
+ managedUserVM.setLastName(UPDATED_LASTNAME);
+ managedUserVM.setEmail(UPDATED_EMAIL);
+ managedUserVM.setActivated(updatedUser.isActivated());
+ managedUserVM.setImageUrl(UPDATED_IMAGEURL);
+ managedUserVM.setLangKey(UPDATED_LANGKEY);
+ managedUserVM.setCreatedBy(updatedUser.getCreatedBy());
+ managedUserVM.setCreatedDate(updatedUser.getCreatedDate());
+ managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy());
+ managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate());
+ managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ restUserMockMvc
+ .perform(
+ put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM))
+ )
+ .andExpect(status().isOk());
+
+ // Validate the User in the database
+ assertPersistedUsers(users -> {
+ assertThat(users).hasSize(databaseSizeBeforeUpdate);
+ User testUser = users.stream().filter(usr -> usr.getId().equals(updatedUser.getId())).findFirst().get();
+ assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME);
+ assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME);
+ assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL);
+ assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL);
+ assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY);
+ });
+ }
+
+ @Test
+ @Transactional
+ void updateUserLogin() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+ int databaseSizeBeforeUpdate = userRepository.findAll().size();
+
+ // Update the user
+ User updatedUser = userRepository.findById(user.getId()).get();
+
+ ManagedUserVM managedUserVM = new ManagedUserVM();
+ managedUserVM.setId(updatedUser.getId());
+ managedUserVM.setLogin(UPDATED_LOGIN);
+ managedUserVM.setPassword(UPDATED_PASSWORD);
+ managedUserVM.setFirstName(UPDATED_FIRSTNAME);
+ managedUserVM.setLastName(UPDATED_LASTNAME);
+ managedUserVM.setEmail(UPDATED_EMAIL);
+ managedUserVM.setActivated(updatedUser.isActivated());
+ managedUserVM.setImageUrl(UPDATED_IMAGEURL);
+ managedUserVM.setLangKey(UPDATED_LANGKEY);
+ managedUserVM.setCreatedBy(updatedUser.getCreatedBy());
+ managedUserVM.setCreatedDate(updatedUser.getCreatedDate());
+ managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy());
+ managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate());
+ managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ restUserMockMvc
+ .perform(
+ put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM))
+ )
+ .andExpect(status().isOk());
+
+ // Validate the User in the database
+ assertPersistedUsers(users -> {
+ assertThat(users).hasSize(databaseSizeBeforeUpdate);
+ User testUser = users.stream().filter(usr -> usr.getId().equals(updatedUser.getId())).findFirst().get();
+ assertThat(testUser.getLogin()).isEqualTo(UPDATED_LOGIN);
+ assertThat(testUser.getFirstName()).isEqualTo(UPDATED_FIRSTNAME);
+ assertThat(testUser.getLastName()).isEqualTo(UPDATED_LASTNAME);
+ assertThat(testUser.getEmail()).isEqualTo(UPDATED_EMAIL);
+ assertThat(testUser.getImageUrl()).isEqualTo(UPDATED_IMAGEURL);
+ assertThat(testUser.getLangKey()).isEqualTo(UPDATED_LANGKEY);
+ });
+ }
+
+ @Test
+ @Transactional
+ void updateUserExistingEmail() throws Exception {
+ // Initialize the database with 2 users
+ userRepository.saveAndFlush(user);
+
+ User anotherUser = new User();
+ anotherUser.setLogin("jhipster");
+ anotherUser.setPassword(RandomStringUtils.random(60));
+ anotherUser.setActivated(true);
+ anotherUser.setEmail("jhipster@localhost");
+ anotherUser.setFirstName("java");
+ anotherUser.setLastName("hipster");
+ anotherUser.setImageUrl("");
+ anotherUser.setLangKey("en");
+ userRepository.saveAndFlush(anotherUser);
+
+ // Update the user
+ User updatedUser = userRepository.findById(user.getId()).get();
+
+ ManagedUserVM managedUserVM = new ManagedUserVM();
+ managedUserVM.setId(updatedUser.getId());
+ managedUserVM.setLogin(updatedUser.getLogin());
+ managedUserVM.setPassword(updatedUser.getPassword());
+ managedUserVM.setFirstName(updatedUser.getFirstName());
+ managedUserVM.setLastName(updatedUser.getLastName());
+ managedUserVM.setEmail("jhipster@localhost"); // this email should already be used by anotherUser
+ managedUserVM.setActivated(updatedUser.isActivated());
+ managedUserVM.setImageUrl(updatedUser.getImageUrl());
+ managedUserVM.setLangKey(updatedUser.getLangKey());
+ managedUserVM.setCreatedBy(updatedUser.getCreatedBy());
+ managedUserVM.setCreatedDate(updatedUser.getCreatedDate());
+ managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy());
+ managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate());
+ managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ restUserMockMvc
+ .perform(
+ put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM))
+ )
+ .andExpect(status().isBadRequest());
+ }
+
+ @Test
+ @Transactional
+ void updateUserExistingLogin() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+
+ User anotherUser = new User();
+ anotherUser.setLogin("jhipster");
+ anotherUser.setPassword(RandomStringUtils.random(60));
+ anotherUser.setActivated(true);
+ anotherUser.setEmail("jhipster@localhost");
+ anotherUser.setFirstName("java");
+ anotherUser.setLastName("hipster");
+ anotherUser.setImageUrl("");
+ anotherUser.setLangKey("en");
+ userRepository.saveAndFlush(anotherUser);
+
+ // Update the user
+ User updatedUser = userRepository.findById(user.getId()).get();
+
+ ManagedUserVM managedUserVM = new ManagedUserVM();
+ managedUserVM.setId(updatedUser.getId());
+ managedUserVM.setLogin("jhipster"); // this login should already be used by anotherUser
+ managedUserVM.setPassword(updatedUser.getPassword());
+ managedUserVM.setFirstName(updatedUser.getFirstName());
+ managedUserVM.setLastName(updatedUser.getLastName());
+ managedUserVM.setEmail(updatedUser.getEmail());
+ managedUserVM.setActivated(updatedUser.isActivated());
+ managedUserVM.setImageUrl(updatedUser.getImageUrl());
+ managedUserVM.setLangKey(updatedUser.getLangKey());
+ managedUserVM.setCreatedBy(updatedUser.getCreatedBy());
+ managedUserVM.setCreatedDate(updatedUser.getCreatedDate());
+ managedUserVM.setLastModifiedBy(updatedUser.getLastModifiedBy());
+ managedUserVM.setLastModifiedDate(updatedUser.getLastModifiedDate());
+ managedUserVM.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ restUserMockMvc
+ .perform(
+ put("/api/admin/users").contentType(MediaType.APPLICATION_JSON).content(TestUtil.convertObjectToJsonBytes(managedUserVM))
+ )
+ .andExpect(status().isBadRequest());
+ }
+
+ @Test
+ @Transactional
+ void deleteUser() throws Exception {
+ // Initialize the database
+ userRepository.saveAndFlush(user);
+ int databaseSizeBeforeDelete = userRepository.findAll().size();
+
+ // Delete the user
+ restUserMockMvc
+ .perform(delete("/api/admin/users/{login}", user.getLogin()).accept(MediaType.APPLICATION_JSON))
+ .andExpect(status().isNoContent());
+
+ assertThat(cacheManager.getCache(UserRepository.USERS_BY_LOGIN_CACHE).get(user.getLogin())).isNull();
+
+ // Validate the database is empty
+ assertPersistedUsers(users -> assertThat(users).hasSize(databaseSizeBeforeDelete - 1));
+ }
+
+ @Test
+ void testUserEquals() throws Exception {
+ TestUtil.equalsVerifier(User.class);
+ User user1 = new User();
+ user1.setId(DEFAULT_ID);
+ User user2 = new User();
+ user2.setId(user1.getId());
+ assertThat(user1).isEqualTo(user2);
+ user2.setId(2L);
+ assertThat(user1).isNotEqualTo(user2);
+ user1.setId(null);
+ assertThat(user1).isNotEqualTo(user2);
+ }
+
+ @Test
+ void testUserDTOtoUser() {
+ AdminUserDTO userDTO = new AdminUserDTO();
+ userDTO.setId(DEFAULT_ID);
+ userDTO.setLogin(DEFAULT_LOGIN);
+ userDTO.setFirstName(DEFAULT_FIRSTNAME);
+ userDTO.setLastName(DEFAULT_LASTNAME);
+ userDTO.setEmail(DEFAULT_EMAIL);
+ userDTO.setActivated(true);
+ userDTO.setImageUrl(DEFAULT_IMAGEURL);
+ userDTO.setLangKey(DEFAULT_LANGKEY);
+ userDTO.setCreatedBy(DEFAULT_LOGIN);
+ userDTO.setLastModifiedBy(DEFAULT_LOGIN);
+ userDTO.setAuthorities(Collections.singleton(AuthoritiesConstants.USER));
+
+ User user = userMapper.userDTOToUser(userDTO);
+ assertThat(user.getId()).isEqualTo(DEFAULT_ID);
+ assertThat(user.getLogin()).isEqualTo(DEFAULT_LOGIN);
+ assertThat(user.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME);
+ assertThat(user.getLastName()).isEqualTo(DEFAULT_LASTNAME);
+ assertThat(user.getEmail()).isEqualTo(DEFAULT_EMAIL);
+ assertThat(user.isActivated()).isTrue();
+ assertThat(user.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL);
+ assertThat(user.getLangKey()).isEqualTo(DEFAULT_LANGKEY);
+ assertThat(user.getCreatedBy()).isNull();
+ assertThat(user.getCreatedDate()).isNotNull();
+ assertThat(user.getLastModifiedBy()).isNull();
+ assertThat(user.getLastModifiedDate()).isNotNull();
+ assertThat(user.getAuthorities()).extracting("name").containsExactly(AuthoritiesConstants.USER);
+ }
+
+ @Test
+ void testUserToUserDTO() {
+ user.setId(DEFAULT_ID);
+ user.setCreatedBy(DEFAULT_LOGIN);
+ user.setCreatedDate(Instant.now());
+ user.setLastModifiedBy(DEFAULT_LOGIN);
+ user.setLastModifiedDate(Instant.now());
+ Set authorities = new HashSet<>();
+ Authority authority = new Authority();
+ authority.setName(AuthoritiesConstants.USER);
+ authorities.add(authority);
+ user.setAuthorities(authorities);
+
+ AdminUserDTO userDTO = userMapper.userToAdminUserDTO(user);
+
+ assertThat(userDTO.getId()).isEqualTo(DEFAULT_ID);
+ assertThat(userDTO.getLogin()).isEqualTo(DEFAULT_LOGIN);
+ assertThat(userDTO.getFirstName()).isEqualTo(DEFAULT_FIRSTNAME);
+ assertThat(userDTO.getLastName()).isEqualTo(DEFAULT_LASTNAME);
+ assertThat(userDTO.getEmail()).isEqualTo(DEFAULT_EMAIL);
+ assertThat(userDTO.isActivated()).isTrue();
+ assertThat(userDTO.getImageUrl()).isEqualTo(DEFAULT_IMAGEURL);
+ assertThat(userDTO.getLangKey()).isEqualTo(DEFAULT_LANGKEY);
+ assertThat(userDTO.getCreatedBy()).isEqualTo(DEFAULT_LOGIN);
+ assertThat(userDTO.getCreatedDate()).isEqualTo(user.getCreatedDate());
+ assertThat(userDTO.getLastModifiedBy()).isEqualTo(DEFAULT_LOGIN);
+ assertThat(userDTO.getLastModifiedDate()).isEqualTo(user.getLastModifiedDate());
+ assertThat(userDTO.getAuthorities()).containsExactly(AuthoritiesConstants.USER);
+ assertThat(userDTO.toString()).isNotNull();
+ }
+
+ @Test
+ void testAuthorityEquals() {
+ Authority authorityA = new Authority();
+ assertThat(authorityA).isNotEqualTo(null).isNotEqualTo(new Object());
+ assertThat(authorityA.hashCode()).isZero();
+ assertThat(authorityA.toString()).isNotNull();
+
+ Authority authorityB = new Authority();
+ assertThat(authorityA).isEqualTo(authorityB);
+
+ authorityB.setName(AuthoritiesConstants.ADMIN);
+ assertThat(authorityA).isNotEqualTo(authorityB);
+
+ authorityA.setName(AuthoritiesConstants.USER);
+ assertThat(authorityA).isNotEqualTo(authorityB);
+
+ authorityB.setName(AuthoritiesConstants.USER);
+ assertThat(authorityA).isEqualTo(authorityB).hasSameHashCodeAs(authorityB);
+ }
+
+ private void assertPersistedUsers(Consumer> userAssertion) {
+ userAssertion.accept(userRepository.findAll());
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/web/rest/WithUnauthenticatedMockUser.java b/myApp/src/test/java/com/mycompany/myapp/web/rest/WithUnauthenticatedMockUser.java
new file mode 100644
index 000000000..5c9befbad
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/web/rest/WithUnauthenticatedMockUser.java
@@ -0,0 +1,23 @@
+package com.mycompany.myapp.web.rest;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.springframework.security.core.context.SecurityContext;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.test.context.support.WithSecurityContext;
+import org.springframework.security.test.context.support.WithSecurityContextFactory;
+
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@WithSecurityContext(factory = WithUnauthenticatedMockUser.Factory.class)
+public @interface WithUnauthenticatedMockUser {
+ class Factory implements WithSecurityContextFactory {
+
+ @Override
+ public SecurityContext createSecurityContext(WithUnauthenticatedMockUser annotation) {
+ return SecurityContextHolder.createEmptyContext();
+ }
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/web/rest/errors/ExceptionTranslatorIT.java b/myApp/src/test/java/com/mycompany/myapp/web/rest/errors/ExceptionTranslatorIT.java
new file mode 100644
index 000000000..e096d4e31
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/web/rest/errors/ExceptionTranslatorIT.java
@@ -0,0 +1,118 @@
+package com.mycompany.myapp.web.rest.errors;
+
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
+
+import com.mycompany.myapp.IntegrationTest;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.http.MediaType;
+import org.springframework.security.test.context.support.WithMockUser;
+import org.springframework.test.web.servlet.MockMvc;
+
+/**
+ * Integration tests {@link ExceptionTranslator} controller advice.
+ */
+@WithMockUser
+@AutoConfigureMockMvc
+@IntegrationTest
+class ExceptionTranslatorIT {
+
+ @Autowired
+ private MockMvc mockMvc;
+
+ @Test
+ void testConcurrencyFailure() throws Exception {
+ mockMvc
+ .perform(get("/api/exception-translator-test/concurrency-failure"))
+ .andExpect(status().isConflict())
+ .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(jsonPath("$.message").value(ErrorConstants.ERR_CONCURRENCY_FAILURE));
+ }
+
+ @Test
+ void testMethodArgumentNotValid() throws Exception {
+ mockMvc
+ .perform(post("/api/exception-translator-test/method-argument").content("{}").contentType(MediaType.APPLICATION_JSON))
+ .andExpect(status().isBadRequest())
+ .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(jsonPath("$.message").value(ErrorConstants.ERR_VALIDATION))
+ .andExpect(jsonPath("$.fieldErrors.[0].objectName").value("test"))
+ .andExpect(jsonPath("$.fieldErrors.[0].field").value("test"))
+ .andExpect(jsonPath("$.fieldErrors.[0].message").value("must not be null"));
+ }
+
+ @Test
+ void testMissingServletRequestPartException() throws Exception {
+ mockMvc
+ .perform(get("/api/exception-translator-test/missing-servlet-request-part"))
+ .andExpect(status().isBadRequest())
+ .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(jsonPath("$.message").value("error.http.400"));
+ }
+
+ @Test
+ void testMissingServletRequestParameterException() throws Exception {
+ mockMvc
+ .perform(get("/api/exception-translator-test/missing-servlet-request-parameter"))
+ .andExpect(status().isBadRequest())
+ .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(jsonPath("$.message").value("error.http.400"));
+ }
+
+ @Test
+ void testAccessDenied() throws Exception {
+ mockMvc
+ .perform(get("/api/exception-translator-test/access-denied"))
+ .andExpect(status().isForbidden())
+ .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(jsonPath("$.message").value("error.http.403"))
+ .andExpect(jsonPath("$.detail").value("test access denied!"));
+ }
+
+ @Test
+ void testUnauthorized() throws Exception {
+ mockMvc
+ .perform(get("/api/exception-translator-test/unauthorized"))
+ .andExpect(status().isUnauthorized())
+ .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(jsonPath("$.message").value("error.http.401"))
+ .andExpect(jsonPath("$.path").value("/api/exception-translator-test/unauthorized"))
+ .andExpect(jsonPath("$.detail").value("test authentication failed!"));
+ }
+
+ @Test
+ void testMethodNotSupported() throws Exception {
+ mockMvc
+ .perform(post("/api/exception-translator-test/access-denied"))
+ .andExpect(status().isMethodNotAllowed())
+ .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(jsonPath("$.message").value("error.http.405"))
+ .andExpect(jsonPath("$.detail").value("Request method 'POST' not supported"));
+ }
+
+ @Test
+ void testExceptionWithResponseStatus() throws Exception {
+ mockMvc
+ .perform(get("/api/exception-translator-test/response-status"))
+ .andExpect(status().isBadRequest())
+ .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(jsonPath("$.message").value("error.http.400"))
+ .andExpect(jsonPath("$.title").value("test response status"));
+ }
+
+ @Test
+ void testInternalServerError() throws Exception {
+ mockMvc
+ .perform(get("/api/exception-translator-test/internal-server-error"))
+ .andExpect(status().isInternalServerError())
+ .andExpect(content().contentType(MediaType.APPLICATION_PROBLEM_JSON))
+ .andExpect(jsonPath("$.message").value("error.http.500"))
+ .andExpect(jsonPath("$.title").value("Internal Server Error"));
+ }
+}
diff --git a/myApp/src/test/java/com/mycompany/myapp/web/rest/errors/ExceptionTranslatorTestController.java b/myApp/src/test/java/com/mycompany/myapp/web/rest/errors/ExceptionTranslatorTestController.java
new file mode 100644
index 000000000..600438165
--- /dev/null
+++ b/myApp/src/test/java/com/mycompany/myapp/web/rest/errors/ExceptionTranslatorTestController.java
@@ -0,0 +1,66 @@
+package com.mycompany.myapp.web.rest.errors;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import org.springframework.dao.ConcurrencyFailureException;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.web.bind.annotation.*;
+
+@RestController
+@RequestMapping("/api/exception-translator-test")
+public class ExceptionTranslatorTestController {
+
+ @GetMapping("/concurrency-failure")
+ public void concurrencyFailure() {
+ throw new ConcurrencyFailureException("test concurrency failure");
+ }
+
+ @PostMapping("/method-argument")
+ public void methodArgument(@Valid @RequestBody TestDTO testDTO) {}
+
+ @GetMapping("/missing-servlet-request-part")
+ public void missingServletRequestPartException(@RequestPart String part) {}
+
+ @GetMapping("/missing-servlet-request-parameter")
+ public void missingServletRequestParameterException(@RequestParam String param) {}
+
+ @GetMapping("/access-denied")
+ public void accessdenied() {
+ throw new AccessDeniedException("test access denied!");
+ }
+
+ @GetMapping("/unauthorized")
+ public void unauthorized() {
+ throw new BadCredentialsException("test authentication failed!");
+ }
+
+ @GetMapping("/response-status")
+ public void exceptionWithResponseStatus() {
+ throw new TestResponseStatusException();
+ }
+
+ @GetMapping("/internal-server-error")
+ public void internalServerError() {
+ throw new RuntimeException();
+ }
+
+ public static class TestDTO {
+
+ @NotNull
+ private String test;
+
+ public String getTest() {
+ return test;
+ }
+
+ public void setTest(String test) {
+ this.test = test;
+ }
+ }
+
+ @ResponseStatus(value = HttpStatus.BAD_REQUEST, reason = "test response status")
+ @SuppressWarnings("serial")
+ public static class TestResponseStatusException extends RuntimeException {}
+}
diff --git a/myApp/src/test/resources/config/application-testcontainers.yml b/myApp/src/test/resources/config/application-testcontainers.yml
new file mode 100644
index 000000000..d86b4484e
--- /dev/null
+++ b/myApp/src/test/resources/config/application-testcontainers.yml
@@ -0,0 +1,22 @@
+# ===================================================================
+# Spring Boot configuration.
+#
+# This configuration is used for unit/integration tests with testcontainers database containers.
+#
+# To activate this configuration launch integration tests with the 'testcontainers' profile
+#
+# More information on database containers: https://www.testcontainers.org/modules/databases/
+# ===================================================================
+
+spring:
+ datasource:
+ type: com.zaxxer.hikari.HikariDataSource
+ driver-class-name: org.testcontainers.jdbc.ContainerDatabaseDriver
+ url: jdbc:tc:postgresql:13.5:///myApp?TC_TMPFS=/testtmpfs:rw
+ username: myApp
+ password:
+ hikari:
+ poolName: Hikari
+ auto-commit: false
+ jpa:
+ database-platform: tech.jhipster.domain.util.FixedPostgreSQL10Dialect
diff --git a/myApp/src/test/resources/config/application.yml b/myApp/src/test/resources/config/application.yml
new file mode 100644
index 000000000..30f43654d
--- /dev/null
+++ b/myApp/src/test/resources/config/application.yml
@@ -0,0 +1,112 @@
+# ===================================================================
+# Spring Boot configuration.
+#
+# This configuration is used for unit/integration tests.
+#
+# More information on profiles: https://www.jhipster.tech/profiles/
+# More information on configuration properties: https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+# ===================================================================
+# Standard Spring Boot properties.
+# Full reference is available at:
+# http://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html
+# ===================================================================
+
+spring:
+ profiles:
+ # Uncomment the following line to enable tests against production database type rather than H2, using Testcontainers
+ #active: testcontainers
+ application:
+ name: myApp
+ datasource:
+ type: com.zaxxer.hikari.HikariDataSource
+ url: jdbc:h2:mem:myapp;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE
+ name:
+ username:
+ password:
+ hikari:
+ auto-commit: false
+ jackson:
+ serialization:
+ write-durations-as-timestamps: false
+ jpa:
+ database-platform: tech.jhipster.domain.util.FixedH2Dialect
+ open-in-view: false
+ hibernate:
+ ddl-auto: none
+ naming:
+ physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy
+ implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy
+ properties:
+ hibernate.id.new_generator_mappings: true
+ hibernate.connection.provider_disables_autocommit: true
+ hibernate.cache.use_second_level_cache: false
+ hibernate.cache.use_query_cache: false
+ hibernate.generate_statistics: false
+ hibernate.hbm2ddl.auto: validate
+ hibernate.jdbc.time_zone: UTC
+ hibernate.query.fail_on_pagination_over_collection_fetch: true
+ liquibase:
+ contexts: test
+ mail:
+ host: localhost
+ main:
+ allow-bean-definition-overriding: true
+ messages:
+ basename: i18n/messages
+ task:
+ execution:
+ thread-name-prefix: my-app-task-
+ pool:
+ core-size: 1
+ max-size: 50
+ queue-capacity: 10000
+ scheduling:
+ thread-name-prefix: my-app-scheduling-
+ pool:
+ size: 1
+ thymeleaf:
+ mode: HTML
+
+server:
+ port: 10344
+ address: localhost
+
+# ===================================================================
+# JHipster specific properties
+#
+# Full reference is available at: https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+jhipster:
+ clientApp:
+ name: 'myApp'
+ logging:
+ # To test json console appender
+ use-json-format: false
+ logstash:
+ enabled: false
+ host: localhost
+ port: 5000
+ queue-size: 512
+ mail:
+ from: test@localhost
+ base-url: http://127.0.0.1:8080
+ security:
+ authentication:
+ jwt:
+ # This token must be encoded using Base64 (you can type `echo 'secret-key'|base64` on your command line)
+ base64-secret: YjEwZTA0MjIxN2I0MTA4ZWJmY2M1ZjliMDE3OTBjNDIzMjgxYjE5YzM1MDM1ZDM0Y2ZlZWNlYzRmY2ZmODk3OGMyMTRkZjBlZmZmMzM0YmUwMDMzZGNkNTE3YTk3MzU1Yzg5YjZiYWU2MTYwOTdjN2M2YWU0ZDkyM2M3NDM4OGY=
+ # Token is valid 24 hours
+ token-validity-in-seconds: 86400
+# ===================================================================
+# Application specific properties
+# Add your own application properties here, see the ApplicationProperties class
+# to have type-safe configuration, like in the JHipsterProperties above
+#
+# More documentation is available at:
+# https://www.jhipster.tech/common-application-properties/
+# ===================================================================
+
+# application:
diff --git a/myApp/src/test/resources/config/bootstrap.yml b/myApp/src/test/resources/config/bootstrap.yml
new file mode 100644
index 000000000..e69de29bb
diff --git a/myApp/src/test/resources/i18n/messages_en.properties b/myApp/src/test/resources/i18n/messages_en.properties
new file mode 100644
index 000000000..19d237356
--- /dev/null
+++ b/myApp/src/test/resources/i18n/messages_en.properties
@@ -0,0 +1,4 @@
+email.test.title=test title
+# Value used for English locale unit test in MailServiceIT
+# as this file is loaded instead of real file
+email.activation.title=myApp account activation
diff --git a/myApp/src/test/resources/logback.xml b/myApp/src/test/resources/logback.xml
new file mode 100644
index 000000000..7e68ce2e8
--- /dev/null
+++ b/myApp/src/test/resources/logback.xml
@@ -0,0 +1,49 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ WARN
+
+
+
+
diff --git a/myApp/src/test/resources/templates/mail/testEmail.html b/myApp/src/test/resources/templates/mail/testEmail.html
new file mode 100644
index 000000000..a4ca16a79
--- /dev/null
+++ b/myApp/src/test/resources/templates/mail/testEmail.html
@@ -0,0 +1 @@
+
diff --git a/myApp/system.properties b/myApp/system.properties
new file mode 100644
index 000000000..9146af538
--- /dev/null
+++ b/myApp/system.properties
@@ -0,0 +1 @@
+java.runtime.version=11
diff --git a/myApp/tsconfig.json b/myApp/tsconfig.json
new file mode 100644
index 000000000..f84a29f1b
--- /dev/null
+++ b/myApp/tsconfig.json
@@ -0,0 +1,28 @@
+{
+ "compilerOptions": {
+ "jsx": "react",
+ "target": "es6",
+ "module": "esnext",
+ "moduleResolution": "node",
+ "sourceMap": true,
+ "emitDecoratorMetadata": true,
+ "experimentalDecorators": true,
+ "removeComments": false,
+ "noImplicitAny": false,
+ "suppressImplicitAnyIndexErrors": true,
+ "outDir": "target/classes/static/app",
+ "lib": ["dom", "es2015", "es2016", "es2017"],
+ "types": ["jest", "webpack-env"],
+ "allowJs": true,
+ "checkJs": false,
+ "baseUrl": "./",
+ "paths": {
+ "app/*": ["src/main/webapp/app/*"]
+ },
+ "importHelpers": true,
+ "esModuleInterop": true,
+ "allowSyntheticDefaultImports": true
+ },
+ "include": ["src/main/webapp/app", "src/test/javascript/spec"],
+ "exclude": ["node_modules"]
+}
diff --git a/myApp/tsconfig.test.json b/myApp/tsconfig.test.json
new file mode 100644
index 000000000..fef6fc503
--- /dev/null
+++ b/myApp/tsconfig.test.json
@@ -0,0 +1,7 @@
+{
+ "extends": "./tsconfig",
+ "compilerOptions": {
+ "module": "commonjs",
+ "types": ["jest", "webpack-env"]
+ }
+}
diff --git a/myApp/webpack/environment.js b/myApp/webpack/environment.js
new file mode 100644
index 000000000..1f816c628
--- /dev/null
+++ b/myApp/webpack/environment.js
@@ -0,0 +1,9 @@
+module.exports = {
+ // APP_VERSION is passed as an environment variable from the Gradle / Maven build tasks.
+ VERSION: process.env.hasOwnProperty('APP_VERSION') ? process.env.APP_VERSION : 'DEV',
+ // The root URL for API calls, ending with a '/' - for example: `"https://www.jhipster.tech:8081/myservice/"`.
+ // If this URL is left empty (""), then it will be relative to the current context.
+ // If you use an API server, in `prod` mode, you will need to enable CORS
+ // (see the `jhipster.cors` common JHipster property in the `application-*.yml` configurations)
+ SERVER_API_URL: '',
+};
diff --git a/myApp/webpack/logo-jhipster.png b/myApp/webpack/logo-jhipster.png
new file mode 100644
index 000000000..e301aa90f
Binary files /dev/null and b/myApp/webpack/logo-jhipster.png differ
diff --git a/myApp/webpack/utils.js b/myApp/webpack/utils.js
new file mode 100644
index 000000000..736589de7
--- /dev/null
+++ b/myApp/webpack/utils.js
@@ -0,0 +1,39 @@
+const path = require('path');
+
+const tsconfig = require('../tsconfig.json');
+
+module.exports = {
+ root,
+ mapTypescriptAliasToWebpackAlias,
+};
+
+const _root = path.resolve(__dirname, '..');
+
+function root(args) {
+ args = Array.prototype.slice.call(arguments, 0);
+ return path.join.apply(path, [_root].concat(args));
+}
+
+function mapTypescriptAliasToWebpackAlias(alias = {}) {
+ const webpackAliases = { ...alias };
+ if (!tsconfig.compilerOptions.paths) {
+ return webpackAliases;
+ }
+ Object.entries(tsconfig.compilerOptions.paths)
+ .filter(([key, value]) => {
+ // use Typescript alias in Webpack only if this has value
+ return !!value.length;
+ })
+ .map(([key, value]) => {
+ // if Typescript alias ends with /* then remove this for Webpack
+ const regexToReplace = /\/\*$/;
+ const aliasKey = key.replace(regexToReplace, '');
+ const aliasValue = value[0].replace(regexToReplace, '');
+ return [aliasKey, root(aliasValue)];
+ })
+ .reduce((aliases, [key, value]) => {
+ aliases[key] = value;
+ return aliases;
+ }, webpackAliases);
+ return webpackAliases;
+}
diff --git a/myApp/webpack/webpack.common.js b/myApp/webpack/webpack.common.js
new file mode 100644
index 000000000..1afdd4842
--- /dev/null
+++ b/myApp/webpack/webpack.common.js
@@ -0,0 +1,153 @@
+const path = require('path');
+const webpack = require('webpack');
+const { merge } = require('webpack-merge');
+const CopyWebpackPlugin = require('copy-webpack-plugin');
+const HtmlWebpackPlugin = require('html-webpack-plugin');
+const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
+const ESLintPlugin = require('eslint-webpack-plugin');
+const { hashElement } = require('folder-hash');
+const MergeJsonWebpackPlugin = require('merge-jsons-webpack-plugin');
+const utils = require('./utils.js');
+const environment = require('./environment');
+
+const getTsLoaderRule = env => {
+ const rules = [
+ {
+ loader: 'thread-loader',
+ options: {
+ // There should be 1 cpu for the fork-ts-checker-webpack-plugin.
+ // The value may need to be adjusted (e.g. to 1) in some CI environments,
+ // as cpus() may report more cores than what are available to the build.
+ workers: require('os').cpus().length - 1,
+ },
+ },
+ {
+ loader: 'ts-loader',
+ options: {
+ transpileOnly: true,
+ happyPackMode: true,
+ },
+ },
+ ];
+ return rules;
+};
+
+module.exports = async options => {
+ const development = options.env === 'development';
+ const languagesHash = await hashElement(path.resolve(__dirname, '../src/main/webapp/i18n'), {
+ algo: 'md5',
+ encoding: 'hex',
+ files: { include: ['*.json'] },
+ });
+
+ return merge(
+ {
+ cache: {
+ // 1. Set cache type to filesystem
+ type: 'filesystem',
+ cacheDirectory: path.resolve(__dirname, '../target/webpack'),
+ buildDependencies: {
+ // 2. Add your config as buildDependency to get cache invalidation on config change
+ config: [
+ __filename,
+ path.resolve(__dirname, `webpack.${development ? 'dev' : 'prod'}.js`),
+ path.resolve(__dirname, 'environment.js'),
+ path.resolve(__dirname, 'utils.js'),
+ path.resolve(__dirname, '../postcss.config.js'),
+ path.resolve(__dirname, '../tsconfig.json'),
+ ],
+ },
+ },
+ resolve: {
+ extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
+ modules: ['node_modules'],
+ alias: utils.mapTypescriptAliasToWebpackAlias(),
+ fallback: {
+ path: require.resolve('path-browserify'),
+ },
+ },
+ module: {
+ rules: [
+ {
+ test: /\.tsx?$/,
+ use: getTsLoaderRule(options.env),
+ include: [utils.root('./src/main/webapp/app')],
+ exclude: [utils.root('node_modules')],
+ },
+ /*
+ ,
+ Disabled due to https://github.com/jhipster/generator-jhipster/issues/16116
+ Can be enabled with @reduxjs/toolkit@>1.6.1
+ {
+ enforce: 'pre',
+ test: /\.jsx?$/,
+ loader: 'source-map-loader'
+ }
+ */
+ ],
+ },
+ stats: {
+ children: false,
+ },
+ optimization: {
+ splitChunks: {
+ cacheGroups: {
+ commons: {
+ test: /[\\/]node_modules[\\/]/,
+ name: 'vendors',
+ chunks: 'all',
+ },
+ },
+ },
+ },
+ plugins: [
+ new webpack.EnvironmentPlugin({
+ // react-jhipster requires LOG_LEVEL config.
+ LOG_LEVEL: development ? 'info' : 'error',
+ }),
+ new webpack.DefinePlugin({
+ I18N_HASH: JSON.stringify(languagesHash.hash),
+ DEVELOPMENT: JSON.stringify(development),
+ VERSION: JSON.stringify(environment.VERSION),
+ SERVER_API_URL: JSON.stringify(environment.SERVER_API_URL),
+ }),
+ new ESLintPlugin({
+ extensions: ['js', 'ts', 'jsx', 'tsx'],
+ }),
+ new ForkTsCheckerWebpackPlugin(),
+ new CopyWebpackPlugin({
+ patterns: [
+ {
+ context: './node_modules/swagger-ui-dist/',
+ from: '*.{js,css,html,png}',
+ to: 'swagger-ui/',
+ globOptions: { ignore: ['**/index.html'] },
+ },
+ { from: './node_modules/axios/dist/axios.min.js', to: 'swagger-ui/' },
+ { from: './src/main/webapp/swagger-ui/', to: 'swagger-ui/' },
+ { from: './src/main/webapp/content/', to: 'content/' },
+ { from: './src/main/webapp/favicon.ico', to: 'favicon.ico' },
+ { from: './src/main/webapp/manifest.webapp', to: 'manifest.webapp' },
+ // jhipster-needle-add-assets-to-webpack - JHipster will add/remove third-party resources in this array
+ { from: './src/main/webapp/robots.txt', to: 'robots.txt' },
+ ],
+ }),
+ new HtmlWebpackPlugin({
+ template: './src/main/webapp/index.html',
+ chunksSortMode: 'auto',
+ inject: 'body',
+ base: '/',
+ }),
+ new MergeJsonWebpackPlugin({
+ output: {
+ groupBy: [
+ { pattern: './src/main/webapp/i18n/en/*.json', fileName: './i18n/en.json' },
+ // jhipster-needle-i18n-language-webpack - JHipster will add/remove languages in this array
+ ],
+ },
+ }),
+ ],
+ }
+ // jhipster-needle-add-webpack-config - JHipster will add custom config
+ );
+};
diff --git a/myApp/webpack/webpack.dev.js b/myApp/webpack/webpack.dev.js
new file mode 100644
index 000000000..ca6d75499
--- /dev/null
+++ b/myApp/webpack/webpack.dev.js
@@ -0,0 +1,103 @@
+const webpack = require('webpack');
+const webpackMerge = require('webpack-merge').merge;
+const BrowserSyncPlugin = require('browser-sync-webpack-plugin');
+const SimpleProgressWebpackPlugin = require('simple-progress-webpack-plugin');
+const WebpackNotifierPlugin = require('webpack-notifier');
+const path = require('path');
+const sass = require('sass');
+
+const utils = require('./utils.js');
+const commonConfig = require('./webpack.common.js');
+
+const ENV = 'development';
+
+module.exports = async options =>
+ webpackMerge(await commonConfig({ env: ENV }), {
+ devtool: 'cheap-module-source-map', // https://reactjs.org/docs/cross-origin-errors.html
+ mode: ENV,
+ entry: ['./src/main/webapp/app/index'],
+ output: {
+ path: utils.root('target/classes/static/'),
+ filename: 'app/[name].bundle.js',
+ chunkFilename: 'app/[id].chunk.js',
+ },
+ optimization: {
+ moduleIds: 'named',
+ },
+ module: {
+ rules: [
+ {
+ test: /\.(sa|sc|c)ss$/,
+ use: [
+ 'style-loader',
+ 'css-loader',
+ {
+ loader: 'postcss-loader',
+ },
+ {
+ loader: 'sass-loader',
+ options: { implementation: sass },
+ },
+ ],
+ },
+ ],
+ },
+ devServer: {
+ hot: true,
+ static: {
+ directory: './target/classes/static/',
+ },
+ port: 9060,
+ proxy: [
+ {
+ context: ['/api', '/services', '/management', '/v3/api-docs', '/h2-console', '/auth'],
+ target: `http${options.tls ? 's' : ''}://localhost:8080`,
+ secure: false,
+ changeOrigin: options.tls,
+ },
+ ],
+ https: options.tls,
+ historyApiFallback: true,
+ },
+ stats: process.env.JHI_DISABLE_WEBPACK_LOGS ? 'none' : options.stats,
+ plugins: [
+ process.env.JHI_DISABLE_WEBPACK_LOGS
+ ? null
+ : new SimpleProgressWebpackPlugin({
+ format: options.stats === 'minimal' ? 'compact' : 'expanded',
+ }),
+ new BrowserSyncPlugin(
+ {
+ https: options.tls,
+ host: 'localhost',
+ port: 9000,
+ proxy: {
+ target: `http${options.tls ? 's' : ''}://localhost:9060`,
+ proxyOptions: {
+ changeOrigin: false, //pass the Host header to the backend unchanged https://github.com/Browsersync/browser-sync/issues/430
+ },
+ },
+ socket: {
+ clients: {
+ heartbeatTimeout: 60000,
+ },
+ },
+ /*
+ ,ghostMode: { // uncomment this part to disable BrowserSync ghostMode; https://github.com/jhipster/generator-jhipster/issues/11116
+ clicks: false,
+ location: false,
+ forms: false,
+ scroll: false
+ } */
+ },
+ {
+ reload: false,
+ }
+ ),
+ new webpack.HotModuleReplacementPlugin(),
+ new WebpackNotifierPlugin({
+ title: 'My App',
+ contentImage: path.join(__dirname, 'logo-jhipster.png'),
+ }),
+ ].filter(Boolean),
+ });
diff --git a/myApp/webpack/webpack.prod.js b/myApp/webpack/webpack.prod.js
new file mode 100644
index 000000000..9393d124f
--- /dev/null
+++ b/myApp/webpack/webpack.prod.js
@@ -0,0 +1,99 @@
+const webpack = require('webpack');
+const webpackMerge = require('webpack-merge').merge;
+const MiniCssExtractPlugin = require('mini-css-extract-plugin');
+const WorkboxPlugin = require('workbox-webpack-plugin');
+const TerserPlugin = require('terser-webpack-plugin');
+const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
+const sass = require('sass');
+
+const utils = require('./utils.js');
+const commonConfig = require('./webpack.common.js');
+
+const ENV = 'production';
+
+module.exports = async () =>
+ webpackMerge(await commonConfig({ env: ENV }), {
+ // devtool: 'source-map', // Enable source maps. Please note that this will slow down the build
+ mode: ENV,
+ entry: {
+ main: './src/main/webapp/app/index',
+ },
+ output: {
+ path: utils.root('target/classes/static/'),
+ filename: 'app/[name].[contenthash].bundle.js',
+ chunkFilename: 'app/[name].[chunkhash].chunk.js',
+ },
+ module: {
+ rules: [
+ {
+ test: /\.(sa|sc|c)ss$/,
+ use: [
+ {
+ loader: MiniCssExtractPlugin.loader,
+ options: {
+ publicPath: '../',
+ },
+ },
+ 'css-loader',
+ {
+ loader: 'postcss-loader',
+ },
+ {
+ loader: 'sass-loader',
+ options: { implementation: sass },
+ },
+ ],
+ },
+ ],
+ },
+ optimization: {
+ runtimeChunk: false,
+ minimizer: [
+ new TerserPlugin({
+ parallel: true,
+ // sourceMap: true, // Enable source maps. Please note that this will slow down the build
+ terserOptions: {
+ ecma: 6,
+ toplevel: true,
+ module: true,
+ compress: {
+ warnings: false,
+ ecma: 6,
+ module: true,
+ toplevel: true,
+ },
+ output: {
+ comments: false,
+ beautify: false,
+ indent_level: 2,
+ ecma: 6,
+ },
+ mangle: {
+ keep_fnames: true,
+ module: true,
+ toplevel: true,
+ },
+ },
+ }),
+ new CssMinimizerPlugin({
+ parallel: true,
+ }),
+ ],
+ },
+ plugins: [
+ new MiniCssExtractPlugin({
+ // Options similar to the same options in webpackOptions.output
+ filename: 'content/[name].[contenthash].css',
+ chunkFilename: 'content/[name].[chunkhash].css',
+ }),
+ new webpack.LoaderOptionsPlugin({
+ minimize: true,
+ debug: false,
+ }),
+ new WorkboxPlugin.GenerateSW({
+ clientsClaim: true,
+ skipWaiting: true,
+ exclude: [/swagger-ui/],
+ }),
+ ],
+ });
diff --git a/myApp/yarn.lock b/myApp/yarn.lock
new file mode 100644
index 000000000..bf8a879fb
--- /dev/null
+++ b/myApp/yarn.lock
@@ -0,0 +1,11326 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@apideck/better-ajv-errors@^0.3.1":
+ "integrity" "sha512-JdEazx7qiVqTBzzBl5rolRwl5cmhihjfIcpqRzIZjtT6b18liVmDn/VlWpqW4C/qP2hrFFMLRV1wlex8ZVBPTg=="
+ "resolved" "https://registry.npmjs.org/@apideck/better-ajv-errors/-/better-ajv-errors-0.3.2.tgz"
+ "version" "0.3.2"
+ dependencies:
+ "json-schema" "^0.4.0"
+ "jsonpointer" "^5.0.0"
+ "leven" "^3.1.0"
+
+"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.12.13", "@babel/code-frame@^7.16.7", "@babel/code-frame@^7.8.3":
+ "integrity" "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg=="
+ "resolved" "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/highlight" "^7.16.7"
+
+"@babel/compat-data@^7.13.11", "@babel/compat-data@^7.16.4":
+ "integrity" "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q=="
+ "resolved" "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.16.4.tgz"
+ "version" "7.16.4"
+
+"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.1.0", "@babel/core@^7.11.1", "@babel/core@^7.12.0", "@babel/core@^7.12.3", "@babel/core@^7.13.0", "@babel/core@^7.4.0-0", "@babel/core@^7.7.2", "@babel/core@^7.8.0", "@babel/core@>=7.0.0-beta.0 <8":
+ "integrity" "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA=="
+ "resolved" "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/code-frame" "^7.16.7"
+ "@babel/generator" "^7.16.7"
+ "@babel/helper-compilation-targets" "^7.16.7"
+ "@babel/helper-module-transforms" "^7.16.7"
+ "@babel/helpers" "^7.16.7"
+ "@babel/parser" "^7.16.7"
+ "@babel/template" "^7.16.7"
+ "@babel/traverse" "^7.16.7"
+ "@babel/types" "^7.16.7"
+ "convert-source-map" "^1.7.0"
+ "debug" "^4.1.0"
+ "gensync" "^1.0.0-beta.2"
+ "json5" "^2.1.2"
+ "semver" "^6.3.0"
+ "source-map" "^0.5.0"
+
+"@babel/generator@^7.16.7", "@babel/generator@^7.7.2":
+ "integrity" "sha512-/ST3Sg8MLGY5HVYmrjOgL60ENux/HfO/CsUh7y4MalThufhE/Ff/6EibFDHi4jiDCaWfJKoqbE6oTh21c5hrRg=="
+ "resolved" "https://registry.npmjs.org/@babel/generator/-/generator-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+ "jsesc" "^2.5.1"
+ "source-map" "^0.5.0"
+
+"@babel/helper-annotate-as-pure@^7.16.7":
+ "integrity" "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.16.7":
+ "integrity" "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-explode-assignable-expression" "^7.16.7"
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-compilation-targets@^7.13.0", "@babel/helper-compilation-targets@^7.16.7":
+ "integrity" "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/compat-data" "^7.16.4"
+ "@babel/helper-validator-option" "^7.16.7"
+ "browserslist" "^4.17.5"
+ "semver" "^6.3.0"
+
+"@babel/helper-create-class-features-plugin@^7.16.7":
+ "integrity" "sha512-kIFozAvVfK05DM4EVQYKK+zteWvY85BFdGBRQBytRyY3y+6PX0DkDOn/CZ3lEuczCfrCxEzwt0YtP/87YPTWSw=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.16.7"
+ "@babel/helper-environment-visitor" "^7.16.7"
+ "@babel/helper-function-name" "^7.16.7"
+ "@babel/helper-member-expression-to-functions" "^7.16.7"
+ "@babel/helper-optimise-call-expression" "^7.16.7"
+ "@babel/helper-replace-supers" "^7.16.7"
+ "@babel/helper-split-export-declaration" "^7.16.7"
+
+"@babel/helper-create-regexp-features-plugin@^7.16.7":
+ "integrity" "sha512-fk5A6ymfp+O5+p2yCkXAu5Kyj6v0xh0RBeNcAkYUMDvvAAoxvSKXn+Jb37t/yWFiQVDFK1ELpUTD8/aLhCPu+g=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.16.7"
+ "regexpu-core" "^4.7.1"
+
+"@babel/helper-define-polyfill-provider@^0.3.0":
+ "integrity" "sha512-7hfT8lUljl/tM3h+izTX/pO3W3frz2ok6Pk+gzys8iJqDfZrZy2pXjRTZAvG2YmfHun1X4q8/UZRLatMfqc5Tg=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.0.tgz"
+ "version" "0.3.0"
+ dependencies:
+ "@babel/helper-compilation-targets" "^7.13.0"
+ "@babel/helper-module-imports" "^7.12.13"
+ "@babel/helper-plugin-utils" "^7.13.0"
+ "@babel/traverse" "^7.13.0"
+ "debug" "^4.1.1"
+ "lodash.debounce" "^4.0.8"
+ "resolve" "^1.14.2"
+ "semver" "^6.1.2"
+
+"@babel/helper-environment-visitor@^7.16.7":
+ "integrity" "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-explode-assignable-expression@^7.16.7":
+ "integrity" "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-function-name@^7.16.7":
+ "integrity" "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-get-function-arity" "^7.16.7"
+ "@babel/template" "^7.16.7"
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-get-function-arity@^7.16.7":
+ "integrity" "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-hoist-variables@^7.16.7":
+ "integrity" "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-member-expression-to-functions@^7.16.7":
+ "integrity" "sha512-VtJ/65tYiU/6AbMTDwyoXGPKHgTsfRarivm+YbB5uAzKUyuPjgZSgAFeG87FCigc7KNHu2Pegh1XIT3lXjvz3Q=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-module-imports@^7.10.4", "@babel/helper-module-imports@^7.12.13", "@babel/helper-module-imports@^7.16.7":
+ "integrity" "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-module-transforms@^7.16.7":
+ "integrity" "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.16.7"
+ "@babel/helper-module-imports" "^7.16.7"
+ "@babel/helper-simple-access" "^7.16.7"
+ "@babel/helper-split-export-declaration" "^7.16.7"
+ "@babel/helper-validator-identifier" "^7.16.7"
+ "@babel/template" "^7.16.7"
+ "@babel/traverse" "^7.16.7"
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-optimise-call-expression@^7.16.7":
+ "integrity" "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.13.0", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.16.7", "@babel/helper-plugin-utils@^7.8.0", "@babel/helper-plugin-utils@^7.8.3":
+ "integrity" "sha512-Qg3Nk7ZxpgMrsox6HreY1ZNKdBq7K72tDSliA6dCl5f007jR4ne8iD5UzuNnCJH2xBf2BEEVGr+/OL6Gdp7RxA=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.16.7.tgz"
+ "version" "7.16.7"
+
+"@babel/helper-remap-async-to-generator@^7.16.7":
+ "integrity" "sha512-C3o117GnP/j/N2OWo+oepeWbFEKRfNaay+F1Eo5Mj3A1SRjyx+qaFhm23nlipub7Cjv2azdUUiDH+VlpdwUFRg=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.16.7"
+ "@babel/helper-wrap-function" "^7.16.7"
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-replace-supers@^7.16.7":
+ "integrity" "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-environment-visitor" "^7.16.7"
+ "@babel/helper-member-expression-to-functions" "^7.16.7"
+ "@babel/helper-optimise-call-expression" "^7.16.7"
+ "@babel/traverse" "^7.16.7"
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-simple-access@^7.16.7":
+ "integrity" "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-skip-transparent-expression-wrappers@^7.16.0":
+ "integrity" "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz"
+ "version" "7.16.0"
+ dependencies:
+ "@babel/types" "^7.16.0"
+
+"@babel/helper-split-export-declaration@^7.16.7":
+ "integrity" "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/types" "^7.16.7"
+
+"@babel/helper-validator-identifier@^7.16.7":
+ "integrity" "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz"
+ "version" "7.16.7"
+
+"@babel/helper-validator-option@^7.16.7":
+ "integrity" "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz"
+ "version" "7.16.7"
+
+"@babel/helper-wrap-function@^7.16.7":
+ "integrity" "sha512-7a9sABeVwcunnztZZ7WTgSw6jVYLzM1wua0Z4HIXm9S3/HC96WKQTkFgGEaj5W06SHHihPJ6Le6HzS5cGOQMNw=="
+ "resolved" "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-function-name" "^7.16.7"
+ "@babel/template" "^7.16.7"
+ "@babel/traverse" "^7.16.7"
+ "@babel/types" "^7.16.7"
+
+"@babel/helpers@^7.16.7":
+ "integrity" "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw=="
+ "resolved" "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/template" "^7.16.7"
+ "@babel/traverse" "^7.16.7"
+ "@babel/types" "^7.16.7"
+
+"@babel/highlight@^7.16.7":
+ "integrity" "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw=="
+ "resolved" "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.16.7"
+ "chalk" "^2.0.0"
+ "js-tokens" "^4.0.0"
+
+"@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.16.7":
+ "integrity" "sha512-sR4eaSrnM7BV7QPzGfEX5paG/6wrZM3I0HDzfIAK06ESvo9oy3xBuVBxE3MbQaKNhvg8g/ixjMWo2CGpzpHsDA=="
+ "resolved" "https://registry.npmjs.org/@babel/parser/-/parser-7.16.7.tgz"
+ "version" "7.16.7"
+
+"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@^7.16.7":
+ "integrity" "sha512-anv/DObl7waiGEnC24O9zqL0pSuI9hljihqiDuFHC8d7/bjr/4RLGPWuc8rYOff/QPzbEPSkzG8wGG9aDuhHRg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@^7.16.7":
+ "integrity" "sha512-di8vUHRdf+4aJ7ltXhaDbPoszdkh59AQtJM5soLsuHpQJdFQZOA4uGj0V2u/CZ8bJ/u8ULDL5yq6FO/bCXnKHw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0"
+ "@babel/plugin-proposal-optional-chaining" "^7.16.7"
+
+"@babel/plugin-proposal-async-generator-functions@^7.16.7":
+ "integrity" "sha512-TTXBT3A5c11eqRzaC6beO6rlFT3Mo9C2e8eB44tTr52ESXSK2CIc2fOp1ynpAwQA8HhBMho+WXhMHWlAe3xkpw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-remap-async-to-generator" "^7.16.7"
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+
+"@babel/plugin-proposal-class-properties@^7.16.7":
+ "integrity" "sha512-IobU0Xme31ewjYOShSIqd/ZGM/r/cuOz2z0MDbNrhF5FW+ZVgi0f2lyeoj9KFPDOAqsYxmLWZte1WOwlvY9aww=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-proposal-class-static-block@^7.16.7":
+ "integrity" "sha512-dgqJJrcZoG/4CkMopzhPJjGxsIe9A8RlkQLnL/Vhhx8AA9ZuaRwGSlscSh42hazc7WSrya/IK7mTeoF0DP9tEw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-class-static-block" "^7.14.5"
+
+"@babel/plugin-proposal-dynamic-import@^7.16.7":
+ "integrity" "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-dynamic-import" "^7.8.3"
+
+"@babel/plugin-proposal-export-namespace-from@^7.16.7":
+ "integrity" "sha512-ZxdtqDXLRGBL64ocZcs7ovt71L3jhC1RGSyR996svrCi3PYqHNkb3SwPJCs8RIzD86s+WPpt2S73+EHCGO+NUA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
+
+"@babel/plugin-proposal-json-strings@^7.16.7":
+ "integrity" "sha512-lNZ3EEggsGY78JavgbHsK9u5P3pQaW7k4axlgFLYkMd7UBsiNahCITShLjNQschPyjtO6dADrL24757IdhBrsQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+
+"@babel/plugin-proposal-logical-assignment-operators@^7.16.7":
+ "integrity" "sha512-K3XzyZJGQCr00+EtYtrDjmwX7o7PLK6U9bi1nCwkQioRFVUv6dJoxbQjtWVtP+bCPy82bONBKG8NPyQ4+i6yjg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+
+"@babel/plugin-proposal-nullish-coalescing-operator@^7.16.7":
+ "integrity" "sha512-aUOrYU3EVtjf62jQrCj63pYZ7k6vns2h/DQvHPWGmsJRYzWXZ6/AsfgpiRy6XiuIDADhJzP2Q9MwSMKauBQ+UQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+
+"@babel/plugin-proposal-numeric-separator@^7.16.7":
+ "integrity" "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-numeric-separator" "^7.10.4"
+
+"@babel/plugin-proposal-object-rest-spread@^7.16.7":
+ "integrity" "sha512-3O0Y4+dw94HA86qSg9IHfyPktgR7q3gpNVAeiKQd+8jBKFaU5NQS1Yatgo4wY+UFNuLjvxcSmzcsHqrhgTyBUA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/compat-data" "^7.16.4"
+ "@babel/helper-compilation-targets" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-transform-parameters" "^7.16.7"
+
+"@babel/plugin-proposal-optional-catch-binding@^7.16.7":
+ "integrity" "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+
+"@babel/plugin-proposal-optional-chaining@^7.16.7":
+ "integrity" "sha512-eC3xy+ZrUcBtP7x+sq62Q/HYd674pPTb/77XZMb5wbDPGWIdUbSr4Agr052+zaUPSb+gGRnjxXfKFvx5iMJ+DA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+
+"@babel/plugin-proposal-private-methods@^7.16.7":
+ "integrity" "sha512-7twV3pzhrRxSwHeIvFE6coPgvo+exNDOiGUMg39o2LiLo1Y+4aKpfkcLGcg1UHonzorCt7SNXnoMyCnnIOA8Sw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-create-class-features-plugin" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-proposal-private-property-in-object@^7.16.7":
+ "integrity" "sha512-rMQkjcOFbm+ufe3bTZLyOfsOUOxyvLXZJCTARhJr+8UMSoZmqTe1K1BgkFcrW37rAchWg57yI69ORxiWvUINuQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.16.7"
+ "@babel/helper-create-class-features-plugin" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
+
+"@babel/plugin-proposal-unicode-property-regex@^7.16.7", "@babel/plugin-proposal-unicode-property-regex@^7.4.4":
+ "integrity" "sha512-QRK0YI/40VLhNVGIjRNAAQkEHws0cswSdFFjpFyt943YmJIU1da9uW63Iu6NFV6CxTZW5eTDCrwZUstBWgp/Rg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-syntax-async-generators@^7.8.4":
+ "integrity" "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz"
+ "version" "7.8.4"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-bigint@^7.8.3":
+ "integrity" "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz"
+ "version" "7.8.3"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3":
+ "integrity" "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz"
+ "version" "7.12.13"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.12.13"
+
+"@babel/plugin-syntax-class-static-block@^7.14.5":
+ "integrity" "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz"
+ "version" "7.14.5"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-dynamic-import@^7.8.3":
+ "integrity" "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz"
+ "version" "7.8.3"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-export-namespace-from@^7.8.3":
+ "integrity" "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz"
+ "version" "7.8.3"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.3"
+
+"@babel/plugin-syntax-import-meta@^7.8.3":
+ "integrity" "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz"
+ "version" "7.10.4"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-json-strings@^7.8.3":
+ "integrity" "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz"
+ "version" "7.8.3"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3":
+ "integrity" "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz"
+ "version" "7.10.4"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3":
+ "integrity" "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz"
+ "version" "7.8.3"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3":
+ "integrity" "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz"
+ "version" "7.10.4"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.10.4"
+
+"@babel/plugin-syntax-object-rest-spread@^7.8.3":
+ "integrity" "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz"
+ "version" "7.8.3"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-catch-binding@^7.8.3":
+ "integrity" "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz"
+ "version" "7.8.3"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-optional-chaining@^7.8.3":
+ "integrity" "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz"
+ "version" "7.8.3"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.8.0"
+
+"@babel/plugin-syntax-private-property-in-object@^7.14.5":
+ "integrity" "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz"
+ "version" "7.14.5"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3":
+ "integrity" "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz"
+ "version" "7.14.5"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.14.5"
+
+"@babel/plugin-syntax-typescript@^7.7.2":
+ "integrity" "sha512-YhUIJHHGkqPgEcMYkPCKTyGUdoGKWtopIycQyjJH8OjvRgOYsXsaKehLVPScKJWAULPxMa4N1vCe6szREFlZ7A=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-arrow-functions@^7.16.7":
+ "integrity" "sha512-9ffkFFMbvzTvv+7dTp/66xvZAWASuPD5Tl9LK3Z9vhOmANo6j94rik+5YMBt4CwHVMWLWpMsriIc2zsa3WW3xQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-async-to-generator@^7.16.7":
+ "integrity" "sha512-pFEfjnK4DfXCfAlA5I98BYdDJD8NltMzx19gt6DAmfE+2lXRfPUoa0/5SUjT4+TDE1W/rcxU/1lgN55vpAjjdg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-module-imports" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-remap-async-to-generator" "^7.16.7"
+
+"@babel/plugin-transform-block-scoped-functions@^7.16.7":
+ "integrity" "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-block-scoping@^7.16.7":
+ "integrity" "sha512-ObZev2nxVAYA4bhyusELdo9hb3H+A56bxH3FZMbEImZFiEDYVHXQSJ1hQKFlDnlt8G9bBrCZ5ZpURZUrV4G5qQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-classes@^7.16.7":
+ "integrity" "sha512-WY7og38SFAGYRe64BrjKf8OrE6ulEHtr5jEYaZMwox9KebgqPi67Zqz8K53EKk1fFEJgm96r32rkKZ3qA2nCWQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-annotate-as-pure" "^7.16.7"
+ "@babel/helper-environment-visitor" "^7.16.7"
+ "@babel/helper-function-name" "^7.16.7"
+ "@babel/helper-optimise-call-expression" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-replace-supers" "^7.16.7"
+ "@babel/helper-split-export-declaration" "^7.16.7"
+ "globals" "^11.1.0"
+
+"@babel/plugin-transform-computed-properties@^7.16.7":
+ "integrity" "sha512-gN72G9bcmenVILj//sv1zLNaPyYcOzUho2lIJBMh/iakJ9ygCo/hEF9cpGb61SCMEDxbbyBoVQxrt+bWKu5KGw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-destructuring@^7.16.7":
+ "integrity" "sha512-VqAwhTHBnu5xBVDCvrvqJbtLUa++qZaWC0Fgr2mqokBlulZARGyIvZDoqbPlPaKImQ9dKAcCzbv+ul//uqu70A=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-dotall-regex@^7.16.7", "@babel/plugin-transform-dotall-regex@^7.4.4":
+ "integrity" "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-duplicate-keys@^7.16.7":
+ "integrity" "sha512-03DvpbRfvWIXyK0/6QiR1KMTWeT6OcQ7tbhjrXyFS02kjuX/mu5Bvnh5SDSWHxyawit2g5aWhKwI86EE7GUnTw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-exponentiation-operator@^7.16.7":
+ "integrity" "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-builder-binary-assignment-operator-visitor" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-for-of@^7.16.7":
+ "integrity" "sha512-/QZm9W92Ptpw7sjI9Nx1mbcsWz33+l8kuMIQnDwgQBG5s3fAfQvkRjQ7NqXhtNcKOnPkdICmUHyCaWW06HCsqg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-function-name@^7.16.7":
+ "integrity" "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-compilation-targets" "^7.16.7"
+ "@babel/helper-function-name" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-literals@^7.16.7":
+ "integrity" "sha512-6tH8RTpTWI0s2sV6uq3e/C9wPo4PTqqZps4uF0kzQ9/xPLFQtipynvmT1g/dOfEJ+0EQsHhkQ/zyRId8J2b8zQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-member-expression-literals@^7.16.7":
+ "integrity" "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-modules-amd@^7.16.7":
+ "integrity" "sha512-KaaEtgBL7FKYwjJ/teH63oAmE3lP34N3kshz8mm4VMAw7U3PxjVwwUmxEFksbgsNUaO3wId9R2AVQYSEGRa2+g=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-module-transforms" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "babel-plugin-dynamic-import-node" "^2.3.3"
+
+"@babel/plugin-transform-modules-commonjs@^7.16.7":
+ "integrity" "sha512-h2RP2kE7He1ZWKyAlanMZrAbdv+Acw1pA8dQZhE025WJZE2z0xzFADAinXA9fxd5bn7JnM+SdOGcndGx1ARs9w=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-module-transforms" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-simple-access" "^7.16.7"
+ "babel-plugin-dynamic-import-node" "^2.3.3"
+
+"@babel/plugin-transform-modules-systemjs@^7.16.7":
+ "integrity" "sha512-DuK5E3k+QQmnOqBR9UkusByy5WZWGRxfzV529s9nPra1GE7olmxfqO2FHobEOYSPIjPBTr4p66YDcjQnt8cBmw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-hoist-variables" "^7.16.7"
+ "@babel/helper-module-transforms" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-validator-identifier" "^7.16.7"
+ "babel-plugin-dynamic-import-node" "^2.3.3"
+
+"@babel/plugin-transform-modules-umd@^7.16.7":
+ "integrity" "sha512-EMh7uolsC8O4xhudF2F6wedbSHm1HHZ0C6aJ7K67zcDNidMzVcxWdGr+htW9n21klm+bOn+Rx4CBsAntZd3rEQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-module-transforms" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-named-capturing-groups-regex@^7.16.7":
+ "integrity" "sha512-kFy35VwmwIQwCjwrAQhl3+c/kr292i4KdLPKp5lPH03Ltc51qnFlIADoyPxc/6Naz3ok3WdYKg+KK6AH+D4utg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.16.7"
+
+"@babel/plugin-transform-new-target@^7.16.7":
+ "integrity" "sha512-xiLDzWNMfKoGOpc6t3U+etCE2yRnn3SM09BXqWPIZOBpL2gvVrBWUKnsJx0K/ADi5F5YC5f8APFfWrz25TdlGg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-object-super@^7.16.7":
+ "integrity" "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-replace-supers" "^7.16.7"
+
+"@babel/plugin-transform-parameters@^7.16.7":
+ "integrity" "sha512-AT3MufQ7zZEhU2hwOA11axBnExW0Lszu4RL/tAlUJBuNoRak+wehQW8h6KcXOcgjY42fHtDxswuMhMjFEuv/aw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-property-literals@^7.16.7":
+ "integrity" "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-regenerator@^7.16.7":
+ "integrity" "sha512-mF7jOgGYCkSJagJ6XCujSQg+6xC1M77/03K2oBmVJWoFGNUtnVJO4WHKJk3dnPC8HCcj4xBQP1Egm8DWh3Pb3Q=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "regenerator-transform" "^0.14.2"
+
+"@babel/plugin-transform-reserved-words@^7.16.7":
+ "integrity" "sha512-KQzzDnZ9hWQBjwi5lpY5v9shmm6IVG0U9pB18zvMu2i4H90xpT4gmqwPYsn8rObiadYe2M0gmgsiOIF5A/2rtg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-shorthand-properties@^7.16.7":
+ "integrity" "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-spread@^7.16.7":
+ "integrity" "sha512-+pjJpgAngb53L0iaA5gU/1MLXJIfXcYepLgXB3esVRf4fqmj8f2cxM3/FKaHsZms08hFQJkFccEWuIpm429TXg=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-skip-transparent-expression-wrappers" "^7.16.0"
+
+"@babel/plugin-transform-sticky-regex@^7.16.7":
+ "integrity" "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-template-literals@^7.16.7":
+ "integrity" "sha512-VwbkDDUeenlIjmfNeDX/V0aWrQH2QiVyJtwymVQSzItFDTpxfyJh3EVaQiS0rIN/CqbLGr0VcGmuwyTdZtdIsA=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-typeof-symbol@^7.16.7":
+ "integrity" "sha512-p2rOixCKRJzpg9JB4gjnG4gjWkWa89ZoYUnl9snJ1cWIcTH/hvxZqfO+WjG6T8DRBpctEol5jw1O5rA8gkCokQ=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-unicode-escapes@^7.16.7":
+ "integrity" "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/plugin-transform-unicode-regex@^7.16.7":
+ "integrity" "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q=="
+ "resolved" "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-create-regexp-features-plugin" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+
+"@babel/preset-env@^7.11.0":
+ "integrity" "sha512-urX3Cee4aOZbRWOSa3mKPk0aqDikfILuo+C7qq7HY0InylGNZ1fekq9jmlr3pLWwZHF4yD7heQooc2Pow2KMyQ=="
+ "resolved" "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/compat-data" "^7.16.4"
+ "@babel/helper-compilation-targets" "^7.16.7"
+ "@babel/helper-plugin-utils" "^7.16.7"
+ "@babel/helper-validator-option" "^7.16.7"
+ "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression" "^7.16.7"
+ "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining" "^7.16.7"
+ "@babel/plugin-proposal-async-generator-functions" "^7.16.7"
+ "@babel/plugin-proposal-class-properties" "^7.16.7"
+ "@babel/plugin-proposal-class-static-block" "^7.16.7"
+ "@babel/plugin-proposal-dynamic-import" "^7.16.7"
+ "@babel/plugin-proposal-export-namespace-from" "^7.16.7"
+ "@babel/plugin-proposal-json-strings" "^7.16.7"
+ "@babel/plugin-proposal-logical-assignment-operators" "^7.16.7"
+ "@babel/plugin-proposal-nullish-coalescing-operator" "^7.16.7"
+ "@babel/plugin-proposal-numeric-separator" "^7.16.7"
+ "@babel/plugin-proposal-object-rest-spread" "^7.16.7"
+ "@babel/plugin-proposal-optional-catch-binding" "^7.16.7"
+ "@babel/plugin-proposal-optional-chaining" "^7.16.7"
+ "@babel/plugin-proposal-private-methods" "^7.16.7"
+ "@babel/plugin-proposal-private-property-in-object" "^7.16.7"
+ "@babel/plugin-proposal-unicode-property-regex" "^7.16.7"
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+ "@babel/plugin-syntax-class-properties" "^7.12.13"
+ "@babel/plugin-syntax-class-static-block" "^7.14.5"
+ "@babel/plugin-syntax-dynamic-import" "^7.8.3"
+ "@babel/plugin-syntax-export-namespace-from" "^7.8.3"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.10.4"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-syntax-numeric-separator" "^7.10.4"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+ "@babel/plugin-syntax-private-property-in-object" "^7.14.5"
+ "@babel/plugin-syntax-top-level-await" "^7.14.5"
+ "@babel/plugin-transform-arrow-functions" "^7.16.7"
+ "@babel/plugin-transform-async-to-generator" "^7.16.7"
+ "@babel/plugin-transform-block-scoped-functions" "^7.16.7"
+ "@babel/plugin-transform-block-scoping" "^7.16.7"
+ "@babel/plugin-transform-classes" "^7.16.7"
+ "@babel/plugin-transform-computed-properties" "^7.16.7"
+ "@babel/plugin-transform-destructuring" "^7.16.7"
+ "@babel/plugin-transform-dotall-regex" "^7.16.7"
+ "@babel/plugin-transform-duplicate-keys" "^7.16.7"
+ "@babel/plugin-transform-exponentiation-operator" "^7.16.7"
+ "@babel/plugin-transform-for-of" "^7.16.7"
+ "@babel/plugin-transform-function-name" "^7.16.7"
+ "@babel/plugin-transform-literals" "^7.16.7"
+ "@babel/plugin-transform-member-expression-literals" "^7.16.7"
+ "@babel/plugin-transform-modules-amd" "^7.16.7"
+ "@babel/plugin-transform-modules-commonjs" "^7.16.7"
+ "@babel/plugin-transform-modules-systemjs" "^7.16.7"
+ "@babel/plugin-transform-modules-umd" "^7.16.7"
+ "@babel/plugin-transform-named-capturing-groups-regex" "^7.16.7"
+ "@babel/plugin-transform-new-target" "^7.16.7"
+ "@babel/plugin-transform-object-super" "^7.16.7"
+ "@babel/plugin-transform-parameters" "^7.16.7"
+ "@babel/plugin-transform-property-literals" "^7.16.7"
+ "@babel/plugin-transform-regenerator" "^7.16.7"
+ "@babel/plugin-transform-reserved-words" "^7.16.7"
+ "@babel/plugin-transform-shorthand-properties" "^7.16.7"
+ "@babel/plugin-transform-spread" "^7.16.7"
+ "@babel/plugin-transform-sticky-regex" "^7.16.7"
+ "@babel/plugin-transform-template-literals" "^7.16.7"
+ "@babel/plugin-transform-typeof-symbol" "^7.16.7"
+ "@babel/plugin-transform-unicode-escapes" "^7.16.7"
+ "@babel/plugin-transform-unicode-regex" "^7.16.7"
+ "@babel/preset-modules" "^0.1.5"
+ "@babel/types" "^7.16.7"
+ "babel-plugin-polyfill-corejs2" "^0.3.0"
+ "babel-plugin-polyfill-corejs3" "^0.4.0"
+ "babel-plugin-polyfill-regenerator" "^0.3.0"
+ "core-js-compat" "^3.19.1"
+ "semver" "^6.3.0"
+
+"@babel/preset-modules@^0.1.5":
+ "integrity" "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA=="
+ "resolved" "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz"
+ "version" "0.1.5"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
+ "@babel/plugin-transform-dotall-regex" "^7.4.4"
+ "@babel/types" "^7.4.4"
+ "esutils" "^2.0.2"
+
+"@babel/runtime@^7.1.2", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.1", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.15.4", "@babel/runtime@^7.5.5", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
+ "integrity" "sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ=="
+ "resolved" "https://registry.npmjs.org/@babel/runtime/-/runtime-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "regenerator-runtime" "^0.13.4"
+
+"@babel/template@^7.16.7", "@babel/template@^7.3.3":
+ "integrity" "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w=="
+ "resolved" "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/code-frame" "^7.16.7"
+ "@babel/parser" "^7.16.7"
+ "@babel/types" "^7.16.7"
+
+"@babel/traverse@^7.13.0", "@babel/traverse@^7.16.7", "@babel/traverse@^7.7.2":
+ "integrity" "sha512-8KWJPIb8c2VvY8AJrydh6+fVRo2ODx1wYBU2398xJVq0JomuLBZmVQzLPBblJgHIGYG4znCpUZUZ0Pt2vdmVYQ=="
+ "resolved" "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/code-frame" "^7.16.7"
+ "@babel/generator" "^7.16.7"
+ "@babel/helper-environment-visitor" "^7.16.7"
+ "@babel/helper-function-name" "^7.16.7"
+ "@babel/helper-hoist-variables" "^7.16.7"
+ "@babel/helper-split-export-declaration" "^7.16.7"
+ "@babel/parser" "^7.16.7"
+ "@babel/types" "^7.16.7"
+ "debug" "^4.1.0"
+ "globals" "^11.1.0"
+
+"@babel/types@^7.0.0", "@babel/types@^7.16.0", "@babel/types@^7.16.7", "@babel/types@^7.3.0", "@babel/types@^7.3.3", "@babel/types@^7.4.4":
+ "integrity" "sha512-E8HuV7FO9qLpx6OtoGfUQ2cjIYnbFwvZWYBS+87EwtdMvmUPJSwykpovFB+8insbpF0uJcpr8KMUi64XZntZcg=="
+ "resolved" "https://registry.npmjs.org/@babel/types/-/types-7.16.7.tgz"
+ "version" "7.16.7"
+ dependencies:
+ "@babel/helper-validator-identifier" "^7.16.7"
+ "to-fast-properties" "^2.0.0"
+
+"@bcoe/v8-coverage@^0.2.3":
+ "integrity" "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw=="
+ "resolved" "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz"
+ "version" "0.2.3"
+
+"@discoveryjs/json-ext@^0.5.0":
+ "integrity" "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA=="
+ "resolved" "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz"
+ "version" "0.5.6"
+
+"@eslint/eslintrc@^1.0.5":
+ "integrity" "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ=="
+ "resolved" "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz"
+ "version" "1.0.5"
+ dependencies:
+ "ajv" "^6.12.4"
+ "debug" "^4.3.2"
+ "espree" "^9.2.0"
+ "globals" "^13.9.0"
+ "ignore" "^4.0.6"
+ "import-fresh" "^3.2.1"
+ "js-yaml" "^4.1.0"
+ "minimatch" "^3.0.4"
+ "strip-json-comments" "^3.1.1"
+
+"@fortawesome/fontawesome-common-types@^0.2.36":
+ "integrity" "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg=="
+ "resolved" "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz"
+ "version" "0.2.36"
+
+"@fortawesome/fontawesome-svg-core@~1 || >=1.3.0-beta1", "@fortawesome/fontawesome-svg-core@1.2.36":
+ "integrity" "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA=="
+ "resolved" "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz"
+ "version" "1.2.36"
+ dependencies:
+ "@fortawesome/fontawesome-common-types" "^0.2.36"
+
+"@fortawesome/free-solid-svg-icons@5.15.4":
+ "integrity" "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w=="
+ "resolved" "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz"
+ "version" "5.15.4"
+ dependencies:
+ "@fortawesome/fontawesome-common-types" "^0.2.36"
+
+"@fortawesome/react-fontawesome@0.1.16":
+ "integrity" "sha512-aLmzDwC9rEOAJv2UJdMns89VZR5Ry4IHu5dQQh24Z/lWKEm44lfQr1UNalZlkUaQN8d155tNh+CS7ntntj1VMA=="
+ "resolved" "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.16.tgz"
+ "version" "0.1.16"
+ dependencies:
+ "prop-types" "^15.7.2"
+
+"@hapi/hoek@^9.0.0":
+ "integrity" "sha512-gfta+H8aziZsm8pZa0vj04KO6biEiisppNgA1kbJvFrrWu9Vm7eaUEy76DIxsuTaWvti5fkJVhllWc6ZTE+Mdw=="
+ "resolved" "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.2.1.tgz"
+ "version" "9.2.1"
+
+"@hapi/topo@^5.0.0":
+ "integrity" "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg=="
+ "resolved" "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz"
+ "version" "5.1.0"
+ dependencies:
+ "@hapi/hoek" "^9.0.0"
+
+"@humanwhocodes/config-array@^0.9.2":
+ "integrity" "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA=="
+ "resolved" "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz"
+ "version" "0.9.2"
+ dependencies:
+ "@humanwhocodes/object-schema" "^1.2.1"
+ "debug" "^4.1.1"
+ "minimatch" "^3.0.4"
+
+"@humanwhocodes/object-schema@^1.2.1":
+ "integrity" "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA=="
+ "resolved" "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz"
+ "version" "1.2.1"
+
+"@istanbuljs/load-nyc-config@^1.0.0":
+ "integrity" "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ=="
+ "resolved" "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz"
+ "version" "1.1.0"
+ dependencies:
+ "camelcase" "^5.3.1"
+ "find-up" "^4.1.0"
+ "get-package-type" "^0.1.0"
+ "js-yaml" "^3.13.1"
+ "resolve-from" "^5.0.0"
+
+"@istanbuljs/schema@^0.1.2":
+ "integrity" "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA=="
+ "resolved" "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz"
+ "version" "0.1.3"
+
+"@jest/console@^27.4.6":
+ "integrity" "sha512-jauXyacQD33n47A44KrlOVeiXHEXDqapSdfb9kTekOchH/Pd18kBIO1+xxJQRLuG+LUuljFCwTG92ra4NW7SpA=="
+ "resolved" "https://registry.npmjs.org/@jest/console/-/console-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "chalk" "^4.0.0"
+ "jest-message-util" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "slash" "^3.0.0"
+
+"@jest/core@^27.4.5", "@jest/core@^27.4.7":
+ "integrity" "sha512-n181PurSJkVMS+kClIFSX/LLvw9ExSb+4IMtD6YnfxZVerw9ANYtW0bPrm0MJu2pfe9SY9FJ9FtQ+MdZkrZwjg=="
+ "resolved" "https://registry.npmjs.org/@jest/core/-/core-27.4.7.tgz"
+ "version" "27.4.7"
+ dependencies:
+ "@jest/console" "^27.4.6"
+ "@jest/reporters" "^27.4.6"
+ "@jest/test-result" "^27.4.6"
+ "@jest/transform" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "ansi-escapes" "^4.2.1"
+ "chalk" "^4.0.0"
+ "emittery" "^0.8.1"
+ "exit" "^0.1.2"
+ "graceful-fs" "^4.2.4"
+ "jest-changed-files" "^27.4.2"
+ "jest-config" "^27.4.7"
+ "jest-haste-map" "^27.4.6"
+ "jest-message-util" "^27.4.6"
+ "jest-regex-util" "^27.4.0"
+ "jest-resolve" "^27.4.6"
+ "jest-resolve-dependencies" "^27.4.6"
+ "jest-runner" "^27.4.6"
+ "jest-runtime" "^27.4.6"
+ "jest-snapshot" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "jest-validate" "^27.4.6"
+ "jest-watcher" "^27.4.6"
+ "micromatch" "^4.0.4"
+ "rimraf" "^3.0.0"
+ "slash" "^3.0.0"
+ "strip-ansi" "^6.0.0"
+
+"@jest/environment@^27.4.6":
+ "integrity" "sha512-E6t+RXPfATEEGVidr84WngLNWZ8ffCPky8RqqRK6u1Bn0LK92INe0MDttyPl/JOzaq92BmDzOeuqk09TvM22Sg=="
+ "resolved" "https://registry.npmjs.org/@jest/environment/-/environment-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/fake-timers" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "jest-mock" "^27.4.6"
+
+"@jest/fake-timers@^27.4.6":
+ "integrity" "sha512-mfaethuYF8scV8ntPpiVGIHQgS0XIALbpY2jt2l7wb/bvq4Q5pDLk4EP4D7SAvYT1QrPOPVZAtbdGAOOyIgs7A=="
+ "resolved" "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "@sinonjs/fake-timers" "^8.0.1"
+ "@types/node" "*"
+ "jest-message-util" "^27.4.6"
+ "jest-mock" "^27.4.6"
+ "jest-util" "^27.4.2"
+
+"@jest/globals@^27.4.6":
+ "integrity" "sha512-kAiwMGZ7UxrgPzu8Yv9uvWmXXxsy0GciNejlHvfPIfWkSxChzv6bgTS3YqBkGuHcis+ouMFI2696n2t+XYIeFw=="
+ "resolved" "https://registry.npmjs.org/@jest/globals/-/globals-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/environment" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "expect" "^27.4.6"
+
+"@jest/reporters@^27.4.6":
+ "integrity" "sha512-+Zo9gV81R14+PSq4wzee4GC2mhAN9i9a7qgJWL90Gpx7fHYkWpTBvwWNZUXvJByYR9tAVBdc8VxDWqfJyIUrIQ=="
+ "resolved" "https://registry.npmjs.org/@jest/reporters/-/reporters-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@bcoe/v8-coverage" "^0.2.3"
+ "@jest/console" "^27.4.6"
+ "@jest/test-result" "^27.4.6"
+ "@jest/transform" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "chalk" "^4.0.0"
+ "collect-v8-coverage" "^1.0.0"
+ "exit" "^0.1.2"
+ "glob" "^7.1.2"
+ "graceful-fs" "^4.2.4"
+ "istanbul-lib-coverage" "^3.0.0"
+ "istanbul-lib-instrument" "^5.1.0"
+ "istanbul-lib-report" "^3.0.0"
+ "istanbul-lib-source-maps" "^4.0.0"
+ "istanbul-reports" "^3.1.3"
+ "jest-haste-map" "^27.4.6"
+ "jest-resolve" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "jest-worker" "^27.4.6"
+ "slash" "^3.0.0"
+ "source-map" "^0.6.0"
+ "string-length" "^4.0.1"
+ "terminal-link" "^2.0.0"
+ "v8-to-istanbul" "^8.1.0"
+
+"@jest/source-map@^27.4.0":
+ "integrity" "sha512-Ntjx9jzP26Bvhbm93z/AKcPRj/9wrkI88/gK60glXDx1q+IeI0rf7Lw2c89Ch6ofonB0On/iRDreQuQ6te9pgQ=="
+ "resolved" "https://registry.npmjs.org/@jest/source-map/-/source-map-27.4.0.tgz"
+ "version" "27.4.0"
+ dependencies:
+ "callsites" "^3.0.0"
+ "graceful-fs" "^4.2.4"
+ "source-map" "^0.6.0"
+
+"@jest/test-result@^27.4.6":
+ "integrity" "sha512-fi9IGj3fkOrlMmhQqa/t9xum8jaJOOAi/lZlm6JXSc55rJMXKHxNDN1oCP39B0/DhNOa2OMupF9BcKZnNtXMOQ=="
+ "resolved" "https://registry.npmjs.org/@jest/test-result/-/test-result-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/console" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ "collect-v8-coverage" "^1.0.0"
+
+"@jest/test-sequencer@^27.4.6":
+ "integrity" "sha512-3GL+nsf6E1PsyNsJuvPyIz+DwFuCtBdtvPpm/LMXVkBJbdFvQYCDpccYT56qq5BGniXWlE81n2qk1sdXfZebnw=="
+ "resolved" "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/test-result" "^27.4.6"
+ "graceful-fs" "^4.2.4"
+ "jest-haste-map" "^27.4.6"
+ "jest-runtime" "^27.4.6"
+
+"@jest/transform@^27.4.6":
+ "integrity" "sha512-9MsufmJC8t5JTpWEQJ0OcOOAXaH5ioaIX6uHVBLBMoCZPfKKQF+EqP8kACAvCZ0Y1h2Zr3uOccg8re+Dr5jxyw=="
+ "resolved" "https://registry.npmjs.org/@jest/transform/-/transform-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@babel/core" "^7.1.0"
+ "@jest/types" "^27.4.2"
+ "babel-plugin-istanbul" "^6.1.1"
+ "chalk" "^4.0.0"
+ "convert-source-map" "^1.4.0"
+ "fast-json-stable-stringify" "^2.0.0"
+ "graceful-fs" "^4.2.4"
+ "jest-haste-map" "^27.4.6"
+ "jest-regex-util" "^27.4.0"
+ "jest-util" "^27.4.2"
+ "micromatch" "^4.0.4"
+ "pirates" "^4.0.4"
+ "slash" "^3.0.0"
+ "source-map" "^0.6.1"
+ "write-file-atomic" "^3.0.0"
+
+"@jest/types@^27.4.2":
+ "integrity" "sha512-j35yw0PMTPpZsUoOBiuHzr1zTYoad1cVIE0ajEjcrJONxxrko/IRGKkXx3os0Nsi4Hu3+5VmDbVfq5WhG/pWAg=="
+ "resolved" "https://registry.npmjs.org/@jest/types/-/types-27.4.2.tgz"
+ "version" "27.4.2"
+ dependencies:
+ "@types/istanbul-lib-coverage" "^2.0.0"
+ "@types/istanbul-reports" "^3.0.0"
+ "@types/node" "*"
+ "@types/yargs" "^16.0.0"
+ "chalk" "^4.0.0"
+
+"@nodelib/fs.scandir@2.1.5":
+ "integrity" "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g=="
+ "resolved" "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz"
+ "version" "2.1.5"
+ dependencies:
+ "@nodelib/fs.stat" "2.0.5"
+ "run-parallel" "^1.1.9"
+
+"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5":
+ "integrity" "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A=="
+ "resolved" "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz"
+ "version" "2.0.5"
+
+"@nodelib/fs.walk@^1.2.3":
+ "integrity" "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg=="
+ "resolved" "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz"
+ "version" "1.2.8"
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.5"
+ "fastq" "^1.6.0"
+
+"@popperjs/core@^2.0.0", "@popperjs/core@^2.10.2", "@popperjs/core@^2.6.0":
+ "integrity" "sha512-92FRmppjjqz29VMJ2dn+xdyXZBrMlE42AV6Kq6BwjWV7CNUW1hs2FtxSNLQE+gJhaZ6AAmYuO9y8dshhcBl7vA=="
+ "resolved" "https://registry.npmjs.org/@popperjs/core/-/core-2.11.2.tgz"
+ "version" "2.11.2"
+
+"@reduxjs/toolkit@1.7.1":
+ "integrity" "sha512-wXwXYjBVz/ItxB7SMzEAMmEE/FBiY1ze18N+VVVX7NtVbRUrdOGKhpQMHivIJfkbJvSdLUU923a/yAagJQzY0Q=="
+ "resolved" "https://registry.npmjs.org/@reduxjs/toolkit/-/toolkit-1.7.1.tgz"
+ "version" "1.7.1"
+ dependencies:
+ "immer" "^9.0.7"
+ "redux" "^4.1.2"
+ "redux-thunk" "^2.4.1"
+ "reselect" "^4.1.5"
+
+"@rollup/plugin-babel@^5.2.0":
+ "integrity" "sha512-9uIC8HZOnVLrLHxayq/PTzw+uS25E14KPUBh5ktF+18Mjo5yK0ToMMx6epY0uEgkjwJw0aBW4x2horYXh8juWw=="
+ "resolved" "https://registry.npmjs.org/@rollup/plugin-babel/-/plugin-babel-5.3.0.tgz"
+ "version" "5.3.0"
+ dependencies:
+ "@babel/helper-module-imports" "^7.10.4"
+ "@rollup/pluginutils" "^3.1.0"
+
+"@rollup/plugin-node-resolve@^11.2.1":
+ "integrity" "sha512-yc2n43jcqVyGE2sqV5/YCmocy9ArjVAP/BeXyTtADTBBX6V0e5UMqwO8CdQ0kzjb6zu5P1qMzsScCMRvE9OlVg=="
+ "resolved" "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-11.2.1.tgz"
+ "version" "11.2.1"
+ dependencies:
+ "@rollup/pluginutils" "^3.1.0"
+ "@types/resolve" "1.17.1"
+ "builtin-modules" "^3.1.0"
+ "deepmerge" "^4.2.2"
+ "is-module" "^1.0.0"
+ "resolve" "^1.19.0"
+
+"@rollup/plugin-replace@^2.4.1":
+ "integrity" "sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg=="
+ "resolved" "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-2.4.2.tgz"
+ "version" "2.4.2"
+ dependencies:
+ "@rollup/pluginutils" "^3.1.0"
+ "magic-string" "^0.25.7"
+
+"@rollup/pluginutils@^3.1.0":
+ "integrity" "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg=="
+ "resolved" "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz"
+ "version" "3.1.0"
+ dependencies:
+ "@types/estree" "0.0.39"
+ "estree-walker" "^1.0.1"
+ "picomatch" "^2.2.2"
+
+"@sideway/address@^4.1.3":
+ "integrity" "sha512-8ncEUtmnTsMmL7z1YPB47kPUq7LpKWJNFPsRzHiIajGC5uXlWGn+AmkYPcHNl8S4tcEGx+cnORnNYaw2wvL+LQ=="
+ "resolved" "https://registry.npmjs.org/@sideway/address/-/address-4.1.3.tgz"
+ "version" "4.1.3"
+ dependencies:
+ "@hapi/hoek" "^9.0.0"
+
+"@sideway/formula@^3.0.0":
+ "integrity" "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg=="
+ "resolved" "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz"
+ "version" "3.0.0"
+
+"@sideway/pinpoint@^2.0.0":
+ "integrity" "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ=="
+ "resolved" "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz"
+ "version" "2.0.0"
+
+"@sinonjs/commons@^1.6.0", "@sinonjs/commons@^1.7.0", "@sinonjs/commons@^1.8.3":
+ "integrity" "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ=="
+ "resolved" "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz"
+ "version" "1.8.3"
+ dependencies:
+ "type-detect" "4.0.8"
+
+"@sinonjs/fake-timers@^7.0.4":
+ "integrity" "sha512-iQADsW4LBMISqZ6Ci1dupJL9pprqwcVFTcOsEmQOEhW+KLCVn/Y4Jrvg2k19fIHCp+iFprriYPTdRcQR8NbUPg=="
+ "resolved" "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-7.1.2.tgz"
+ "version" "7.1.2"
+ dependencies:
+ "@sinonjs/commons" "^1.7.0"
+
+"@sinonjs/fake-timers@^8.0.1", "@sinonjs/fake-timers@^8.1.0":
+ "integrity" "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg=="
+ "resolved" "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz"
+ "version" "8.1.0"
+ dependencies:
+ "@sinonjs/commons" "^1.7.0"
+
+"@sinonjs/samsam@^6.0.2":
+ "integrity" "sha512-jxPRPp9n93ci7b8hMfJOFDPRLFYadN6FSpeROFTR4UNF4i5b+EK6m4QXPO46BDhFgRy1JuS87zAnFOzCUwMJcQ=="
+ "resolved" "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-6.0.2.tgz"
+ "version" "6.0.2"
+ dependencies:
+ "@sinonjs/commons" "^1.6.0"
+ "lodash.get" "^4.4.2"
+ "type-detect" "^4.0.8"
+
+"@sinonjs/text-encoding@^0.7.1":
+ "integrity" "sha512-+iTbntw2IZPb/anVDbypzfQa+ay64MW0Zo8aJ8gZPWMMK6/OubMVb6lUPMagqjOPnmtauXnFCACVl3O7ogjeqQ=="
+ "resolved" "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.1.tgz"
+ "version" "0.7.1"
+
+"@surma/rollup-plugin-off-main-thread@^2.2.3":
+ "integrity" "sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ=="
+ "resolved" "https://registry.npmjs.org/@surma/rollup-plugin-off-main-thread/-/rollup-plugin-off-main-thread-2.2.3.tgz"
+ "version" "2.2.3"
+ dependencies:
+ "ejs" "^3.1.6"
+ "json5" "^2.2.0"
+ "magic-string" "^0.25.0"
+ "string.prototype.matchall" "^4.0.6"
+
+"@testing-library/dom@^8.0.0":
+ "integrity" "sha512-3KQDyx9r0RKYailW2MiYrSSKEfH0GTkI51UGEvJenvcoDoeRYs0PZpi2SXqtnMClQvCqdtTTpOfFETDTVADpAg=="
+ "resolved" "https://registry.npmjs.org/@testing-library/dom/-/dom-8.11.1.tgz"
+ "version" "8.11.1"
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ "@babel/runtime" "^7.12.5"
+ "@types/aria-query" "^4.2.0"
+ "aria-query" "^5.0.0"
+ "chalk" "^4.1.0"
+ "dom-accessibility-api" "^0.5.9"
+ "lz-string" "^1.4.4"
+ "pretty-format" "^27.0.2"
+
+"@testing-library/react@12.1.2":
+ "integrity" "sha512-ihQiEOklNyHIpo2Y8FREkyD1QAea054U0MVbwH1m8N9TxeFz+KoJ9LkqoKqJlzx2JDm56DVwaJ1r36JYxZM05g=="
+ "resolved" "https://registry.npmjs.org/@testing-library/react/-/react-12.1.2.tgz"
+ "version" "12.1.2"
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ "@testing-library/dom" "^8.0.0"
+
+"@tootallnate/once@1":
+ "integrity" "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw=="
+ "resolved" "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz"
+ "version" "1.1.2"
+
+"@trysound/sax@0.2.0":
+ "integrity" "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA=="
+ "resolved" "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz"
+ "version" "0.2.0"
+
+"@types/aria-query@^4.2.0":
+ "integrity" "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig=="
+ "resolved" "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz"
+ "version" "4.2.2"
+
+"@types/babel__core@^7.0.0", "@types/babel__core@^7.1.14", "@types/babel__core@^7.1.9":
+ "integrity" "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ=="
+ "resolved" "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz"
+ "version" "7.1.18"
+ dependencies:
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+ "@types/babel__generator" "*"
+ "@types/babel__template" "*"
+ "@types/babel__traverse" "*"
+
+"@types/babel__generator@*":
+ "integrity" "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg=="
+ "resolved" "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz"
+ "version" "7.6.4"
+ dependencies:
+ "@babel/types" "^7.0.0"
+
+"@types/babel__template@*":
+ "integrity" "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g=="
+ "resolved" "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz"
+ "version" "7.4.1"
+ dependencies:
+ "@babel/parser" "^7.1.0"
+ "@babel/types" "^7.0.0"
+
+"@types/babel__traverse@*", "@types/babel__traverse@^7.0.4", "@types/babel__traverse@^7.0.6":
+ "integrity" "sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA=="
+ "resolved" "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.14.2.tgz"
+ "version" "7.14.2"
+ dependencies:
+ "@babel/types" "^7.3.0"
+
+"@types/body-parser@*":
+ "integrity" "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g=="
+ "resolved" "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz"
+ "version" "1.19.2"
+ dependencies:
+ "@types/connect" "*"
+ "@types/node" "*"
+
+"@types/bonjour@^3.5.9":
+ "integrity" "sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw=="
+ "resolved" "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.10.tgz"
+ "version" "3.5.10"
+ dependencies:
+ "@types/node" "*"
+
+"@types/connect-history-api-fallback@^1.3.5":
+ "integrity" "sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw=="
+ "resolved" "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.3.5.tgz"
+ "version" "1.3.5"
+ dependencies:
+ "@types/express-serve-static-core" "*"
+ "@types/node" "*"
+
+"@types/connect@*":
+ "integrity" "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ=="
+ "resolved" "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz"
+ "version" "3.4.35"
+ dependencies:
+ "@types/node" "*"
+
+"@types/eslint-scope@^3.7.0":
+ "integrity" "sha512-TzgYCWoPiTeRg6RQYgtuW7iODtVoKu3RVL72k3WohqhjfaOLK5Mg2T4Tg1o2bSfu0vPkoI48wdQFv5b/Xe04wQ=="
+ "resolved" "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.2.tgz"
+ "version" "3.7.2"
+ dependencies:
+ "@types/eslint" "*"
+ "@types/estree" "*"
+
+"@types/eslint@*", "@types/eslint@^7.28.2":
+ "integrity" "sha512-VNcvioYDH8/FxaeTKkM4/TiTwt6pBV9E3OfGmvaw8tPl0rrHCJ4Ll15HRT+pMiFAf/MLQvAzC+6RzUMEL9Ceng=="
+ "resolved" "https://registry.npmjs.org/@types/eslint/-/eslint-7.29.0.tgz"
+ "version" "7.29.0"
+ dependencies:
+ "@types/estree" "*"
+ "@types/json-schema" "*"
+
+"@types/estree@*", "@types/estree@^0.0.50":
+ "integrity" "sha512-C6N5s2ZFtuZRj54k2/zyRhNDjJwwcViAM3Nbm8zjBpbqAdZ00mr0CFxvSKeO8Y/e03WVFLpQMdHYVfUd6SB+Hw=="
+ "resolved" "https://registry.npmjs.org/@types/estree/-/estree-0.0.50.tgz"
+ "version" "0.0.50"
+
+"@types/estree@0.0.39":
+ "integrity" "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw=="
+ "resolved" "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz"
+ "version" "0.0.39"
+
+"@types/express-serve-static-core@*", "@types/express-serve-static-core@^4.17.18":
+ "integrity" "sha512-e/sVallzUTPdyOTiqi8O8pMdBBphscvI6E4JYaKlja4Lm+zh7UFSSdW5VMkRbhDtmrONqOUHOXRguPsDckzxNA=="
+ "resolved" "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.27.tgz"
+ "version" "4.17.27"
+ dependencies:
+ "@types/node" "*"
+ "@types/qs" "*"
+ "@types/range-parser" "*"
+
+"@types/express@*":
+ "integrity" "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA=="
+ "resolved" "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz"
+ "version" "4.17.13"
+ dependencies:
+ "@types/body-parser" "*"
+ "@types/express-serve-static-core" "^4.17.18"
+ "@types/qs" "*"
+ "@types/serve-static" "*"
+
+"@types/glob@^7.1.1":
+ "integrity" "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA=="
+ "resolved" "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz"
+ "version" "7.2.0"
+ dependencies:
+ "@types/minimatch" "*"
+ "@types/node" "*"
+
+"@types/graceful-fs@^4.1.2":
+ "integrity" "sha512-anKkLmZZ+xm4p8JWBf4hElkM4XR+EZeA2M9BAkkTldmcyDY4mbdIJnRghDJH3Ov5ooY7/UAoENtmdMSkaAd7Cw=="
+ "resolved" "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.5.tgz"
+ "version" "4.1.5"
+ dependencies:
+ "@types/node" "*"
+
+"@types/history@*":
+ "integrity" "sha512-MUc6zSmU3tEVnkQ78q0peeEjKWPUADMlC/t++2bI8WnAG2tvYRPIgHG8lWkXwqc8MsUF6Z2MOf+Mh5sazOmhiQ=="
+ "resolved" "https://registry.npmjs.org/@types/history/-/history-4.7.9.tgz"
+ "version" "4.7.9"
+
+"@types/hoist-non-react-statics@^3.3.0":
+ "integrity" "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA=="
+ "resolved" "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz"
+ "version" "3.3.1"
+ dependencies:
+ "@types/react" "*"
+ "hoist-non-react-statics" "^3.3.0"
+
+"@types/html-minifier-terser@^6.0.0":
+ "integrity" "sha512-oh/6byDPnL1zeNXFrDXFLyZjkr1MsBG667IM792caf1L2UPOOMf65NFzjUH/ltyfwjAGfs1rsX1eftK0jC/KIg=="
+ "resolved" "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz"
+ "version" "6.1.0"
+
+"@types/http-proxy@^1.17.5":
+ "integrity" "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA=="
+ "resolved" "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz"
+ "version" "1.17.8"
+ dependencies:
+ "@types/node" "*"
+
+"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1":
+ "integrity" "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g=="
+ "resolved" "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz"
+ "version" "2.0.4"
+
+"@types/istanbul-lib-report@*":
+ "integrity" "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg=="
+ "resolved" "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "@types/istanbul-lib-coverage" "*"
+
+"@types/istanbul-reports@^3.0.0":
+ "integrity" "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw=="
+ "resolved" "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz"
+ "version" "3.0.1"
+ dependencies:
+ "@types/istanbul-lib-report" "*"
+
+"@types/jest@^27.0.0", "@types/jest@27.4.0":
+ "integrity" "sha512-gHl8XuC1RZ8H2j5sHv/JqsaxXkDDM9iDOgu0Wp8sjs4u/snb2PVehyWXJPr+ORA0RPpgw231mnutWI1+0hgjIQ=="
+ "resolved" "https://registry.npmjs.org/@types/jest/-/jest-27.4.0.tgz"
+ "version" "27.4.0"
+ dependencies:
+ "jest-diff" "^27.0.0"
+ "pretty-format" "^27.0.0"
+
+"@types/json-schema@*", "@types/json-schema@^7.0.4", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8", "@types/json-schema@^7.0.9":
+ "integrity" "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ=="
+ "resolved" "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz"
+ "version" "7.0.9"
+
+"@types/lodash@4.14.178":
+ "integrity" "sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw=="
+ "resolved" "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.178.tgz"
+ "version" "4.14.178"
+
+"@types/mime@^1":
+ "integrity" "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw=="
+ "resolved" "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz"
+ "version" "1.3.2"
+
+"@types/minimatch@*":
+ "integrity" "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ=="
+ "resolved" "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz"
+ "version" "3.0.5"
+
+"@types/node@*", "@types/node@16.11.17":
+ "integrity" "sha512-C1vTZME8cFo8uxY2ui41xcynEotVkczIVI5AjLmy5pkpBv/FtG+jhtOlfcPysI8VRVwoOMv6NJm44LGnoMSWkw=="
+ "resolved" "https://registry.npmjs.org/@types/node/-/node-16.11.17.tgz"
+ "version" "16.11.17"
+
+"@types/parse-json@^4.0.0":
+ "integrity" "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA=="
+ "resolved" "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz"
+ "version" "4.0.0"
+
+"@types/prettier@^2.1.5":
+ "integrity" "sha512-ekoj4qOQYp7CvjX8ZDBgN86w3MqQhLE1hczEJbEIjgFEumDy+na/4AJAbLXfgEWFNB2pKadM5rPFtuSGMWK7xA=="
+ "resolved" "https://registry.npmjs.org/@types/prettier/-/prettier-2.4.2.tgz"
+ "version" "2.4.2"
+
+"@types/prop-types@*":
+ "integrity" "sha512-rZ5drC/jWjrArrS8BR6SIr4cWpW09RNTYt9AMZo3Jwwif+iacXAqgVjm0B0Bv/S1jhDXKHqRVNCbACkJ89RAnQ=="
+ "resolved" "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.4.tgz"
+ "version" "15.7.4"
+
+"@types/qs@*":
+ "integrity" "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw=="
+ "resolved" "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz"
+ "version" "6.9.7"
+
+"@types/range-parser@*":
+ "integrity" "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw=="
+ "resolved" "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz"
+ "version" "1.2.4"
+
+"@types/react-dom@17.0.11":
+ "integrity" "sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q=="
+ "resolved" "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.11.tgz"
+ "version" "17.0.11"
+ dependencies:
+ "@types/react" "*"
+
+"@types/react-redux@^7.1.20", "@types/react-redux@7.1.21":
+ "integrity" "sha512-bLdglUiBSQNzWVVbmNPKGYYjrzp3/YDPwfOH3nLEz99I4awLlaRAPWjo6bZ2POpxztFWtDDXIPxBLVykXqBt+w=="
+ "resolved" "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.21.tgz"
+ "version" "7.1.21"
+ dependencies:
+ "@types/hoist-non-react-statics" "^3.3.0"
+ "@types/react" "*"
+ "hoist-non-react-statics" "^3.3.0"
+ "redux" "^4.0.0"
+
+"@types/react-router-dom@5.3.2":
+ "integrity" "sha512-ELEYRUie2czuJzaZ5+ziIp9Hhw+juEw8b7C11YNA4QdLCVbQ3qLi2l4aq8XnlqM7V31LZX8dxUuFUCrzHm6sqQ=="
+ "resolved" "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.2.tgz"
+ "version" "5.3.2"
+ dependencies:
+ "@types/history" "*"
+ "@types/react" "*"
+ "@types/react-router" "*"
+
+"@types/react-router@*":
+ "integrity" "sha512-RNSXOyb3VyRs/EOGmjBhhGKTbnN6fHWvy5FNLzWfOWOGjgVUKqJZXfpKzLmgoU8h6Hj8mpALj/mbXQASOb92wQ=="
+ "resolved" "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.17.tgz"
+ "version" "5.1.17"
+ dependencies:
+ "@types/history" "*"
+ "@types/react" "*"
+
+"@types/react@*", "@types/react@17.0.38":
+ "integrity" "sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ=="
+ "resolved" "https://registry.npmjs.org/@types/react/-/react-17.0.38.tgz"
+ "version" "17.0.38"
+ dependencies:
+ "@types/prop-types" "*"
+ "@types/scheduler" "*"
+ "csstype" "^3.0.2"
+
+"@types/redux@3.6.31":
+ "integrity" "sha1-QOr6dXXbNrkSzgBZuF3pjCBbBwg="
+ "resolved" "https://registry.npmjs.org/@types/redux/-/redux-3.6.31.tgz"
+ "version" "3.6.31"
+
+"@types/resolve@1.17.1":
+ "integrity" "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw=="
+ "resolved" "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz"
+ "version" "1.17.1"
+ dependencies:
+ "@types/node" "*"
+
+"@types/retry@^0.12.0":
+ "integrity" "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g=="
+ "resolved" "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz"
+ "version" "0.12.1"
+
+"@types/scheduler@*":
+ "integrity" "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew=="
+ "resolved" "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz"
+ "version" "0.16.2"
+
+"@types/serve-index@^1.9.1":
+ "integrity" "sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg=="
+ "resolved" "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz"
+ "version" "1.9.1"
+ dependencies:
+ "@types/express" "*"
+
+"@types/serve-static@*":
+ "integrity" "sha512-nCkHGI4w7ZgAdNkrEu0bv+4xNV/XDqW+DydknebMOQwkpDGx8G+HTlj7R7ABI8i8nKxVw0wtKPi1D+lPOkh4YQ=="
+ "resolved" "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.13.10.tgz"
+ "version" "1.13.10"
+ dependencies:
+ "@types/mime" "^1"
+ "@types/node" "*"
+
+"@types/sockjs@^0.3.33":
+ "integrity" "sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw=="
+ "resolved" "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.33.tgz"
+ "version" "0.3.33"
+ dependencies:
+ "@types/node" "*"
+
+"@types/stack-utils@^2.0.0":
+ "integrity" "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw=="
+ "resolved" "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz"
+ "version" "2.0.1"
+
+"@types/trusted-types@^2.0.2":
+ "integrity" "sha512-F5DIZ36YVLE+PN+Zwws4kJogq47hNgX3Nx6WyDJ3kcplxyke3XIzB8uK5n/Lpm1HBsbGzd6nmGehL8cPekP+Tg=="
+ "resolved" "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.2.tgz"
+ "version" "2.0.2"
+
+"@types/webpack-env@1.16.3":
+ "integrity" "sha512-9gtOPPkfyNoEqCQgx4qJKkuNm/x0R2hKR7fdl7zvTJyHnIisuE/LfvXOsYWL0o3qq6uiBnKZNNNzi3l0y/X+xw=="
+ "resolved" "https://registry.npmjs.org/@types/webpack-env/-/webpack-env-1.16.3.tgz"
+ "version" "1.16.3"
+
+"@types/ws@^8.2.2":
+ "integrity" "sha512-NOn5eIcgWLOo6qW8AcuLZ7G8PycXu0xTxxkS6Q18VWFxgPUSOwV0pBj2a/4viNZVu25i7RIB7GttdkAIUUXOOg=="
+ "resolved" "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz"
+ "version" "8.2.2"
+ dependencies:
+ "@types/node" "*"
+
+"@types/yargs-parser@*":
+ "integrity" "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw=="
+ "resolved" "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-20.2.1.tgz"
+ "version" "20.2.1"
+
+"@types/yargs@^16.0.0":
+ "integrity" "sha512-T8Yc9wt/5LbJyCaLiHPReJa0kApcIgJ7Bn735GjItUfh08Z1pJvu8QZqb9s+mMvKV6WUQRV7K2R46YbjMXTTJw=="
+ "resolved" "https://registry.npmjs.org/@types/yargs/-/yargs-16.0.4.tgz"
+ "version" "16.0.4"
+ dependencies:
+ "@types/yargs-parser" "*"
+
+"@typescript-eslint/eslint-plugin@5.8.1":
+ "integrity" "sha512-wTZ5oEKrKj/8/366qTM366zqhIKAp6NCMweoRONtfuC07OAU9nVI2GZZdqQ1qD30WAAtcPdkH+npDwtRFdp4Rw=="
+ "resolved" "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.8.1.tgz"
+ "version" "5.8.1"
+ dependencies:
+ "@typescript-eslint/experimental-utils" "5.8.1"
+ "@typescript-eslint/scope-manager" "5.8.1"
+ "debug" "^4.3.2"
+ "functional-red-black-tree" "^1.0.1"
+ "ignore" "^5.1.8"
+ "regexpp" "^3.2.0"
+ "semver" "^7.3.5"
+ "tsutils" "^3.21.0"
+
+"@typescript-eslint/experimental-utils@5.8.1":
+ "integrity" "sha512-fbodVnjIDU4JpeXWRDsG5IfIjYBxEvs8EBO8W1+YVdtrc2B9ppfof5sZhVEDOtgTfFHnYQJDI8+qdqLYO4ceww=="
+ "resolved" "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.8.1.tgz"
+ "version" "5.8.1"
+ dependencies:
+ "@types/json-schema" "^7.0.9"
+ "@typescript-eslint/scope-manager" "5.8.1"
+ "@typescript-eslint/types" "5.8.1"
+ "@typescript-eslint/typescript-estree" "5.8.1"
+ "eslint-scope" "^5.1.1"
+ "eslint-utils" "^3.0.0"
+
+"@typescript-eslint/parser@^5.0.0", "@typescript-eslint/parser@5.8.1":
+ "integrity" "sha512-K1giKHAjHuyB421SoXMXFHHVI4NdNY603uKw92++D3qyxSeYvC10CBJ/GE5Thpo4WTUvu1mmJI2/FFkz38F2Gw=="
+ "resolved" "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.8.1.tgz"
+ "version" "5.8.1"
+ dependencies:
+ "@typescript-eslint/scope-manager" "5.8.1"
+ "@typescript-eslint/types" "5.8.1"
+ "@typescript-eslint/typescript-estree" "5.8.1"
+ "debug" "^4.3.2"
+
+"@typescript-eslint/scope-manager@5.8.1":
+ "integrity" "sha512-DGxJkNyYruFH3NIZc3PwrzwOQAg7vvgsHsHCILOLvUpupgkwDZdNq/cXU3BjF4LNrCsVg0qxEyWasys5AiJ85Q=="
+ "resolved" "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.8.1.tgz"
+ "version" "5.8.1"
+ dependencies:
+ "@typescript-eslint/types" "5.8.1"
+ "@typescript-eslint/visitor-keys" "5.8.1"
+
+"@typescript-eslint/types@5.8.1":
+ "integrity" "sha512-L/FlWCCgnjKOLefdok90/pqInkomLnAcF9UAzNr+DSqMC3IffzumHTQTrINXhP1gVp9zlHiYYjvozVZDPleLcA=="
+ "resolved" "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.8.1.tgz"
+ "version" "5.8.1"
+
+"@typescript-eslint/typescript-estree@5.8.1":
+ "integrity" "sha512-26lQ8l8tTbG7ri7xEcCFT9ijU5Fk+sx/KRRyyzCv7MQ+rZZlqiDPtMKWLC8P7o+dtCnby4c+OlxuX1tp8WfafQ=="
+ "resolved" "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.8.1.tgz"
+ "version" "5.8.1"
+ dependencies:
+ "@typescript-eslint/types" "5.8.1"
+ "@typescript-eslint/visitor-keys" "5.8.1"
+ "debug" "^4.3.2"
+ "globby" "^11.0.4"
+ "is-glob" "^4.0.3"
+ "semver" "^7.3.5"
+ "tsutils" "^3.21.0"
+
+"@typescript-eslint/visitor-keys@5.8.1":
+ "integrity" "sha512-SWgiWIwocK6NralrJarPZlWdr0hZnj5GXHIgfdm8hNkyKvpeQuFyLP6YjSIe9kf3YBIfU6OHSZLYkQ+smZwtNg=="
+ "resolved" "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.8.1.tgz"
+ "version" "5.8.1"
+ dependencies:
+ "@typescript-eslint/types" "5.8.1"
+ "eslint-visitor-keys" "^3.0.0"
+
+"@webassemblyjs/ast@1.11.1":
+ "integrity" "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@webassemblyjs/helper-numbers" "1.11.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+
+"@webassemblyjs/floating-point-hex-parser@1.11.1":
+ "integrity" "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz"
+ "version" "1.11.1"
+
+"@webassemblyjs/helper-api-error@1.11.1":
+ "integrity" "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz"
+ "version" "1.11.1"
+
+"@webassemblyjs/helper-buffer@1.11.1":
+ "integrity" "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz"
+ "version" "1.11.1"
+
+"@webassemblyjs/helper-numbers@1.11.1":
+ "integrity" "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@webassemblyjs/floating-point-hex-parser" "1.11.1"
+ "@webassemblyjs/helper-api-error" "1.11.1"
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/helper-wasm-bytecode@1.11.1":
+ "integrity" "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz"
+ "version" "1.11.1"
+
+"@webassemblyjs/helper-wasm-section@1.11.1":
+ "integrity" "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@webassemblyjs/ast" "1.11.1"
+ "@webassemblyjs/helper-buffer" "1.11.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+ "@webassemblyjs/wasm-gen" "1.11.1"
+
+"@webassemblyjs/ieee754@1.11.1":
+ "integrity" "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.11.1":
+ "integrity" "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.11.1":
+ "integrity" "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz"
+ "version" "1.11.1"
+
+"@webassemblyjs/wasm-edit@1.11.1":
+ "integrity" "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@webassemblyjs/ast" "1.11.1"
+ "@webassemblyjs/helper-buffer" "1.11.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+ "@webassemblyjs/helper-wasm-section" "1.11.1"
+ "@webassemblyjs/wasm-gen" "1.11.1"
+ "@webassemblyjs/wasm-opt" "1.11.1"
+ "@webassemblyjs/wasm-parser" "1.11.1"
+ "@webassemblyjs/wast-printer" "1.11.1"
+
+"@webassemblyjs/wasm-gen@1.11.1":
+ "integrity" "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@webassemblyjs/ast" "1.11.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+ "@webassemblyjs/ieee754" "1.11.1"
+ "@webassemblyjs/leb128" "1.11.1"
+ "@webassemblyjs/utf8" "1.11.1"
+
+"@webassemblyjs/wasm-opt@1.11.1":
+ "integrity" "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@webassemblyjs/ast" "1.11.1"
+ "@webassemblyjs/helper-buffer" "1.11.1"
+ "@webassemblyjs/wasm-gen" "1.11.1"
+ "@webassemblyjs/wasm-parser" "1.11.1"
+
+"@webassemblyjs/wasm-parser@1.11.1":
+ "integrity" "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@webassemblyjs/ast" "1.11.1"
+ "@webassemblyjs/helper-api-error" "1.11.1"
+ "@webassemblyjs/helper-wasm-bytecode" "1.11.1"
+ "@webassemblyjs/ieee754" "1.11.1"
+ "@webassemblyjs/leb128" "1.11.1"
+ "@webassemblyjs/utf8" "1.11.1"
+
+"@webassemblyjs/wast-printer@1.11.1":
+ "integrity" "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg=="
+ "resolved" "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz"
+ "version" "1.11.1"
+ dependencies:
+ "@webassemblyjs/ast" "1.11.1"
+ "@xtuc/long" "4.2.2"
+
+"@webpack-cli/configtest@^1.1.0":
+ "integrity" "sha512-ttOkEkoalEHa7RaFYpM0ErK1xc4twg3Am9hfHhL7MVqlHebnkYd2wuI/ZqTDj0cVzZho6PdinY0phFZV3O0Mzg=="
+ "resolved" "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.0.tgz"
+ "version" "1.1.0"
+
+"@webpack-cli/info@^1.4.0":
+ "integrity" "sha512-F6b+Man0rwE4n0409FyAJHStYA5OIZERxmnUfLVwv0mc0V1wLad3V7jqRlMkgKBeAq07jUvglacNaa6g9lOpuw=="
+ "resolved" "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.0.tgz"
+ "version" "1.4.0"
+ dependencies:
+ "envinfo" "^7.7.3"
+
+"@webpack-cli/serve@^1.6.0":
+ "integrity" "sha512-ZkVeqEmRpBV2GHvjjUZqEai2PpUbuq8Bqd//vEYsp63J8WyexI8ppCqVS3Zs0QADf6aWuPdU+0XsPI647PVlQA=="
+ "resolved" "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.0.tgz"
+ "version" "1.6.0"
+
+"@xtuc/ieee754@^1.2.0":
+ "integrity" "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA=="
+ "resolved" "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz"
+ "version" "1.2.0"
+
+"@xtuc/long@4.2.2":
+ "integrity" "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ=="
+ "resolved" "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz"
+ "version" "4.2.2"
+
+"abab@^2.0.3", "abab@^2.0.5":
+ "integrity" "sha512-9IK9EadsbHo6jLWIpxpR6pL0sazTXV6+SQv25ZB+F7Bj9mJNaOc4nCRabwd5M/JwmUa8idz6Eci6eKfJryPs6Q=="
+ "resolved" "https://registry.npmjs.org/abab/-/abab-2.0.5.tgz"
+ "version" "2.0.5"
+
+"abbrev@1", "abbrev@1.0.x":
+ "integrity" "sha1-kbR5JYinc4wl813W9jdSovh3YTU="
+ "resolved" "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz"
+ "version" "1.0.9"
+
+"accepts@~1.3.4", "accepts@~1.3.5", "accepts@~1.3.7":
+ "integrity" "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA=="
+ "resolved" "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz"
+ "version" "1.3.7"
+ dependencies:
+ "mime-types" "~2.1.24"
+ "negotiator" "0.6.2"
+
+"acorn-globals@^6.0.0":
+ "integrity" "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg=="
+ "resolved" "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz"
+ "version" "6.0.0"
+ dependencies:
+ "acorn" "^7.1.1"
+ "acorn-walk" "^7.1.1"
+
+"acorn-import-assertions@^1.7.6":
+ "integrity" "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw=="
+ "resolved" "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz"
+ "version" "1.8.0"
+
+"acorn-jsx@^5.3.1":
+ "integrity" "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ=="
+ "resolved" "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz"
+ "version" "5.3.2"
+
+"acorn-walk@^7.1.1":
+ "integrity" "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA=="
+ "resolved" "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz"
+ "version" "7.2.0"
+
+"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", "acorn@^8", "acorn@^8.2.4", "acorn@^8.4.1", "acorn@^8.5.0", "acorn@^8.7.0":
+ "integrity" "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ=="
+ "resolved" "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz"
+ "version" "8.7.0"
+
+"acorn@^7.1.1":
+ "integrity" "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
+ "resolved" "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz"
+ "version" "7.4.1"
+
+"after@0.8.2":
+ "integrity" "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8="
+ "resolved" "https://registry.npmjs.org/after/-/after-0.8.2.tgz"
+ "version" "0.8.2"
+
+"agent-base@6":
+ "integrity" "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="
+ "resolved" "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz"
+ "version" "6.0.2"
+ dependencies:
+ "debug" "4"
+
+"aggregate-error@^3.0.0":
+ "integrity" "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA=="
+ "resolved" "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz"
+ "version" "3.1.0"
+ dependencies:
+ "clean-stack" "^2.0.0"
+ "indent-string" "^4.0.0"
+
+"ajv-formats@^2.1.1":
+ "integrity" "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA=="
+ "resolved" "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz"
+ "version" "2.1.1"
+ dependencies:
+ "ajv" "^8.0.0"
+
+"ajv-keywords@^3.4.1", "ajv-keywords@^3.5.2":
+ "integrity" "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ=="
+ "resolved" "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz"
+ "version" "3.5.2"
+
+"ajv-keywords@^5.0.0":
+ "integrity" "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw=="
+ "resolved" "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz"
+ "version" "5.1.0"
+ dependencies:
+ "fast-deep-equal" "^3.1.3"
+
+"ajv@^6.10.0", "ajv@^6.12.2", "ajv@^6.12.3", "ajv@^6.12.4", "ajv@^6.12.5", "ajv@^6.9.1":
+ "integrity" "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="
+ "resolved" "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz"
+ "version" "6.12.6"
+ dependencies:
+ "fast-deep-equal" "^3.1.1"
+ "fast-json-stable-stringify" "^2.0.0"
+ "json-schema-traverse" "^0.4.1"
+ "uri-js" "^4.2.2"
+
+"ajv@^8.0.0":
+ "integrity" "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw=="
+ "resolved" "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz"
+ "version" "8.8.2"
+ dependencies:
+ "fast-deep-equal" "^3.1.1"
+ "json-schema-traverse" "^1.0.0"
+ "require-from-string" "^2.0.2"
+ "uri-js" "^4.2.2"
+
+"ajv@^8.6.0", "ajv@>=8":
+ "integrity" "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw=="
+ "resolved" "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz"
+ "version" "8.8.2"
+ dependencies:
+ "fast-deep-equal" "^3.1.1"
+ "json-schema-traverse" "^1.0.0"
+ "require-from-string" "^2.0.2"
+ "uri-js" "^4.2.2"
+
+"ajv@^8.8.0", "ajv@^8.8.2":
+ "integrity" "sha512-x9VuX+R/jcFj1DHo/fCp99esgGDWiHENrKxaCENuCxpoMCmAt/COCGVDwA7kleEpEzJjDnvh3yGoOuLu0Dtllw=="
+ "resolved" "https://registry.npmjs.org/ajv/-/ajv-8.8.2.tgz"
+ "version" "8.8.2"
+ dependencies:
+ "fast-deep-equal" "^3.1.1"
+ "json-schema-traverse" "^1.0.0"
+ "require-from-string" "^2.0.2"
+ "uri-js" "^4.2.2"
+
+"alphanum-sort@^1.0.2":
+ "integrity" "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM="
+ "resolved" "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz"
+ "version" "1.0.2"
+
+"amdefine@>=0.0.4":
+ "integrity" "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
+ "resolved" "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz"
+ "version" "1.0.1"
+
+"ansi-colors@^4.1.1":
+ "integrity" "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA=="
+ "resolved" "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz"
+ "version" "4.1.1"
+
+"ansi-escapes@^1.1.0":
+ "integrity" "sha1-06ioOzGapneTZisT52HHkRQiMG4="
+ "resolved" "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz"
+ "version" "1.4.0"
+
+"ansi-escapes@^3.0.0":
+ "integrity" "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ=="
+ "resolved" "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz"
+ "version" "3.2.0"
+
+"ansi-escapes@^4.2.1":
+ "integrity" "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="
+ "resolved" "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz"
+ "version" "4.3.2"
+ dependencies:
+ "type-fest" "^0.21.3"
+
+"ansi-escapes@^4.3.0":
+ "integrity" "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ=="
+ "resolved" "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz"
+ "version" "4.3.2"
+ dependencies:
+ "type-fest" "^0.21.3"
+
+"ansi-html-community@^0.0.8":
+ "integrity" "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw=="
+ "resolved" "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz"
+ "version" "0.0.8"
+
+"ansi-regex@^2.0.0":
+ "integrity" "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
+ "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
+ "version" "2.1.1"
+
+"ansi-regex@^3.0.0":
+ "integrity" "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
+ "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz"
+ "version" "3.0.0"
+
+"ansi-regex@^5.0.1":
+ "integrity" "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
+ "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz"
+ "version" "5.0.1"
+
+"ansi-regex@^6.0.1":
+ "integrity" "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA=="
+ "resolved" "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz"
+ "version" "6.0.1"
+
+"ansi-styles@^2.2.1":
+ "integrity" "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
+ "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
+ "version" "2.2.1"
+
+"ansi-styles@^3.1.0":
+ "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="
+ "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
+ "version" "3.2.1"
+ dependencies:
+ "color-convert" "^1.9.0"
+
+"ansi-styles@^3.2.1":
+ "integrity" "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA=="
+ "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz"
+ "version" "3.2.1"
+ dependencies:
+ "color-convert" "^1.9.0"
+
+"ansi-styles@^4.0.0", "ansi-styles@^4.1.0":
+ "integrity" "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="
+ "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz"
+ "version" "4.3.0"
+ dependencies:
+ "color-convert" "^2.0.1"
+
+"ansi-styles@^5.0.0":
+ "integrity" "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
+ "resolved" "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz"
+ "version" "5.2.0"
+
+"ansi@^0.3.0", "ansi@~0.3.1":
+ "integrity" "sha1-DELU+xcWDVqa8eSEus4cZpIsGyE="
+ "resolved" "https://registry.npmjs.org/ansi/-/ansi-0.3.1.tgz"
+ "version" "0.3.1"
+
+"anymatch@^3.0.3", "anymatch@~3.1.2":
+ "integrity" "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg=="
+ "resolved" "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz"
+ "version" "3.1.2"
+ dependencies:
+ "normalize-path" "^3.0.0"
+ "picomatch" "^2.0.4"
+
+"are-we-there-yet@~1.1.2":
+ "integrity" "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g=="
+ "resolved" "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz"
+ "version" "1.1.7"
+ dependencies:
+ "delegates" "^1.0.0"
+ "readable-stream" "^2.0.6"
+
+"argparse@^1.0.7":
+ "integrity" "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg=="
+ "resolved" "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz"
+ "version" "1.0.10"
+ dependencies:
+ "sprintf-js" "~1.0.2"
+
+"argparse@^2.0.1":
+ "integrity" "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="
+ "resolved" "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz"
+ "version" "2.0.1"
+
+"aria-query@^5.0.0":
+ "integrity" "sha512-V+SM7AbUwJ+EBnB8+DXs0hPZHO0W6pqBcc0dW90OwtVG02PswOu/teuARoLQjdDOH+t9pJgGnW5/Qmouf3gPJg=="
+ "resolved" "https://registry.npmjs.org/aria-query/-/aria-query-5.0.0.tgz"
+ "version" "5.0.0"
+
+"array-differ@^1.0.0":
+ "integrity" "sha1-7/UuN1gknTO+QCuLuOVkuytdQDE="
+ "resolved" "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz"
+ "version" "1.0.0"
+
+"array-find-index@^1.0.1":
+ "integrity" "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E="
+ "resolved" "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz"
+ "version" "1.0.2"
+
+"array-flatten@^2.1.0":
+ "integrity" "sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ=="
+ "resolved" "https://registry.npmjs.org/array-flatten/-/array-flatten-2.1.2.tgz"
+ "version" "2.1.2"
+
+"array-flatten@1.1.1":
+ "integrity" "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+ "resolved" "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz"
+ "version" "1.1.1"
+
+"array-includes@^3.1.3", "array-includes@^3.1.4":
+ "integrity" "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw=="
+ "resolved" "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz"
+ "version" "3.1.4"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "define-properties" "^1.1.3"
+ "es-abstract" "^1.19.1"
+ "get-intrinsic" "^1.1.1"
+ "is-string" "^1.0.7"
+
+"array-union@^1.0.1":
+ "integrity" "sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk="
+ "resolved" "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "array-uniq" "^1.0.1"
+
+"array-union@^2.1.0":
+ "integrity" "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw=="
+ "resolved" "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz"
+ "version" "2.1.0"
+
+"array-union@^3.0.1":
+ "integrity" "sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw=="
+ "resolved" "https://registry.npmjs.org/array-union/-/array-union-3.0.1.tgz"
+ "version" "3.0.1"
+
+"array-uniq@^1.0.1":
+ "integrity" "sha1-r2rId6Jcx/dOBYiUdThY39sk/bY="
+ "resolved" "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz"
+ "version" "1.0.3"
+
+"array.prototype.flatmap@^1.2.5":
+ "integrity" "sha512-08u6rVyi1Lj7oqWbS9nUxliETrtIROT4XGTA4D/LWGten6E3ocm7cy9SIrmNHOL5XVbVuckUp3X6Xyg8/zpvHA=="
+ "resolved" "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.2.5.tgz"
+ "version" "1.2.5"
+ dependencies:
+ "call-bind" "^1.0.0"
+ "define-properties" "^1.1.3"
+ "es-abstract" "^1.19.0"
+
+"arraybuffer.slice@~0.0.7":
+ "integrity" "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog=="
+ "resolved" "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz"
+ "version" "0.0.7"
+
+"arrify@^1.0.0":
+ "integrity" "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0="
+ "resolved" "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz"
+ "version" "1.0.1"
+
+"asn1@~0.2.3":
+ "integrity" "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ=="
+ "resolved" "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz"
+ "version" "0.2.6"
+ dependencies:
+ "safer-buffer" "~2.1.0"
+
+"assert-plus@^1.0.0", "assert-plus@1.0.0":
+ "integrity" "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
+ "resolved" "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+ "version" "1.0.0"
+
+"astral-regex@^2.0.0":
+ "integrity" "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ=="
+ "resolved" "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz"
+ "version" "2.0.0"
+
+"async-each-series@0.1.1":
+ "integrity" "sha1-dhfBkXQB/Yykooqtzj266Yr+tDI="
+ "resolved" "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz"
+ "version" "0.1.1"
+
+"async@^1.4.2":
+ "integrity" "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ "resolved" "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
+ "version" "1.5.2"
+
+"async@^2.5.0", "async@^2.6.2":
+ "integrity" "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg=="
+ "resolved" "https://registry.npmjs.org/async/-/async-2.6.3.tgz"
+ "version" "2.6.3"
+ dependencies:
+ "lodash" "^4.17.14"
+
+"async@~1.0.0":
+ "integrity" "sha1-+PwEyjoTeErenhZBr5hXjPvWR6k="
+ "resolved" "https://registry.npmjs.org/async/-/async-1.0.0.tgz"
+ "version" "1.0.0"
+
+"async@0.9.x":
+ "integrity" "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0="
+ "resolved" "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
+ "version" "0.9.2"
+
+"async@1.5.2":
+ "integrity" "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ "resolved" "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
+ "version" "1.5.2"
+
+"async@1.x":
+ "integrity" "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo="
+ "resolved" "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
+ "version" "1.5.2"
+
+"asynckit@^0.4.0":
+ "integrity" "sha1-x57Zf380y48robyXkLzDZkdLS3k="
+ "resolved" "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
+ "version" "0.4.0"
+
+"at-least-node@^1.0.0":
+ "integrity" "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
+ "resolved" "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz"
+ "version" "1.0.0"
+
+"autoprefixer@10.4.1":
+ "integrity" "sha512-B3ZEG7wtzXDRCEFsan7HmR2AeNsxdJB0+sEC0Hc5/c2NbhJqPwuZm+tn233GBVw82L+6CtD6IPSfVruwKjfV3A=="
+ "resolved" "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.1.tgz"
+ "version" "10.4.1"
+ dependencies:
+ "browserslist" "^4.19.1"
+ "caniuse-lite" "^1.0.30001294"
+ "fraction.js" "^4.1.2"
+ "normalize-range" "^0.1.2"
+ "picocolors" "^1.0.0"
+ "postcss-value-parser" "^4.2.0"
+
+"aws-sign2@~0.7.0":
+ "integrity" "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
+ "resolved" "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz"
+ "version" "0.7.0"
+
+"aws4@^1.8.0":
+ "integrity" "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
+ "resolved" "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz"
+ "version" "1.11.0"
+
+"axios@*", "axios@0.24.0":
+ "integrity" "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA=="
+ "resolved" "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz"
+ "version" "0.24.0"
+ dependencies:
+ "follow-redirects" "^1.14.4"
+
+"axios@^0.21.1":
+ "integrity" "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg=="
+ "resolved" "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz"
+ "version" "0.21.4"
+ dependencies:
+ "follow-redirects" "^1.14.0"
+
+"axios@0.21.4":
+ "integrity" "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg=="
+ "resolved" "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz"
+ "version" "0.21.4"
+ dependencies:
+ "follow-redirects" "^1.14.0"
+
+"babel-jest@^27.4.6", "babel-jest@>=27.0.0 <28":
+ "integrity" "sha512-qZL0JT0HS1L+lOuH+xC2DVASR3nunZi/ozGhpgauJHgmI7f8rudxf6hUjEHympdQ/J64CdKmPkgfJ+A3U6QCrg=="
+ "resolved" "https://registry.npmjs.org/babel-jest/-/babel-jest-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/transform" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/babel__core" "^7.1.14"
+ "babel-plugin-istanbul" "^6.1.1"
+ "babel-preset-jest" "^27.4.0"
+ "chalk" "^4.0.0"
+ "graceful-fs" "^4.2.4"
+ "slash" "^3.0.0"
+
+"babel-plugin-dynamic-import-node@^2.3.3":
+ "integrity" "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ=="
+ "resolved" "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz"
+ "version" "2.3.3"
+ dependencies:
+ "object.assign" "^4.1.0"
+
+"babel-plugin-istanbul@^6.1.1":
+ "integrity" "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA=="
+ "resolved" "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz"
+ "version" "6.1.1"
+ dependencies:
+ "@babel/helper-plugin-utils" "^7.0.0"
+ "@istanbuljs/load-nyc-config" "^1.0.0"
+ "@istanbuljs/schema" "^0.1.2"
+ "istanbul-lib-instrument" "^5.0.4"
+ "test-exclude" "^6.0.0"
+
+"babel-plugin-jest-hoist@^27.4.0":
+ "integrity" "sha512-Jcu7qS4OX5kTWBc45Hz7BMmgXuJqRnhatqpUhnzGC3OBYpOmf2tv6jFNwZpwM7wU7MUuv2r9IPS/ZlYOuburVw=="
+ "resolved" "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-27.4.0.tgz"
+ "version" "27.4.0"
+ dependencies:
+ "@babel/template" "^7.3.3"
+ "@babel/types" "^7.3.3"
+ "@types/babel__core" "^7.0.0"
+ "@types/babel__traverse" "^7.0.6"
+
+"babel-plugin-polyfill-corejs2@^0.3.0":
+ "integrity" "sha512-wMDoBJ6uG4u4PNFh72Ty6t3EgfA91puCuAwKIazbQlci+ENb/UU9A3xG5lutjUIiXCIn1CY5L15r9LimiJyrSA=="
+ "resolved" "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.0.tgz"
+ "version" "0.3.0"
+ dependencies:
+ "@babel/compat-data" "^7.13.11"
+ "@babel/helper-define-polyfill-provider" "^0.3.0"
+ "semver" "^6.1.1"
+
+"babel-plugin-polyfill-corejs3@^0.4.0":
+ "integrity" "sha512-YxFreYwUfglYKdLUGvIF2nJEsGwj+RhWSX/ije3D2vQPOXuyMLMtg/cCGMDpOA7Nd+MwlNdnGODbd2EwUZPlsw=="
+ "resolved" "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.4.0.tgz"
+ "version" "0.4.0"
+ dependencies:
+ "@babel/helper-define-polyfill-provider" "^0.3.0"
+ "core-js-compat" "^3.18.0"
+
+"babel-plugin-polyfill-regenerator@^0.3.0":
+ "integrity" "sha512-dhAPTDLGoMW5/84wkgwiLRwMnio2i1fUe53EuvtKMv0pn2p3S8OCoV1xAzfJPl0KOX7IB89s2ib85vbYiea3jg=="
+ "resolved" "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.0.tgz"
+ "version" "0.3.0"
+ dependencies:
+ "@babel/helper-define-polyfill-provider" "^0.3.0"
+
+"babel-polyfill@6.23.0":
+ "integrity" "sha1-g2TKYt+Or7gwSZ9pkXdGbDsDSZ0="
+ "resolved" "https://registry.npmjs.org/babel-polyfill/-/babel-polyfill-6.23.0.tgz"
+ "version" "6.23.0"
+ dependencies:
+ "babel-runtime" "^6.22.0"
+ "core-js" "^2.4.0"
+ "regenerator-runtime" "^0.10.0"
+
+"babel-preset-current-node-syntax@^1.0.0":
+ "integrity" "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ=="
+ "resolved" "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz"
+ "version" "1.0.1"
+ dependencies:
+ "@babel/plugin-syntax-async-generators" "^7.8.4"
+ "@babel/plugin-syntax-bigint" "^7.8.3"
+ "@babel/plugin-syntax-class-properties" "^7.8.3"
+ "@babel/plugin-syntax-import-meta" "^7.8.3"
+ "@babel/plugin-syntax-json-strings" "^7.8.3"
+ "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3"
+ "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3"
+ "@babel/plugin-syntax-numeric-separator" "^7.8.3"
+ "@babel/plugin-syntax-object-rest-spread" "^7.8.3"
+ "@babel/plugin-syntax-optional-catch-binding" "^7.8.3"
+ "@babel/plugin-syntax-optional-chaining" "^7.8.3"
+ "@babel/plugin-syntax-top-level-await" "^7.8.3"
+
+"babel-preset-jest@^27.4.0":
+ "integrity" "sha512-NK4jGYpnBvNxcGo7/ZpZJr51jCGT+3bwwpVIDY2oNfTxJJldRtB4VAcYdgp1loDE50ODuTu+yBjpMAswv5tlpg=="
+ "resolved" "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-27.4.0.tgz"
+ "version" "27.4.0"
+ dependencies:
+ "babel-plugin-jest-hoist" "^27.4.0"
+ "babel-preset-current-node-syntax" "^1.0.0"
+
+"babel-runtime@^6.22.0":
+ "integrity" "sha1-llxwWGaOgrVde/4E/yM3vItWR/4="
+ "resolved" "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz"
+ "version" "6.26.0"
+ dependencies:
+ "core-js" "^2.4.0"
+ "regenerator-runtime" "^0.11.0"
+
+"backo2@1.0.2":
+ "integrity" "sha1-MasayLEpNjRj41s+u2n038+6eUc="
+ "resolved" "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz"
+ "version" "1.0.2"
+
+"balanced-match@^1.0.0":
+ "integrity" "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ "resolved" "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz"
+ "version" "1.0.2"
+
+"base64-arraybuffer@0.1.4":
+ "integrity" "sha1-mBjHngWbE1X5fgQooBfIOOkLqBI="
+ "resolved" "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.4.tgz"
+ "version" "0.1.4"
+
+"base64id@2.0.0":
+ "integrity" "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog=="
+ "resolved" "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz"
+ "version" "2.0.0"
+
+"batch@0.6.1":
+ "integrity" "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY="
+ "resolved" "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz"
+ "version" "0.6.1"
+
+"bcrypt-pbkdf@^1.0.0":
+ "integrity" "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4="
+ "resolved" "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "tweetnacl" "^0.14.3"
+
+"big.js@^3.1.3":
+ "integrity" "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q=="
+ "resolved" "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz"
+ "version" "3.2.0"
+
+"big.js@^5.2.2":
+ "integrity" "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ=="
+ "resolved" "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz"
+ "version" "5.2.2"
+
+"binary-extensions@^2.0.0":
+ "integrity" "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA=="
+ "resolved" "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz"
+ "version" "2.2.0"
+
+"binaryextensions@^2.1.2":
+ "integrity" "sha512-nAihlQsYGyc5Bwq6+EsubvANYGExeJKHDO3RjnvwU042fawQTQfM3Kxn7IHUXQOz4bzfwsGYYHGSvXyW4zOGLg=="
+ "resolved" "https://registry.npmjs.org/binaryextensions/-/binaryextensions-2.3.0.tgz"
+ "version" "2.3.0"
+
+"blob@0.0.5":
+ "integrity" "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig=="
+ "resolved" "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz"
+ "version" "0.0.5"
+
+"body-parser@1.19.1":
+ "integrity" "sha512-8ljfQi5eBk8EJfECMrgqNGWPEY5jWP+1IzkzkGdFFEwFQZZyaZ21UqdaHktgiMlH0xLHqIFtE/u2OYE5dOtViA=="
+ "resolved" "https://registry.npmjs.org/body-parser/-/body-parser-1.19.1.tgz"
+ "version" "1.19.1"
+ dependencies:
+ "bytes" "3.1.1"
+ "content-type" "~1.0.4"
+ "debug" "2.6.9"
+ "depd" "~1.1.2"
+ "http-errors" "1.8.1"
+ "iconv-lite" "0.4.24"
+ "on-finished" "~2.3.0"
+ "qs" "6.9.6"
+ "raw-body" "2.4.2"
+ "type-is" "~1.6.18"
+
+"bonjour@^3.5.0":
+ "integrity" "sha1-jokKGD2O6aI5OzhExpGkK897yfU="
+ "resolved" "https://registry.npmjs.org/bonjour/-/bonjour-3.5.0.tgz"
+ "version" "3.5.0"
+ dependencies:
+ "array-flatten" "^2.1.0"
+ "deep-equal" "^1.0.1"
+ "dns-equal" "^1.0.0"
+ "dns-txt" "^2.0.2"
+ "multicast-dns" "^6.0.1"
+ "multicast-dns-service-types" "^1.1.0"
+
+"boolbase@^1.0.0", "boolbase@~1.0.0":
+ "integrity" "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
+ "resolved" "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz"
+ "version" "1.0.0"
+
+"bootstrap@5.1.3":
+ "integrity" "sha512-fcQztozJ8jToQWXxVuEyXWW+dSo8AiXWKwiSSrKWsRB/Qt+Ewwza+JWoLKiTuQLaEPhdNAJ7+Dosc9DOIqNy7Q=="
+ "resolved" "https://registry.npmjs.org/bootstrap/-/bootstrap-5.1.3.tgz"
+ "version" "5.1.3"
+
+"bootswatch@5.1.3":
+ "integrity" "sha512-NmZFN6rOCoXWQ/PkzmD8FFWDe24kocX9OXWHNVaLxVVnpqpAzEbMFsf8bAfKwVtpNXibasZCzv09B5fLieAh2g=="
+ "resolved" "https://registry.npmjs.org/bootswatch/-/bootswatch-5.1.3.tgz"
+ "version" "5.1.3"
+
+"brace-expansion@^1.1.7":
+ "integrity" "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA=="
+ "resolved" "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz"
+ "version" "1.1.11"
+ dependencies:
+ "balanced-match" "^1.0.0"
+ "concat-map" "0.0.1"
+
+"braces@^3.0.1", "braces@~3.0.2":
+ "integrity" "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A=="
+ "resolved" "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz"
+ "version" "3.0.2"
+ dependencies:
+ "fill-range" "^7.0.1"
+
+"browser-process-hrtime@^1.0.0":
+ "integrity" "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
+ "resolved" "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz"
+ "version" "1.0.0"
+
+"browser-sync-client@^2.27.7":
+ "integrity" "sha512-wKg9UP9a4sCIkBBAXUdbkdWFJzfSAQizGh+nC19W9y9zOo9s5jqeYRFUUbs7x5WKhjtspT+xetVp9AtBJ6BmWg=="
+ "resolved" "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-2.27.7.tgz"
+ "version" "2.27.7"
+ dependencies:
+ "etag" "1.8.1"
+ "fresh" "0.5.2"
+ "mitt" "^1.1.3"
+ "rxjs" "^5.5.6"
+
+"browser-sync-ui@^2.27.7":
+ "integrity" "sha512-Bt4OQpx9p18OIzk0KKyu7jqlvmjacasUlk8ARY3uuIyiFWSBiRgr2i6XY8dEMF14DtbooaEBOpHEu9VCYvMcCw=="
+ "resolved" "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-2.27.7.tgz"
+ "version" "2.27.7"
+ dependencies:
+ "async-each-series" "0.1.1"
+ "connect-history-api-fallback" "^1"
+ "immutable" "^3"
+ "server-destroy" "1.0.1"
+ "socket.io-client" "^2.4.0"
+ "stream-throttle" "^0.1.3"
+
+"browser-sync-webpack-plugin@2.3.0":
+ "integrity" "sha512-MDvuRrTCtoL11dTdwMymo9CNJvYxJoW67gOO61cThfzHNX40S5WcBU+0bVQ86ll7r7aNpNgyzxF7RtnXMTDbyA=="
+ "resolved" "https://registry.npmjs.org/browser-sync-webpack-plugin/-/browser-sync-webpack-plugin-2.3.0.tgz"
+ "version" "2.3.0"
+ dependencies:
+ "lodash" "^4"
+
+"browser-sync@^2", "browser-sync@2.27.7":
+ "integrity" "sha512-9ElnnA/u+s2Jd+IgY+2SImB+sAEIteHsMG0NR96m7Ph/wztpvJCUpyC2on1KqmG9iAp941j+5jfmd34tEguGbg=="
+ "resolved" "https://registry.npmjs.org/browser-sync/-/browser-sync-2.27.7.tgz"
+ "version" "2.27.7"
+ dependencies:
+ "browser-sync-client" "^2.27.7"
+ "browser-sync-ui" "^2.27.7"
+ "bs-recipes" "1.3.4"
+ "bs-snippet-injector" "^2.0.1"
+ "chokidar" "^3.5.1"
+ "connect" "3.6.6"
+ "connect-history-api-fallback" "^1"
+ "dev-ip" "^1.0.1"
+ "easy-extender" "^2.3.4"
+ "eazy-logger" "3.1.0"
+ "etag" "^1.8.1"
+ "fresh" "^0.5.2"
+ "fs-extra" "3.0.1"
+ "http-proxy" "^1.18.1"
+ "immutable" "^3"
+ "localtunnel" "^2.0.1"
+ "micromatch" "^4.0.2"
+ "opn" "5.3.0"
+ "portscanner" "2.1.1"
+ "qs" "6.2.3"
+ "raw-body" "^2.3.2"
+ "resp-modifier" "6.0.2"
+ "rx" "4.1.0"
+ "send" "0.16.2"
+ "serve-index" "1.9.1"
+ "serve-static" "1.13.2"
+ "server-destroy" "1.0.1"
+ "socket.io" "2.4.0"
+ "ua-parser-js" "1.0.2"
+ "yargs" "^15.4.1"
+
+"browserslist@^4.0.0", "browserslist@^4.14.5", "browserslist@^4.16.0", "browserslist@^4.16.6", "browserslist@^4.17.5", "browserslist@^4.19.1":
+ "integrity" "sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A=="
+ "resolved" "https://registry.npmjs.org/browserslist/-/browserslist-4.19.1.tgz"
+ "version" "4.19.1"
+ dependencies:
+ "caniuse-lite" "^1.0.30001286"
+ "electron-to-chromium" "^1.4.17"
+ "escalade" "^3.1.1"
+ "node-releases" "^2.0.1"
+ "picocolors" "^1.0.0"
+
+"bs-logger@0.x":
+ "integrity" "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog=="
+ "resolved" "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz"
+ "version" "0.2.6"
+ dependencies:
+ "fast-json-stable-stringify" "2.x"
+
+"bs-recipes@1.3.4":
+ "integrity" "sha1-DS1NSKcYyMBEdp/cT4lZLci2lYU="
+ "resolved" "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz"
+ "version" "1.3.4"
+
+"bs-snippet-injector@^2.0.1":
+ "integrity" "sha1-YbU5PxH1JVntEgaTEANDtu2wTdU="
+ "resolved" "https://registry.npmjs.org/bs-snippet-injector/-/bs-snippet-injector-2.0.1.tgz"
+ "version" "2.0.1"
+
+"bser@2.1.1":
+ "integrity" "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ=="
+ "resolved" "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz"
+ "version" "2.1.1"
+ dependencies:
+ "node-int64" "^0.4.0"
+
+"buffer-from@^1.0.0":
+ "integrity" "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="
+ "resolved" "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz"
+ "version" "1.1.2"
+
+"buffer-indexof@^1.0.0":
+ "integrity" "sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g=="
+ "resolved" "https://registry.npmjs.org/buffer-indexof/-/buffer-indexof-1.1.1.tgz"
+ "version" "1.1.1"
+
+"builtin-modules@^3.1.0":
+ "integrity" "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA=="
+ "resolved" "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz"
+ "version" "3.2.0"
+
+"bytes@3.0.0":
+ "integrity" "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
+ "resolved" "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz"
+ "version" "3.0.0"
+
+"bytes@3.1.1":
+ "integrity" "sha512-dWe4nWO/ruEOY7HkUJ5gFt1DCFV9zPRoJr8pV0/ASQermOZjtq8jMjOprC0Kd10GLN+l7xaUPvxzJFWtxGu8Fg=="
+ "resolved" "https://registry.npmjs.org/bytes/-/bytes-3.1.1.tgz"
+ "version" "3.1.1"
+
+"call-bind@^1.0.0", "call-bind@^1.0.2":
+ "integrity" "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA=="
+ "resolved" "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "function-bind" "^1.1.1"
+ "get-intrinsic" "^1.0.2"
+
+"callsites@^3.0.0":
+ "integrity" "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ=="
+ "resolved" "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz"
+ "version" "3.1.0"
+
+"camel-case@^4.1.2":
+ "integrity" "sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw=="
+ "resolved" "https://registry.npmjs.org/camel-case/-/camel-case-4.1.2.tgz"
+ "version" "4.1.2"
+ dependencies:
+ "pascal-case" "^3.1.2"
+ "tslib" "^2.0.3"
+
+"camelcase-keys@^2.0.0":
+ "integrity" "sha1-MIvur/3ygRkFHvodkyITyRuPkuc="
+ "resolved" "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "camelcase" "^2.0.0"
+ "map-obj" "^1.0.0"
+
+"camelcase@^2.0.0":
+ "integrity" "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
+ "resolved" "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz"
+ "version" "2.1.1"
+
+"camelcase@^5.0.0", "camelcase@^5.3.1":
+ "integrity" "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg=="
+ "resolved" "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz"
+ "version" "5.3.1"
+
+"camelcase@^6.2.0":
+ "integrity" "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA=="
+ "resolved" "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz"
+ "version" "6.3.0"
+
+"caniuse-api@^3.0.0":
+ "integrity" "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw=="
+ "resolved" "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "browserslist" "^4.0.0"
+ "caniuse-lite" "^1.0.0"
+ "lodash.memoize" "^4.1.2"
+ "lodash.uniq" "^4.5.0"
+
+"caniuse-lite@^1.0.0", "caniuse-lite@^1.0.30001286", "caniuse-lite@^1.0.30001294":
+ "integrity" "sha512-WfrtPEoNSoeATDlf4y3QvkwiELl9GyPLISV5GejTbbQRtQx4LhsXmc9IQ6XCL2d7UxCyEzToEZNMeqR79OUw8Q=="
+ "resolved" "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001296.tgz"
+ "version" "1.0.30001296"
+
+"caseless@~0.12.0":
+ "integrity" "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
+ "resolved" "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz"
+ "version" "0.12.0"
+
+"chalk@^1.0.0", "chalk@1.1.3":
+ "integrity" "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg="
+ "resolved" "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz"
+ "version" "1.1.3"
+ dependencies:
+ "ansi-styles" "^2.2.1"
+ "escape-string-regexp" "^1.0.2"
+ "has-ansi" "^2.0.0"
+ "strip-ansi" "^3.0.0"
+ "supports-color" "^2.0.0"
+
+"chalk@^1.1.3":
+ "integrity" "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg="
+ "resolved" "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz"
+ "version" "1.1.3"
+ dependencies:
+ "ansi-styles" "^2.2.1"
+ "escape-string-regexp" "^1.0.2"
+ "has-ansi" "^2.0.0"
+ "strip-ansi" "^3.0.0"
+ "supports-color" "^2.0.0"
+
+"chalk@^2.0.0", "chalk@^2.1.0":
+ "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="
+ "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
+ "version" "2.4.2"
+ dependencies:
+ "ansi-styles" "^3.2.1"
+ "escape-string-regexp" "^1.0.5"
+ "supports-color" "^5.3.0"
+
+"chalk@^2.0.1":
+ "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="
+ "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
+ "version" "2.4.2"
+ dependencies:
+ "ansi-styles" "^3.2.1"
+ "escape-string-regexp" "^1.0.5"
+ "supports-color" "^5.3.0"
+
+"chalk@^2.1.0":
+ "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="
+ "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
+ "version" "2.4.2"
+ dependencies:
+ "ansi-styles" "^3.2.1"
+ "escape-string-regexp" "^1.0.5"
+ "supports-color" "^5.3.0"
+
+"chalk@^2.4.2":
+ "integrity" "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ=="
+ "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz"
+ "version" "2.4.2"
+ dependencies:
+ "ansi-styles" "^3.2.1"
+ "escape-string-regexp" "^1.0.5"
+ "supports-color" "^5.3.0"
+
+"chalk@^4.0.0", "chalk@^4.1.0", "chalk@4.1.x":
+ "integrity" "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="
+ "resolved" "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz"
+ "version" "4.1.2"
+ dependencies:
+ "ansi-styles" "^4.1.0"
+ "supports-color" "^7.1.0"
+
+"chalk@2.3.0":
+ "integrity" "sha512-Az5zJR2CBujap2rqXGaJKaPHyJ0IrUimvYNX+ncCy8PJP4ltOGTrHUIo097ZaL2zMeKYpiCdqDvS6zdrTFok3Q=="
+ "resolved" "https://registry.npmjs.org/chalk/-/chalk-2.3.0.tgz"
+ "version" "2.3.0"
+ dependencies:
+ "ansi-styles" "^3.1.0"
+ "escape-string-regexp" "^1.0.5"
+ "supports-color" "^4.0.0"
+
+"char-regex@^1.0.2":
+ "integrity" "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw=="
+ "resolved" "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz"
+ "version" "1.0.2"
+
+"chardet@^0.4.0":
+ "integrity" "sha1-tUc7M9yXxCTl2Y3IfVXU2KKci/I="
+ "resolved" "https://registry.npmjs.org/chardet/-/chardet-0.4.2.tgz"
+ "version" "0.4.2"
+
+"cheerio@^0.19.0":
+ "integrity" "sha1-dy5wFfLuKZZQltcepBdbdas1SSU="
+ "resolved" "https://registry.npmjs.org/cheerio/-/cheerio-0.19.0.tgz"
+ "version" "0.19.0"
+ dependencies:
+ "css-select" "~1.0.0"
+ "dom-serializer" "~0.1.0"
+ "entities" "~1.1.1"
+ "htmlparser2" "~3.8.1"
+ "lodash" "^3.2.0"
+
+"cheerio@0.22.0":
+ "integrity" "sha1-qbqoYKP5tZWmuBsahocxIe06Jp4="
+ "resolved" "https://registry.npmjs.org/cheerio/-/cheerio-0.22.0.tgz"
+ "version" "0.22.0"
+ dependencies:
+ "css-select" "~1.2.0"
+ "dom-serializer" "~0.1.0"
+ "entities" "~1.1.1"
+ "htmlparser2" "^3.9.1"
+ "lodash.assignin" "^4.0.9"
+ "lodash.bind" "^4.1.4"
+ "lodash.defaults" "^4.0.1"
+ "lodash.filter" "^4.4.0"
+ "lodash.flatten" "^4.2.0"
+ "lodash.foreach" "^4.3.0"
+ "lodash.map" "^4.4.0"
+ "lodash.merge" "^4.4.0"
+ "lodash.pick" "^4.2.1"
+ "lodash.reduce" "^4.4.0"
+ "lodash.reject" "^4.4.0"
+ "lodash.some" "^4.4.0"
+
+"chevrotain@6.5.0":
+ "integrity" "sha512-BwqQ/AgmKJ8jcMEjaSnfMybnKMgGTrtDKowfTP3pX4jwVy0kNjRsT/AP6h+wC3+3NC+X8X15VWBnTCQlX+wQFg=="
+ "resolved" "https://registry.npmjs.org/chevrotain/-/chevrotain-6.5.0.tgz"
+ "version" "6.5.0"
+ dependencies:
+ "regexp-to-ast" "0.4.0"
+
+"chokidar@^3.4.2", "chokidar@^3.5.1", "chokidar@^3.5.2", "chokidar@>=3.0.0 <4.0.0":
+ "integrity" "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ=="
+ "resolved" "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz"
+ "version" "3.5.2"
+ dependencies:
+ "anymatch" "~3.1.2"
+ "braces" "~3.0.2"
+ "glob-parent" "~5.1.2"
+ "is-binary-path" "~2.1.0"
+ "is-glob" "~4.0.1"
+ "normalize-path" "~3.0.0"
+ "readdirp" "~3.6.0"
+ optionalDependencies:
+ "fsevents" "~2.3.2"
+
+"chrome-trace-event@^1.0.2":
+ "integrity" "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg=="
+ "resolved" "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz"
+ "version" "1.0.3"
+
+"ci-info@^3.2.0":
+ "integrity" "sha512-riT/3vI5YpVH6/qomlDnJow6TBee2PBKSEpx3O32EGPYbWGIRsIlGRms3Sm74wYE1JMo8RnO04Hb12+v1J5ICw=="
+ "resolved" "https://registry.npmjs.org/ci-info/-/ci-info-3.3.0.tgz"
+ "version" "3.3.0"
+
+"cjs-module-lexer@^1.0.0":
+ "integrity" "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA=="
+ "resolved" "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz"
+ "version" "1.2.2"
+
+"classnames@^2.2.3":
+ "integrity" "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA=="
+ "resolved" "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz"
+ "version" "2.3.1"
+
+"clean-css@^5.2.2":
+ "integrity" "sha512-/eR8ru5zyxKzpBLv9YZvMXgTSSQn7AdkMItMYynsFgGwTveCRVam9IUPFloE85B4vAIj05IuKmmEoV7/AQjT0w=="
+ "resolved" "https://registry.npmjs.org/clean-css/-/clean-css-5.2.2.tgz"
+ "version" "5.2.2"
+ dependencies:
+ "source-map" "~0.6.0"
+
+"clean-stack@^2.0.0":
+ "integrity" "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A=="
+ "resolved" "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz"
+ "version" "2.2.0"
+
+"cli-cursor@^1.0.1":
+ "integrity" "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc="
+ "resolved" "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "restore-cursor" "^1.0.1"
+
+"cli-cursor@^2.1.0":
+ "integrity" "sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU="
+ "resolved" "https://registry.npmjs.org/cli-cursor/-/cli-cursor-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "restore-cursor" "^2.0.0"
+
+"cli-cursor@^3.1.0":
+ "integrity" "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw=="
+ "resolved" "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz"
+ "version" "3.1.0"
+ dependencies:
+ "restore-cursor" "^3.1.0"
+
+"cli-table@^0.3.1":
+ "integrity" "sha512-IqLQi4lO0nIB4tcdTpN4LCB9FI3uqrJZK7RC515EnhZ6qBaglkIgICb1wjeAqpdoOabm1+SuQtkXIPdYC93jhQ=="
+ "resolved" "https://registry.npmjs.org/cli-table/-/cli-table-0.3.11.tgz"
+ "version" "0.3.11"
+ dependencies:
+ "colors" "1.0.3"
+
+"cli-width@^1.0.1":
+ "integrity" "sha1-pNKT72frt7iNSk1CwMzwDE0eNm0="
+ "resolved" "https://registry.npmjs.org/cli-width/-/cli-width-1.1.1.tgz"
+ "version" "1.1.1"
+
+"cli-width@^2.0.0":
+ "integrity" "sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw=="
+ "resolved" "https://registry.npmjs.org/cli-width/-/cli-width-2.2.1.tgz"
+ "version" "2.2.1"
+
+"cliui@^6.0.0":
+ "integrity" "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ=="
+ "resolved" "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz"
+ "version" "6.0.0"
+ dependencies:
+ "string-width" "^4.2.0"
+ "strip-ansi" "^6.0.0"
+ "wrap-ansi" "^6.2.0"
+
+"cliui@^7.0.2":
+ "integrity" "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ=="
+ "resolved" "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz"
+ "version" "7.0.4"
+ dependencies:
+ "string-width" "^4.2.0"
+ "strip-ansi" "^6.0.0"
+ "wrap-ansi" "^7.0.0"
+
+"clone-buffer@^1.0.0":
+ "integrity" "sha1-4+JbIHrE5wGvch4staFnksrD3Fg="
+ "resolved" "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz"
+ "version" "1.0.0"
+
+"clone-deep@^4.0.1":
+ "integrity" "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ=="
+ "resolved" "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz"
+ "version" "4.0.1"
+ dependencies:
+ "is-plain-object" "^2.0.4"
+ "kind-of" "^6.0.2"
+ "shallow-clone" "^3.0.0"
+
+"clone-stats@^1.0.0":
+ "integrity" "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA="
+ "resolved" "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz"
+ "version" "1.0.0"
+
+"clone@^2.1.1":
+ "integrity" "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18="
+ "resolved" "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz"
+ "version" "2.1.2"
+
+"cloneable-readable@^1.0.0":
+ "integrity" "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ=="
+ "resolved" "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz"
+ "version" "1.1.3"
+ dependencies:
+ "inherits" "^2.0.1"
+ "process-nextick-args" "^2.0.0"
+ "readable-stream" "^2.3.5"
+
+"clsx@^1.1.1":
+ "integrity" "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA=="
+ "resolved" "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz"
+ "version" "1.1.1"
+
+"co@^4.6.0":
+ "integrity" "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
+ "resolved" "https://registry.npmjs.org/co/-/co-4.6.0.tgz"
+ "version" "4.6.0"
+
+"code-point-at@^1.0.0":
+ "integrity" "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
+ "resolved" "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz"
+ "version" "1.1.0"
+
+"collect-v8-coverage@^1.0.0":
+ "integrity" "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg=="
+ "resolved" "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz"
+ "version" "1.0.1"
+
+"color-convert@^1.9.0":
+ "integrity" "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg=="
+ "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz"
+ "version" "1.9.3"
+ dependencies:
+ "color-name" "1.1.3"
+
+"color-convert@^2.0.1":
+ "integrity" "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="
+ "resolved" "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "color-name" "~1.1.4"
+
+"color-name@~1.1.4":
+ "integrity" "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
+ "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz"
+ "version" "1.1.4"
+
+"color-name@1.1.3":
+ "integrity" "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
+ "resolved" "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz"
+ "version" "1.1.3"
+
+"colord@^2.9.1":
+ "integrity" "sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ=="
+ "resolved" "https://registry.npmjs.org/colord/-/colord-2.9.2.tgz"
+ "version" "2.9.2"
+
+"colorette@^2.0.10", "colorette@^2.0.14":
+ "integrity" "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g=="
+ "resolved" "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz"
+ "version" "2.0.16"
+
+"colors@1.0.3", "colors@1.0.x":
+ "integrity" "sha1-BDP0TYCWgP3rYO0mDxsMJi6CpAs="
+ "resolved" "https://registry.npmjs.org/colors/-/colors-1.0.3.tgz"
+ "version" "1.0.3"
+
+"combined-stream@^1.0.6", "combined-stream@^1.0.8", "combined-stream@~1.0.6":
+ "integrity" "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg=="
+ "resolved" "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz"
+ "version" "1.0.8"
+ dependencies:
+ "delayed-stream" "~1.0.0"
+
+"commander@^2.2.0":
+ "integrity" "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ "resolved" "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"
+ "version" "2.20.3"
+
+"commander@^2.20.0":
+ "integrity" "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ=="
+ "resolved" "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz"
+ "version" "2.20.3"
+
+"commander@^7.0.0":
+ "integrity" "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="
+ "resolved" "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz"
+ "version" "7.2.0"
+
+"commander@^7.2.0":
+ "integrity" "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw=="
+ "resolved" "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz"
+ "version" "7.2.0"
+
+"commander@^8.3.0":
+ "integrity" "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww=="
+ "resolved" "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz"
+ "version" "8.3.0"
+
+"commander@2.12.2":
+ "integrity" "sha512-BFnaq5ZOGcDN7FlrtBT4xxkgIToalIIxwjxLWVJ8bGTpe1LroqMiqQXdA7ygc7CRvaYS+9zfPGFnJqFSayx+AA=="
+ "resolved" "https://registry.npmjs.org/commander/-/commander-2.12.2.tgz"
+ "version" "2.12.2"
+
+"common-tags@^1.8.0":
+ "integrity" "sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA=="
+ "resolved" "https://registry.npmjs.org/common-tags/-/common-tags-1.8.2.tgz"
+ "version" "1.8.2"
+
+"commondir@^1.0.1":
+ "integrity" "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs="
+ "resolved" "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz"
+ "version" "1.0.1"
+
+"component-bind@1.0.0":
+ "integrity" "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E="
+ "resolved" "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz"
+ "version" "1.0.0"
+
+"component-emitter@~1.3.0":
+ "integrity" "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg=="
+ "resolved" "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz"
+ "version" "1.3.0"
+
+"component-emitter@1.2.1":
+ "integrity" "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY="
+ "resolved" "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz"
+ "version" "1.2.1"
+
+"component-inherit@0.0.3":
+ "integrity" "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM="
+ "resolved" "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz"
+ "version" "0.0.3"
+
+"compressible@~2.0.16":
+ "integrity" "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg=="
+ "resolved" "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz"
+ "version" "2.0.18"
+ dependencies:
+ "mime-db" ">= 1.43.0 < 2"
+
+"compression@^1.7.4":
+ "integrity" "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ=="
+ "resolved" "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz"
+ "version" "1.7.4"
+ dependencies:
+ "accepts" "~1.3.5"
+ "bytes" "3.0.0"
+ "compressible" "~2.0.16"
+ "debug" "2.6.9"
+ "on-headers" "~1.0.2"
+ "safe-buffer" "5.1.2"
+ "vary" "~1.1.2"
+
+"concat-map@0.0.1":
+ "integrity" "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
+ "resolved" "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+ "version" "0.0.1"
+
+"concat-stream@^1.4.7":
+ "integrity" "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw=="
+ "resolved" "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz"
+ "version" "1.6.2"
+ dependencies:
+ "buffer-from" "^1.0.0"
+ "inherits" "^2.0.3"
+ "readable-stream" "^2.2.2"
+ "typedarray" "^0.0.6"
+
+"concurrently@6.5.1":
+ "integrity" "sha512-FlSwNpGjWQfRwPLXvJ/OgysbBxPkWpiVjy1042b0U7on7S7qwwMIILRj7WTN1mTgqa582bG6NFuScOoh6Zgdag=="
+ "resolved" "https://registry.npmjs.org/concurrently/-/concurrently-6.5.1.tgz"
+ "version" "6.5.1"
+ dependencies:
+ "chalk" "^4.1.0"
+ "date-fns" "^2.16.1"
+ "lodash" "^4.17.21"
+ "rxjs" "^6.6.3"
+ "spawn-command" "^0.0.2-1"
+ "supports-color" "^8.1.0"
+ "tree-kill" "^1.2.2"
+ "yargs" "^16.2.0"
+
+"configstore@^1.0.0":
+ "integrity" "sha1-w1eB0FAdJowlxUuLF/YkDopPsCE="
+ "resolved" "https://registry.npmjs.org/configstore/-/configstore-1.4.0.tgz"
+ "version" "1.4.0"
+ dependencies:
+ "graceful-fs" "^4.1.2"
+ "mkdirp" "^0.5.0"
+ "object-assign" "^4.0.1"
+ "os-tmpdir" "^1.0.0"
+ "osenv" "^0.1.0"
+ "uuid" "^2.0.1"
+ "write-file-atomic" "^1.1.2"
+ "xdg-basedir" "^2.0.0"
+
+"connect-history-api-fallback@^1", "connect-history-api-fallback@^1.6.0":
+ "integrity" "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg=="
+ "resolved" "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz"
+ "version" "1.6.0"
+
+"connect@3.6.6":
+ "integrity" "sha1-Ce/2xVr3I24TcTWnJXSFi2eG9SQ="
+ "resolved" "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz"
+ "version" "3.6.6"
+ dependencies:
+ "debug" "2.6.9"
+ "finalhandler" "1.1.0"
+ "parseurl" "~1.3.2"
+ "utils-merge" "1.0.1"
+
+"content-disposition@0.5.4":
+ "integrity" "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ=="
+ "resolved" "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz"
+ "version" "0.5.4"
+ dependencies:
+ "safe-buffer" "5.2.1"
+
+"content-type@~1.0.4":
+ "integrity" "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+ "resolved" "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz"
+ "version" "1.0.4"
+
+"convert-source-map@^1.4.0", "convert-source-map@^1.6.0", "convert-source-map@^1.7.0":
+ "integrity" "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA=="
+ "resolved" "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz"
+ "version" "1.8.0"
+ dependencies:
+ "safe-buffer" "~5.1.1"
+
+"cookie-signature@1.0.6":
+ "integrity" "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+ "resolved" "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
+ "version" "1.0.6"
+
+"cookie@~0.4.1", "cookie@0.4.1":
+ "integrity" "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA=="
+ "resolved" "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz"
+ "version" "0.4.1"
+
+"copy-webpack-plugin@10.2.0":
+ "integrity" "sha512-my6iXII95c78w14HzYCNya5TlJYa44lOppAge5GSTMM1SyDxNsVGCJvhP4/ld6snm8lzjn3XOonMZD6s1L86Og=="
+ "resolved" "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-10.2.0.tgz"
+ "version" "10.2.0"
+ dependencies:
+ "fast-glob" "^3.2.7"
+ "glob-parent" "^6.0.1"
+ "globby" "^12.0.2"
+ "normalize-path" "^3.0.0"
+ "schema-utils" "^4.0.0"
+ "serialize-javascript" "^6.0.0"
+
+"core-js-compat@^3.18.0", "core-js-compat@^3.19.1":
+ "integrity" "sha512-qZEzVQ+5Qh6cROaTPFLNS4lkvQ6mBzE3R6A6EEpssj7Zr2egMHgsy4XapdifqJDGC9CBiNv7s+ejI96rLNQFdg=="
+ "resolved" "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.20.2.tgz"
+ "version" "3.20.2"
+ dependencies:
+ "browserslist" "^4.19.1"
+ "semver" "7.0.0"
+
+"core-js@^2.4.0":
+ "integrity" "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ=="
+ "resolved" "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz"
+ "version" "2.6.12"
+
+"core-js@3.20.1":
+ "integrity" "sha512-btdpStYFQScnNVQ5slVcr858KP0YWYjV16eGJQw8Gg7CWtu/2qNvIM3qVRIR3n1pK2R9NNOrTevbvAYxajwEjg=="
+ "resolved" "https://registry.npmjs.org/core-js/-/core-js-3.20.1.tgz"
+ "version" "3.20.1"
+
+"core-util-is@~1.0.0":
+ "integrity" "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
+ "resolved" "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz"
+ "version" "1.0.3"
+
+"core-util-is@1.0.2":
+ "integrity" "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
+ "resolved" "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
+ "version" "1.0.2"
+
+"cosmiconfig@^6.0.0":
+ "integrity" "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg=="
+ "resolved" "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz"
+ "version" "6.0.0"
+ dependencies:
+ "@types/parse-json" "^4.0.0"
+ "import-fresh" "^3.1.0"
+ "parse-json" "^5.0.0"
+ "path-type" "^4.0.0"
+ "yaml" "^1.7.2"
+
+"cosmiconfig@^7.0.0":
+ "integrity" "sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ=="
+ "resolved" "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz"
+ "version" "7.0.1"
+ dependencies:
+ "@types/parse-json" "^4.0.0"
+ "import-fresh" "^3.2.1"
+ "parse-json" "^5.0.0"
+ "path-type" "^4.0.0"
+ "yaml" "^1.10.0"
+
+"cross-env@7.0.3":
+ "integrity" "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw=="
+ "resolved" "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz"
+ "version" "7.0.3"
+ dependencies:
+ "cross-spawn" "^7.0.1"
+
+"cross-spawn@^5.1.0":
+ "integrity" "sha1-6L0O/uWPz/b4+UUQoKVUu/ojVEk="
+ "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-5.1.0.tgz"
+ "version" "5.1.0"
+ dependencies:
+ "lru-cache" "^4.0.1"
+ "shebang-command" "^1.2.0"
+ "which" "^1.2.9"
+
+"cross-spawn@^7.0.1", "cross-spawn@^7.0.2", "cross-spawn@^7.0.3":
+ "integrity" "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w=="
+ "resolved" "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz"
+ "version" "7.0.3"
+ dependencies:
+ "path-key" "^3.1.0"
+ "shebang-command" "^2.0.0"
+ "which" "^2.0.1"
+
+"crypto-random-string@^2.0.0":
+ "integrity" "sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA=="
+ "resolved" "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz"
+ "version" "2.0.0"
+
+"css-declaration-sorter@^6.0.3":
+ "integrity" "sha512-SvjQjNRZgh4ULK1LDJ2AduPKUKxIqmtU7ZAyi47BTV+M90Qvxr9AB6lKlLbDUfXqI9IQeYA8LbAsCZPpJEV3aA=="
+ "resolved" "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz"
+ "version" "6.1.3"
+ dependencies:
+ "timsort" "^0.3.0"
+
+"css-loader@6.5.1":
+ "integrity" "sha512-gEy2w9AnJNnD9Kuo4XAP9VflW/ujKoS9c/syO+uWMlm5igc7LysKzPXaDoR2vroROkSwsTS2tGr1yGGEbZOYZQ=="
+ "resolved" "https://registry.npmjs.org/css-loader/-/css-loader-6.5.1.tgz"
+ "version" "6.5.1"
+ dependencies:
+ "icss-utils" "^5.1.0"
+ "postcss" "^8.2.15"
+ "postcss-modules-extract-imports" "^3.0.0"
+ "postcss-modules-local-by-default" "^4.0.0"
+ "postcss-modules-scope" "^3.0.0"
+ "postcss-modules-values" "^4.0.0"
+ "postcss-value-parser" "^4.1.0"
+ "semver" "^7.3.5"
+
+"css-minimizer-webpack-plugin@3.3.1":
+ "integrity" "sha512-SHA7Hu/EiF0dOwdmV2+agvqYpG+ljlUa7Dvn1AVOmSH3N8KOERoaM9lGpstz9nGsoTjANGyUXdrxl/EwdMScRg=="
+ "resolved" "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-3.3.1.tgz"
+ "version" "3.3.1"
+ dependencies:
+ "cssnano" "^5.0.6"
+ "jest-worker" "^27.0.2"
+ "postcss" "^8.3.5"
+ "schema-utils" "^4.0.0"
+ "serialize-javascript" "^6.0.0"
+ "source-map" "^0.6.1"
+
+"css-select@^4.1.3":
+ "integrity" "sha512-/aUslKhzkTNCQUB2qTX84lVmfia9NyjP3WpDGtj/WxhwBzWBYUV3DgUpurHTme8UTPcPlAD1DJ+b0nN/t50zDQ=="
+ "resolved" "https://registry.npmjs.org/css-select/-/css-select-4.2.1.tgz"
+ "version" "4.2.1"
+ dependencies:
+ "boolbase" "^1.0.0"
+ "css-what" "^5.1.0"
+ "domhandler" "^4.3.0"
+ "domutils" "^2.8.0"
+ "nth-check" "^2.0.1"
+
+"css-select@~1.0.0":
+ "integrity" "sha1-sRIcpRhI3SZOIkTQWM7iVN7rRLA="
+ "resolved" "https://registry.npmjs.org/css-select/-/css-select-1.0.0.tgz"
+ "version" "1.0.0"
+ dependencies:
+ "boolbase" "~1.0.0"
+ "css-what" "1.0"
+ "domutils" "1.4"
+ "nth-check" "~1.0.0"
+
+"css-select@~1.2.0":
+ "integrity" "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg="
+ "resolved" "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz"
+ "version" "1.2.0"
+ dependencies:
+ "boolbase" "~1.0.0"
+ "css-what" "2.1"
+ "domutils" "1.5.1"
+ "nth-check" "~1.0.1"
+
+"css-tree@^1.1.2", "css-tree@^1.1.3":
+ "integrity" "sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q=="
+ "resolved" "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz"
+ "version" "1.1.3"
+ dependencies:
+ "mdn-data" "2.0.14"
+ "source-map" "^0.6.1"
+
+"css-what@^5.1.0":
+ "integrity" "sha512-arSMRWIIFY0hV8pIxZMEfmMI47Wj3R/aWpZDDxWYCPEiOMv6tfOrnpDtgxBYPEQD4V0Y/958+1TdC3iWTFcUPw=="
+ "resolved" "https://registry.npmjs.org/css-what/-/css-what-5.1.0.tgz"
+ "version" "5.1.0"
+
+"css-what@1.0":
+ "integrity" "sha1-18wt9FGAZm+Z0rFEYmOUaeAPc2w="
+ "resolved" "https://registry.npmjs.org/css-what/-/css-what-1.0.0.tgz"
+ "version" "1.0.0"
+
+"css-what@2.1":
+ "integrity" "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg=="
+ "resolved" "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz"
+ "version" "2.1.3"
+
+"cssesc@^3.0.0":
+ "integrity" "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg=="
+ "resolved" "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz"
+ "version" "3.0.0"
+
+"cssnano-preset-default@^5.1.9":
+ "integrity" "sha512-RhkEucqlQ+OxEi14K1p8gdXcMQy1mSpo7P1oC44oRls7BYIj8p+cht4IFBFV3W4iOjTP8EUB33XV1fX9KhDzyA=="
+ "resolved" "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.9.tgz"
+ "version" "5.1.9"
+ dependencies:
+ "css-declaration-sorter" "^6.0.3"
+ "cssnano-utils" "^2.0.1"
+ "postcss-calc" "^8.0.0"
+ "postcss-colormin" "^5.2.2"
+ "postcss-convert-values" "^5.0.2"
+ "postcss-discard-comments" "^5.0.1"
+ "postcss-discard-duplicates" "^5.0.1"
+ "postcss-discard-empty" "^5.0.1"
+ "postcss-discard-overridden" "^5.0.1"
+ "postcss-merge-longhand" "^5.0.4"
+ "postcss-merge-rules" "^5.0.3"
+ "postcss-minify-font-values" "^5.0.1"
+ "postcss-minify-gradients" "^5.0.3"
+ "postcss-minify-params" "^5.0.2"
+ "postcss-minify-selectors" "^5.1.0"
+ "postcss-normalize-charset" "^5.0.1"
+ "postcss-normalize-display-values" "^5.0.1"
+ "postcss-normalize-positions" "^5.0.1"
+ "postcss-normalize-repeat-style" "^5.0.1"
+ "postcss-normalize-string" "^5.0.1"
+ "postcss-normalize-timing-functions" "^5.0.1"
+ "postcss-normalize-unicode" "^5.0.1"
+ "postcss-normalize-url" "^5.0.4"
+ "postcss-normalize-whitespace" "^5.0.1"
+ "postcss-ordered-values" "^5.0.2"
+ "postcss-reduce-initial" "^5.0.2"
+ "postcss-reduce-transforms" "^5.0.1"
+ "postcss-svgo" "^5.0.3"
+ "postcss-unique-selectors" "^5.0.2"
+
+"cssnano-utils@^2.0.1":
+ "integrity" "sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ=="
+ "resolved" "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-2.0.1.tgz"
+ "version" "2.0.1"
+
+"cssnano@^5.0.6":
+ "integrity" "sha512-qzhRkFvBhv08tbyKCIfWbxBXmkIpLl1uNblt8SpTHkgLfON5OCPX/CCnkdNmEosvo8bANQYmTTMEgcVBlisHaw=="
+ "resolved" "https://registry.npmjs.org/cssnano/-/cssnano-5.0.14.tgz"
+ "version" "5.0.14"
+ dependencies:
+ "cssnano-preset-default" "^5.1.9"
+ "lilconfig" "^2.0.3"
+ "yaml" "^1.10.2"
+
+"csso@^4.2.0":
+ "integrity" "sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA=="
+ "resolved" "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz"
+ "version" "4.2.0"
+ dependencies:
+ "css-tree" "^1.1.2"
+
+"cssom@^0.4.4":
+ "integrity" "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw=="
+ "resolved" "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz"
+ "version" "0.4.4"
+
+"cssom@~0.3.6":
+ "integrity" "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
+ "resolved" "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz"
+ "version" "0.3.8"
+
+"cssstyle@^2.3.0":
+ "integrity" "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A=="
+ "resolved" "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz"
+ "version" "2.3.0"
+ dependencies:
+ "cssom" "~0.3.6"
+
+"csstype@^3.0.2":
+ "integrity" "sha512-2u44ZG2OcNUO9HDp/Jl8C07x6pU/eTR3ncV91SiK3dhG9TWvRVsCoJw14Ckx5DgWkzGA3waZWO3d7pgqpUI/XA=="
+ "resolved" "https://registry.npmjs.org/csstype/-/csstype-3.0.10.tgz"
+ "version" "3.0.10"
+
+"currently-unhandled@^0.4.1":
+ "integrity" "sha1-mI3zP+qxke95mmE2nddsF635V+o="
+ "resolved" "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz"
+ "version" "0.4.1"
+ dependencies:
+ "array-find-index" "^1.0.1"
+
+"cycle@1.0.x":
+ "integrity" "sha1-IegLK+hYD5i0aPN5QwZisEbDStI="
+ "resolved" "https://registry.npmjs.org/cycle/-/cycle-1.0.3.tgz"
+ "version" "1.0.3"
+
+"dargs@^5.1.0":
+ "integrity" "sha1-7H6lDHhWTNNsnV7Bj2Yyn63ieCk="
+ "resolved" "https://registry.npmjs.org/dargs/-/dargs-5.1.0.tgz"
+ "version" "5.1.0"
+
+"dashdash@^1.12.0":
+ "integrity" "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA="
+ "resolved" "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz"
+ "version" "1.14.1"
+ dependencies:
+ "assert-plus" "^1.0.0"
+
+"data-urls@^2.0.0":
+ "integrity" "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ=="
+ "resolved" "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "abab" "^2.0.3"
+ "whatwg-mimetype" "^2.3.0"
+ "whatwg-url" "^8.0.0"
+
+"date-fns@^2.16.1":
+ "integrity" "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw=="
+ "resolved" "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz"
+ "version" "2.28.0"
+
+"dateformat@^3.0.2":
+ "integrity" "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q=="
+ "resolved" "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz"
+ "version" "3.0.3"
+
+"dayjs@^1.10.4", "dayjs@1.10.7":
+ "integrity" "sha512-P6twpd70BcPK34K26uJ1KT3wlhpuOAPoMwJzpsIWUxHZ7wpmbdZL/hQqBDfz7hGurYSa5PhzdhDHtt319hL3ig=="
+ "resolved" "https://registry.npmjs.org/dayjs/-/dayjs-1.10.7.tgz"
+ "version" "1.10.7"
+
+"debug@^2.2.0":
+ "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
+ "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
+ "version" "2.6.9"
+ dependencies:
+ "ms" "2.0.0"
+
+"debug@^3.1.0":
+ "integrity" "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="
+ "resolved" "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
+ "version" "3.2.7"
+ dependencies:
+ "ms" "^2.1.1"
+
+"debug@^3.1.1":
+ "integrity" "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ=="
+ "resolved" "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz"
+ "version" "3.2.7"
+ dependencies:
+ "ms" "^2.1.1"
+
+"debug@^4.1.0", "debug@^4.1.1", "debug@^4.3.2", "debug@4":
+ "integrity" "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q=="
+ "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz"
+ "version" "4.3.3"
+ dependencies:
+ "ms" "2.1.2"
+
+"debug@~3.1.0":
+ "integrity" "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g=="
+ "resolved" "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz"
+ "version" "3.1.0"
+ dependencies:
+ "ms" "2.0.0"
+
+"debug@~4.1.0":
+ "integrity" "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw=="
+ "resolved" "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz"
+ "version" "4.1.1"
+ dependencies:
+ "ms" "^2.1.1"
+
+"debug@2.6.9":
+ "integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
+ "resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
+ "version" "2.6.9"
+ dependencies:
+ "ms" "2.0.0"
+
+"debug@4.3.2":
+ "integrity" "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw=="
+ "resolved" "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz"
+ "version" "4.3.2"
+ dependencies:
+ "ms" "2.1.2"
+
+"decamelize@^1.1.2", "decamelize@^1.2.0":
+ "integrity" "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
+ "resolved" "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz"
+ "version" "1.2.0"
+
+"decimal.js@^10.2.1":
+ "integrity" "sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ=="
+ "resolved" "https://registry.npmjs.org/decimal.js/-/decimal.js-10.3.1.tgz"
+ "version" "10.3.1"
+
+"decompress-response@^3.2.0":
+ "integrity" "sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M="
+ "resolved" "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz"
+ "version" "3.3.0"
+ dependencies:
+ "mimic-response" "^1.0.0"
+
+"dedent@^0.7.0":
+ "integrity" "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw="
+ "resolved" "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz"
+ "version" "0.7.0"
+
+"deep-equal@^1.0.1":
+ "integrity" "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g=="
+ "resolved" "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz"
+ "version" "1.1.1"
+ dependencies:
+ "is-arguments" "^1.0.4"
+ "is-date-object" "^1.0.1"
+ "is-regex" "^1.0.4"
+ "object-is" "^1.0.1"
+ "object-keys" "^1.1.1"
+ "regexp.prototype.flags" "^1.2.0"
+
+"deep-extend@^0.4.0":
+ "integrity" "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8="
+ "resolved" "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz"
+ "version" "0.4.2"
+
+"deep-is@^0.1.3", "deep-is@~0.1.3":
+ "integrity" "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="
+ "resolved" "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz"
+ "version" "0.1.4"
+
+"deepmerge@^4.2.2":
+ "integrity" "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg=="
+ "resolved" "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz"
+ "version" "4.2.2"
+
+"default-gateway@^6.0.3":
+ "integrity" "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg=="
+ "resolved" "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz"
+ "version" "6.0.3"
+ dependencies:
+ "execa" "^5.0.0"
+
+"define-lazy-prop@^2.0.0":
+ "integrity" "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og=="
+ "resolved" "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz"
+ "version" "2.0.0"
+
+"define-properties@^1.1.3":
+ "integrity" "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ=="
+ "resolved" "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz"
+ "version" "1.1.3"
+ dependencies:
+ "object-keys" "^1.0.12"
+
+"del@^6.0.0":
+ "integrity" "sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ=="
+ "resolved" "https://registry.npmjs.org/del/-/del-6.0.0.tgz"
+ "version" "6.0.0"
+ dependencies:
+ "globby" "^11.0.1"
+ "graceful-fs" "^4.2.4"
+ "is-glob" "^4.0.1"
+ "is-path-cwd" "^2.2.0"
+ "is-path-inside" "^3.0.2"
+ "p-map" "^4.0.0"
+ "rimraf" "^3.0.2"
+ "slash" "^3.0.0"
+
+"delayed-stream@~1.0.0":
+ "integrity" "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
+ "resolved" "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
+ "version" "1.0.0"
+
+"delegates@^1.0.0":
+ "integrity" "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
+ "resolved" "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz"
+ "version" "1.0.0"
+
+"depd@~1.1.2":
+ "integrity" "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+ "resolved" "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz"
+ "version" "1.1.2"
+
+"destroy@~1.0.4":
+ "integrity" "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+ "resolved" "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz"
+ "version" "1.0.4"
+
+"detect-conflict@^1.0.0":
+ "integrity" "sha1-CIZXpmqWHAUBnbfEIwiDsca0F24="
+ "resolved" "https://registry.npmjs.org/detect-conflict/-/detect-conflict-1.0.1.tgz"
+ "version" "1.0.1"
+
+"detect-indent@^6.0.0":
+ "integrity" "sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA=="
+ "resolved" "https://registry.npmjs.org/detect-indent/-/detect-indent-6.1.0.tgz"
+ "version" "6.1.0"
+
+"detect-newline@^1.0.3":
+ "integrity" "sha1-6XsQA4d9cMCa8a81v63/Fo3kkg0="
+ "resolved" "https://registry.npmjs.org/detect-newline/-/detect-newline-1.0.3.tgz"
+ "version" "1.0.3"
+ dependencies:
+ "get-stdin" "^4.0.1"
+ "minimist" "^1.1.0"
+
+"detect-newline@^3.0.0", "detect-newline@3.1.0":
+ "integrity" "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA=="
+ "resolved" "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz"
+ "version" "3.1.0"
+
+"detect-node@^2.0.4":
+ "integrity" "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g=="
+ "resolved" "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz"
+ "version" "2.1.0"
+
+"dev-ip@^1.0.1":
+ "integrity" "sha1-p2o+0YVb56ASu4rBbLgPPADcKPA="
+ "resolved" "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz"
+ "version" "1.0.1"
+
+"didyoumean@1.2.1":
+ "integrity" "sha1-6S7f2tplN9SE1zwBcv0eugxJdv8="
+ "resolved" "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz"
+ "version" "1.2.1"
+
+"diff-sequences@^27.4.0":
+ "integrity" "sha512-YqiQzkrsmHMH5uuh8OdQFU9/ZpADnwzml8z0O5HvRNda+5UZsaX/xN+AAxfR2hWq1Y7HZnAzO9J5lJXOuDz2Ww=="
+ "resolved" "https://registry.npmjs.org/diff-sequences/-/diff-sequences-27.4.0.tgz"
+ "version" "27.4.0"
+
+"diff@^3.3.1":
+ "integrity" "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA=="
+ "resolved" "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz"
+ "version" "3.5.0"
+
+"diff@^5.0.0":
+ "integrity" "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w=="
+ "resolved" "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz"
+ "version" "5.0.0"
+
+"dir-glob@^3.0.1":
+ "integrity" "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA=="
+ "resolved" "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz"
+ "version" "3.0.1"
+ dependencies:
+ "path-type" "^4.0.0"
+
+"discontinuous-range@1.0.0":
+ "integrity" "sha1-44Mx8IRLukm5qctxx3FYWqsbxlo="
+ "resolved" "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz"
+ "version" "1.0.0"
+
+"dlv@^1.1.3":
+ "integrity" "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
+ "resolved" "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz"
+ "version" "1.1.3"
+
+"dns-equal@^1.0.0":
+ "integrity" "sha1-s55/HabrCnW6nBcySzR1PEfgZU0="
+ "resolved" "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz"
+ "version" "1.0.0"
+
+"dns-packet@^1.3.1":
+ "integrity" "sha512-BQ6F4vycLXBvdrJZ6S3gZewt6rcrks9KBgM9vrhW+knGRqc8uEdT7fuCwloc7nny5xNoMJ17HGH0R/6fpo8ECA=="
+ "resolved" "https://registry.npmjs.org/dns-packet/-/dns-packet-1.3.4.tgz"
+ "version" "1.3.4"
+ dependencies:
+ "ip" "^1.1.0"
+ "safe-buffer" "^5.0.1"
+
+"dns-txt@^2.0.2":
+ "integrity" "sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY="
+ "resolved" "https://registry.npmjs.org/dns-txt/-/dns-txt-2.0.2.tgz"
+ "version" "2.0.2"
+ dependencies:
+ "buffer-indexof" "^1.0.0"
+
+"doctrine@^2.1.0":
+ "integrity" "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw=="
+ "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "esutils" "^2.0.2"
+
+"doctrine@^3.0.0":
+ "integrity" "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w=="
+ "resolved" "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "esutils" "^2.0.2"
+
+"dom-accessibility-api@^0.5.9":
+ "integrity" "sha512-Xu9mD0UjrJisTmv7lmVSDMagQcU9R5hwAbxsaAE/35XPnPLJobbuREfV/rraiSaEj/UOvgrzQs66zyTWTlyd+g=="
+ "resolved" "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.10.tgz"
+ "version" "0.5.10"
+
+"dom-converter@^0.2.0":
+ "integrity" "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA=="
+ "resolved" "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz"
+ "version" "0.2.0"
+ dependencies:
+ "utila" "~0.4"
+
+"dom-helpers@^5.0.1":
+ "integrity" "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA=="
+ "resolved" "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz"
+ "version" "5.2.1"
+ dependencies:
+ "@babel/runtime" "^7.8.7"
+ "csstype" "^3.0.2"
+
+"dom-serializer@^1.0.1":
+ "integrity" "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig=="
+ "resolved" "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz"
+ "version" "1.3.2"
+ dependencies:
+ "domelementtype" "^2.0.1"
+ "domhandler" "^4.2.0"
+ "entities" "^2.0.0"
+
+"dom-serializer@~0.1.0", "dom-serializer@0":
+ "integrity" "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA=="
+ "resolved" "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz"
+ "version" "0.1.1"
+ dependencies:
+ "domelementtype" "^1.3.0"
+ "entities" "^1.1.1"
+
+"domelementtype@^1.3.0", "domelementtype@^1.3.1", "domelementtype@1":
+ "integrity" "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
+ "resolved" "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz"
+ "version" "1.3.1"
+
+"domelementtype@^2.0.1", "domelementtype@^2.2.0":
+ "integrity" "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A=="
+ "resolved" "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz"
+ "version" "2.2.0"
+
+"domexception@^2.0.1":
+ "integrity" "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg=="
+ "resolved" "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "webidl-conversions" "^5.0.0"
+
+"domhandler@^2.3.0":
+ "integrity" "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA=="
+ "resolved" "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz"
+ "version" "2.4.2"
+ dependencies:
+ "domelementtype" "1"
+
+"domhandler@^4.0.0", "domhandler@^4.2.0", "domhandler@^4.3.0":
+ "integrity" "sha512-fC0aXNQXqKSFTr2wDNZDhsEYjCiYsDWl3D01kwt25hm1YIPyDGHvvi3rw+PLqHAl/m71MaiF7d5zvBr0p5UB2g=="
+ "resolved" "https://registry.npmjs.org/domhandler/-/domhandler-4.3.0.tgz"
+ "version" "4.3.0"
+ dependencies:
+ "domelementtype" "^2.2.0"
+
+"domhandler@2.3":
+ "integrity" "sha1-LeWaCCLVAn+r/28DLCsloqir5zg="
+ "resolved" "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz"
+ "version" "2.3.0"
+ dependencies:
+ "domelementtype" "1"
+
+"domutils@^1.5.1", "domutils@1.5.1":
+ "integrity" "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8="
+ "resolved" "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz"
+ "version" "1.5.1"
+ dependencies:
+ "dom-serializer" "0"
+ "domelementtype" "1"
+
+"domutils@^2.5.2", "domutils@^2.8.0":
+ "integrity" "sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A=="
+ "resolved" "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz"
+ "version" "2.8.0"
+ dependencies:
+ "dom-serializer" "^1.0.1"
+ "domelementtype" "^2.2.0"
+ "domhandler" "^4.2.0"
+
+"domutils@1.4":
+ "integrity" "sha1-CGVRN5bGswYDGFDhdVFrr4C3Km8="
+ "resolved" "https://registry.npmjs.org/domutils/-/domutils-1.4.3.tgz"
+ "version" "1.4.3"
+ dependencies:
+ "domelementtype" "1"
+
+"domutils@1.5":
+ "integrity" "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8="
+ "resolved" "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz"
+ "version" "1.5.1"
+ dependencies:
+ "dom-serializer" "0"
+ "domelementtype" "1"
+
+"dot-case@^3.0.4":
+ "integrity" "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w=="
+ "resolved" "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz"
+ "version" "3.0.4"
+ dependencies:
+ "no-case" "^3.0.4"
+ "tslib" "^2.0.3"
+
+"dotenv@^10.0.0":
+ "integrity" "sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q=="
+ "resolved" "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz"
+ "version" "10.0.0"
+
+"duplexer3@^0.1.4":
+ "integrity" "sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI="
+ "resolved" "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.4.tgz"
+ "version" "0.1.4"
+
+"easy-extender@^2.3.4":
+ "integrity" "sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q=="
+ "resolved" "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.4.tgz"
+ "version" "2.3.4"
+ dependencies:
+ "lodash" "^4.17.10"
+
+"eazy-logger@3.1.0":
+ "integrity" "sha512-/snsn2JqBtUSSstEl4R0RKjkisGHAhvYj89i7r3ytNUKW12y178KDZwXLXIgwDqLW6E/VRMT9qfld7wvFae8bQ=="
+ "resolved" "https://registry.npmjs.org/eazy-logger/-/eazy-logger-3.1.0.tgz"
+ "version" "3.1.0"
+ dependencies:
+ "tfunk" "^4.0.0"
+
+"ecc-jsbn@~0.1.1":
+ "integrity" "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk="
+ "resolved" "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz"
+ "version" "0.1.2"
+ dependencies:
+ "jsbn" "~0.1.0"
+ "safer-buffer" "^2.1.0"
+
+"editions@^2.2.0":
+ "integrity" "sha512-ptGvkwTvGdGfC0hfhKg0MT+TRLRKGtUiWGBInxOm5pz7ssADezahjCUaYuZ8Dr+C05FW0AECIIPt4WBxVINEhA=="
+ "resolved" "https://registry.npmjs.org/editions/-/editions-2.3.1.tgz"
+ "version" "2.3.1"
+ dependencies:
+ "errlop" "^2.0.0"
+ "semver" "^6.3.0"
+
+"ee-first@1.1.1":
+ "integrity" "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+ "resolved" "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz"
+ "version" "1.1.1"
+
+"ejs@^2.3.1":
+ "integrity" "sha512-7vmuyh5+kuUyJKePhQfRQBhXV5Ce+RnaeeQArKu1EAMpL3WbgMt5WG6uQZpEVvYSSsxMXRKOewtDk9RaTKXRlA=="
+ "resolved" "https://registry.npmjs.org/ejs/-/ejs-2.7.4.tgz"
+ "version" "2.7.4"
+
+"ejs@^3.1.6":
+ "integrity" "sha512-9lt9Zse4hPucPkoP7FHDF0LQAlGyF9JVpnClFLFH3aSSbxmyoqINRpp/9wePWJTUl4KOQwRL72Iw3InHPDkoGw=="
+ "resolved" "https://registry.npmjs.org/ejs/-/ejs-3.1.6.tgz"
+ "version" "3.1.6"
+ dependencies:
+ "jake" "^10.6.1"
+
+"ejs@2.5.7":
+ "integrity" "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo="
+ "resolved" "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz"
+ "version" "2.5.7"
+
+"electron-to-chromium@^1.4.17":
+ "integrity" "sha512-MbLlbF39vKrXWlFEFpCgDHwdlz4O3LmHM5W4tiLRHjSmEUXjJjz8sZkMgWgvYxlZw3N1iDTmCEtOkkESb5TMCg=="
+ "resolved" "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.36.tgz"
+ "version" "1.4.36"
+
+"emittery@^0.8.1":
+ "integrity" "sha512-uDfvUjVrfGJJhymx/kz6prltenw1u7WrCg1oa94zYY8xxVpLLUu045LAT0dhDZdXG58/EpPL/5kA180fQ/qudg=="
+ "resolved" "https://registry.npmjs.org/emittery/-/emittery-0.8.1.tgz"
+ "version" "0.8.1"
+
+"emoji-regex@^8.0.0":
+ "integrity" "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="
+ "resolved" "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz"
+ "version" "8.0.0"
+
+"emojis-list@^2.0.0":
+ "integrity" "sha1-TapNnbAPmBmIDHn6RXrlsJof04k="
+ "resolved" "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz"
+ "version" "2.1.0"
+
+"emojis-list@^3.0.0":
+ "integrity" "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q=="
+ "resolved" "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz"
+ "version" "3.0.0"
+
+"encodeurl@~1.0.1", "encodeurl@~1.0.2":
+ "integrity" "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+ "resolved" "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz"
+ "version" "1.0.2"
+
+"encoding@^0.1.11":
+ "integrity" "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A=="
+ "resolved" "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz"
+ "version" "0.1.13"
+ dependencies:
+ "iconv-lite" "^0.6.2"
+
+"engine.io-client@~3.5.0":
+ "integrity" "sha512-QEqIp+gJ/kMHeUun7f5Vv3bteRHppHH/FMBQX/esFj/fuYfjyUKWGMo3VCvIP/V8bE9KcjHmRZrhIz2Z9oNsDA=="
+ "resolved" "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.5.2.tgz"
+ "version" "3.5.2"
+ dependencies:
+ "component-emitter" "~1.3.0"
+ "component-inherit" "0.0.3"
+ "debug" "~3.1.0"
+ "engine.io-parser" "~2.2.0"
+ "has-cors" "1.1.0"
+ "indexof" "0.0.1"
+ "parseqs" "0.0.6"
+ "parseuri" "0.0.6"
+ "ws" "~7.4.2"
+ "xmlhttprequest-ssl" "~1.6.2"
+ "yeast" "0.1.2"
+
+"engine.io-parser@~2.2.0":
+ "integrity" "sha512-x+dN/fBH8Ro8TFwJ+rkB2AmuVw9Yu2mockR/p3W8f8YtExwFgDvBDi0GWyb4ZLkpahtDGZgtr3zLovanJghPqg=="
+ "resolved" "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.2.1.tgz"
+ "version" "2.2.1"
+ dependencies:
+ "after" "0.8.2"
+ "arraybuffer.slice" "~0.0.7"
+ "base64-arraybuffer" "0.1.4"
+ "blob" "0.0.5"
+ "has-binary2" "~1.0.2"
+
+"engine.io@~3.5.0":
+ "integrity" "sha512-21HlvPUKaitDGE4GXNtQ7PLP0Sz4aWLddMPw2VTyFz1FVZqu/kZsJUO8WNpKuE/OCL7nkfRaOui2ZCJloGznGA=="
+ "resolved" "https://registry.npmjs.org/engine.io/-/engine.io-3.5.0.tgz"
+ "version" "3.5.0"
+ dependencies:
+ "accepts" "~1.3.4"
+ "base64id" "2.0.0"
+ "cookie" "~0.4.1"
+ "debug" "~4.1.0"
+ "engine.io-parser" "~2.2.0"
+ "ws" "~7.4.2"
+
+"enhanced-resolve@^5.0.0", "enhanced-resolve@^5.8.3":
+ "integrity" "sha512-EGAbGvH7j7Xt2nc0E7D99La1OiEs8LnyimkRgwExpUMScN6O+3x9tIWs7PLQZVNx4YD+00skHXPXi1yQHpAmZA=="
+ "resolved" "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz"
+ "version" "5.8.3"
+ dependencies:
+ "graceful-fs" "^4.2.4"
+ "tapable" "^2.2.0"
+
+"enquirer@^2.3.5":
+ "integrity" "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg=="
+ "resolved" "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz"
+ "version" "2.3.6"
+ dependencies:
+ "ansi-colors" "^4.1.1"
+
+"entities@^1.1.1", "entities@~1.1.1":
+ "integrity" "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w=="
+ "resolved" "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz"
+ "version" "1.1.2"
+
+"entities@^2.0.0":
+ "integrity" "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A=="
+ "resolved" "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz"
+ "version" "2.2.0"
+
+"entities@1.0":
+ "integrity" "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY="
+ "resolved" "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz"
+ "version" "1.0.0"
+
+"envinfo@^7.7.3":
+ "integrity" "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw=="
+ "resolved" "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz"
+ "version" "7.8.1"
+
+"errlop@^2.0.0":
+ "integrity" "sha512-e64Qj9+4aZzjzzFpZC7p5kmm/ccCrbLhAJplhsDXQFs87XTsXwOpH4s1Io2s90Tau/8r2j9f4l/thhDevRjzxw=="
+ "resolved" "https://registry.npmjs.org/errlop/-/errlop-2.2.0.tgz"
+ "version" "2.2.0"
+
+"error-ex@^1.2.0", "error-ex@^1.3.1":
+ "integrity" "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g=="
+ "resolved" "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz"
+ "version" "1.3.2"
+ dependencies:
+ "is-arrayish" "^0.2.1"
+
+"error@^7.0.2":
+ "integrity" "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA=="
+ "resolved" "https://registry.npmjs.org/error/-/error-7.2.1.tgz"
+ "version" "7.2.1"
+ dependencies:
+ "string-template" "~0.2.1"
+
+"es-abstract@^1.19.0", "es-abstract@^1.19.1":
+ "integrity" "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w=="
+ "resolved" "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz"
+ "version" "1.19.1"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "es-to-primitive" "^1.2.1"
+ "function-bind" "^1.1.1"
+ "get-intrinsic" "^1.1.1"
+ "get-symbol-description" "^1.0.0"
+ "has" "^1.0.3"
+ "has-symbols" "^1.0.2"
+ "internal-slot" "^1.0.3"
+ "is-callable" "^1.2.4"
+ "is-negative-zero" "^2.0.1"
+ "is-regex" "^1.1.4"
+ "is-shared-array-buffer" "^1.0.1"
+ "is-string" "^1.0.7"
+ "is-weakref" "^1.0.1"
+ "object-inspect" "^1.11.0"
+ "object-keys" "^1.1.1"
+ "object.assign" "^4.1.2"
+ "string.prototype.trimend" "^1.0.4"
+ "string.prototype.trimstart" "^1.0.4"
+ "unbox-primitive" "^1.0.1"
+
+"es-module-lexer@^0.9.0":
+ "integrity" "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ=="
+ "resolved" "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz"
+ "version" "0.9.3"
+
+"es-to-primitive@^1.2.1":
+ "integrity" "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA=="
+ "resolved" "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz"
+ "version" "1.2.1"
+ dependencies:
+ "is-callable" "^1.1.4"
+ "is-date-object" "^1.0.1"
+ "is-symbol" "^1.0.2"
+
+"escalade@^3.1.1":
+ "integrity" "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw=="
+ "resolved" "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz"
+ "version" "3.1.1"
+
+"escape-html@~1.0.3":
+ "integrity" "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+ "resolved" "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz"
+ "version" "1.0.3"
+
+"escape-string-regexp@^1.0.2", "escape-string-regexp@^1.0.5":
+ "integrity" "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
+ "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
+ "version" "1.0.5"
+
+"escape-string-regexp@^2.0.0":
+ "integrity" "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w=="
+ "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz"
+ "version" "2.0.0"
+
+"escape-string-regexp@^4.0.0":
+ "integrity" "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA=="
+ "resolved" "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz"
+ "version" "4.0.0"
+
+"escodegen@^2.0.0":
+ "integrity" "sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw=="
+ "resolved" "https://registry.npmjs.org/escodegen/-/escodegen-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "esprima" "^4.0.1"
+ "estraverse" "^5.2.0"
+ "esutils" "^2.0.2"
+ "optionator" "^0.8.1"
+ optionalDependencies:
+ "source-map" "~0.6.1"
+
+"escodegen@1.8.x":
+ "integrity" "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg="
+ "resolved" "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz"
+ "version" "1.8.1"
+ dependencies:
+ "esprima" "^2.7.1"
+ "estraverse" "^1.9.1"
+ "esutils" "^2.0.2"
+ "optionator" "^0.8.1"
+ optionalDependencies:
+ "source-map" "~0.2.0"
+
+"eslint-config-prettier@8.3.0":
+ "integrity" "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew=="
+ "resolved" "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz"
+ "version" "8.3.0"
+
+"eslint-plugin-react@7.28.0":
+ "integrity" "sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw=="
+ "resolved" "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.28.0.tgz"
+ "version" "7.28.0"
+ dependencies:
+ "array-includes" "^3.1.4"
+ "array.prototype.flatmap" "^1.2.5"
+ "doctrine" "^2.1.0"
+ "estraverse" "^5.3.0"
+ "jsx-ast-utils" "^2.4.1 || ^3.0.0"
+ "minimatch" "^3.0.4"
+ "object.entries" "^1.1.5"
+ "object.fromentries" "^2.0.5"
+ "object.hasown" "^1.1.0"
+ "object.values" "^1.1.5"
+ "prop-types" "^15.7.2"
+ "resolve" "^2.0.0-next.3"
+ "semver" "^6.3.0"
+ "string.prototype.matchall" "^4.0.6"
+
+"eslint-scope@^5.1.1", "eslint-scope@5.1.1":
+ "integrity" "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw=="
+ "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz"
+ "version" "5.1.1"
+ dependencies:
+ "esrecurse" "^4.3.0"
+ "estraverse" "^4.1.1"
+
+"eslint-scope@^7.1.0":
+ "integrity" "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg=="
+ "resolved" "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz"
+ "version" "7.1.0"
+ dependencies:
+ "esrecurse" "^4.3.0"
+ "estraverse" "^5.2.0"
+
+"eslint-utils@^3.0.0":
+ "integrity" "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA=="
+ "resolved" "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "eslint-visitor-keys" "^2.0.0"
+
+"eslint-visitor-keys@^2.0.0":
+ "integrity" "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw=="
+ "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz"
+ "version" "2.1.0"
+
+"eslint-visitor-keys@^3.0.0", "eslint-visitor-keys@^3.1.0":
+ "integrity" "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA=="
+ "resolved" "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz"
+ "version" "3.1.0"
+
+"eslint-webpack-plugin@3.1.1":
+ "integrity" "sha512-xSucskTN9tOkfW7so4EaiFIkulWLXwCB/15H917lR6pTv0Zot6/fetFucmENRb7J5whVSFKIvwnrnsa78SG2yg=="
+ "resolved" "https://registry.npmjs.org/eslint-webpack-plugin/-/eslint-webpack-plugin-3.1.1.tgz"
+ "version" "3.1.1"
+ dependencies:
+ "@types/eslint" "^7.28.2"
+ "jest-worker" "^27.3.1"
+ "micromatch" "^4.0.4"
+ "normalize-path" "^3.0.0"
+ "schema-utils" "^3.1.1"
+
+"eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^6.0.0 || ^7.0.0 || ^8.0.0", "eslint@^7.0.0 || ^8.0.0", "eslint@>= 6", "eslint@>=5", "eslint@>=7.0.0", "eslint@8.5.0":
+ "integrity" "sha512-tVGSkgNbOfiHyVte8bCM8OmX+xG9PzVG/B4UCF60zx7j61WIVY/AqJECDgpLD4DbbESD0e174gOg3ZlrX15GDg=="
+ "resolved" "https://registry.npmjs.org/eslint/-/eslint-8.5.0.tgz"
+ "version" "8.5.0"
+ dependencies:
+ "@eslint/eslintrc" "^1.0.5"
+ "@humanwhocodes/config-array" "^0.9.2"
+ "ajv" "^6.10.0"
+ "chalk" "^4.0.0"
+ "cross-spawn" "^7.0.2"
+ "debug" "^4.3.2"
+ "doctrine" "^3.0.0"
+ "enquirer" "^2.3.5"
+ "escape-string-regexp" "^4.0.0"
+ "eslint-scope" "^7.1.0"
+ "eslint-utils" "^3.0.0"
+ "eslint-visitor-keys" "^3.1.0"
+ "espree" "^9.2.0"
+ "esquery" "^1.4.0"
+ "esutils" "^2.0.2"
+ "fast-deep-equal" "^3.1.3"
+ "file-entry-cache" "^6.0.1"
+ "functional-red-black-tree" "^1.0.1"
+ "glob-parent" "^6.0.1"
+ "globals" "^13.6.0"
+ "ignore" "^4.0.6"
+ "import-fresh" "^3.0.0"
+ "imurmurhash" "^0.1.4"
+ "is-glob" "^4.0.0"
+ "js-yaml" "^4.1.0"
+ "json-stable-stringify-without-jsonify" "^1.0.1"
+ "levn" "^0.4.1"
+ "lodash.merge" "^4.6.2"
+ "minimatch" "^3.0.4"
+ "natural-compare" "^1.4.0"
+ "optionator" "^0.9.1"
+ "progress" "^2.0.0"
+ "regexpp" "^3.2.0"
+ "semver" "^7.2.1"
+ "strip-ansi" "^6.0.1"
+ "strip-json-comments" "^3.1.0"
+ "text-table" "^0.2.0"
+ "v8-compile-cache" "^2.0.3"
+
+"espree@^9.2.0":
+ "integrity" "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ=="
+ "resolved" "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz"
+ "version" "9.3.0"
+ dependencies:
+ "acorn" "^8.7.0"
+ "acorn-jsx" "^5.3.1"
+ "eslint-visitor-keys" "^3.1.0"
+
+"esprima@^2.7.1", "esprima@2.7.x":
+ "integrity" "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE="
+ "resolved" "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz"
+ "version" "2.7.3"
+
+"esprima@^4.0.0", "esprima@^4.0.1":
+ "integrity" "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
+ "resolved" "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz"
+ "version" "4.0.1"
+
+"esquery@^1.4.0":
+ "integrity" "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w=="
+ "resolved" "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz"
+ "version" "1.4.0"
+ dependencies:
+ "estraverse" "^5.1.0"
+
+"esrecurse@^4.3.0":
+ "integrity" "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="
+ "resolved" "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz"
+ "version" "4.3.0"
+ dependencies:
+ "estraverse" "^5.2.0"
+
+"estraverse@^1.9.1":
+ "integrity" "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q="
+ "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
+ "version" "1.9.3"
+
+"estraverse@^4.1.1":
+ "integrity" "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw=="
+ "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz"
+ "version" "4.3.0"
+
+"estraverse@^5.1.0", "estraverse@^5.2.0", "estraverse@^5.3.0":
+ "integrity" "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA=="
+ "resolved" "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz"
+ "version" "5.3.0"
+
+"estree-walker@^1.0.1":
+ "integrity" "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg=="
+ "resolved" "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz"
+ "version" "1.0.1"
+
+"esutils@^2.0.2":
+ "integrity" "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g=="
+ "resolved" "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz"
+ "version" "2.0.3"
+
+"etag@^1.8.1", "etag@~1.8.1", "etag@1.8.1":
+ "integrity" "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+ "resolved" "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz"
+ "version" "1.8.1"
+
+"eventemitter3@^4.0.0":
+ "integrity" "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw=="
+ "resolved" "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz"
+ "version" "4.0.7"
+
+"events@^3.2.0":
+ "integrity" "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q=="
+ "resolved" "https://registry.npmjs.org/events/-/events-3.3.0.tgz"
+ "version" "3.3.0"
+
+"execa@^5.0.0":
+ "integrity" "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="
+ "resolved" "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz"
+ "version" "5.1.1"
+ dependencies:
+ "cross-spawn" "^7.0.3"
+ "get-stream" "^6.0.0"
+ "human-signals" "^2.1.0"
+ "is-stream" "^2.0.0"
+ "merge-stream" "^2.0.0"
+ "npm-run-path" "^4.0.1"
+ "onetime" "^5.1.2"
+ "signal-exit" "^3.0.3"
+ "strip-final-newline" "^2.0.0"
+
+"exit-hook@^1.0.0":
+ "integrity" "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g="
+ "resolved" "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz"
+ "version" "1.1.1"
+
+"exit@^0.1.2":
+ "integrity" "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw="
+ "resolved" "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz"
+ "version" "0.1.2"
+
+"expect@^27.4.6":
+ "integrity" "sha512-1M/0kAALIaj5LaG66sFJTbRsWTADnylly82cu4bspI0nl+pgP4E6Bh/aqdHlTUjul06K7xQnnrAoqfxVU0+/ag=="
+ "resolved" "https://registry.npmjs.org/expect/-/expect-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "jest-get-type" "^27.4.0"
+ "jest-matcher-utils" "^27.4.6"
+ "jest-message-util" "^27.4.6"
+
+"express@^4.17.1":
+ "integrity" "sha512-oxlxJxcQlYwqPWKVJJtvQiwHgosH/LrLSPA+H4UxpyvSS6jC5aH+5MoHFM+KABgTOt0APue4w66Ha8jCUo9QGg=="
+ "resolved" "https://registry.npmjs.org/express/-/express-4.17.2.tgz"
+ "version" "4.17.2"
+ dependencies:
+ "accepts" "~1.3.7"
+ "array-flatten" "1.1.1"
+ "body-parser" "1.19.1"
+ "content-disposition" "0.5.4"
+ "content-type" "~1.0.4"
+ "cookie" "0.4.1"
+ "cookie-signature" "1.0.6"
+ "debug" "2.6.9"
+ "depd" "~1.1.2"
+ "encodeurl" "~1.0.2"
+ "escape-html" "~1.0.3"
+ "etag" "~1.8.1"
+ "finalhandler" "~1.1.2"
+ "fresh" "0.5.2"
+ "merge-descriptors" "1.0.1"
+ "methods" "~1.1.2"
+ "on-finished" "~2.3.0"
+ "parseurl" "~1.3.3"
+ "path-to-regexp" "0.1.7"
+ "proxy-addr" "~2.0.7"
+ "qs" "6.9.6"
+ "range-parser" "~1.2.1"
+ "safe-buffer" "5.2.1"
+ "send" "0.17.2"
+ "serve-static" "1.14.2"
+ "setprototypeof" "1.2.0"
+ "statuses" "~1.5.0"
+ "type-is" "~1.6.18"
+ "utils-merge" "1.0.1"
+ "vary" "~1.1.2"
+
+"extend@^3.0.0", "extend@~3.0.2":
+ "integrity" "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
+ "resolved" "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz"
+ "version" "3.0.2"
+
+"external-editor@^1.1.0":
+ "integrity" "sha1-Etew24UPf/fnCBuvQAVwAGDEYAs="
+ "resolved" "https://registry.npmjs.org/external-editor/-/external-editor-1.1.1.tgz"
+ "version" "1.1.1"
+ dependencies:
+ "extend" "^3.0.0"
+ "spawn-sync" "^1.0.15"
+ "tmp" "^0.0.29"
+
+"external-editor@^2.0.1", "external-editor@^2.0.4":
+ "integrity" "sha512-bSn6gvGxKt+b7+6TKEv1ZycHleA7aHhRHyAqJyp5pbUFuYYNIzpZnQDk7AsYckyWdEnTeAnay0aCy2aV6iTk9A=="
+ "resolved" "https://registry.npmjs.org/external-editor/-/external-editor-2.2.0.tgz"
+ "version" "2.2.0"
+ dependencies:
+ "chardet" "^0.4.0"
+ "iconv-lite" "^0.4.17"
+ "tmp" "^0.0.33"
+
+"extsprintf@^1.2.0", "extsprintf@1.3.0":
+ "integrity" "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
+ "resolved" "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz"
+ "version" "1.3.0"
+
+"eyes@0.1.x":
+ "integrity" "sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A="
+ "resolved" "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz"
+ "version" "0.1.8"
+
+"fast-deep-equal@^3.1.1", "fast-deep-equal@^3.1.3":
+ "integrity" "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
+ "resolved" "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz"
+ "version" "3.1.3"
+
+"fast-glob@^3.0.3", "fast-glob@^3.1.1", "fast-glob@^3.2.7":
+ "integrity" "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q=="
+ "resolved" "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz"
+ "version" "3.2.7"
+ dependencies:
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ "glob-parent" "^5.1.2"
+ "merge2" "^1.3.0"
+ "micromatch" "^4.0.4"
+
+"fast-json-stable-stringify@^2.0.0", "fast-json-stable-stringify@^2.1.0", "fast-json-stable-stringify@2.x":
+ "integrity" "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
+ "resolved" "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz"
+ "version" "2.1.0"
+
+"fast-levenshtein@^2.0.6", "fast-levenshtein@~2.0.6":
+ "integrity" "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc="
+ "resolved" "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz"
+ "version" "2.0.6"
+
+"fastest-levenshtein@^1.0.12":
+ "integrity" "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow=="
+ "resolved" "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz"
+ "version" "1.0.12"
+
+"fastq@^1.6.0":
+ "integrity" "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw=="
+ "resolved" "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz"
+ "version" "1.13.0"
+ dependencies:
+ "reusify" "^1.0.4"
+
+"faye-websocket@^0.11.3":
+ "integrity" "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g=="
+ "resolved" "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz"
+ "version" "0.11.4"
+ dependencies:
+ "websocket-driver" ">=0.5.1"
+
+"fb-watchman@^2.0.0":
+ "integrity" "sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg=="
+ "resolved" "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "bser" "2.1.1"
+
+"figures@^1.3.5":
+ "integrity" "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4="
+ "resolved" "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz"
+ "version" "1.7.0"
+ dependencies:
+ "escape-string-regexp" "^1.0.5"
+ "object-assign" "^4.1.0"
+
+"figures@^2.0.0":
+ "integrity" "sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI="
+ "resolved" "https://registry.npmjs.org/figures/-/figures-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "escape-string-regexp" "^1.0.5"
+
+"figures@3.2.x":
+ "integrity" "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg=="
+ "resolved" "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz"
+ "version" "3.2.0"
+ dependencies:
+ "escape-string-regexp" "^1.0.5"
+
+"file-entry-cache@^6.0.1":
+ "integrity" "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg=="
+ "resolved" "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz"
+ "version" "6.0.1"
+ dependencies:
+ "flat-cache" "^3.0.4"
+
+"filelist@^1.0.1":
+ "integrity" "sha512-z7O0IS8Plc39rTCq6i6iHxk43duYOn8uFJiWSewIq0Bww1RNybVHSCjahmcC87ZqAm4OTvFzlzeGu3XAzG1ctQ=="
+ "resolved" "https://registry.npmjs.org/filelist/-/filelist-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "minimatch" "^3.0.4"
+
+"fill-range@^7.0.1":
+ "integrity" "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ=="
+ "resolved" "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz"
+ "version" "7.0.1"
+ dependencies:
+ "to-regex-range" "^5.0.1"
+
+"finalhandler@~1.1.2":
+ "integrity" "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA=="
+ "resolved" "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz"
+ "version" "1.1.2"
+ dependencies:
+ "debug" "2.6.9"
+ "encodeurl" "~1.0.2"
+ "escape-html" "~1.0.3"
+ "on-finished" "~2.3.0"
+ "parseurl" "~1.3.3"
+ "statuses" "~1.5.0"
+ "unpipe" "~1.0.0"
+
+"finalhandler@1.1.0":
+ "integrity" "sha1-zgtoVbRYU+eRsvzGgARtiCU91/U="
+ "resolved" "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz"
+ "version" "1.1.0"
+ dependencies:
+ "debug" "2.6.9"
+ "encodeurl" "~1.0.1"
+ "escape-html" "~1.0.3"
+ "on-finished" "~2.3.0"
+ "parseurl" "~1.3.2"
+ "statuses" "~1.3.1"
+ "unpipe" "~1.0.0"
+
+"find-up@^1.0.0":
+ "integrity" "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8="
+ "resolved" "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz"
+ "version" "1.1.2"
+ dependencies:
+ "path-exists" "^2.0.0"
+ "pinkie-promise" "^2.0.0"
+
+"find-up@^2.0.0", "find-up@^2.1.0":
+ "integrity" "sha1-RdG35QbHF93UgndaK3eSCjwMV6c="
+ "resolved" "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "locate-path" "^2.0.0"
+
+"find-up@^4.0.0", "find-up@^4.1.0":
+ "integrity" "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw=="
+ "resolved" "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz"
+ "version" "4.1.0"
+ dependencies:
+ "locate-path" "^5.0.0"
+ "path-exists" "^4.0.0"
+
+"first-chunk-stream@^2.0.0":
+ "integrity" "sha1-G97NuOCDwGZLkZRVgVd6Q6nzHXA="
+ "resolved" "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "readable-stream" "^2.0.2"
+
+"flat-cache@^3.0.4":
+ "integrity" "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg=="
+ "resolved" "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz"
+ "version" "3.0.4"
+ dependencies:
+ "flatted" "^3.1.0"
+ "rimraf" "^3.0.2"
+
+"flatted@^3.1.0":
+ "integrity" "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw=="
+ "resolved" "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz"
+ "version" "3.2.4"
+
+"folder-hash@4.0.1":
+ "integrity" "sha512-oF1MGtGAPezYJJRMRPzTwtDYwZdQ16UTnthsVAxjVZnlrQ36WuF6YxSgyZxnoUEK6JNPX+04FCFAkw5CzE5OMw=="
+ "resolved" "https://registry.npmjs.org/folder-hash/-/folder-hash-4.0.1.tgz"
+ "version" "4.0.1"
+ dependencies:
+ "debug" "^4.1.1"
+ "graceful-fs" "~4.2.0"
+ "minimatch" "~3.0.4"
+
+"follow-redirects@^1.0.0", "follow-redirects@^1.14.0", "follow-redirects@^1.14.4":
+ "integrity" "sha512-fhUl5EwSJbbl8AR+uYL2KQDxLkdSjZGR36xy46AO7cOMTrCMON6Sa28FmAnC2tRTDbd/Uuzz3aJBv7EBN7JH8A=="
+ "resolved" "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.6.tgz"
+ "version" "1.14.6"
+
+"forever-agent@~0.6.1":
+ "integrity" "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
+ "resolved" "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
+ "version" "0.6.1"
+
+"fork-ts-checker-webpack-plugin@6.5.0":
+ "integrity" "sha512-cS178Y+xxtIjEUorcHddKS7yCMlrDPV31mt47blKKRfMd70Kxu5xruAFE2o9sDY6wVC5deuob/u/alD04YYHnw=="
+ "resolved" "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-6.5.0.tgz"
+ "version" "6.5.0"
+ dependencies:
+ "@babel/code-frame" "^7.8.3"
+ "@types/json-schema" "^7.0.5"
+ "chalk" "^4.1.0"
+ "chokidar" "^3.4.2"
+ "cosmiconfig" "^6.0.0"
+ "deepmerge" "^4.2.2"
+ "fs-extra" "^9.0.0"
+ "glob" "^7.1.6"
+ "memfs" "^3.1.2"
+ "minimatch" "^3.0.4"
+ "schema-utils" "2.7.0"
+ "semver" "^7.3.2"
+ "tapable" "^1.0.0"
+
+"form-data@^3.0.0":
+ "integrity" "sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg=="
+ "resolved" "https://registry.npmjs.org/form-data/-/form-data-3.0.1.tgz"
+ "version" "3.0.1"
+ dependencies:
+ "asynckit" "^0.4.0"
+ "combined-stream" "^1.0.8"
+ "mime-types" "^2.1.12"
+
+"form-data@~2.3.2":
+ "integrity" "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ=="
+ "resolved" "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz"
+ "version" "2.3.3"
+ dependencies:
+ "asynckit" "^0.4.0"
+ "combined-stream" "^1.0.6"
+ "mime-types" "^2.1.12"
+
+"forwarded@0.2.0":
+ "integrity" "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+ "resolved" "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz"
+ "version" "0.2.0"
+
+"fraction.js@^4.1.2":
+ "integrity" "sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA=="
+ "resolved" "https://registry.npmjs.org/fraction.js/-/fraction.js-4.1.2.tgz"
+ "version" "4.1.2"
+
+"fresh@^0.5.2", "fresh@0.5.2":
+ "integrity" "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+ "resolved" "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz"
+ "version" "0.5.2"
+
+"fs-extra@^9.0.0":
+ "integrity" "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="
+ "resolved" "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz"
+ "version" "9.1.0"
+ dependencies:
+ "at-least-node" "^1.0.0"
+ "graceful-fs" "^4.2.0"
+ "jsonfile" "^6.0.1"
+ "universalify" "^2.0.0"
+
+"fs-extra@^9.0.1":
+ "integrity" "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ=="
+ "resolved" "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz"
+ "version" "9.1.0"
+ dependencies:
+ "at-least-node" "^1.0.0"
+ "graceful-fs" "^4.2.0"
+ "jsonfile" "^6.0.1"
+ "universalify" "^2.0.0"
+
+"fs-extra@3.0.1":
+ "integrity" "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE="
+ "resolved" "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz"
+ "version" "3.0.1"
+ dependencies:
+ "graceful-fs" "^4.1.2"
+ "jsonfile" "^3.0.0"
+ "universalify" "^0.1.0"
+
+"fs-monkey@1.0.3":
+ "integrity" "sha512-cybjIfiiE+pTWicSCLFHSrXZ6EilF30oh91FDP9S2B051prEa7QWfrVTQm10/dDpswBDXZugPa1Ogu8Yh+HV0Q=="
+ "resolved" "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.3.tgz"
+ "version" "1.0.3"
+
+"fs.realpath@^1.0.0":
+ "integrity" "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
+ "resolved" "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
+ "version" "1.0.0"
+
+"fsevents@^2.3.2", "fsevents@~2.3.2":
+ "integrity" "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="
+ "resolved" "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz"
+ "version" "2.3.2"
+
+"function-bind@^1.1.1":
+ "integrity" "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+ "resolved" "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz"
+ "version" "1.1.1"
+
+"functional-red-black-tree@^1.0.1":
+ "integrity" "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc="
+ "resolved" "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz"
+ "version" "1.0.1"
+
+"gauge@~1.2.5":
+ "integrity" "sha1-6c7FSD09TuDvRLYKfZnkk14TbZM="
+ "resolved" "https://registry.npmjs.org/gauge/-/gauge-1.2.7.tgz"
+ "version" "1.2.7"
+ dependencies:
+ "ansi" "^0.3.0"
+ "has-unicode" "^2.0.0"
+ "lodash.pad" "^4.1.0"
+ "lodash.padend" "^4.1.0"
+ "lodash.padstart" "^4.1.0"
+
+"generator-jhipster@^4.14.5":
+ "integrity" "sha512-D9pfVeAQiDGmhZDfBMxcFx4dlAQ2sxxvt7vA3JF/CjAP4qtnl9Df0mNUQVR1z0wYkXT/tykTNuvmHXfCcO1a7Q=="
+ "resolved" "https://registry.npmjs.org/generator-jhipster/-/generator-jhipster-4.14.5.tgz"
+ "version" "4.14.5"
+ dependencies:
+ "chalk" "2.3.0"
+ "cheerio" "0.22.0"
+ "commander" "2.12.2"
+ "didyoumean" "1.2.1"
+ "ejs" "2.5.7"
+ "glob" "7.1.2"
+ "html-wiring" "1.2.0"
+ "insight" "0.8.4"
+ "jhipster-core" "1.4.4"
+ "js-yaml" "3.10.0"
+ "lodash" "4.17.4"
+ "meow" "3.7.0"
+ "mkdirp" "0.5.1"
+ "opencollective" "1.0.3"
+ "pluralize" "7.0.0"
+ "randexp" "0.4.6"
+ "semver" "5.4.1"
+ "shelljs" "0.7.8"
+ "tabtab" "2.2.2"
+ "yeoman-environment" "2.0.5"
+ "yeoman-generator" "2.0.1"
+
+"gensync@^1.0.0-beta.2":
+ "integrity" "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg=="
+ "resolved" "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz"
+ "version" "1.0.0-beta.2"
+
+"get-caller-file@^2.0.1", "get-caller-file@^2.0.5":
+ "integrity" "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="
+ "resolved" "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz"
+ "version" "2.0.5"
+
+"get-intrinsic@^1.0.2", "get-intrinsic@^1.1.0", "get-intrinsic@^1.1.1":
+ "integrity" "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q=="
+ "resolved" "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz"
+ "version" "1.1.1"
+ dependencies:
+ "function-bind" "^1.1.1"
+ "has" "^1.0.3"
+ "has-symbols" "^1.0.1"
+
+"get-own-enumerable-property-symbols@^3.0.0":
+ "integrity" "sha512-I0UBV/XOz1XkIJHEUDMZAbzCThU/H8DxmSfmdGcKPnVhu2VfFqr34jr9777IyaTYvxjedWhqVIilEDsCdP5G6g=="
+ "resolved" "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.2.tgz"
+ "version" "3.0.2"
+
+"get-package-type@^0.1.0":
+ "integrity" "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q=="
+ "resolved" "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz"
+ "version" "0.1.0"
+
+"get-stdin@^4.0.1":
+ "integrity" "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
+ "resolved" "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
+ "version" "4.0.1"
+
+"get-stream@^3.0.0":
+ "integrity" "sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ="
+ "resolved" "https://registry.npmjs.org/get-stream/-/get-stream-3.0.0.tgz"
+ "version" "3.0.0"
+
+"get-stream@^6.0.0":
+ "integrity" "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg=="
+ "resolved" "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz"
+ "version" "6.0.1"
+
+"get-symbol-description@^1.0.0":
+ "integrity" "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw=="
+ "resolved" "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz"
+ "version" "1.0.0"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "get-intrinsic" "^1.1.1"
+
+"getpass@^0.1.1":
+ "integrity" "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo="
+ "resolved" "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz"
+ "version" "0.1.7"
+ dependencies:
+ "assert-plus" "^1.0.0"
+
+"gh-got@^6.0.0":
+ "integrity" "sha512-F/mS+fsWQMo1zfgG9MD8KWvTWPPzzhuVwY++fhQ5Ggd+0P+CAMHtzMZhNxG+TqGfHDChJKsbh6otfMGqO2AKBw=="
+ "resolved" "https://registry.npmjs.org/gh-got/-/gh-got-6.0.0.tgz"
+ "version" "6.0.0"
+ dependencies:
+ "got" "^7.0.0"
+ "is-plain-obj" "^1.1.0"
+
+"git-hooks-list@1.0.3":
+ "integrity" "sha512-Y7wLWcrLUXwk2noSka166byGCvhMtDRpgHdzCno1UQv/n/Hegp++a2xBWJL1lJarnKD3SWaljD+0z1ztqxuKyQ=="
+ "resolved" "https://registry.npmjs.org/git-hooks-list/-/git-hooks-list-1.0.3.tgz"
+ "version" "1.0.3"
+
+"github-username@^4.0.0":
+ "integrity" "sha1-y+KABBiDIG2kISrp5LXxacML9Bc="
+ "resolved" "https://registry.npmjs.org/github-username/-/github-username-4.1.0.tgz"
+ "version" "4.1.0"
+ dependencies:
+ "gh-got" "^6.0.0"
+
+"glob-parent@^5.1.2", "glob-parent@~5.1.2":
+ "integrity" "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow=="
+ "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz"
+ "version" "5.1.2"
+ dependencies:
+ "is-glob" "^4.0.1"
+
+"glob-parent@^6.0.1":
+ "integrity" "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A=="
+ "resolved" "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz"
+ "version" "6.0.2"
+ dependencies:
+ "is-glob" "^4.0.3"
+
+"glob-to-regexp@^0.4.1":
+ "integrity" "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw=="
+ "resolved" "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz"
+ "version" "0.4.1"
+
+"glob@^5.0.15":
+ "integrity" "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E="
+ "resolved" "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
+ "version" "5.0.15"
+ dependencies:
+ "inflight" "^1.0.4"
+ "inherits" "2"
+ "minimatch" "2 || 3"
+ "once" "^1.3.0"
+ "path-is-absolute" "^1.0.0"
+
+"glob@^7.0.0", "glob@^7.0.3", "glob@^7.1.1", "glob@^7.1.2", "glob@^7.1.3", "glob@^7.1.4", "glob@^7.1.6":
+ "integrity" "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q=="
+ "resolved" "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz"
+ "version" "7.2.0"
+ dependencies:
+ "fs.realpath" "^1.0.0"
+ "inflight" "^1.0.4"
+ "inherits" "2"
+ "minimatch" "^3.0.4"
+ "once" "^1.3.0"
+ "path-is-absolute" "^1.0.0"
+
+"glob@7.1.1":
+ "integrity" "sha1-gFIR3wT6rxxjo2ADBs31reULLsg="
+ "resolved" "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz"
+ "version" "7.1.1"
+ dependencies:
+ "fs.realpath" "^1.0.0"
+ "inflight" "^1.0.4"
+ "inherits" "2"
+ "minimatch" "^3.0.2"
+ "once" "^1.3.0"
+ "path-is-absolute" "^1.0.0"
+
+"glob@7.1.2":
+ "integrity" "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ=="
+ "resolved" "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz"
+ "version" "7.1.2"
+ dependencies:
+ "fs.realpath" "^1.0.0"
+ "inflight" "^1.0.4"
+ "inherits" "2"
+ "minimatch" "^3.0.4"
+ "once" "^1.3.0"
+ "path-is-absolute" "^1.0.0"
+
+"globals@^11.1.0":
+ "integrity" "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA=="
+ "resolved" "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz"
+ "version" "11.12.0"
+
+"globals@^13.6.0", "globals@^13.9.0":
+ "integrity" "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg=="
+ "resolved" "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz"
+ "version" "13.12.0"
+ dependencies:
+ "type-fest" "^0.20.2"
+
+"globby@^11.0.1", "globby@^11.0.4":
+ "integrity" "sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg=="
+ "resolved" "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz"
+ "version" "11.0.4"
+ dependencies:
+ "array-union" "^2.1.0"
+ "dir-glob" "^3.0.1"
+ "fast-glob" "^3.1.1"
+ "ignore" "^5.1.4"
+ "merge2" "^1.3.0"
+ "slash" "^3.0.0"
+
+"globby@^12.0.2":
+ "integrity" "sha512-lAsmb/5Lww4r7MM9nCCliDZVIKbZTavrsunAsHLr9oHthrZP1qi7/gAnHOsUs9bLvEt2vKVJhHmxuL7QbDuPdQ=="
+ "resolved" "https://registry.npmjs.org/globby/-/globby-12.0.2.tgz"
+ "version" "12.0.2"
+ dependencies:
+ "array-union" "^3.0.1"
+ "dir-glob" "^3.0.1"
+ "fast-glob" "^3.2.7"
+ "ignore" "^5.1.8"
+ "merge2" "^1.4.1"
+ "slash" "^4.0.0"
+
+"globby@^6.1.0":
+ "integrity" "sha1-9abXDoOV4hyFj7BInWTfAkJNUGw="
+ "resolved" "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz"
+ "version" "6.1.0"
+ dependencies:
+ "array-union" "^1.0.1"
+ "glob" "^7.0.3"
+ "object-assign" "^4.0.1"
+ "pify" "^2.0.0"
+ "pinkie-promise" "^2.0.0"
+
+"globby@10.0.0":
+ "integrity" "sha512-3LifW9M4joGZasyYPz2A1U74zbC/45fvpXUvO/9KbSa+VV0aGZarWkfdgKyR9sExNP0t0x0ss/UMJpNpcaTspw=="
+ "resolved" "https://registry.npmjs.org/globby/-/globby-10.0.0.tgz"
+ "version" "10.0.0"
+ dependencies:
+ "@types/glob" "^7.1.1"
+ "array-union" "^2.1.0"
+ "dir-glob" "^3.0.1"
+ "fast-glob" "^3.0.3"
+ "glob" "^7.1.3"
+ "ignore" "^5.1.1"
+ "merge2" "^1.2.3"
+ "slash" "^3.0.0"
+
+"got@^7.0.0":
+ "integrity" "sha512-Y5WMo7xKKq1muPsxD+KmrR8DH5auG7fBdDVueZwETwV6VytKyU9OX/ddpq2/1hp1vIPvVb4T81dKQz3BivkNLw=="
+ "resolved" "https://registry.npmjs.org/got/-/got-7.1.0.tgz"
+ "version" "7.1.0"
+ dependencies:
+ "decompress-response" "^3.2.0"
+ "duplexer3" "^0.1.4"
+ "get-stream" "^3.0.0"
+ "is-plain-obj" "^1.1.0"
+ "is-retry-allowed" "^1.0.0"
+ "is-stream" "^1.0.0"
+ "isurl" "^1.0.0-alpha5"
+ "lowercase-keys" "^1.0.0"
+ "p-cancelable" "^0.3.0"
+ "p-timeout" "^1.1.1"
+ "safe-buffer" "^5.0.1"
+ "timed-out" "^4.0.0"
+ "url-parse-lax" "^1.0.0"
+ "url-to-options" "^1.0.1"
+
+"graceful-fs@^4.1.11", "graceful-fs@^4.1.2", "graceful-fs@^4.1.6", "graceful-fs@^4.2.0", "graceful-fs@^4.2.4", "graceful-fs@^4.2.6", "graceful-fs@~4.2.0":
+ "integrity" "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ=="
+ "resolved" "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz"
+ "version" "4.2.9"
+
+"grouped-queue@^0.3.3":
+ "integrity" "sha1-wWfSpTGcWg4JZO9qJbfC34mWyFw="
+ "resolved" "https://registry.npmjs.org/grouped-queue/-/grouped-queue-0.3.3.tgz"
+ "version" "0.3.3"
+ dependencies:
+ "lodash" "^4.17.2"
+
+"growly@^1.3.0":
+ "integrity" "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE="
+ "resolved" "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz"
+ "version" "1.3.0"
+
+"handle-thing@^2.0.0":
+ "integrity" "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg=="
+ "resolved" "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz"
+ "version" "2.0.1"
+
+"handlebars@^4.0.1":
+ "integrity" "sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA=="
+ "resolved" "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz"
+ "version" "4.7.7"
+ dependencies:
+ "minimist" "^1.2.5"
+ "neo-async" "^2.6.0"
+ "source-map" "^0.6.1"
+ "wordwrap" "^1.0.0"
+ optionalDependencies:
+ "uglify-js" "^3.1.4"
+
+"har-schema@^2.0.0":
+ "integrity" "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
+ "resolved" "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz"
+ "version" "2.0.0"
+
+"har-validator@~5.1.3":
+ "integrity" "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w=="
+ "resolved" "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz"
+ "version" "5.1.5"
+ dependencies:
+ "ajv" "^6.12.3"
+ "har-schema" "^2.0.0"
+
+"harmony-reflect@^1.4.6":
+ "integrity" "sha512-HIp/n38R9kQjDEziXyDTuW3vvoxxyxjxFzXLrBr18uB47GnSt+G9D29fqrpM5ZkspMcPICud3XsBJQ4Y2URg8g=="
+ "resolved" "https://registry.npmjs.org/harmony-reflect/-/harmony-reflect-1.6.2.tgz"
+ "version" "1.6.2"
+
+"has-ansi@^2.0.0":
+ "integrity" "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE="
+ "resolved" "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "ansi-regex" "^2.0.0"
+
+"has-bigints@^1.0.1":
+ "integrity" "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA=="
+ "resolved" "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz"
+ "version" "1.0.1"
+
+"has-binary2@~1.0.2":
+ "integrity" "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw=="
+ "resolved" "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz"
+ "version" "1.0.3"
+ dependencies:
+ "isarray" "2.0.1"
+
+"has-cors@1.1.0":
+ "integrity" "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk="
+ "resolved" "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz"
+ "version" "1.1.0"
+
+"has-flag@^1.0.0":
+ "integrity" "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo="
+ "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz"
+ "version" "1.0.0"
+
+"has-flag@^2.0.0":
+ "integrity" "sha1-6CB68cx7MNRGzHC3NLXovhj4jVE="
+ "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-2.0.0.tgz"
+ "version" "2.0.0"
+
+"has-flag@^3.0.0":
+ "integrity" "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
+ "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz"
+ "version" "3.0.0"
+
+"has-flag@^4.0.0":
+ "integrity" "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
+ "resolved" "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz"
+ "version" "4.0.0"
+
+"has-symbol-support-x@^1.4.1":
+ "integrity" "sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw=="
+ "resolved" "https://registry.npmjs.org/has-symbol-support-x/-/has-symbol-support-x-1.4.2.tgz"
+ "version" "1.4.2"
+
+"has-symbols@^1.0.1", "has-symbols@^1.0.2":
+ "integrity" "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
+ "resolved" "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz"
+ "version" "1.0.2"
+
+"has-to-string-tag-x@^1.2.0":
+ "integrity" "sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw=="
+ "resolved" "https://registry.npmjs.org/has-to-string-tag-x/-/has-to-string-tag-x-1.4.1.tgz"
+ "version" "1.4.1"
+ dependencies:
+ "has-symbol-support-x" "^1.4.1"
+
+"has-tostringtag@^1.0.0":
+ "integrity" "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ=="
+ "resolved" "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz"
+ "version" "1.0.0"
+ dependencies:
+ "has-symbols" "^1.0.2"
+
+"has-unicode@^2.0.0":
+ "integrity" "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
+ "resolved" "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz"
+ "version" "2.0.1"
+
+"has@^1.0.3":
+ "integrity" "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw=="
+ "resolved" "https://registry.npmjs.org/has/-/has-1.0.3.tgz"
+ "version" "1.0.3"
+ dependencies:
+ "function-bind" "^1.1.1"
+
+"he@^1.2.0":
+ "integrity" "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw=="
+ "resolved" "https://registry.npmjs.org/he/-/he-1.2.0.tgz"
+ "version" "1.2.0"
+
+"history@^4.9.0":
+ "integrity" "sha512-36nwAD620w12kuzPAsyINPWJqlNbij+hpK1k9XRloDtym8mxzGYl2c17LnV6IAGB2Dmg4tEa7G7DlawS0+qjew=="
+ "resolved" "https://registry.npmjs.org/history/-/history-4.10.1.tgz"
+ "version" "4.10.1"
+ dependencies:
+ "@babel/runtime" "^7.1.2"
+ "loose-envify" "^1.2.0"
+ "resolve-pathname" "^3.0.0"
+ "tiny-invariant" "^1.0.2"
+ "tiny-warning" "^1.0.0"
+ "value-equal" "^1.0.1"
+
+"hoist-non-react-statics@^3.1.0", "hoist-non-react-statics@^3.3.0", "hoist-non-react-statics@^3.3.2":
+ "integrity" "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw=="
+ "resolved" "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz"
+ "version" "3.3.2"
+ dependencies:
+ "react-is" "^16.7.0"
+
+"hosted-git-info@^2.1.4":
+ "integrity" "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw=="
+ "resolved" "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz"
+ "version" "2.8.9"
+
+"hpack.js@^2.1.6":
+ "integrity" "sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI="
+ "resolved" "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz"
+ "version" "2.1.6"
+ dependencies:
+ "inherits" "^2.0.1"
+ "obuf" "^1.0.0"
+ "readable-stream" "^2.0.1"
+ "wbuf" "^1.1.0"
+
+"html-encoding-sniffer@^2.0.1":
+ "integrity" "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ=="
+ "resolved" "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "whatwg-encoding" "^1.0.5"
+
+"html-entities@^2.3.2":
+ "integrity" "sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ=="
+ "resolved" "https://registry.npmjs.org/html-entities/-/html-entities-2.3.2.tgz"
+ "version" "2.3.2"
+
+"html-escaper@^2.0.0":
+ "integrity" "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg=="
+ "resolved" "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz"
+ "version" "2.0.2"
+
+"html-minifier-terser@^6.0.2":
+ "integrity" "sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw=="
+ "resolved" "https://registry.npmjs.org/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz"
+ "version" "6.1.0"
+ dependencies:
+ "camel-case" "^4.1.2"
+ "clean-css" "^5.2.2"
+ "commander" "^8.3.0"
+ "he" "^1.2.0"
+ "param-case" "^3.0.4"
+ "relateurl" "^0.2.7"
+ "terser" "^5.10.0"
+
+"html-webpack-plugin@5.5.0":
+ "integrity" "sha512-sy88PC2cRTVxvETRgUHFrL4No3UxvcH8G1NepGhqaTT+GXN2kTamqasot0inS5hXeg1cMbFDt27zzo9p35lZVw=="
+ "resolved" "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz"
+ "version" "5.5.0"
+ dependencies:
+ "@types/html-minifier-terser" "^6.0.0"
+ "html-minifier-terser" "^6.0.2"
+ "lodash" "^4.17.21"
+ "pretty-error" "^4.0.0"
+ "tapable" "^2.0.0"
+
+"html-wiring@1.2.0":
+ "integrity" "sha1-xfkKd24KJyQdxt+QIsNxhtAnD54="
+ "resolved" "https://registry.npmjs.org/html-wiring/-/html-wiring-1.2.0.tgz"
+ "version" "1.2.0"
+ dependencies:
+ "cheerio" "^0.19.0"
+ "detect-newline" "^1.0.3"
+
+"htmlparser2@^3.9.1":
+ "integrity" "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ=="
+ "resolved" "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz"
+ "version" "3.10.1"
+ dependencies:
+ "domelementtype" "^1.3.1"
+ "domhandler" "^2.3.0"
+ "domutils" "^1.5.1"
+ "entities" "^1.1.1"
+ "inherits" "^2.0.1"
+ "readable-stream" "^3.1.1"
+
+"htmlparser2@^6.0.0", "htmlparser2@^6.1.0":
+ "integrity" "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A=="
+ "resolved" "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz"
+ "version" "6.1.0"
+ dependencies:
+ "domelementtype" "^2.0.1"
+ "domhandler" "^4.0.0"
+ "domutils" "^2.5.2"
+ "entities" "^2.0.0"
+
+"htmlparser2@~3.8.1":
+ "integrity" "sha1-mWwosZFRaovoZQGn15dX5ccMEGg="
+ "resolved" "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz"
+ "version" "3.8.3"
+ dependencies:
+ "domelementtype" "1"
+ "domhandler" "2.3"
+ "domutils" "1.5"
+ "entities" "1.0"
+ "readable-stream" "1.1"
+
+"http-deceiver@^1.2.7":
+ "integrity" "sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc="
+ "resolved" "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz"
+ "version" "1.2.7"
+
+"http-errors@~1.6.2":
+ "integrity" "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0="
+ "resolved" "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz"
+ "version" "1.6.3"
+ dependencies:
+ "depd" "~1.1.2"
+ "inherits" "2.0.3"
+ "setprototypeof" "1.1.0"
+ "statuses" ">= 1.4.0 < 2"
+
+"http-errors@1.8.1":
+ "integrity" "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g=="
+ "resolved" "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz"
+ "version" "1.8.1"
+ dependencies:
+ "depd" "~1.1.2"
+ "inherits" "2.0.4"
+ "setprototypeof" "1.2.0"
+ "statuses" ">= 1.5.0 < 2"
+ "toidentifier" "1.0.1"
+
+"http-parser-js@>=0.5.1":
+ "integrity" "sha512-x+JVEkO2PoM8qqpbPbOL3cqHPwerep7OwzK7Ay+sMQjKzaKCqWvjoXm5tqMP9tXWWTnTzAjIhXg+J99XYuPhPA=="
+ "resolved" "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.5.tgz"
+ "version" "0.5.5"
+
+"http-proxy-agent@^4.0.1":
+ "integrity" "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg=="
+ "resolved" "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz"
+ "version" "4.0.1"
+ dependencies:
+ "@tootallnate/once" "1"
+ "agent-base" "6"
+ "debug" "4"
+
+"http-proxy-middleware@^2.0.0":
+ "integrity" "sha512-cfaXRVoZxSed/BmkA7SwBVNI9Kj7HFltaE5rqYOub5kWzWZ+gofV2koVN1j2rMW7pEfSSlCHGJ31xmuyFyfLOg=="
+ "resolved" "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "@types/http-proxy" "^1.17.5"
+ "http-proxy" "^1.18.1"
+ "is-glob" "^4.0.1"
+ "is-plain-obj" "^3.0.0"
+ "micromatch" "^4.0.2"
+
+"http-proxy@^1.18.1":
+ "integrity" "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ=="
+ "resolved" "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz"
+ "version" "1.18.1"
+ dependencies:
+ "eventemitter3" "^4.0.0"
+ "follow-redirects" "^1.0.0"
+ "requires-port" "^1.0.0"
+
+"http-signature@~1.2.0":
+ "integrity" "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE="
+ "resolved" "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz"
+ "version" "1.2.0"
+ dependencies:
+ "assert-plus" "^1.0.0"
+ "jsprim" "^1.2.2"
+ "sshpk" "^1.7.0"
+
+"https-proxy-agent@^5.0.0":
+ "integrity" "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA=="
+ "resolved" "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz"
+ "version" "5.0.0"
+ dependencies:
+ "agent-base" "6"
+ "debug" "4"
+
+"human-signals@^2.1.0":
+ "integrity" "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw=="
+ "resolved" "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz"
+ "version" "2.1.0"
+
+"iconv-lite@^0.4.17", "iconv-lite@0.4.24":
+ "integrity" "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA=="
+ "resolved" "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz"
+ "version" "0.4.24"
+ dependencies:
+ "safer-buffer" ">= 2.1.2 < 3"
+
+"iconv-lite@^0.6.2":
+ "integrity" "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="
+ "resolved" "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz"
+ "version" "0.6.3"
+ dependencies:
+ "safer-buffer" ">= 2.1.2 < 3.0.0"
+
+"icss-utils@^5.0.0", "icss-utils@^5.1.0":
+ "integrity" "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA=="
+ "resolved" "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz"
+ "version" "5.1.0"
+
+"idb@^6.1.4":
+ "integrity" "sha512-IJtugpKkiVXQn5Y+LteyBCNk1N8xpGV3wWZk9EVtZWH8DYkjBn0bX1XnGP9RkyZF0sAcywa6unHqSWKe7q4LGw=="
+ "resolved" "https://registry.npmjs.org/idb/-/idb-6.1.5.tgz"
+ "version" "6.1.5"
+
+"identity-obj-proxy@3.0.0":
+ "integrity" "sha1-lNK9qWCERT7zb7xarsN+D3nx/BQ="
+ "resolved" "https://registry.npmjs.org/identity-obj-proxy/-/identity-obj-proxy-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "harmony-reflect" "^1.4.6"
+
+"ignore@^4.0.6":
+ "integrity" "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg=="
+ "resolved" "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz"
+ "version" "4.0.6"
+
+"ignore@^5.1.1", "ignore@^5.1.4", "ignore@^5.1.8":
+ "integrity" "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ=="
+ "resolved" "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz"
+ "version" "5.2.0"
+
+"immer@^9.0.7":
+ "integrity" "sha512-KGllzpbamZDvOIxnmJ0jI840g7Oikx58lBPWV0hUh7dtAyZpFqqrBZdKka5GlTwMTZ1Tjc/bKKW4VSFAt6BqMA=="
+ "resolved" "https://registry.npmjs.org/immer/-/immer-9.0.7.tgz"
+ "version" "9.0.7"
+
+"immutable@^3":
+ "integrity" "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM="
+ "resolved" "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz"
+ "version" "3.8.2"
+
+"immutable@^4.0.0":
+ "integrity" "sha512-zIE9hX70qew5qTUjSS7wi1iwj/l7+m54KWU247nhM3v806UdGj1yDndXj+IOYxxtW9zyLI+xqFNZjTuDaLUqFw=="
+ "resolved" "https://registry.npmjs.org/immutable/-/immutable-4.0.0.tgz"
+ "version" "4.0.0"
+
+"import-fresh@^3.0.0", "import-fresh@^3.1.0", "import-fresh@^3.2.1":
+ "integrity" "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw=="
+ "resolved" "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz"
+ "version" "3.3.0"
+ dependencies:
+ "parent-module" "^1.0.0"
+ "resolve-from" "^4.0.0"
+
+"import-local@^3.0.2":
+ "integrity" "sha512-bE9iaUY3CXH8Cwfan/abDKAxe1KGT9kyGsBPqf6DMK/z0a2OzAsrukeYNgIH6cH5Xr452jb1TUL8rSfCLjZ9uA=="
+ "resolved" "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz"
+ "version" "3.0.3"
+ dependencies:
+ "pkg-dir" "^4.2.0"
+ "resolve-cwd" "^3.0.0"
+
+"imurmurhash@^0.1.4":
+ "integrity" "sha1-khi5srkoojixPcT7a21XbyMUU+o="
+ "resolved" "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz"
+ "version" "0.1.4"
+
+"indent-string@^2.1.0":
+ "integrity" "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA="
+ "resolved" "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "repeating" "^2.0.0"
+
+"indent-string@^4.0.0":
+ "integrity" "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg=="
+ "resolved" "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz"
+ "version" "4.0.0"
+
+"indexof@0.0.1":
+ "integrity" "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10="
+ "resolved" "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz"
+ "version" "0.0.1"
+
+"inflight@^1.0.4":
+ "integrity" "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk="
+ "resolved" "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
+ "version" "1.0.6"
+ dependencies:
+ "once" "^1.3.0"
+ "wrappy" "1"
+
+"inherits@^2.0.1", "inherits@^2.0.3", "inherits@^2.0.4", "inherits@~2.0.1", "inherits@~2.0.3", "inherits@2", "inherits@2.0.4":
+ "integrity" "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz"
+ "version" "2.0.4"
+
+"inherits@2.0.3":
+ "integrity" "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+ "resolved" "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
+ "version" "2.0.3"
+
+"inquirer@^0.10.0":
+ "integrity" "sha1-6iXkzmnKFF4FyZ5G3P7AXkASWUo="
+ "resolved" "https://registry.npmjs.org/inquirer/-/inquirer-0.10.1.tgz"
+ "version" "0.10.1"
+ dependencies:
+ "ansi-escapes" "^1.1.0"
+ "ansi-regex" "^2.0.0"
+ "chalk" "^1.0.0"
+ "cli-cursor" "^1.0.1"
+ "cli-width" "^1.0.1"
+ "figures" "^1.3.5"
+ "lodash" "^3.3.1"
+ "readline2" "^1.0.1"
+ "run-async" "^0.1.0"
+ "rx-lite" "^3.1.2"
+ "strip-ansi" "^3.0.0"
+ "through" "^2.3.6"
+
+"inquirer@^1.0.2":
+ "integrity" "sha1-TexvMvN+97sLLtPx0aXD9UUHSRg="
+ "resolved" "https://registry.npmjs.org/inquirer/-/inquirer-1.2.3.tgz"
+ "version" "1.2.3"
+ dependencies:
+ "ansi-escapes" "^1.1.0"
+ "chalk" "^1.0.0"
+ "cli-cursor" "^1.0.1"
+ "cli-width" "^2.0.0"
+ "external-editor" "^1.1.0"
+ "figures" "^1.3.5"
+ "lodash" "^4.3.0"
+ "mute-stream" "0.0.6"
+ "pinkie-promise" "^2.0.0"
+ "run-async" "^2.2.0"
+ "rx" "^4.1.0"
+ "string-width" "^1.0.1"
+ "strip-ansi" "^3.0.0"
+ "through" "^2.3.6"
+
+"inquirer@^3.3.0":
+ "integrity" "sha512-h+xtnyk4EwKvFWHrUYsWErEVR+igKtLdchu+o0Z1RL7VU/jVMFbYir2bp6bAj8efFNxWqHX0dIss6fJQ+/+qeQ=="
+ "resolved" "https://registry.npmjs.org/inquirer/-/inquirer-3.3.0.tgz"
+ "version" "3.3.0"
+ dependencies:
+ "ansi-escapes" "^3.0.0"
+ "chalk" "^2.0.0"
+ "cli-cursor" "^2.1.0"
+ "cli-width" "^2.0.0"
+ "external-editor" "^2.0.4"
+ "figures" "^2.0.0"
+ "lodash" "^4.3.0"
+ "mute-stream" "0.0.7"
+ "run-async" "^2.2.0"
+ "rx-lite" "^4.0.8"
+ "rx-lite-aggregates" "^4.0.8"
+ "string-width" "^2.1.0"
+ "strip-ansi" "^4.0.0"
+ "through" "^2.3.6"
+
+"inquirer@3.0.6":
+ "integrity" "sha1-4EqqnQW3o8ubD0B9BDdfBEcZA0c="
+ "resolved" "https://registry.npmjs.org/inquirer/-/inquirer-3.0.6.tgz"
+ "version" "3.0.6"
+ dependencies:
+ "ansi-escapes" "^1.1.0"
+ "chalk" "^1.0.0"
+ "cli-cursor" "^2.1.0"
+ "cli-width" "^2.0.0"
+ "external-editor" "^2.0.1"
+ "figures" "^2.0.0"
+ "lodash" "^4.3.0"
+ "mute-stream" "0.0.7"
+ "run-async" "^2.2.0"
+ "rx" "^4.1.0"
+ "string-width" "^2.0.0"
+ "strip-ansi" "^3.0.0"
+ "through" "^2.3.6"
+
+"insight@0.8.4":
+ "integrity" "sha1-ZxyvZbR8n+jD0bMgbPRbshG3WIQ="
+ "resolved" "https://registry.npmjs.org/insight/-/insight-0.8.4.tgz"
+ "version" "0.8.4"
+ dependencies:
+ "async" "^1.4.2"
+ "chalk" "^1.0.0"
+ "configstore" "^1.0.0"
+ "inquirer" "^0.10.0"
+ "lodash.debounce" "^3.0.1"
+ "object-assign" "^4.0.1"
+ "os-name" "^1.0.0"
+ "request" "^2.74.0"
+ "tough-cookie" "^2.0.0"
+ "uuid" "^3.0.0"
+
+"internal-slot@^1.0.3":
+ "integrity" "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA=="
+ "resolved" "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz"
+ "version" "1.0.3"
+ dependencies:
+ "get-intrinsic" "^1.1.0"
+ "has" "^1.0.3"
+ "side-channel" "^1.0.4"
+
+"interpret@^1.0.0":
+ "integrity" "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA=="
+ "resolved" "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz"
+ "version" "1.4.0"
+
+"interpret@^2.2.0":
+ "integrity" "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw=="
+ "resolved" "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz"
+ "version" "2.2.0"
+
+"ip@^1.1.0":
+ "integrity" "sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo="
+ "resolved" "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz"
+ "version" "1.1.5"
+
+"ipaddr.js@^2.0.1":
+ "integrity" "sha512-1qTgH9NG+IIJ4yfKs2e6Pp1bZg8wbDbKHT21HrLIeYBTRLgMYKnMTPAuI3Lcs61nfx5h1xlXnbJtH1kX5/d/ng=="
+ "resolved" "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.0.1.tgz"
+ "version" "2.0.1"
+
+"ipaddr.js@1.9.1":
+ "integrity" "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+ "resolved" "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz"
+ "version" "1.9.1"
+
+"is-arguments@^1.0.4":
+ "integrity" "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA=="
+ "resolved" "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz"
+ "version" "1.1.1"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "has-tostringtag" "^1.0.0"
+
+"is-arrayish@^0.2.1":
+ "integrity" "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
+ "resolved" "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
+ "version" "0.2.1"
+
+"is-bigint@^1.0.1":
+ "integrity" "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg=="
+ "resolved" "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz"
+ "version" "1.0.4"
+ dependencies:
+ "has-bigints" "^1.0.1"
+
+"is-binary-path@~2.1.0":
+ "integrity" "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw=="
+ "resolved" "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "binary-extensions" "^2.0.0"
+
+"is-boolean-object@^1.1.0":
+ "integrity" "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA=="
+ "resolved" "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz"
+ "version" "1.1.2"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "has-tostringtag" "^1.0.0"
+
+"is-callable@^1.1.4", "is-callable@^1.2.4":
+ "integrity" "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w=="
+ "resolved" "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz"
+ "version" "1.2.4"
+
+"is-core-module@^2.2.0", "is-core-module@^2.8.0":
+ "integrity" "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw=="
+ "resolved" "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz"
+ "version" "2.8.0"
+ dependencies:
+ "has" "^1.0.3"
+
+"is-date-object@^1.0.1":
+ "integrity" "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ=="
+ "resolved" "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz"
+ "version" "1.0.5"
+ dependencies:
+ "has-tostringtag" "^1.0.0"
+
+"is-docker@^2.0.0", "is-docker@^2.1.1":
+ "integrity" "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ=="
+ "resolved" "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz"
+ "version" "2.2.1"
+
+"is-extglob@^2.1.1":
+ "integrity" "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI="
+ "resolved" "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
+ "version" "2.1.1"
+
+"is-finite@^1.0.0":
+ "integrity" "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w=="
+ "resolved" "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz"
+ "version" "1.1.0"
+
+"is-fullwidth-code-point@^1.0.0":
+ "integrity" "sha1-754xOG8DGn8NZDr4L95QxFfvAMs="
+ "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz"
+ "version" "1.0.0"
+ dependencies:
+ "number-is-nan" "^1.0.0"
+
+"is-fullwidth-code-point@^2.0.0":
+ "integrity" "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
+ "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz"
+ "version" "2.0.0"
+
+"is-fullwidth-code-point@^3.0.0":
+ "integrity" "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="
+ "resolved" "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz"
+ "version" "3.0.0"
+
+"is-generator-fn@^2.0.0":
+ "integrity" "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ=="
+ "resolved" "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz"
+ "version" "2.1.0"
+
+"is-glob@^4.0.0", "is-glob@^4.0.1", "is-glob@^4.0.3", "is-glob@~4.0.1":
+ "integrity" "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg=="
+ "resolved" "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz"
+ "version" "4.0.3"
+ dependencies:
+ "is-extglob" "^2.1.1"
+
+"is-module@^1.0.0":
+ "integrity" "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE="
+ "resolved" "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz"
+ "version" "1.0.0"
+
+"is-negative-zero@^2.0.1":
+ "integrity" "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA=="
+ "resolved" "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz"
+ "version" "2.0.2"
+
+"is-number-like@^1.0.3":
+ "integrity" "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA=="
+ "resolved" "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz"
+ "version" "1.0.8"
+ dependencies:
+ "lodash.isfinite" "^3.3.2"
+
+"is-number-object@^1.0.4":
+ "integrity" "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g=="
+ "resolved" "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz"
+ "version" "1.0.6"
+ dependencies:
+ "has-tostringtag" "^1.0.0"
+
+"is-number@^7.0.0":
+ "integrity" "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng=="
+ "resolved" "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz"
+ "version" "7.0.0"
+
+"is-obj@^1.0.1":
+ "integrity" "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
+ "resolved" "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz"
+ "version" "1.0.1"
+
+"is-object@^1.0.1":
+ "integrity" "sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA=="
+ "resolved" "https://registry.npmjs.org/is-object/-/is-object-1.0.2.tgz"
+ "version" "1.0.2"
+
+"is-path-cwd@^2.2.0":
+ "integrity" "sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ=="
+ "resolved" "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-2.2.0.tgz"
+ "version" "2.2.0"
+
+"is-path-inside@^3.0.2":
+ "integrity" "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ=="
+ "resolved" "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz"
+ "version" "3.0.3"
+
+"is-plain-obj@^1.1.0":
+ "integrity" "sha1-caUMhCnfync8kqOQpKA7OfzVHT4="
+ "resolved" "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz"
+ "version" "1.1.0"
+
+"is-plain-obj@^3.0.0":
+ "integrity" "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA=="
+ "resolved" "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz"
+ "version" "3.0.0"
+
+"is-plain-obj@2.1.0":
+ "integrity" "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA=="
+ "resolved" "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz"
+ "version" "2.1.0"
+
+"is-plain-object@^2.0.4":
+ "integrity" "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og=="
+ "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz"
+ "version" "2.0.4"
+ dependencies:
+ "isobject" "^3.0.1"
+
+"is-plain-object@^5.0.0":
+ "integrity" "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
+ "resolved" "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz"
+ "version" "5.0.0"
+
+"is-potential-custom-element-name@^1.0.1":
+ "integrity" "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
+ "resolved" "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz"
+ "version" "1.0.1"
+
+"is-regex@^1.0.4", "is-regex@^1.1.4":
+ "integrity" "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg=="
+ "resolved" "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz"
+ "version" "1.1.4"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "has-tostringtag" "^1.0.0"
+
+"is-regexp@^1.0.0":
+ "integrity" "sha1-/S2INUXEa6xaYz57mgnof6LLUGk="
+ "resolved" "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz"
+ "version" "1.0.0"
+
+"is-retry-allowed@^1.0.0":
+ "integrity" "sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg=="
+ "resolved" "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.2.0.tgz"
+ "version" "1.2.0"
+
+"is-scoped@^1.0.0":
+ "integrity" "sha1-RJypgpnnEwOCViieyytUDcQ3yzA="
+ "resolved" "https://registry.npmjs.org/is-scoped/-/is-scoped-1.0.0.tgz"
+ "version" "1.0.0"
+ dependencies:
+ "scoped-regex" "^1.0.0"
+
+"is-shared-array-buffer@^1.0.1":
+ "integrity" "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA=="
+ "resolved" "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz"
+ "version" "1.0.1"
+
+"is-stream@^1.0.0":
+ "integrity" "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+ "resolved" "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz"
+ "version" "1.1.0"
+
+"is-stream@^1.0.1":
+ "integrity" "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
+ "resolved" "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz"
+ "version" "1.1.0"
+
+"is-stream@^2.0.0":
+ "integrity" "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg=="
+ "resolved" "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz"
+ "version" "2.0.1"
+
+"is-string@^1.0.5", "is-string@^1.0.7":
+ "integrity" "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg=="
+ "resolved" "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz"
+ "version" "1.0.7"
+ dependencies:
+ "has-tostringtag" "^1.0.0"
+
+"is-symbol@^1.0.2", "is-symbol@^1.0.3":
+ "integrity" "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg=="
+ "resolved" "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz"
+ "version" "1.0.4"
+ dependencies:
+ "has-symbols" "^1.0.2"
+
+"is-typedarray@^1.0.0", "is-typedarray@~1.0.0":
+ "integrity" "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
+ "resolved" "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
+ "version" "1.0.0"
+
+"is-utf8@^0.2.0", "is-utf8@^0.2.1":
+ "integrity" "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
+ "resolved" "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz"
+ "version" "0.2.1"
+
+"is-weakref@^1.0.1":
+ "integrity" "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ=="
+ "resolved" "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "call-bind" "^1.0.2"
+
+"is-wsl@^1.1.0":
+ "integrity" "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0="
+ "resolved" "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz"
+ "version" "1.1.0"
+
+"is-wsl@^2.2.0":
+ "integrity" "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww=="
+ "resolved" "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz"
+ "version" "2.2.0"
+ dependencies:
+ "is-docker" "^2.0.0"
+
+"isarray@~1.0.0":
+ "integrity" "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
+ "resolved" "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+ "version" "1.0.0"
+
+"isarray@0.0.1":
+ "integrity" "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
+ "resolved" "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+ "version" "0.0.1"
+
+"isarray@2.0.1":
+ "integrity" "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4="
+ "resolved" "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz"
+ "version" "2.0.1"
+
+"isexe@^2.0.0":
+ "integrity" "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
+ "resolved" "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz"
+ "version" "2.0.0"
+
+"isobject@^3.0.1":
+ "integrity" "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
+ "resolved" "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz"
+ "version" "3.0.1"
+
+"isstream@~0.1.2", "isstream@0.1.x":
+ "integrity" "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
+ "resolved" "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+ "version" "0.1.2"
+
+"istanbul-lib-coverage@^3.0.0", "istanbul-lib-coverage@^3.2.0":
+ "integrity" "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw=="
+ "resolved" "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz"
+ "version" "3.2.0"
+
+"istanbul-lib-instrument@^5.0.4", "istanbul-lib-instrument@^5.1.0":
+ "integrity" "sha512-czwUz525rkOFDJxfKK6mYfIs9zBKILyrZQxjz3ABhjQXhbhFsSbo1HW/BFcsDnfJYJWA6thRR5/TUY2qs5W99Q=="
+ "resolved" "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.1.0.tgz"
+ "version" "5.1.0"
+ dependencies:
+ "@babel/core" "^7.12.3"
+ "@babel/parser" "^7.14.7"
+ "@istanbuljs/schema" "^0.1.2"
+ "istanbul-lib-coverage" "^3.2.0"
+ "semver" "^6.3.0"
+
+"istanbul-lib-report@^3.0.0":
+ "integrity" "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw=="
+ "resolved" "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "istanbul-lib-coverage" "^3.0.0"
+ "make-dir" "^3.0.0"
+ "supports-color" "^7.1.0"
+
+"istanbul-lib-source-maps@^4.0.0":
+ "integrity" "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw=="
+ "resolved" "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz"
+ "version" "4.0.1"
+ dependencies:
+ "debug" "^4.1.1"
+ "istanbul-lib-coverage" "^3.0.0"
+ "source-map" "^0.6.1"
+
+"istanbul-reports@^3.1.3":
+ "integrity" "sha512-x9LtDVtfm/t1GFiLl3NffC7hz+I1ragvgX1P/Lg1NlIagifZDKUkuuaAxH/qpwj2IuEfD8G2Bs/UKp+sZ/pKkg=="
+ "resolved" "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.3.tgz"
+ "version" "3.1.3"
+ dependencies:
+ "html-escaper" "^2.0.0"
+ "istanbul-lib-report" "^3.0.0"
+
+"istanbul@0.x.x":
+ "integrity" "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs="
+ "resolved" "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz"
+ "version" "0.4.5"
+ dependencies:
+ "abbrev" "1.0.x"
+ "async" "1.x"
+ "escodegen" "1.8.x"
+ "esprima" "2.7.x"
+ "glob" "^5.0.15"
+ "handlebars" "^4.0.1"
+ "js-yaml" "3.x"
+ "mkdirp" "0.5.x"
+ "nopt" "3.x"
+ "once" "1.x"
+ "resolve" "1.1.x"
+ "supports-color" "^3.1.0"
+ "which" "^1.1.1"
+ "wordwrap" "^1.0.0"
+
+"istextorbinary@^2.1.0":
+ "integrity" "sha512-+XRlFseT8B3L9KyjxxLjfXSLMuErKDsd8DBNrsaxoViABMEZlOSCstwmw0qpoFX3+U6yWU1yhLudAe6/lETGGA=="
+ "resolved" "https://registry.npmjs.org/istextorbinary/-/istextorbinary-2.6.0.tgz"
+ "version" "2.6.0"
+ dependencies:
+ "binaryextensions" "^2.1.2"
+ "editions" "^2.2.0"
+ "textextensions" "^2.5.0"
+
+"isurl@^1.0.0-alpha5":
+ "integrity" "sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w=="
+ "resolved" "https://registry.npmjs.org/isurl/-/isurl-1.0.0.tgz"
+ "version" "1.0.0"
+ dependencies:
+ "has-to-string-tag-x" "^1.2.0"
+ "is-object" "^1.0.1"
+
+"jake@^10.6.1":
+ "integrity" "sha512-eLpKyrfG3mzvGE2Du8VoPbeSkRry093+tyNjdYaBbJS9v17knImYGNXQCUV0gLxQtF82m3E8iRb/wdSQZLoq7A=="
+ "resolved" "https://registry.npmjs.org/jake/-/jake-10.8.2.tgz"
+ "version" "10.8.2"
+ dependencies:
+ "async" "0.9.x"
+ "chalk" "^2.4.2"
+ "filelist" "^1.0.1"
+ "minimatch" "^3.0.4"
+
+"java-parser@2.0.0":
+ "integrity" "sha512-5sTEggUlp+uns7tfHGwRTN+cMlgPHw00oNjAz6YdwEyQyWQ9VzUNbYuPuDyJDWfcFyZTlHKD5f7VbtChKZf4xw=="
+ "resolved" "https://registry.npmjs.org/java-parser/-/java-parser-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "chevrotain" "6.5.0"
+ "lodash" "4.17.21"
+
+"jest-changed-files@^27.4.2":
+ "integrity" "sha512-/9x8MjekuzUQoPjDHbBiXbNEBauhrPU2ct7m8TfCg69ywt1y/N+yYwGh3gCpnqUS3klYWDU/lSNgv+JhoD2k1A=="
+ "resolved" "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-27.4.2.tgz"
+ "version" "27.4.2"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "execa" "^5.0.0"
+ "throat" "^6.0.1"
+
+"jest-circus@^27.4.6":
+ "integrity" "sha512-UA7AI5HZrW4wRM72Ro80uRR2Fg+7nR0GESbSI/2M+ambbzVuA63mn5T1p3Z/wlhntzGpIG1xx78GP2YIkf6PhQ=="
+ "resolved" "https://registry.npmjs.org/jest-circus/-/jest-circus-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/environment" "^27.4.6"
+ "@jest/test-result" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "chalk" "^4.0.0"
+ "co" "^4.6.0"
+ "dedent" "^0.7.0"
+ "expect" "^27.4.6"
+ "is-generator-fn" "^2.0.0"
+ "jest-each" "^27.4.6"
+ "jest-matcher-utils" "^27.4.6"
+ "jest-message-util" "^27.4.6"
+ "jest-runtime" "^27.4.6"
+ "jest-snapshot" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "pretty-format" "^27.4.6"
+ "slash" "^3.0.0"
+ "stack-utils" "^2.0.3"
+ "throat" "^6.0.1"
+
+"jest-cli@^27.4.5":
+ "integrity" "sha512-zREYhvjjqe1KsGV15mdnxjThKNDgza1fhDT+iUsXWLCq3sxe9w5xnvyctcYVT5PcdLSjv7Y5dCwTS3FCF1tiuw=="
+ "resolved" "https://registry.npmjs.org/jest-cli/-/jest-cli-27.4.7.tgz"
+ "version" "27.4.7"
+ dependencies:
+ "@jest/core" "^27.4.7"
+ "@jest/test-result" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "chalk" "^4.0.0"
+ "exit" "^0.1.2"
+ "graceful-fs" "^4.2.4"
+ "import-local" "^3.0.2"
+ "jest-config" "^27.4.7"
+ "jest-util" "^27.4.2"
+ "jest-validate" "^27.4.6"
+ "prompts" "^2.0.1"
+ "yargs" "^16.2.0"
+
+"jest-config@^27.4.7":
+ "integrity" "sha512-xz/o/KJJEedHMrIY9v2ParIoYSrSVY6IVeE4z5Z3i101GoA5XgfbJz+1C8EYPsv7u7f39dS8F9v46BHDhn0vlw=="
+ "resolved" "https://registry.npmjs.org/jest-config/-/jest-config-27.4.7.tgz"
+ "version" "27.4.7"
+ dependencies:
+ "@babel/core" "^7.8.0"
+ "@jest/test-sequencer" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "babel-jest" "^27.4.6"
+ "chalk" "^4.0.0"
+ "ci-info" "^3.2.0"
+ "deepmerge" "^4.2.2"
+ "glob" "^7.1.1"
+ "graceful-fs" "^4.2.4"
+ "jest-circus" "^27.4.6"
+ "jest-environment-jsdom" "^27.4.6"
+ "jest-environment-node" "^27.4.6"
+ "jest-get-type" "^27.4.0"
+ "jest-jasmine2" "^27.4.6"
+ "jest-regex-util" "^27.4.0"
+ "jest-resolve" "^27.4.6"
+ "jest-runner" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "jest-validate" "^27.4.6"
+ "micromatch" "^4.0.4"
+ "pretty-format" "^27.4.6"
+ "slash" "^3.0.0"
+
+"jest-diff@^27.0.0", "jest-diff@^27.4.6":
+ "integrity" "sha512-zjaB0sh0Lb13VyPsd92V7HkqF6yKRH9vm33rwBt7rPYrpQvS1nCvlIy2pICbKta+ZjWngYLNn4cCK4nyZkjS/w=="
+ "resolved" "https://registry.npmjs.org/jest-diff/-/jest-diff-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "chalk" "^4.0.0"
+ "diff-sequences" "^27.4.0"
+ "jest-get-type" "^27.4.0"
+ "pretty-format" "^27.4.6"
+
+"jest-docblock@^27.4.0":
+ "integrity" "sha512-7TBazUdCKGV7svZ+gh7C8esAnweJoG+SvcF6Cjqj4l17zA2q1cMwx2JObSioubk317H+cjcHgP+7fTs60paulg=="
+ "resolved" "https://registry.npmjs.org/jest-docblock/-/jest-docblock-27.4.0.tgz"
+ "version" "27.4.0"
+ dependencies:
+ "detect-newline" "^3.0.0"
+
+"jest-each@^27.4.6":
+ "integrity" "sha512-n6QDq8y2Hsmn22tRkgAk+z6MCX7MeVlAzxmZDshfS2jLcaBlyhpF3tZSJLR+kXmh23GEvS0ojMR8i6ZeRvpQcA=="
+ "resolved" "https://registry.npmjs.org/jest-each/-/jest-each-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "chalk" "^4.0.0"
+ "jest-get-type" "^27.4.0"
+ "jest-util" "^27.4.2"
+ "pretty-format" "^27.4.6"
+
+"jest-environment-jsdom@^27.4.6":
+ "integrity" "sha512-o3dx5p/kHPbUlRvSNjypEcEtgs6LmvESMzgRFQE6c+Prwl2JLA4RZ7qAnxc5VM8kutsGRTB15jXeeSbJsKN9iA=="
+ "resolved" "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/environment" "^27.4.6"
+ "@jest/fake-timers" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "jest-mock" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "jsdom" "^16.6.0"
+
+"jest-environment-node@^27.4.6":
+ "integrity" "sha512-yfHlZ9m+kzTKZV0hVfhVu6GuDxKAYeFHrfulmy7Jxwsq4V7+ZK7f+c0XP/tbVDMQW7E4neG2u147hFkuVz0MlQ=="
+ "resolved" "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/environment" "^27.4.6"
+ "@jest/fake-timers" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "jest-mock" "^27.4.6"
+ "jest-util" "^27.4.2"
+
+"jest-get-type@^27.4.0":
+ "integrity" "sha512-tk9o+ld5TWq41DkK14L4wox4s2D9MtTpKaAVzXfr5CUKm5ZK2ExcaFE0qls2W71zE/6R2TxxrK9w2r6svAFDBQ=="
+ "resolved" "https://registry.npmjs.org/jest-get-type/-/jest-get-type-27.4.0.tgz"
+ "version" "27.4.0"
+
+"jest-haste-map@^27.4.6":
+ "integrity" "sha512-0tNpgxg7BKurZeFkIOvGCkbmOHbLFf4LUQOxrQSMjvrQaQe3l6E8x6jYC1NuWkGo5WDdbr8FEzUxV2+LWNawKQ=="
+ "resolved" "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "@types/graceful-fs" "^4.1.2"
+ "@types/node" "*"
+ "anymatch" "^3.0.3"
+ "fb-watchman" "^2.0.0"
+ "graceful-fs" "^4.2.4"
+ "jest-regex-util" "^27.4.0"
+ "jest-serializer" "^27.4.0"
+ "jest-util" "^27.4.2"
+ "jest-worker" "^27.4.6"
+ "micromatch" "^4.0.4"
+ "walker" "^1.0.7"
+ optionalDependencies:
+ "fsevents" "^2.3.2"
+
+"jest-jasmine2@^27.4.6":
+ "integrity" "sha512-uAGNXF644I/whzhsf7/qf74gqy9OuhvJ0XYp8SDecX2ooGeaPnmJMjXjKt0mqh1Rl5dtRGxJgNrHlBQIBfS5Nw=="
+ "resolved" "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/environment" "^27.4.6"
+ "@jest/source-map" "^27.4.0"
+ "@jest/test-result" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "chalk" "^4.0.0"
+ "co" "^4.6.0"
+ "expect" "^27.4.6"
+ "is-generator-fn" "^2.0.0"
+ "jest-each" "^27.4.6"
+ "jest-matcher-utils" "^27.4.6"
+ "jest-message-util" "^27.4.6"
+ "jest-runtime" "^27.4.6"
+ "jest-snapshot" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "pretty-format" "^27.4.6"
+ "throat" "^6.0.1"
+
+"jest-junit@13.0.0":
+ "integrity" "sha512-JSHR+Dhb32FGJaiKkqsB7AR3OqWKtldLd6ZH2+FJ8D4tsweb8Id8zEVReU4+OlrRO1ZluqJLQEETm+Q6/KilBg=="
+ "resolved" "https://registry.npmjs.org/jest-junit/-/jest-junit-13.0.0.tgz"
+ "version" "13.0.0"
+ dependencies:
+ "mkdirp" "^1.0.4"
+ "strip-ansi" "^6.0.1"
+ "uuid" "^8.3.2"
+ "xml" "^1.0.1"
+
+"jest-leak-detector@^27.4.6":
+ "integrity" "sha512-kkaGixDf9R7CjHm2pOzfTxZTQQQ2gHTIWKY/JZSiYTc90bZp8kSZnUMS3uLAfwTZwc0tcMRoEX74e14LG1WapA=="
+ "resolved" "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "jest-get-type" "^27.4.0"
+ "pretty-format" "^27.4.6"
+
+"jest-matcher-utils@^27.4.6":
+ "integrity" "sha512-XD4PKT3Wn1LQnRAq7ZsTI0VRuEc9OrCPFiO1XL7bftTGmfNF0DcEwMHRgqiu7NGf8ZoZDREpGrCniDkjt79WbA=="
+ "resolved" "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "chalk" "^4.0.0"
+ "jest-diff" "^27.4.6"
+ "jest-get-type" "^27.4.0"
+ "pretty-format" "^27.4.6"
+
+"jest-message-util@^27.4.6":
+ "integrity" "sha512-0p5szriFU0U74czRSFjH6RyS7UYIAkn/ntwMuOwTGWrQIOh5NzXXrq72LOqIkJKKvFbPq+byZKuBz78fjBERBA=="
+ "resolved" "https://registry.npmjs.org/jest-message-util/-/jest-message-util-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@babel/code-frame" "^7.12.13"
+ "@jest/types" "^27.4.2"
+ "@types/stack-utils" "^2.0.0"
+ "chalk" "^4.0.0"
+ "graceful-fs" "^4.2.4"
+ "micromatch" "^4.0.4"
+ "pretty-format" "^27.4.6"
+ "slash" "^3.0.0"
+ "stack-utils" "^2.0.3"
+
+"jest-mock@^27.4.6":
+ "integrity" "sha512-kvojdYRkst8iVSZ1EJ+vc1RRD9llueBjKzXzeCytH3dMM7zvPV/ULcfI2nr0v0VUgm3Bjt3hBCQvOeaBz+ZTHw=="
+ "resolved" "https://registry.npmjs.org/jest-mock/-/jest-mock-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+
+"jest-pnp-resolver@^1.2.2":
+ "integrity" "sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w=="
+ "resolved" "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz"
+ "version" "1.2.2"
+
+"jest-regex-util@^27.4.0":
+ "integrity" "sha512-WeCpMpNnqJYMQoOjm1nTtsgbR4XHAk1u00qDoNBQoykM280+/TmgA5Qh5giC1ecy6a5d4hbSsHzpBtu5yvlbEg=="
+ "resolved" "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-27.4.0.tgz"
+ "version" "27.4.0"
+
+"jest-resolve-dependencies@^27.4.6":
+ "integrity" "sha512-W85uJZcFXEVZ7+MZqIPCscdjuctruNGXUZ3OHSXOfXR9ITgbUKeHj+uGcies+0SsvI5GtUfTw4dY7u9qjTvQOw=="
+ "resolved" "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "jest-regex-util" "^27.4.0"
+ "jest-snapshot" "^27.4.6"
+
+"jest-resolve@*", "jest-resolve@^27.4.6":
+ "integrity" "sha512-SFfITVApqtirbITKFAO7jOVN45UgFzcRdQanOFzjnbd+CACDoyeX7206JyU92l4cRr73+Qy/TlW51+4vHGt+zw=="
+ "resolved" "https://registry.npmjs.org/jest-resolve/-/jest-resolve-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "chalk" "^4.0.0"
+ "graceful-fs" "^4.2.4"
+ "jest-haste-map" "^27.4.6"
+ "jest-pnp-resolver" "^1.2.2"
+ "jest-util" "^27.4.2"
+ "jest-validate" "^27.4.6"
+ "resolve" "^1.20.0"
+ "resolve.exports" "^1.1.0"
+ "slash" "^3.0.0"
+
+"jest-runner@^27.4.6":
+ "integrity" "sha512-IDeFt2SG4DzqalYBZRgbbPmpwV3X0DcntjezPBERvnhwKGWTW7C5pbbA5lVkmvgteeNfdd/23gwqv3aiilpYPg=="
+ "resolved" "https://registry.npmjs.org/jest-runner/-/jest-runner-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/console" "^27.4.6"
+ "@jest/environment" "^27.4.6"
+ "@jest/test-result" "^27.4.6"
+ "@jest/transform" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "chalk" "^4.0.0"
+ "emittery" "^0.8.1"
+ "exit" "^0.1.2"
+ "graceful-fs" "^4.2.4"
+ "jest-docblock" "^27.4.0"
+ "jest-environment-jsdom" "^27.4.6"
+ "jest-environment-node" "^27.4.6"
+ "jest-haste-map" "^27.4.6"
+ "jest-leak-detector" "^27.4.6"
+ "jest-message-util" "^27.4.6"
+ "jest-resolve" "^27.4.6"
+ "jest-runtime" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "jest-worker" "^27.4.6"
+ "source-map-support" "^0.5.6"
+ "throat" "^6.0.1"
+
+"jest-runtime@^27.4.6":
+ "integrity" "sha512-eXYeoR/MbIpVDrjqy5d6cGCFOYBFFDeKaNWqTp0h6E74dK0zLHzASQXJpl5a2/40euBmKnprNLJ0Kh0LCndnWQ=="
+ "resolved" "https://registry.npmjs.org/jest-runtime/-/jest-runtime-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/environment" "^27.4.6"
+ "@jest/fake-timers" "^27.4.6"
+ "@jest/globals" "^27.4.6"
+ "@jest/source-map" "^27.4.0"
+ "@jest/test-result" "^27.4.6"
+ "@jest/transform" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "chalk" "^4.0.0"
+ "cjs-module-lexer" "^1.0.0"
+ "collect-v8-coverage" "^1.0.0"
+ "execa" "^5.0.0"
+ "glob" "^7.1.3"
+ "graceful-fs" "^4.2.4"
+ "jest-haste-map" "^27.4.6"
+ "jest-message-util" "^27.4.6"
+ "jest-mock" "^27.4.6"
+ "jest-regex-util" "^27.4.0"
+ "jest-resolve" "^27.4.6"
+ "jest-snapshot" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "slash" "^3.0.0"
+ "strip-bom" "^4.0.0"
+
+"jest-serializer@^27.4.0":
+ "integrity" "sha512-RDhpcn5f1JYTX2pvJAGDcnsNTnsV9bjYPU8xcV+xPwOXnUPOQwf4ZEuiU6G9H1UztH+OapMgu/ckEVwO87PwnQ=="
+ "resolved" "https://registry.npmjs.org/jest-serializer/-/jest-serializer-27.4.0.tgz"
+ "version" "27.4.0"
+ dependencies:
+ "@types/node" "*"
+ "graceful-fs" "^4.2.4"
+
+"jest-snapshot@^27.4.6":
+ "integrity" "sha512-fafUCDLQfzuNP9IRcEqaFAMzEe7u5BF7mude51wyWv7VRex60WznZIC7DfKTgSIlJa8aFzYmXclmN328aqSDmQ=="
+ "resolved" "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@babel/core" "^7.7.2"
+ "@babel/generator" "^7.7.2"
+ "@babel/plugin-syntax-typescript" "^7.7.2"
+ "@babel/traverse" "^7.7.2"
+ "@babel/types" "^7.0.0"
+ "@jest/transform" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/babel__traverse" "^7.0.4"
+ "@types/prettier" "^2.1.5"
+ "babel-preset-current-node-syntax" "^1.0.0"
+ "chalk" "^4.0.0"
+ "expect" "^27.4.6"
+ "graceful-fs" "^4.2.4"
+ "jest-diff" "^27.4.6"
+ "jest-get-type" "^27.4.0"
+ "jest-haste-map" "^27.4.6"
+ "jest-matcher-utils" "^27.4.6"
+ "jest-message-util" "^27.4.6"
+ "jest-util" "^27.4.2"
+ "natural-compare" "^1.4.0"
+ "pretty-format" "^27.4.6"
+ "semver" "^7.3.2"
+
+"jest-sonar-reporter@2.0.0":
+ "integrity" "sha512-ZervDCgEX5gdUbdtWsjdipLN3bKJwpxbvhkYNXTAYvAckCihobSLr9OT/IuyNIRT1EZMDDwR6DroWtrq+IL64w=="
+ "resolved" "https://registry.npmjs.org/jest-sonar-reporter/-/jest-sonar-reporter-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "xml" "^1.0.1"
+
+"jest-util@^27.0.0", "jest-util@^27.4.2":
+ "integrity" "sha512-YuxxpXU6nlMan9qyLuxHaMMOzXAl5aGZWCSzben5DhLHemYQxCc4YK+4L3ZrCutT8GPQ+ui9k5D8rUJoDioMnA=="
+ "resolved" "https://registry.npmjs.org/jest-util/-/jest-util-27.4.2.tgz"
+ "version" "27.4.2"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "chalk" "^4.0.0"
+ "ci-info" "^3.2.0"
+ "graceful-fs" "^4.2.4"
+ "picomatch" "^2.2.3"
+
+"jest-validate@^27.4.6":
+ "integrity" "sha512-872mEmCPVlBqbA5dToC57vA3yJaMRfIdpCoD3cyHWJOMx+SJwLNw0I71EkWs41oza/Er9Zno9XuTkRYCPDUJXQ=="
+ "resolved" "https://registry.npmjs.org/jest-validate/-/jest-validate-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/types" "^27.4.2"
+ "camelcase" "^6.2.0"
+ "chalk" "^4.0.0"
+ "jest-get-type" "^27.4.0"
+ "leven" "^3.1.0"
+ "pretty-format" "^27.4.6"
+
+"jest-watcher@^27.4.6":
+ "integrity" "sha512-yKQ20OMBiCDigbD0quhQKLkBO+ObGN79MO4nT7YaCuQ5SM+dkBNWE8cZX0FjU6czwMvWw6StWbe+Wv4jJPJ+fw=="
+ "resolved" "https://registry.npmjs.org/jest-watcher/-/jest-watcher-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@jest/test-result" "^27.4.6"
+ "@jest/types" "^27.4.2"
+ "@types/node" "*"
+ "ansi-escapes" "^4.2.1"
+ "chalk" "^4.0.0"
+ "jest-util" "^27.4.2"
+ "string-length" "^4.0.1"
+
+"jest-worker@^26.2.1":
+ "integrity" "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ=="
+ "resolved" "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz"
+ "version" "26.6.2"
+ dependencies:
+ "@types/node" "*"
+ "merge-stream" "^2.0.0"
+ "supports-color" "^7.0.0"
+
+"jest-worker@^27.0.2", "jest-worker@^27.3.1", "jest-worker@^27.4.1", "jest-worker@^27.4.6":
+ "integrity" "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw=="
+ "resolved" "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "@types/node" "*"
+ "merge-stream" "^2.0.0"
+ "supports-color" "^8.0.0"
+
+"jest@^27.0.0", "jest@27.4.5":
+ "integrity" "sha512-uT5MiVN3Jppt314kidCk47MYIRilJjA/l2mxwiuzzxGUeJIvA8/pDaJOAX5KWvjAo7SCydcW0/4WEtgbLMiJkg=="
+ "resolved" "https://registry.npmjs.org/jest/-/jest-27.4.5.tgz"
+ "version" "27.4.5"
+ dependencies:
+ "@jest/core" "^27.4.5"
+ "import-local" "^3.0.2"
+ "jest-cli" "^27.4.5"
+
+"jhipster-core@1.4.4":
+ "integrity" "sha512-5cbUGesqTgM+adJqTE5QYNSc9Zo/97zYaDIcMgiGFkvf4Ke4H4F3+k0BuPxwSpFarQp5xyczyrmSOvBXXcB4ww=="
+ "resolved" "https://registry.npmjs.org/jhipster-core/-/jhipster-core-1.4.4.tgz"
+ "version" "1.4.4"
+ dependencies:
+ "lodash" "4.17.4"
+ "winston" "2.4.0"
+
+"joi@^17.4.0":
+ "integrity" "sha512-R7hR50COp7StzLnDi4ywOXHrBrgNXuUUfJWIR5lPY5Bm/pOD3jZaTwpluUXVLRWcoWZxkrHBBJ5hLxgnlehbdw=="
+ "resolved" "https://registry.npmjs.org/joi/-/joi-17.5.0.tgz"
+ "version" "17.5.0"
+ dependencies:
+ "@hapi/hoek" "^9.0.0"
+ "@hapi/topo" "^5.0.0"
+ "@sideway/address" "^4.1.3"
+ "@sideway/formula" "^3.0.0"
+ "@sideway/pinpoint" "^2.0.0"
+
+"js-tokens@^3.0.0 || ^4.0.0", "js-tokens@^4.0.0":
+ "integrity" "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
+ "resolved" "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz"
+ "version" "4.0.0"
+
+"js-yaml@^3.13.1":
+ "integrity" "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="
+ "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz"
+ "version" "3.14.1"
+ dependencies:
+ "argparse" "^1.0.7"
+ "esprima" "^4.0.0"
+
+"js-yaml@^4.1.0":
+ "integrity" "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA=="
+ "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz"
+ "version" "4.1.0"
+ dependencies:
+ "argparse" "^2.0.1"
+
+"js-yaml@3.10.0":
+ "integrity" "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA=="
+ "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz"
+ "version" "3.10.0"
+ dependencies:
+ "argparse" "^1.0.7"
+ "esprima" "^4.0.0"
+
+"js-yaml@3.x":
+ "integrity" "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g=="
+ "resolved" "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz"
+ "version" "3.14.1"
+ dependencies:
+ "argparse" "^1.0.7"
+ "esprima" "^4.0.0"
+
+"jsbn@~0.1.0":
+ "integrity" "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
+ "resolved" "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz"
+ "version" "0.1.1"
+
+"jsdom@^16.6.0":
+ "integrity" "sha512-u9Smc2G1USStM+s/x1ru5Sxrl6mPYCbByG1U/hUmqaVsm4tbNyS7CicOSRyuGQYZhTu0h84qkZZQ/I+dzizSVw=="
+ "resolved" "https://registry.npmjs.org/jsdom/-/jsdom-16.7.0.tgz"
+ "version" "16.7.0"
+ dependencies:
+ "abab" "^2.0.5"
+ "acorn" "^8.2.4"
+ "acorn-globals" "^6.0.0"
+ "cssom" "^0.4.4"
+ "cssstyle" "^2.3.0"
+ "data-urls" "^2.0.0"
+ "decimal.js" "^10.2.1"
+ "domexception" "^2.0.1"
+ "escodegen" "^2.0.0"
+ "form-data" "^3.0.0"
+ "html-encoding-sniffer" "^2.0.1"
+ "http-proxy-agent" "^4.0.1"
+ "https-proxy-agent" "^5.0.0"
+ "is-potential-custom-element-name" "^1.0.1"
+ "nwsapi" "^2.2.0"
+ "parse5" "6.0.1"
+ "saxes" "^5.0.1"
+ "symbol-tree" "^3.2.4"
+ "tough-cookie" "^4.0.0"
+ "w3c-hr-time" "^1.0.2"
+ "w3c-xmlserializer" "^2.0.0"
+ "webidl-conversions" "^6.1.0"
+ "whatwg-encoding" "^1.0.5"
+ "whatwg-mimetype" "^2.3.0"
+ "whatwg-url" "^8.5.0"
+ "ws" "^7.4.6"
+ "xml-name-validator" "^3.0.0"
+
+"jsesc@^2.5.1":
+ "integrity" "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA=="
+ "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz"
+ "version" "2.5.2"
+
+"jsesc@~0.5.0":
+ "integrity" "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0="
+ "resolved" "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz"
+ "version" "0.5.0"
+
+"json-loader@0.5.7":
+ "integrity" "sha512-QLPs8Dj7lnf3e3QYS1zkCo+4ZwqOiF9d/nZnYozTISxXWCfNs9yuky5rJw4/W34s7POaNlbZmQGaB5NiXCbP4w=="
+ "resolved" "https://registry.npmjs.org/json-loader/-/json-loader-0.5.7.tgz"
+ "version" "0.5.7"
+
+"json-parse-better-errors@^1.0.2":
+ "integrity" "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw=="
+ "resolved" "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz"
+ "version" "1.0.2"
+
+"json-parse-even-better-errors@^2.3.0":
+ "integrity" "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w=="
+ "resolved" "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz"
+ "version" "2.3.1"
+
+"json-schema-traverse@^0.4.1":
+ "integrity" "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
+ "resolved" "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz"
+ "version" "0.4.1"
+
+"json-schema-traverse@^1.0.0":
+ "integrity" "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug=="
+ "resolved" "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz"
+ "version" "1.0.0"
+
+"json-schema@^0.4.0", "json-schema@0.4.0":
+ "integrity" "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
+ "resolved" "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz"
+ "version" "0.4.0"
+
+"json-stable-stringify-without-jsonify@^1.0.1":
+ "integrity" "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE="
+ "resolved" "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz"
+ "version" "1.0.1"
+
+"json-stringify-safe@~5.0.1":
+ "integrity" "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
+ "resolved" "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
+ "version" "5.0.1"
+
+"json5@^0.5.0":
+ "integrity" "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE="
+ "resolved" "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz"
+ "version" "0.5.1"
+
+"json5@^2.1.2", "json5@^2.2.0", "json5@2.x":
+ "integrity" "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA=="
+ "resolved" "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz"
+ "version" "2.2.0"
+ dependencies:
+ "minimist" "^1.2.5"
+
+"jsonfile@^3.0.0":
+ "integrity" "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY="
+ "resolved" "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz"
+ "version" "3.0.1"
+ optionalDependencies:
+ "graceful-fs" "^4.1.6"
+
+"jsonfile@^6.0.1":
+ "integrity" "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ=="
+ "resolved" "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz"
+ "version" "6.1.0"
+ dependencies:
+ "universalify" "^2.0.0"
+ optionalDependencies:
+ "graceful-fs" "^4.1.6"
+
+"jsonpointer@^5.0.0":
+ "integrity" "sha512-PNYZIdMjVIvVgDSYKTT63Y+KZ6IZvGRNNWcxwD+GNnUz1MKPfv30J8ueCjdwcN0nDx2SlshgyB7Oy0epAzVRRg=="
+ "resolved" "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.0.tgz"
+ "version" "5.0.0"
+
+"jsprim@^1.2.2":
+ "integrity" "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw=="
+ "resolved" "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz"
+ "version" "1.4.2"
+ dependencies:
+ "assert-plus" "1.0.0"
+ "extsprintf" "1.3.0"
+ "json-schema" "0.4.0"
+ "verror" "1.10.0"
+
+"jsx-ast-utils@^2.4.1 || ^3.0.0":
+ "integrity" "sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA=="
+ "resolved" "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.2.1.tgz"
+ "version" "3.2.1"
+ dependencies:
+ "array-includes" "^3.1.3"
+ "object.assign" "^4.1.2"
+
+"just-extend@^4.0.2":
+ "integrity" "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg=="
+ "resolved" "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz"
+ "version" "4.2.1"
+
+"kind-of@^6.0.2":
+ "integrity" "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
+ "resolved" "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz"
+ "version" "6.0.3"
+
+"kleur@^3.0.3":
+ "integrity" "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w=="
+ "resolved" "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz"
+ "version" "3.0.3"
+
+"klona@^2.0.4", "klona@^2.0.5":
+ "integrity" "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ=="
+ "resolved" "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz"
+ "version" "2.0.5"
+
+"leven@^3.1.0":
+ "integrity" "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A=="
+ "resolved" "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz"
+ "version" "3.1.0"
+
+"levn@^0.4.1":
+ "integrity" "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ=="
+ "resolved" "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz"
+ "version" "0.4.1"
+ dependencies:
+ "prelude-ls" "^1.2.1"
+ "type-check" "~0.4.0"
+
+"levn@~0.3.0":
+ "integrity" "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4="
+ "resolved" "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz"
+ "version" "0.3.0"
+ dependencies:
+ "prelude-ls" "~1.1.2"
+ "type-check" "~0.3.2"
+
+"lilconfig@^2.0.3":
+ "integrity" "sha512-bfTIN7lEsiooCocSISTWXkiWJkRqtL9wYtYy+8EK3Y41qh3mpwPU0ycTOgjdY9ErwXCc8QyrQp82bdL0Xkm9yA=="
+ "resolved" "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.4.tgz"
+ "version" "2.0.4"
+
+"limiter@^1.0.5":
+ "integrity" "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA=="
+ "resolved" "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz"
+ "version" "1.1.5"
+
+"lines-and-columns@^1.1.6":
+ "integrity" "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
+ "resolved" "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz"
+ "version" "1.2.4"
+
+"load-json-file@^1.0.0":
+ "integrity" "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA="
+ "resolved" "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz"
+ "version" "1.1.0"
+ dependencies:
+ "graceful-fs" "^4.1.2"
+ "parse-json" "^2.2.0"
+ "pify" "^2.0.0"
+ "pinkie-promise" "^2.0.0"
+ "strip-bom" "^2.0.0"
+
+"load-json-file@^2.0.0":
+ "integrity" "sha1-eUfkIUmvgNaWy/eXvKq8/h/inKg="
+ "resolved" "https://registry.npmjs.org/load-json-file/-/load-json-file-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "graceful-fs" "^4.1.2"
+ "parse-json" "^2.2.0"
+ "pify" "^2.0.0"
+ "strip-bom" "^3.0.0"
+
+"loader-runner@^4.1.0", "loader-runner@^4.2.0":
+ "integrity" "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw=="
+ "resolved" "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz"
+ "version" "4.2.0"
+
+"loader-utils@^2.0.0":
+ "integrity" "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A=="
+ "resolved" "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz"
+ "version" "2.0.2"
+ dependencies:
+ "big.js" "^5.2.2"
+ "emojis-list" "^3.0.0"
+ "json5" "^2.1.2"
+
+"loader-utils@0.x.x":
+ "integrity" "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g="
+ "resolved" "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz"
+ "version" "0.2.17"
+ dependencies:
+ "big.js" "^3.1.3"
+ "emojis-list" "^2.0.0"
+ "json5" "^0.5.0"
+ "object-assign" "^4.0.1"
+
+"localtunnel@^2.0.1":
+ "integrity" "sha512-n418Cn5ynvJd7m/N1d9WVJISLJF/ellZnfsLnx8WBWGzxv/ntNcFkJ1o6se5quUhCplfLGBNL5tYHiq5WF3Nug=="
+ "resolved" "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.2.tgz"
+ "version" "2.0.2"
+ dependencies:
+ "axios" "0.21.4"
+ "debug" "4.3.2"
+ "openurl" "1.1.1"
+ "yargs" "17.1.1"
+
+"locate-path@^2.0.0":
+ "integrity" "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4="
+ "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "p-locate" "^2.0.0"
+ "path-exists" "^3.0.0"
+
+"locate-path@^5.0.0":
+ "integrity" "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g=="
+ "resolved" "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz"
+ "version" "5.0.0"
+ dependencies:
+ "p-locate" "^4.1.0"
+
+"lodash._getnative@^3.0.0":
+ "integrity" "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U="
+ "resolved" "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz"
+ "version" "3.9.1"
+
+"lodash.assignin@^4.0.9":
+ "integrity" "sha1-uo31+4QesKPoBEIysOJjqNxqKKI="
+ "resolved" "https://registry.npmjs.org/lodash.assignin/-/lodash.assignin-4.2.0.tgz"
+ "version" "4.2.0"
+
+"lodash.bind@^4.1.4":
+ "integrity" "sha1-euMBfpOWIqwxt9fX3LGzTbFpDTU="
+ "resolved" "https://registry.npmjs.org/lodash.bind/-/lodash.bind-4.2.1.tgz"
+ "version" "4.2.1"
+
+"lodash.debounce@^3.0.1":
+ "integrity" "sha1-gSIRw3ipTMKdWqTjNGzwv846ffU="
+ "resolved" "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz"
+ "version" "3.1.1"
+ dependencies:
+ "lodash._getnative" "^3.0.0"
+
+"lodash.debounce@^4.0.8":
+ "integrity" "sha1-gteb/zCmfEAF/9XiUVMArZyk168="
+ "resolved" "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz"
+ "version" "4.0.8"
+
+"lodash.defaults@^4.0.1":
+ "integrity" "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
+ "resolved" "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz"
+ "version" "4.2.0"
+
+"lodash.difference@^4.5.0":
+ "integrity" "sha1-nMtOUF1Ia5FlE0V3KIWi3yf9AXw="
+ "resolved" "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz"
+ "version" "4.5.0"
+
+"lodash.filter@^4.4.0":
+ "integrity" "sha1-ZosdSYFgOuHMWm+nYBQ+SAtMSs4="
+ "resolved" "https://registry.npmjs.org/lodash.filter/-/lodash.filter-4.6.0.tgz"
+ "version" "4.6.0"
+
+"lodash.flatten@^4.2.0":
+ "integrity" "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8="
+ "resolved" "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz"
+ "version" "4.4.0"
+
+"lodash.foreach@^4.3.0":
+ "integrity" "sha1-Gmo16s5AEoDH8G3d7DUWWrJ+PlM="
+ "resolved" "https://registry.npmjs.org/lodash.foreach/-/lodash.foreach-4.5.0.tgz"
+ "version" "4.5.0"
+
+"lodash.get@^4.4.2":
+ "integrity" "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
+ "resolved" "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz"
+ "version" "4.4.2"
+
+"lodash.isfinite@^3.3.2":
+ "integrity" "sha1-+4m2WpqAKBgz8LdHizpRBPiY67M="
+ "resolved" "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz"
+ "version" "3.3.2"
+
+"lodash.isplainobject@^4.0.6":
+ "integrity" "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs="
+ "resolved" "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz"
+ "version" "4.0.6"
+
+"lodash.map@^4.4.0":
+ "integrity" "sha1-dx7Hg540c9nEzeKLGTlMNWL09tM="
+ "resolved" "https://registry.npmjs.org/lodash.map/-/lodash.map-4.6.0.tgz"
+ "version" "4.6.0"
+
+"lodash.memoize@^4.1.2", "lodash.memoize@4.x":
+ "integrity" "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
+ "resolved" "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz"
+ "version" "4.1.2"
+
+"lodash.merge@^4.4.0", "lodash.merge@^4.6.2":
+ "integrity" "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
+ "resolved" "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz"
+ "version" "4.6.2"
+
+"lodash.pad@^4.1.0":
+ "integrity" "sha1-QzCUmoM6fI2iLMIPaibE1Z3runA="
+ "resolved" "https://registry.npmjs.org/lodash.pad/-/lodash.pad-4.5.1.tgz"
+ "version" "4.5.1"
+
+"lodash.padend@^4.1.0":
+ "integrity" "sha1-U8y6BH0G4VjTEfRdpiX05J5vFm4="
+ "resolved" "https://registry.npmjs.org/lodash.padend/-/lodash.padend-4.6.1.tgz"
+ "version" "4.6.1"
+
+"lodash.padstart@^4.1.0":
+ "integrity" "sha1-0uPuv/DZ05rVD1y9G1KnvOa7YRs="
+ "resolved" "https://registry.npmjs.org/lodash.padstart/-/lodash.padstart-4.6.1.tgz"
+ "version" "4.6.1"
+
+"lodash.pick@^4.2.1":
+ "integrity" "sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM="
+ "resolved" "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz"
+ "version" "4.4.0"
+
+"lodash.reduce@^4.4.0":
+ "integrity" "sha1-8atrg5KZrUj3hKu/R2WW8DuRTTs="
+ "resolved" "https://registry.npmjs.org/lodash.reduce/-/lodash.reduce-4.6.0.tgz"
+ "version" "4.6.0"
+
+"lodash.reject@^4.4.0":
+ "integrity" "sha1-gNZJLcFHCGS79YNTO2UfQqn1JBU="
+ "resolved" "https://registry.npmjs.org/lodash.reject/-/lodash.reject-4.6.0.tgz"
+ "version" "4.6.0"
+
+"lodash.some@^4.4.0":
+ "integrity" "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0="
+ "resolved" "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz"
+ "version" "4.6.0"
+
+"lodash.sortby@^4.7.0":
+ "integrity" "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg="
+ "resolved" "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz"
+ "version" "4.7.0"
+
+"lodash.uniq@^4.5.0":
+ "integrity" "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M="
+ "resolved" "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz"
+ "version" "4.5.0"
+
+"lodash@^3.2.0":
+ "integrity" "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
+ "resolved" "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
+ "version" "3.10.1"
+
+"lodash@^3.3.1":
+ "integrity" "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y="
+ "resolved" "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
+ "version" "3.10.1"
+
+"lodash@^4", "lodash@^4.11.1", "lodash@^4.17.10", "lodash@^4.17.14", "lodash@^4.17.2", "lodash@^4.17.20", "lodash@^4.17.21", "lodash@^4.17.4", "lodash@^4.3.0", "lodash@^4.7.0", "lodash@4.17.21":
+ "integrity" "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+ "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz"
+ "version" "4.17.21"
+
+"lodash@4.17.4":
+ "integrity" "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
+ "resolved" "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+ "version" "4.17.4"
+
+"log-symbols@^2.1.0":
+ "integrity" "sha512-VeIAFslyIerEJLXHziedo2basKbMKtTw3vfn5IzG0XTjhAVEJyNHnL2p7vc+wBDSdQuUpNw3M2u6xb9QsAY5Eg=="
+ "resolved" "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz"
+ "version" "2.2.0"
+ dependencies:
+ "chalk" "^2.0.1"
+
+"log-update@4.0.x":
+ "integrity" "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg=="
+ "resolved" "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "ansi-escapes" "^4.3.0"
+ "cli-cursor" "^3.1.0"
+ "slice-ansi" "^4.0.0"
+ "wrap-ansi" "^6.2.0"
+
+"loose-envify@^1.0.0", "loose-envify@^1.1.0", "loose-envify@^1.2.0", "loose-envify@^1.3.1", "loose-envify@^1.4.0":
+ "integrity" "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q=="
+ "resolved" "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz"
+ "version" "1.4.0"
+ dependencies:
+ "js-tokens" "^3.0.0 || ^4.0.0"
+
+"loud-rejection@^1.0.0":
+ "integrity" "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8="
+ "resolved" "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz"
+ "version" "1.6.0"
+ dependencies:
+ "currently-unhandled" "^0.4.1"
+ "signal-exit" "^3.0.0"
+
+"lower-case@^2.0.2":
+ "integrity" "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg=="
+ "resolved" "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz"
+ "version" "2.0.2"
+ dependencies:
+ "tslib" "^2.0.3"
+
+"lowercase-keys@^1.0.0":
+ "integrity" "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA=="
+ "resolved" "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz"
+ "version" "1.0.1"
+
+"lru-cache@^4.0.1":
+ "integrity" "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g=="
+ "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz"
+ "version" "4.1.5"
+ dependencies:
+ "pseudomap" "^1.0.2"
+ "yallist" "^2.1.2"
+
+"lru-cache@^6.0.0":
+ "integrity" "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA=="
+ "resolved" "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz"
+ "version" "6.0.0"
+ dependencies:
+ "yallist" "^4.0.0"
+
+"lz-string@^1.4.4":
+ "integrity" "sha1-wNjq82BZ9wV5bh40SBHPTEmNOiY="
+ "resolved" "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz"
+ "version" "1.4.4"
+
+"magic-string@^0.25.0", "magic-string@^0.25.7":
+ "integrity" "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA=="
+ "resolved" "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz"
+ "version" "0.25.7"
+ dependencies:
+ "sourcemap-codec" "^1.4.4"
+
+"make-dir@^1.0.0":
+ "integrity" "sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ=="
+ "resolved" "https://registry.npmjs.org/make-dir/-/make-dir-1.3.0.tgz"
+ "version" "1.3.0"
+ dependencies:
+ "pify" "^3.0.0"
+
+"make-dir@^3.0.0":
+ "integrity" "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw=="
+ "resolved" "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz"
+ "version" "3.1.0"
+ dependencies:
+ "semver" "^6.0.0"
+
+"make-error@1.x":
+ "integrity" "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw=="
+ "resolved" "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz"
+ "version" "1.3.6"
+
+"makeerror@1.0.12":
+ "integrity" "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg=="
+ "resolved" "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz"
+ "version" "1.0.12"
+ dependencies:
+ "tmpl" "1.0.5"
+
+"map-obj@^1.0.0", "map-obj@^1.0.1":
+ "integrity" "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="
+ "resolved" "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
+ "version" "1.0.1"
+
+"mdn-data@2.0.14":
+ "integrity" "sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow=="
+ "resolved" "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz"
+ "version" "2.0.14"
+
+"media-typer@0.3.0":
+ "integrity" "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+ "resolved" "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
+ "version" "0.3.0"
+
+"mem-fs-editor@^3.0.0":
+ "integrity" "sha1-3Qpuryu4prN3QAZ6pUnrUwEFr58="
+ "resolved" "https://registry.npmjs.org/mem-fs-editor/-/mem-fs-editor-3.0.2.tgz"
+ "version" "3.0.2"
+ dependencies:
+ "commondir" "^1.0.1"
+ "deep-extend" "^0.4.0"
+ "ejs" "^2.3.1"
+ "glob" "^7.0.3"
+ "globby" "^6.1.0"
+ "mkdirp" "^0.5.0"
+ "multimatch" "^2.0.0"
+ "rimraf" "^2.2.8"
+ "through2" "^2.0.0"
+ "vinyl" "^2.0.1"
+
+"mem-fs@^1.1.0":
+ "integrity" "sha512-b8g0jWKdl8pM0LqAPdK9i8ERL7nYrzmJfRhxMiWH2uYdfYnb7uXnmwVb0ZGe7xyEl4lj+nLIU3yf4zPUT+XsVQ=="
+ "resolved" "https://registry.npmjs.org/mem-fs/-/mem-fs-1.2.0.tgz"
+ "version" "1.2.0"
+ dependencies:
+ "through2" "^3.0.0"
+ "vinyl" "^2.0.1"
+ "vinyl-file" "^3.0.0"
+
+"memfs@^3.1.2", "memfs@^3.2.2":
+ "integrity" "sha512-1c9VPVvW5P7I85c35zAdEr1TD5+F11IToIHIlrVIcflfnzPkJa0ZoYEoEdYDP8KgPFoSZ/opDrUsAoZWym3mtw=="
+ "resolved" "https://registry.npmjs.org/memfs/-/memfs-3.4.1.tgz"
+ "version" "3.4.1"
+ dependencies:
+ "fs-monkey" "1.0.3"
+
+"meow@3.7.0":
+ "integrity" "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs="
+ "resolved" "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz"
+ "version" "3.7.0"
+ dependencies:
+ "camelcase-keys" "^2.0.0"
+ "decamelize" "^1.1.2"
+ "loud-rejection" "^1.0.0"
+ "map-obj" "^1.0.1"
+ "minimist" "^1.1.3"
+ "normalize-package-data" "^2.3.4"
+ "object-assign" "^4.0.1"
+ "read-pkg-up" "^1.0.1"
+ "redent" "^1.0.0"
+ "trim-newlines" "^1.0.0"
+
+"merge-descriptors@1.0.1":
+ "integrity" "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+ "resolved" "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz"
+ "version" "1.0.1"
+
+"merge-jsons-webpack-plugin@2.0.1":
+ "integrity" "sha512-8GP8rpOX3HSFsm7Gx+b3OAQR7yhgeAQvMqcZOJ+/cQIrqdak1c42a2T2vyeee8pzGPBf7pMLumthPh4CHgv2BA=="
+ "resolved" "https://registry.npmjs.org/merge-jsons-webpack-plugin/-/merge-jsons-webpack-plugin-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "glob" "7.1.1"
+
+"merge-stream@^2.0.0":
+ "integrity" "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
+ "resolved" "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz"
+ "version" "2.0.0"
+
+"merge2@^1.2.3", "merge2@^1.3.0", "merge2@^1.4.1":
+ "integrity" "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg=="
+ "resolved" "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz"
+ "version" "1.4.1"
+
+"methods@~1.1.2":
+ "integrity" "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+ "resolved" "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz"
+ "version" "1.1.2"
+
+"micromatch@^4.0.0", "micromatch@^4.0.2", "micromatch@^4.0.4":
+ "integrity" "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg=="
+ "resolved" "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz"
+ "version" "4.0.4"
+ dependencies:
+ "braces" "^3.0.1"
+ "picomatch" "^2.2.3"
+
+"mime-db@>= 1.43.0 < 2", "mime-db@1.51.0":
+ "integrity" "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g=="
+ "resolved" "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz"
+ "version" "1.51.0"
+
+"mime-types@^2.1.12", "mime-types@^2.1.27", "mime-types@^2.1.31", "mime-types@~2.1.17", "mime-types@~2.1.19", "mime-types@~2.1.24":
+ "integrity" "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A=="
+ "resolved" "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz"
+ "version" "2.1.34"
+ dependencies:
+ "mime-db" "1.51.0"
+
+"mime@1.4.1":
+ "integrity" "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ=="
+ "resolved" "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz"
+ "version" "1.4.1"
+
+"mime@1.6.0":
+ "integrity" "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+ "resolved" "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz"
+ "version" "1.6.0"
+
+"mimic-fn@^1.0.0":
+ "integrity" "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ=="
+ "resolved" "https://registry.npmjs.org/mimic-fn/-/mimic-fn-1.2.0.tgz"
+ "version" "1.2.0"
+
+"mimic-fn@^2.1.0":
+ "integrity" "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
+ "resolved" "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz"
+ "version" "2.1.0"
+
+"mimic-response@^1.0.0":
+ "integrity" "sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ=="
+ "resolved" "https://registry.npmjs.org/mimic-response/-/mimic-response-1.0.1.tgz"
+ "version" "1.0.1"
+
+"mini-create-react-context@^0.4.0":
+ "integrity" "sha512-YWCYEmd5CQeHGSAKrYvXgmzzkrvssZcuuQDDeqkT+PziKGMgE+0MCCtcKbROzocGBG1meBLl2FotlRwf4gAzbQ=="
+ "resolved" "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.4.1.tgz"
+ "version" "0.4.1"
+ dependencies:
+ "@babel/runtime" "^7.12.1"
+ "tiny-warning" "^1.0.3"
+
+"mini-css-extract-plugin@2.4.5":
+ "integrity" "sha512-oEIhRucyn1JbT/1tU2BhnwO6ft1jjH1iCX9Gc59WFMg0n5773rQU0oyQ0zzeYFFuBfONaRbQJyGoPtuNseMxjA=="
+ "resolved" "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.4.5.tgz"
+ "version" "2.4.5"
+ dependencies:
+ "schema-utils" "^4.0.0"
+
+"minimalistic-assert@^1.0.0":
+ "integrity" "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A=="
+ "resolved" "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz"
+ "version" "1.0.1"
+
+"minimatch@^3.0.0", "minimatch@^3.0.2", "minimatch@^3.0.4", "minimatch@~3.0.4", "minimatch@2 || 3":
+ "integrity" "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA=="
+ "resolved" "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz"
+ "version" "3.0.4"
+ dependencies:
+ "brace-expansion" "^1.1.7"
+
+"minimist@^1.1.0", "minimist@^1.1.3", "minimist@^1.2.0", "minimist@^1.2.5":
+ "integrity" "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+ "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz"
+ "version" "1.2.5"
+
+"minimist@0.0.8":
+ "integrity" "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
+ "resolved" "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
+ "version" "0.0.8"
+
+"minimist@1.2.0":
+ "integrity" "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
+ "resolved" "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+ "version" "1.2.0"
+
+"mitt@^1.1.3":
+ "integrity" "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw=="
+ "resolved" "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz"
+ "version" "1.2.0"
+
+"mkdirp@^0.5.0":
+ "integrity" "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ=="
+ "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz"
+ "version" "0.5.5"
+ dependencies:
+ "minimist" "^1.2.5"
+
+"mkdirp@^0.5.1":
+ "integrity" "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ=="
+ "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz"
+ "version" "0.5.5"
+ dependencies:
+ "minimist" "^1.2.5"
+
+"mkdirp@^0.5.5":
+ "integrity" "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ=="
+ "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz"
+ "version" "0.5.5"
+ dependencies:
+ "minimist" "^1.2.5"
+
+"mkdirp@^1.0.4":
+ "integrity" "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw=="
+ "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz"
+ "version" "1.0.4"
+
+"mkdirp@0.5.1":
+ "integrity" "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM="
+ "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
+ "version" "0.5.1"
+ dependencies:
+ "minimist" "0.0.8"
+
+"mkdirp@0.5.x":
+ "integrity" "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ=="
+ "resolved" "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz"
+ "version" "0.5.5"
+ dependencies:
+ "minimist" "^1.2.5"
+
+"ms@^2.1.1", "ms@2.1.2":
+ "integrity" "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz"
+ "version" "2.1.2"
+
+"ms@2.0.0":
+ "integrity" "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+ "resolved" "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz"
+ "version" "2.0.0"
+
+"ms@2.1.3":
+ "integrity" "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
+ "resolved" "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz"
+ "version" "2.1.3"
+
+"multicast-dns-service-types@^1.1.0":
+ "integrity" "sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE="
+ "resolved" "https://registry.npmjs.org/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz"
+ "version" "1.1.0"
+
+"multicast-dns@^6.0.1":
+ "integrity" "sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g=="
+ "resolved" "https://registry.npmjs.org/multicast-dns/-/multicast-dns-6.2.3.tgz"
+ "version" "6.2.3"
+ dependencies:
+ "dns-packet" "^1.3.1"
+ "thunky" "^1.0.2"
+
+"multimatch@^2.0.0":
+ "integrity" "sha1-nHkGoi+0wCkZ4vX3UWG0zb1LKis="
+ "resolved" "https://registry.npmjs.org/multimatch/-/multimatch-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "array-differ" "^1.0.0"
+ "array-union" "^1.0.1"
+ "arrify" "^1.0.0"
+ "minimatch" "^3.0.0"
+
+"mute-stream@0.0.5":
+ "integrity" "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA="
+ "resolved" "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz"
+ "version" "0.0.5"
+
+"mute-stream@0.0.6":
+ "integrity" "sha1-SJYrGeFp/R38JAs/HnMXYnu8R9s="
+ "resolved" "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.6.tgz"
+ "version" "0.0.6"
+
+"mute-stream@0.0.7":
+ "integrity" "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
+ "resolved" "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.7.tgz"
+ "version" "0.0.7"
+
+"nanoid@^3.1.30":
+ "integrity" "sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ=="
+ "resolved" "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz"
+ "version" "3.1.30"
+
+"natural-compare@^1.4.0":
+ "integrity" "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc="
+ "resolved" "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz"
+ "version" "1.4.0"
+
+"negotiator@0.6.2":
+ "integrity" "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+ "resolved" "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz"
+ "version" "0.6.2"
+
+"neo-async@^2.6.0", "neo-async@^2.6.2":
+ "integrity" "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="
+ "resolved" "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz"
+ "version" "2.6.2"
+
+"nise@^5.1.0":
+ "integrity" "sha512-W5WlHu+wvo3PaKLsJJkgPup2LrsXCcm7AWwyNZkUnn5rwPkuPBi3Iwk5SQtN0mv+K65k7nKKjwNQ30wg3wLAQQ=="
+ "resolved" "https://registry.npmjs.org/nise/-/nise-5.1.0.tgz"
+ "version" "5.1.0"
+ dependencies:
+ "@sinonjs/commons" "^1.7.0"
+ "@sinonjs/fake-timers" "^7.0.4"
+ "@sinonjs/text-encoding" "^0.7.1"
+ "just-extend" "^4.0.2"
+ "path-to-regexp" "^1.7.0"
+
+"no-case@^3.0.4":
+ "integrity" "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg=="
+ "resolved" "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz"
+ "version" "3.0.4"
+ dependencies:
+ "lower-case" "^2.0.2"
+ "tslib" "^2.0.3"
+
+"node-fetch@1.6.3":
+ "integrity" "sha1-3CNO3WSJmC1Y6PDbT2lQKavNjAQ="
+ "resolved" "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz"
+ "version" "1.6.3"
+ dependencies:
+ "encoding" "^0.1.11"
+ "is-stream" "^1.0.1"
+
+"node-forge@^0.10.0":
+ "integrity" "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA=="
+ "resolved" "https://registry.npmjs.org/node-forge/-/node-forge-0.10.0.tgz"
+ "version" "0.10.0"
+
+"node-int64@^0.4.0":
+ "integrity" "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs="
+ "resolved" "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz"
+ "version" "0.4.0"
+
+"node-notifier@^8.0.1 || ^9.0.0 || ^10.0.0", "node-notifier@^9.0.0":
+ "integrity" "sha512-fPNFIp2hF/Dq7qLDzSg4vZ0J4e9v60gJR+Qx7RbjbWqzPDdEqeVpEx5CFeDAELIl+A/woaaNn1fQ5nEVerMxJg=="
+ "resolved" "https://registry.npmjs.org/node-notifier/-/node-notifier-9.0.1.tgz"
+ "version" "9.0.1"
+ dependencies:
+ "growly" "^1.3.0"
+ "is-wsl" "^2.2.0"
+ "semver" "^7.3.2"
+ "shellwords" "^0.1.1"
+ "uuid" "^8.3.0"
+ "which" "^2.0.2"
+
+"node-releases@^2.0.1":
+ "integrity" "sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA=="
+ "resolved" "https://registry.npmjs.org/node-releases/-/node-releases-2.0.1.tgz"
+ "version" "2.0.1"
+
+"nopt@3.x":
+ "integrity" "sha1-xkZdvwirzU2zWTF/eaxopkayj/k="
+ "resolved" "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz"
+ "version" "3.0.6"
+ dependencies:
+ "abbrev" "1"
+
+"normalize-package-data@^2.3.2", "normalize-package-data@^2.3.4":
+ "integrity" "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA=="
+ "resolved" "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz"
+ "version" "2.5.0"
+ dependencies:
+ "hosted-git-info" "^2.1.4"
+ "resolve" "^1.10.0"
+ "semver" "2 || 3 || 4 || 5"
+ "validate-npm-package-license" "^3.0.1"
+
+"normalize-path@^3.0.0", "normalize-path@~3.0.0":
+ "integrity" "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA=="
+ "resolved" "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz"
+ "version" "3.0.0"
+
+"normalize-range@^0.1.2":
+ "integrity" "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI="
+ "resolved" "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz"
+ "version" "0.1.2"
+
+"normalize-url@^6.0.1":
+ "integrity" "sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A=="
+ "resolved" "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz"
+ "version" "6.1.0"
+
+"npm-run-path@^4.0.1":
+ "integrity" "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="
+ "resolved" "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz"
+ "version" "4.0.1"
+ dependencies:
+ "path-key" "^3.0.0"
+
+"npmlog@^2.0.3":
+ "integrity" "sha1-mLUlMPJRTKkNCexbIsiEZyI3VpI="
+ "resolved" "https://registry.npmjs.org/npmlog/-/npmlog-2.0.4.tgz"
+ "version" "2.0.4"
+ dependencies:
+ "ansi" "~0.3.1"
+ "are-we-there-yet" "~1.1.2"
+ "gauge" "~1.2.5"
+
+"nth-check@^2.0.1":
+ "integrity" "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w=="
+ "resolved" "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "boolbase" "^1.0.0"
+
+"nth-check@~1.0.0":
+ "integrity" "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg=="
+ "resolved" "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "boolbase" "~1.0.0"
+
+"nth-check@~1.0.1":
+ "integrity" "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg=="
+ "resolved" "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "boolbase" "~1.0.0"
+
+"number-is-nan@^1.0.0":
+ "integrity" "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
+ "resolved" "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz"
+ "version" "1.0.1"
+
+"numeral@^2.0.6":
+ "integrity" "sha1-StCAk21EPCVhrtnyGX7//iX05QY="
+ "resolved" "https://registry.npmjs.org/numeral/-/numeral-2.0.6.tgz"
+ "version" "2.0.6"
+
+"nwsapi@^2.2.0":
+ "integrity" "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ=="
+ "resolved" "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz"
+ "version" "2.2.0"
+
+"oauth-sign@~0.9.0":
+ "integrity" "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
+ "resolved" "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz"
+ "version" "0.9.0"
+
+"object-assign@^4.0.1", "object-assign@^4.1.0", "object-assign@^4.1.1", "object-assign@4.x.x":
+ "integrity" "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+ "resolved" "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
+ "version" "4.1.1"
+
+"object-inspect@^1.11.0", "object-inspect@^1.9.0":
+ "integrity" "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g=="
+ "resolved" "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz"
+ "version" "1.12.0"
+
+"object-is@^1.0.1":
+ "integrity" "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw=="
+ "resolved" "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz"
+ "version" "1.1.5"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "define-properties" "^1.1.3"
+
+"object-keys@^1.0.12", "object-keys@^1.1.1":
+ "integrity" "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA=="
+ "resolved" "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz"
+ "version" "1.1.1"
+
+"object.assign@^4.1.0", "object.assign@^4.1.2":
+ "integrity" "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ=="
+ "resolved" "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz"
+ "version" "4.1.2"
+ dependencies:
+ "call-bind" "^1.0.0"
+ "define-properties" "^1.1.3"
+ "has-symbols" "^1.0.1"
+ "object-keys" "^1.1.1"
+
+"object.entries@^1.1.5":
+ "integrity" "sha512-TyxmjUoZggd4OrrU1W66FMDG6CuqJxsFvymeyXI51+vQLN67zYfZseptRge703kKQdo4uccgAKebXFcRCzk4+g=="
+ "resolved" "https://registry.npmjs.org/object.entries/-/object.entries-1.1.5.tgz"
+ "version" "1.1.5"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "define-properties" "^1.1.3"
+ "es-abstract" "^1.19.1"
+
+"object.fromentries@^2.0.5":
+ "integrity" "sha512-CAyG5mWQRRiBU57Re4FKoTBjXfDoNwdFVH2Y1tS9PqCsfUTymAohOkEMSG3aRNKmv4lV3O7p1et7c187q6bynw=="
+ "resolved" "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.5.tgz"
+ "version" "2.0.5"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "define-properties" "^1.1.3"
+ "es-abstract" "^1.19.1"
+
+"object.hasown@^1.1.0":
+ "integrity" "sha512-MhjYRfj3GBlhSkDHo6QmvgjRLXQ2zndabdf3nX0yTyZK9rPfxb6uRpAac8HXNLy1GpqWtZ81Qh4v3uOls2sRAg=="
+ "resolved" "https://registry.npmjs.org/object.hasown/-/object.hasown-1.1.0.tgz"
+ "version" "1.1.0"
+ dependencies:
+ "define-properties" "^1.1.3"
+ "es-abstract" "^1.19.1"
+
+"object.values@^1.1.5":
+ "integrity" "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg=="
+ "resolved" "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz"
+ "version" "1.1.5"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "define-properties" "^1.1.3"
+ "es-abstract" "^1.19.1"
+
+"obuf@^1.0.0", "obuf@^1.1.2":
+ "integrity" "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="
+ "resolved" "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz"
+ "version" "1.1.2"
+
+"on-finished@~2.3.0":
+ "integrity" "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc="
+ "resolved" "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz"
+ "version" "2.3.0"
+ dependencies:
+ "ee-first" "1.1.1"
+
+"on-headers@~1.0.2":
+ "integrity" "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
+ "resolved" "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz"
+ "version" "1.0.2"
+
+"once@^1.3.0", "once@1.x":
+ "integrity" "sha1-WDsap3WWHUsROsF9nFC6753Xa9E="
+ "resolved" "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
+ "version" "1.4.0"
+ dependencies:
+ "wrappy" "1"
+
+"onetime@^1.0.0":
+ "integrity" "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k="
+ "resolved" "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz"
+ "version" "1.1.0"
+
+"onetime@^2.0.0":
+ "integrity" "sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ="
+ "resolved" "https://registry.npmjs.org/onetime/-/onetime-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "mimic-fn" "^1.0.0"
+
+"onetime@^5.1.0", "onetime@^5.1.2":
+ "integrity" "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg=="
+ "resolved" "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz"
+ "version" "5.1.2"
+ dependencies:
+ "mimic-fn" "^2.1.0"
+
+"open@^8.0.9":
+ "integrity" "sha512-XgFPPM+B28FtCCgSb9I+s9szOC1vZRSwgWsRUA5ylIxRTgKozqjOCrVOqGsYABPYK5qnfqClxZTFBa8PKt2v6Q=="
+ "resolved" "https://registry.npmjs.org/open/-/open-8.4.0.tgz"
+ "version" "8.4.0"
+ dependencies:
+ "define-lazy-prop" "^2.0.0"
+ "is-docker" "^2.1.1"
+ "is-wsl" "^2.2.0"
+
+"opencollective@1.0.3":
+ "integrity" "sha1-ruY3K8KBRFg2kMPKja7PwSDdDvE="
+ "resolved" "https://registry.npmjs.org/opencollective/-/opencollective-1.0.3.tgz"
+ "version" "1.0.3"
+ dependencies:
+ "babel-polyfill" "6.23.0"
+ "chalk" "1.1.3"
+ "inquirer" "3.0.6"
+ "minimist" "1.2.0"
+ "node-fetch" "1.6.3"
+ "opn" "4.0.2"
+
+"openurl@1.1.1":
+ "integrity" "sha1-OHW0sO96UsFW8NtB1GCduw+Us4c="
+ "resolved" "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz"
+ "version" "1.1.1"
+
+"opn@4.0.2":
+ "integrity" "sha1-erwi5kTf9jsKltWrfyeQwPAavJU="
+ "resolved" "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz"
+ "version" "4.0.2"
+ dependencies:
+ "object-assign" "^4.0.1"
+ "pinkie-promise" "^2.0.0"
+
+"opn@5.3.0":
+ "integrity" "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g=="
+ "resolved" "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz"
+ "version" "5.3.0"
+ dependencies:
+ "is-wsl" "^1.1.0"
+
+"optionator@^0.8.1":
+ "integrity" "sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA=="
+ "resolved" "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz"
+ "version" "0.8.3"
+ dependencies:
+ "deep-is" "~0.1.3"
+ "fast-levenshtein" "~2.0.6"
+ "levn" "~0.3.0"
+ "prelude-ls" "~1.1.2"
+ "type-check" "~0.3.2"
+ "word-wrap" "~1.2.3"
+
+"optionator@^0.9.1":
+ "integrity" "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw=="
+ "resolved" "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz"
+ "version" "0.9.1"
+ dependencies:
+ "deep-is" "^0.1.3"
+ "fast-levenshtein" "^2.0.6"
+ "levn" "^0.4.1"
+ "prelude-ls" "^1.2.1"
+ "type-check" "^0.4.0"
+ "word-wrap" "^1.2.3"
+
+"os-homedir@^1.0.0":
+ "integrity" "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
+ "resolved" "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz"
+ "version" "1.0.2"
+
+"os-name@^1.0.0":
+ "integrity" "sha1-GzefZINa98Wn9JizV8uVIVwVnt8="
+ "resolved" "https://registry.npmjs.org/os-name/-/os-name-1.0.3.tgz"
+ "version" "1.0.3"
+ dependencies:
+ "osx-release" "^1.0.0"
+ "win-release" "^1.0.0"
+
+"os-shim@^0.1.2":
+ "integrity" "sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc="
+ "resolved" "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz"
+ "version" "0.1.3"
+
+"os-tmpdir@^1.0.0", "os-tmpdir@~1.0.1", "os-tmpdir@~1.0.2":
+ "integrity" "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
+ "resolved" "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
+ "version" "1.0.2"
+
+"osenv@^0.1.0":
+ "integrity" "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g=="
+ "resolved" "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz"
+ "version" "0.1.5"
+ dependencies:
+ "os-homedir" "^1.0.0"
+ "os-tmpdir" "^1.0.0"
+
+"osx-release@^1.0.0":
+ "integrity" "sha1-8heRGigTaUmvG/kwiyQeJzfTzWw="
+ "resolved" "https://registry.npmjs.org/osx-release/-/osx-release-1.1.0.tgz"
+ "version" "1.1.0"
+ dependencies:
+ "minimist" "^1.1.0"
+
+"p-cancelable@^0.3.0":
+ "integrity" "sha512-RVbZPLso8+jFeq1MfNvgXtCRED2raz/dKpacfTNxsx6pLEpEomM7gah6VeHSYV3+vo0OAi4MkArtQcWWXuQoyw=="
+ "resolved" "https://registry.npmjs.org/p-cancelable/-/p-cancelable-0.3.0.tgz"
+ "version" "0.3.0"
+
+"p-finally@^1.0.0":
+ "integrity" "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4="
+ "resolved" "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz"
+ "version" "1.0.0"
+
+"p-limit@^1.1.0":
+ "integrity" "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q=="
+ "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz"
+ "version" "1.3.0"
+ dependencies:
+ "p-try" "^1.0.0"
+
+"p-limit@^2.2.0":
+ "integrity" "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w=="
+ "resolved" "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz"
+ "version" "2.3.0"
+ dependencies:
+ "p-try" "^2.0.0"
+
+"p-locate@^2.0.0":
+ "integrity" "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM="
+ "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "p-limit" "^1.1.0"
+
+"p-locate@^4.1.0":
+ "integrity" "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A=="
+ "resolved" "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz"
+ "version" "4.1.0"
+ dependencies:
+ "p-limit" "^2.2.0"
+
+"p-map@^4.0.0":
+ "integrity" "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ=="
+ "resolved" "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "aggregate-error" "^3.0.0"
+
+"p-retry@^4.5.0":
+ "integrity" "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA=="
+ "resolved" "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz"
+ "version" "4.6.1"
+ dependencies:
+ "@types/retry" "^0.12.0"
+ "retry" "^0.13.1"
+
+"p-timeout@^1.1.1":
+ "integrity" "sha1-XrOzU7f86Z8QGhA4iAuwVOu+o4Y="
+ "resolved" "https://registry.npmjs.org/p-timeout/-/p-timeout-1.2.1.tgz"
+ "version" "1.2.1"
+ dependencies:
+ "p-finally" "^1.0.0"
+
+"p-try@^1.0.0":
+ "integrity" "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M="
+ "resolved" "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz"
+ "version" "1.0.0"
+
+"p-try@^2.0.0":
+ "integrity" "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ=="
+ "resolved" "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz"
+ "version" "2.2.0"
+
+"param-case@^3.0.4":
+ "integrity" "sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A=="
+ "resolved" "https://registry.npmjs.org/param-case/-/param-case-3.0.4.tgz"
+ "version" "3.0.4"
+ dependencies:
+ "dot-case" "^3.0.4"
+ "tslib" "^2.0.3"
+
+"parent-module@^1.0.0":
+ "integrity" "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g=="
+ "resolved" "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz"
+ "version" "1.0.1"
+ dependencies:
+ "callsites" "^3.0.0"
+
+"parse-json@^2.2.0":
+ "integrity" "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck="
+ "resolved" "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz"
+ "version" "2.2.0"
+ dependencies:
+ "error-ex" "^1.2.0"
+
+"parse-json@^5.0.0":
+ "integrity" "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg=="
+ "resolved" "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz"
+ "version" "5.2.0"
+ dependencies:
+ "@babel/code-frame" "^7.0.0"
+ "error-ex" "^1.3.1"
+ "json-parse-even-better-errors" "^2.3.0"
+ "lines-and-columns" "^1.1.6"
+
+"parse-srcset@^1.0.2":
+ "integrity" "sha1-8r0iH2zJcKk42IVWq8WJyqqiveE="
+ "resolved" "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz"
+ "version" "1.0.2"
+
+"parse5@6.0.1":
+ "integrity" "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
+ "resolved" "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz"
+ "version" "6.0.1"
+
+"parseqs@0.0.6":
+ "integrity" "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w=="
+ "resolved" "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz"
+ "version" "0.0.6"
+
+"parseuri@0.0.6":
+ "integrity" "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow=="
+ "resolved" "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz"
+ "version" "0.0.6"
+
+"parseurl@~1.3.2", "parseurl@~1.3.3":
+ "integrity" "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+ "resolved" "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz"
+ "version" "1.3.3"
+
+"pascal-case@^3.1.2":
+ "integrity" "sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g=="
+ "resolved" "https://registry.npmjs.org/pascal-case/-/pascal-case-3.1.2.tgz"
+ "version" "3.1.2"
+ dependencies:
+ "no-case" "^3.0.4"
+ "tslib" "^2.0.3"
+
+"path-browserify@1.0.1":
+ "integrity" "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
+ "resolved" "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz"
+ "version" "1.0.1"
+
+"path-exists@^2.0.0":
+ "integrity" "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s="
+ "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "pinkie-promise" "^2.0.0"
+
+"path-exists@^3.0.0":
+ "integrity" "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU="
+ "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz"
+ "version" "3.0.0"
+
+"path-exists@^4.0.0":
+ "integrity" "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w=="
+ "resolved" "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz"
+ "version" "4.0.0"
+
+"path-is-absolute@^1.0.0":
+ "integrity" "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
+ "resolved" "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+ "version" "1.0.1"
+
+"path-key@^3.0.0", "path-key@^3.1.0":
+ "integrity" "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
+ "resolved" "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz"
+ "version" "3.1.1"
+
+"path-parse@^1.0.6", "path-parse@^1.0.7":
+ "integrity" "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="
+ "resolved" "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz"
+ "version" "1.0.7"
+
+"path-to-regexp@^1.7.0":
+ "integrity" "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA=="
+ "resolved" "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz"
+ "version" "1.8.0"
+ dependencies:
+ "isarray" "0.0.1"
+
+"path-to-regexp@0.1.7":
+ "integrity" "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+ "resolved" "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz"
+ "version" "0.1.7"
+
+"path-type@^1.0.0":
+ "integrity" "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE="
+ "resolved" "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz"
+ "version" "1.1.0"
+ dependencies:
+ "graceful-fs" "^4.1.2"
+ "pify" "^2.0.0"
+ "pinkie-promise" "^2.0.0"
+
+"path-type@^2.0.0":
+ "integrity" "sha1-8BLMuEFbcJb8LaoQVMPXI4lZTHM="
+ "resolved" "https://registry.npmjs.org/path-type/-/path-type-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "pify" "^2.0.0"
+
+"path-type@^4.0.0":
+ "integrity" "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
+ "resolved" "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz"
+ "version" "4.0.0"
+
+"performance-now@^2.1.0":
+ "integrity" "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
+ "resolved" "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz"
+ "version" "2.1.0"
+
+"picocolors@^1.0.0":
+ "integrity" "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ=="
+ "resolved" "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz"
+ "version" "1.0.0"
+
+"picomatch@^2.0.4", "picomatch@^2.2.1", "picomatch@^2.2.2", "picomatch@^2.2.3":
+ "integrity" "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA=="
+ "resolved" "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz"
+ "version" "2.3.1"
+
+"pify@^2.0.0", "pify@^2.3.0":
+ "integrity" "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
+ "resolved" "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
+ "version" "2.3.0"
+
+"pify@^3.0.0":
+ "integrity" "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY="
+ "resolved" "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz"
+ "version" "3.0.0"
+
+"pinkie-promise@^2.0.0":
+ "integrity" "sha1-ITXW36ejWMBprJsXh3YogihFD/o="
+ "resolved" "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "pinkie" "^2.0.0"
+
+"pinkie@^2.0.0":
+ "integrity" "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+ "resolved" "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz"
+ "version" "2.0.4"
+
+"pirates@^4.0.4":
+ "integrity" "sha512-ZIrVPH+A52Dw84R0L3/VS9Op04PuQ2SEoJL6bkshmiTic/HldyW9Tf7oH5mhJZBK7NmDx27vSMrYEXPXclpDKw=="
+ "resolved" "https://registry.npmjs.org/pirates/-/pirates-4.0.4.tgz"
+ "version" "4.0.4"
+
+"pkg-dir@^4.2.0":
+ "integrity" "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ=="
+ "resolved" "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz"
+ "version" "4.2.0"
+ dependencies:
+ "find-up" "^4.0.0"
+
+"pluralize@7.0.0":
+ "integrity" "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
+ "resolved" "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz"
+ "version" "7.0.0"
+
+"portfinder@^1.0.28":
+ "integrity" "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA=="
+ "resolved" "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz"
+ "version" "1.0.28"
+ dependencies:
+ "async" "^2.6.2"
+ "debug" "^3.1.1"
+ "mkdirp" "^0.5.5"
+
+"portscanner@2.1.1":
+ "integrity" "sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y="
+ "resolved" "https://registry.npmjs.org/portscanner/-/portscanner-2.1.1.tgz"
+ "version" "2.1.1"
+ dependencies:
+ "async" "1.5.2"
+ "is-number-like" "^1.0.3"
+
+"postcss-calc@^8.0.0":
+ "integrity" "sha512-XaJ+DArhRtRAzI+IqjRNTM0i4NFKkMK5StepwynfrF27UfO6/oMaELSVDE4f9ndLHyaO4aDKUwfQKVmje/BzCg=="
+ "resolved" "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.1.0.tgz"
+ "version" "8.1.0"
+ dependencies:
+ "postcss-selector-parser" "^6.0.2"
+ "postcss-value-parser" "^4.0.2"
+
+"postcss-colormin@^5.2.2":
+ "integrity" "sha512-tSEe3NpqWARUTidDlF0LntPkdlhXqfDFuA1yslqpvvGAfpZ7oBaw+/QXd935NKm2U9p4PED0HDZlzmMk7fVC6g=="
+ "resolved" "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.2.tgz"
+ "version" "5.2.2"
+ dependencies:
+ "browserslist" "^4.16.6"
+ "caniuse-api" "^3.0.0"
+ "colord" "^2.9.1"
+ "postcss-value-parser" "^4.2.0"
+
+"postcss-convert-values@^5.0.2":
+ "integrity" "sha512-KQ04E2yadmfa1LqXm7UIDwW1ftxU/QWZmz6NKnHnUvJ3LEYbbcX6i329f/ig+WnEByHegulocXrECaZGLpL8Zg=="
+ "resolved" "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.2.tgz"
+ "version" "5.0.2"
+ dependencies:
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-discard-comments@^5.0.1":
+ "integrity" "sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg=="
+ "resolved" "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz"
+ "version" "5.0.1"
+
+"postcss-discard-duplicates@^5.0.1":
+ "integrity" "sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA=="
+ "resolved" "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz"
+ "version" "5.0.1"
+
+"postcss-discard-empty@^5.0.1":
+ "integrity" "sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw=="
+ "resolved" "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz"
+ "version" "5.0.1"
+
+"postcss-discard-overridden@^5.0.1":
+ "integrity" "sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q=="
+ "resolved" "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz"
+ "version" "5.0.1"
+
+"postcss-loader@6.2.1":
+ "integrity" "sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q=="
+ "resolved" "https://registry.npmjs.org/postcss-loader/-/postcss-loader-6.2.1.tgz"
+ "version" "6.2.1"
+ dependencies:
+ "cosmiconfig" "^7.0.0"
+ "klona" "^2.0.5"
+ "semver" "^7.3.5"
+
+"postcss-merge-longhand@^5.0.4":
+ "integrity" "sha512-2lZrOVD+d81aoYkZDpWu6+3dTAAGkCKbV5DoRhnIR7KOULVrI/R7bcMjhrH9KTRy6iiHKqmtG+n/MMj1WmqHFw=="
+ "resolved" "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.4.tgz"
+ "version" "5.0.4"
+ dependencies:
+ "postcss-value-parser" "^4.1.0"
+ "stylehacks" "^5.0.1"
+
+"postcss-merge-rules@^5.0.3":
+ "integrity" "sha512-cEKTMEbWazVa5NXd8deLdCnXl+6cYG7m2am+1HzqH0EnTdy8fRysatkaXb2dEnR+fdaDxTvuZ5zoBdv6efF6hg=="
+ "resolved" "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.3.tgz"
+ "version" "5.0.3"
+ dependencies:
+ "browserslist" "^4.16.6"
+ "caniuse-api" "^3.0.0"
+ "cssnano-utils" "^2.0.1"
+ "postcss-selector-parser" "^6.0.5"
+
+"postcss-minify-font-values@^5.0.1":
+ "integrity" "sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA=="
+ "resolved" "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-minify-gradients@^5.0.3":
+ "integrity" "sha512-Z91Ol22nB6XJW+5oe31+YxRsYooxOdFKcbOqY/V8Fxse1Y3vqlNRpi1cxCqoACZTQEhl+xvt4hsbWiV5R+XI9Q=="
+ "resolved" "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.3.tgz"
+ "version" "5.0.3"
+ dependencies:
+ "colord" "^2.9.1"
+ "cssnano-utils" "^2.0.1"
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-minify-params@^5.0.2":
+ "integrity" "sha512-qJAPuBzxO1yhLad7h2Dzk/F7n1vPyfHfCCh5grjGfjhi1ttCnq4ZXGIW77GSrEbh9Hus9Lc/e/+tB4vh3/GpDg=="
+ "resolved" "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.2.tgz"
+ "version" "5.0.2"
+ dependencies:
+ "alphanum-sort" "^1.0.2"
+ "browserslist" "^4.16.6"
+ "cssnano-utils" "^2.0.1"
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-minify-selectors@^5.1.0":
+ "integrity" "sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og=="
+ "resolved" "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz"
+ "version" "5.1.0"
+ dependencies:
+ "alphanum-sort" "^1.0.2"
+ "postcss-selector-parser" "^6.0.5"
+
+"postcss-modules-extract-imports@^3.0.0":
+ "integrity" "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw=="
+ "resolved" "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz"
+ "version" "3.0.0"
+
+"postcss-modules-local-by-default@^4.0.0":
+ "integrity" "sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ=="
+ "resolved" "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "icss-utils" "^5.0.0"
+ "postcss-selector-parser" "^6.0.2"
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-modules-scope@^3.0.0":
+ "integrity" "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg=="
+ "resolved" "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "postcss-selector-parser" "^6.0.4"
+
+"postcss-modules-values@^4.0.0":
+ "integrity" "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ=="
+ "resolved" "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "icss-utils" "^5.0.0"
+
+"postcss-normalize-charset@^5.0.1":
+ "integrity" "sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg=="
+ "resolved" "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz"
+ "version" "5.0.1"
+
+"postcss-normalize-display-values@^5.0.1":
+ "integrity" "sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ=="
+ "resolved" "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "cssnano-utils" "^2.0.1"
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-normalize-positions@^5.0.1":
+ "integrity" "sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg=="
+ "resolved" "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-normalize-repeat-style@^5.0.1":
+ "integrity" "sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w=="
+ "resolved" "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "cssnano-utils" "^2.0.1"
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-normalize-string@^5.0.1":
+ "integrity" "sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA=="
+ "resolved" "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-normalize-timing-functions@^5.0.1":
+ "integrity" "sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q=="
+ "resolved" "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "cssnano-utils" "^2.0.1"
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-normalize-unicode@^5.0.1":
+ "integrity" "sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA=="
+ "resolved" "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "browserslist" "^4.16.0"
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-normalize-url@^5.0.4":
+ "integrity" "sha512-cNj3RzK2pgQQyNp7dzq0dqpUpQ/wYtdDZM3DepPmFjCmYIfceuD9VIAcOdvrNetjIU65g1B4uwdP/Krf6AFdXg=="
+ "resolved" "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.4.tgz"
+ "version" "5.0.4"
+ dependencies:
+ "normalize-url" "^6.0.1"
+ "postcss-value-parser" "^4.2.0"
+
+"postcss-normalize-whitespace@^5.0.1":
+ "integrity" "sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA=="
+ "resolved" "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-ordered-values@^5.0.2":
+ "integrity" "sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ=="
+ "resolved" "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz"
+ "version" "5.0.2"
+ dependencies:
+ "cssnano-utils" "^2.0.1"
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-reduce-initial@^5.0.2":
+ "integrity" "sha512-v/kbAAQ+S1V5v9TJvbGkV98V2ERPdU6XvMcKMjqAlYiJ2NtsHGlKYLPjWWcXlaTKNxooId7BGxeraK8qXvzKtw=="
+ "resolved" "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.2.tgz"
+ "version" "5.0.2"
+ dependencies:
+ "browserslist" "^4.16.6"
+ "caniuse-api" "^3.0.0"
+
+"postcss-reduce-transforms@^5.0.1":
+ "integrity" "sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA=="
+ "resolved" "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "cssnano-utils" "^2.0.1"
+ "postcss-value-parser" "^4.1.0"
+
+"postcss-selector-parser@^6.0.2", "postcss-selector-parser@^6.0.4", "postcss-selector-parser@^6.0.5":
+ "integrity" "sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ=="
+ "resolved" "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.8.tgz"
+ "version" "6.0.8"
+ dependencies:
+ "cssesc" "^3.0.0"
+ "util-deprecate" "^1.0.2"
+
+"postcss-svgo@^5.0.3":
+ "integrity" "sha512-41XZUA1wNDAZrQ3XgWREL/M2zSw8LJPvb5ZWivljBsUQAGoEKMYm6okHsTjJxKYI4M75RQEH4KYlEM52VwdXVA=="
+ "resolved" "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.3.tgz"
+ "version" "5.0.3"
+ dependencies:
+ "postcss-value-parser" "^4.1.0"
+ "svgo" "^2.7.0"
+
+"postcss-unique-selectors@^5.0.2":
+ "integrity" "sha512-w3zBVlrtZm7loQWRPVC0yjUwwpty7OM6DnEHkxcSQXO1bMS3RJ+JUS5LFMSDZHJcvGsRwhZinCWVqn8Kej4EDA=="
+ "resolved" "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.2.tgz"
+ "version" "5.0.2"
+ dependencies:
+ "alphanum-sort" "^1.0.2"
+ "postcss-selector-parser" "^6.0.5"
+
+"postcss-value-parser@^4.0.2", "postcss-value-parser@^4.1.0", "postcss-value-parser@^4.2.0":
+ "integrity" "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
+ "resolved" "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz"
+ "version" "4.2.0"
+
+"postcss@^7.0.0 || ^8.0.1", "postcss@^8.0.9", "postcss@^8.1.0", "postcss@^8.2.15", "postcss@^8.2.2", "postcss@^8.3.11", "postcss@^8.3.5":
+ "integrity" "sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg=="
+ "resolved" "https://registry.npmjs.org/postcss/-/postcss-8.4.5.tgz"
+ "version" "8.4.5"
+ dependencies:
+ "nanoid" "^3.1.30"
+ "picocolors" "^1.0.0"
+ "source-map-js" "^1.0.1"
+
+"prelude-ls@^1.2.1":
+ "integrity" "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="
+ "resolved" "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz"
+ "version" "1.2.1"
+
+"prelude-ls@~1.1.2":
+ "integrity" "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
+ "resolved" "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+ "version" "1.1.2"
+
+"prepend-http@^1.0.1":
+ "integrity" "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
+ "resolved" "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz"
+ "version" "1.0.4"
+
+"prettier-plugin-java@1.6.0":
+ "integrity" "sha512-yxeoei7bgQ8DGXEbUVs1m21ZhGknx8YUELlRP5CfHUUK7/yIpUvn+9tuYhPVO9v0nSfphBDAciwYcQH9RUMBLw=="
+ "resolved" "https://registry.npmjs.org/prettier-plugin-java/-/prettier-plugin-java-1.6.0.tgz"
+ "version" "1.6.0"
+ dependencies:
+ "java-parser" "2.0.0"
+ "lodash" "4.17.21"
+ "prettier" "2.3.1"
+
+"prettier-plugin-packagejson@2.2.15":
+ "integrity" "sha512-r3WKxw0ALyD3gr3RlIFK3o7mUejCVkqwVKtUuPQaB3+aNiZYKxmad+GpZ6WFWTm6Zq2jX0wvSdlkGccQ2pEnCg=="
+ "resolved" "https://registry.npmjs.org/prettier-plugin-packagejson/-/prettier-plugin-packagejson-2.2.15.tgz"
+ "version" "2.2.15"
+ dependencies:
+ "sort-package-json" "1.53.1"
+
+"prettier@>= 1.16.0", "prettier@2.5.1":
+ "integrity" "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg=="
+ "resolved" "https://registry.npmjs.org/prettier/-/prettier-2.5.1.tgz"
+ "version" "2.5.1"
+
+"prettier@2.3.1":
+ "integrity" "sha512-p+vNbgpLjif/+D+DwAZAbndtRrR0md0MwfmOVN9N+2RgyACMT+7tfaRnT+WDPkqnuVwleyuBIG2XBxKDme3hPA=="
+ "resolved" "https://registry.npmjs.org/prettier/-/prettier-2.3.1.tgz"
+ "version" "2.3.1"
+
+"pretty-bytes@^4.0.2":
+ "integrity" "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk="
+ "resolved" "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz"
+ "version" "4.0.2"
+
+"pretty-bytes@^5.3.0", "pretty-bytes@^5.4.1":
+ "integrity" "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="
+ "resolved" "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz"
+ "version" "5.6.0"
+
+"pretty-error@^4.0.0":
+ "integrity" "sha512-AoJ5YMAcXKYxKhuJGdcvse+Voc6v1RgnsR3nWcYU7q4t6z0Q6T86sv5Zq8VIRbOWWFpvdGE83LtdSMNd+6Y0xw=="
+ "resolved" "https://registry.npmjs.org/pretty-error/-/pretty-error-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "lodash" "^4.17.20"
+ "renderkid" "^3.0.0"
+
+"pretty-format@^27.0.0", "pretty-format@^27.0.2", "pretty-format@^27.4.6":
+ "integrity" "sha512-NblstegA1y/RJW2VyML+3LlpFjzx62cUrtBIKIWDXEDkjNeleA7Od7nrzcs/VLQvAeV4CgSYhrN39DRN88Qi/g=="
+ "resolved" "https://registry.npmjs.org/pretty-format/-/pretty-format-27.4.6.tgz"
+ "version" "27.4.6"
+ dependencies:
+ "ansi-regex" "^5.0.1"
+ "ansi-styles" "^5.0.0"
+ "react-is" "^17.0.1"
+
+"process-nextick-args@^2.0.0", "process-nextick-args@~2.0.0":
+ "integrity" "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
+ "resolved" "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz"
+ "version" "2.0.1"
+
+"progress@^2.0.0":
+ "integrity" "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
+ "resolved" "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz"
+ "version" "2.0.3"
+
+"prompts@^2.0.1":
+ "integrity" "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q=="
+ "resolved" "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz"
+ "version" "2.4.2"
+ dependencies:
+ "kleur" "^3.0.3"
+ "sisteransi" "^1.0.5"
+
+"prop-types@^15.0.0", "prop-types@^15.5.0", "prop-types@^15.5.8", "prop-types@^15.6.2", "prop-types@^15.7.2":
+ "integrity" "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg=="
+ "resolved" "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz"
+ "version" "15.8.1"
+ dependencies:
+ "loose-envify" "^1.4.0"
+ "object-assign" "^4.1.1"
+ "react-is" "^16.13.1"
+
+"proxy-addr@~2.0.7":
+ "integrity" "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="
+ "resolved" "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz"
+ "version" "2.0.7"
+ dependencies:
+ "forwarded" "0.2.0"
+ "ipaddr.js" "1.9.1"
+
+"pseudomap@^1.0.2":
+ "integrity" "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
+ "resolved" "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz"
+ "version" "1.0.2"
+
+"psl@^1.1.28", "psl@^1.1.33":
+ "integrity" "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
+ "resolved" "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz"
+ "version" "1.8.0"
+
+"punycode@^2.1.0", "punycode@^2.1.1":
+ "integrity" "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
+ "resolved" "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz"
+ "version" "2.1.1"
+
+"qs@~6.5.2":
+ "integrity" "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
+ "resolved" "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz"
+ "version" "6.5.2"
+
+"qs@6.2.3":
+ "integrity" "sha1-HPyyXBCpsrSDBT/zn138kjOQjP4="
+ "resolved" "https://registry.npmjs.org/qs/-/qs-6.2.3.tgz"
+ "version" "6.2.3"
+
+"qs@6.9.6":
+ "integrity" "sha512-TIRk4aqYLNoJUbd+g2lEdz5kLWIuTMRagAXxl78Q0RiVjAOugHmeKNGdd3cwo/ktpf9aL9epCfFqWDEKysUlLQ=="
+ "resolved" "https://registry.npmjs.org/qs/-/qs-6.9.6.tgz"
+ "version" "6.9.6"
+
+"queue-microtask@^1.2.2":
+ "integrity" "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
+ "resolved" "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz"
+ "version" "1.2.3"
+
+"randexp@0.4.6":
+ "integrity" "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ=="
+ "resolved" "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz"
+ "version" "0.4.6"
+ dependencies:
+ "discontinuous-range" "1.0.0"
+ "ret" "~0.1.10"
+
+"randombytes@^2.1.0":
+ "integrity" "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ=="
+ "resolved" "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "safe-buffer" "^5.1.0"
+
+"range-parser@^1.2.1", "range-parser@~1.2.0", "range-parser@~1.2.1":
+ "integrity" "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+ "resolved" "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz"
+ "version" "1.2.1"
+
+"raw-body@^2.3.2", "raw-body@2.4.2":
+ "integrity" "sha512-RPMAFUJP19WIet/99ngh6Iv8fzAbqum4Li7AD6DtGaW2RpMB/11xDoalPiJMTbu6I3hkbMVkATvZrqb9EEqeeQ=="
+ "resolved" "https://registry.npmjs.org/raw-body/-/raw-body-2.4.2.tgz"
+ "version" "2.4.2"
+ dependencies:
+ "bytes" "3.1.1"
+ "http-errors" "1.8.1"
+ "iconv-lite" "0.4.24"
+ "unpipe" "1.0.0"
+
+"react-dom@*", "react-dom@^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "react-dom@^17.0.1", "react-dom@>=16", "react-dom@>=16.6.0", "react-dom@>=16.8.0", "react-dom@17.0.2":
+ "integrity" "sha512-s4h96KtLDUQlsENhMn1ar8t2bEa+q/YAtj8pPPdIjPDGBDIVNsrD9aXNWqspUe6AzKCIG0C1HZZLqLV7qpOBGA=="
+ "resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz"
+ "version" "17.0.2"
+ dependencies:
+ "loose-envify" "^1.1.0"
+ "object-assign" "^4.1.1"
+ "scheduler" "^0.20.2"
+
+"react-fast-compare@^3.0.1":
+ "integrity" "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA=="
+ "resolved" "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz"
+ "version" "3.2.0"
+
+"react-hook-form@^7.6.8", "react-hook-form@7.22.5":
+ "integrity" "sha512-Q2zaeQFXdVQ8l3hcywhltH+Nzj4vo50wMVujHDVN/1Xy9IOaSZJwYBXA2CYTpK6rq41fnXviw3jTLb04c7Gu9Q=="
+ "resolved" "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.22.5.tgz"
+ "version" "7.22.5"
+
+"react-infinite-scroll-component@6.1.0":
+ "integrity" "sha512-SQu5nCqy8DxQWpnUVLx7V7b7LcA37aM7tvoWjTLZp1dk6EJibM5/4EJKzOnl07/BsM1Y40sKLuqjCwwH/xV0TQ=="
+ "resolved" "https://registry.npmjs.org/react-infinite-scroll-component/-/react-infinite-scroll-component-6.1.0.tgz"
+ "version" "6.1.0"
+ dependencies:
+ "throttle-debounce" "^2.1.0"
+
+"react-is@^16.13.1", "react-is@^16.6.0", "react-is@^16.7.0":
+ "integrity" "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ "resolved" "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz"
+ "version" "16.13.1"
+
+"react-is@^17.0.1":
+ "integrity" "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ "resolved" "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
+ "version" "17.0.2"
+
+"react-is@^17.0.2":
+ "integrity" "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="
+ "resolved" "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz"
+ "version" "17.0.2"
+
+"react-jhipster@0.18.0":
+ "integrity" "sha512-JlFgz8TJiae/5lm+1v0m8h8MawuEugW0M6QhB93vv8kzz18NjtpegOS1UlYbEUg478oU/uaVDMpl3Gm0j+r1uA=="
+ "resolved" "https://registry.npmjs.org/react-jhipster/-/react-jhipster-0.18.0.tgz"
+ "version" "0.18.0"
+ dependencies:
+ "lodash.get" "^4.4.2"
+ "numeral" "^2.0.6"
+ "sanitize-html" "^2.3.1"
+ "tslib" "^2.3.1"
+
+"react-lifecycles-compat@^3.0.4":
+ "integrity" "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ "resolved" "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz"
+ "version" "3.0.4"
+
+"react-loadable@5.5.0":
+ "integrity" "sha512-C8Aui0ZpMd4KokxRdVAm2bQtI03k2RMRNzOB+IipV3yxFTSVICv7WoUr5L9ALB5BmKO1iHgZtWM8EvYG83otdg=="
+ "resolved" "https://registry.npmjs.org/react-loadable/-/react-loadable-5.5.0.tgz"
+ "version" "5.5.0"
+ dependencies:
+ "prop-types" "^15.5.0"
+
+"react-popper@^2.2.4":
+ "integrity" "sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw=="
+ "resolved" "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz"
+ "version" "2.2.5"
+ dependencies:
+ "react-fast-compare" "^3.0.1"
+ "warning" "^4.0.2"
+
+"react-redux-loading-bar@5.0.2":
+ "integrity" "sha512-M+gK/Q79UG3iVljv6myRJptdQ5sIKdYDigeukwGocvWLCgWFdtpeP8IY8lBIYsqHXtuFBP/gj7E3qvGwCtcpRQ=="
+ "resolved" "https://registry.npmjs.org/react-redux-loading-bar/-/react-redux-loading-bar-5.0.2.tgz"
+ "version" "5.0.2"
+ dependencies:
+ "prop-types" "^15.7.2"
+ "react-lifecycles-compat" "^3.0.4"
+
+"react-redux@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", "react-redux@^7.2.1 || ^8.0.0-beta", "react-redux@7.2.6":
+ "integrity" "sha512-10RPdsz0UUrRL1NZE0ejTkucnclYSgXp5q+tB5SWx2qeG2ZJQJyymgAhwKy73yiL/13btfB6fPr+rgbMAaZIAQ=="
+ "resolved" "https://registry.npmjs.org/react-redux/-/react-redux-7.2.6.tgz"
+ "version" "7.2.6"
+ dependencies:
+ "@babel/runtime" "^7.15.4"
+ "@types/react-redux" "^7.1.20"
+ "hoist-non-react-statics" "^3.3.2"
+ "loose-envify" "^1.4.0"
+ "prop-types" "^15.7.2"
+ "react-is" "^17.0.2"
+
+"react-router-dom@5.3.0":
+ "integrity" "sha512-ObVBLjUZsphUUMVycibxgMdh5jJ1e3o+KpAZBVeHcNQZ4W+uUGGWsokurzlF4YOldQYRQL4y6yFRWM4m3svmuQ=="
+ "resolved" "https://registry.npmjs.org/react-router-dom/-/react-router-dom-5.3.0.tgz"
+ "version" "5.3.0"
+ dependencies:
+ "@babel/runtime" "^7.12.13"
+ "history" "^4.9.0"
+ "loose-envify" "^1.3.1"
+ "prop-types" "^15.6.2"
+ "react-router" "5.2.1"
+ "tiny-invariant" "^1.0.2"
+ "tiny-warning" "^1.0.0"
+
+"react-router@5.2.1":
+ "integrity" "sha512-lIboRiOtDLFdg1VTemMwud9vRVuOCZmUIT/7lUoZiSpPODiiH1UQlfXy+vPLC/7IWdFYnhRwAyNqA/+I7wnvKQ=="
+ "resolved" "https://registry.npmjs.org/react-router/-/react-router-5.2.1.tgz"
+ "version" "5.2.1"
+ dependencies:
+ "@babel/runtime" "^7.12.13"
+ "history" "^4.9.0"
+ "hoist-non-react-statics" "^3.1.0"
+ "loose-envify" "^1.3.1"
+ "mini-create-react-context" "^0.4.0"
+ "path-to-regexp" "^1.7.0"
+ "prop-types" "^15.6.2"
+ "react-is" "^16.6.0"
+ "tiny-invariant" "^1.0.2"
+ "tiny-warning" "^1.0.0"
+
+"react-toastify@8.1.0":
+ "integrity" "sha512-M+Q3rTmEw/53Csr7NsV/YnldJe4c7uERcY7Tma9mvLU98QT2VhIkKwjBzzxZkJRk/oBKyUAtkyMjMgO00hx6gQ=="
+ "resolved" "https://registry.npmjs.org/react-toastify/-/react-toastify-8.1.0.tgz"
+ "version" "8.1.0"
+ dependencies:
+ "clsx" "^1.1.1"
+
+"react-transition-group@^4.4.2", "react-transition-group@4.4.2":
+ "integrity" "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg=="
+ "resolved" "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz"
+ "version" "4.4.2"
+ dependencies:
+ "@babel/runtime" "^7.5.5"
+ "dom-helpers" "^5.0.1"
+ "loose-envify" "^1.4.0"
+ "prop-types" "^15.6.2"
+
+"react@*", "react@^0.14.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "react@^16.8.0 || ^17", "react@^16.8.3 || ^17", "react@^16.9.0 || ^17.0.0 || 18.0.0-beta", "react@^17.0.1", "react@>=15", "react@>=16", "react@>=16.0.0", "react@>=16.6.0", "react@>=16.8.0", "react@>=16.x", "react@17.0.2":
+ "integrity" "sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA=="
+ "resolved" "https://registry.npmjs.org/react/-/react-17.0.2.tgz"
+ "version" "17.0.2"
+ dependencies:
+ "loose-envify" "^1.1.0"
+ "object-assign" "^4.1.1"
+
+"reactstrap@^9.0.0", "reactstrap@9.0.1":
+ "integrity" "sha512-89VOv7SRlAlpS7RwXhzOQkSWkuhBR8LBsPGfNHifNL3WhtNP9y1sBdTcTYyH1ee2QtI8zRdwD0T5I/blHiwemg=="
+ "resolved" "https://registry.npmjs.org/reactstrap/-/reactstrap-9.0.1.tgz"
+ "version" "9.0.1"
+ dependencies:
+ "@babel/runtime" "^7.12.5"
+ "@popperjs/core" "^2.6.0"
+ "classnames" "^2.2.3"
+ "prop-types" "^15.5.8"
+ "react-popper" "^2.2.4"
+ "react-transition-group" "^4.4.2"
+
+"read-chunk@^2.1.0":
+ "integrity" "sha1-agTAkoAF7Z1C4aasVgDhnLx/9lU="
+ "resolved" "https://registry.npmjs.org/read-chunk/-/read-chunk-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "pify" "^3.0.0"
+ "safe-buffer" "^5.1.1"
+
+"read-pkg-up@^1.0.1":
+ "integrity" "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI="
+ "resolved" "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz"
+ "version" "1.0.1"
+ dependencies:
+ "find-up" "^1.0.0"
+ "read-pkg" "^1.0.0"
+
+"read-pkg-up@^2.0.0":
+ "integrity" "sha1-a3KoBImE4MQeeVEP1en6mbO1Sb4="
+ "resolved" "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "find-up" "^2.0.0"
+ "read-pkg" "^2.0.0"
+
+"read-pkg@^1.0.0":
+ "integrity" "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg="
+ "resolved" "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz"
+ "version" "1.1.0"
+ dependencies:
+ "load-json-file" "^1.0.0"
+ "normalize-package-data" "^2.3.2"
+ "path-type" "^1.0.0"
+
+"read-pkg@^2.0.0":
+ "integrity" "sha1-jvHAYjxqbbDcZxPEv6xGMysjaPg="
+ "resolved" "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "load-json-file" "^2.0.0"
+ "normalize-package-data" "^2.3.2"
+ "path-type" "^2.0.0"
+
+"readable-stream@^2.0.1", "readable-stream@^2.0.2", "readable-stream@^2.0.6", "readable-stream@^2.2.2", "readable-stream@^2.3.5", "readable-stream@~2.3.6", "readable-stream@2 || 3":
+ "integrity" "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw=="
+ "resolved" "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz"
+ "version" "2.3.7"
+ dependencies:
+ "core-util-is" "~1.0.0"
+ "inherits" "~2.0.3"
+ "isarray" "~1.0.0"
+ "process-nextick-args" "~2.0.0"
+ "safe-buffer" "~5.1.1"
+ "string_decoder" "~1.1.1"
+ "util-deprecate" "~1.0.1"
+
+"readable-stream@^3.0.6":
+ "integrity" "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA=="
+ "resolved" "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz"
+ "version" "3.6.0"
+ dependencies:
+ "inherits" "^2.0.3"
+ "string_decoder" "^1.1.1"
+ "util-deprecate" "^1.0.1"
+
+"readable-stream@^3.1.1":
+ "integrity" "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA=="
+ "resolved" "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz"
+ "version" "3.6.0"
+ dependencies:
+ "inherits" "^2.0.3"
+ "string_decoder" "^1.1.1"
+ "util-deprecate" "^1.0.1"
+
+"readable-stream@1.1":
+ "integrity" "sha1-fPTFTvZI44EwhMY23SB54WbAgdk="
+ "resolved" "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz"
+ "version" "1.1.14"
+ dependencies:
+ "core-util-is" "~1.0.0"
+ "inherits" "~2.0.1"
+ "isarray" "0.0.1"
+ "string_decoder" "~0.10.x"
+
+"readdirp@~3.6.0":
+ "integrity" "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="
+ "resolved" "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz"
+ "version" "3.6.0"
+ dependencies:
+ "picomatch" "^2.2.1"
+
+"readline2@^1.0.1":
+ "integrity" "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU="
+ "resolved" "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz"
+ "version" "1.0.1"
+ dependencies:
+ "code-point-at" "^1.0.0"
+ "is-fullwidth-code-point" "^1.0.0"
+ "mute-stream" "0.0.5"
+
+"rechoir@^0.6.2":
+ "integrity" "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q="
+ "resolved" "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz"
+ "version" "0.6.2"
+ dependencies:
+ "resolve" "^1.1.6"
+
+"rechoir@^0.7.0":
+ "integrity" "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg=="
+ "resolved" "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz"
+ "version" "0.7.1"
+ dependencies:
+ "resolve" "^1.9.0"
+
+"redent@^1.0.0":
+ "integrity" "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94="
+ "resolved" "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz"
+ "version" "1.0.0"
+ dependencies:
+ "indent-string" "^2.1.0"
+ "strip-indent" "^1.0.1"
+
+"redux-mock-store@1.5.4":
+ "integrity" "sha512-xmcA0O/tjCLXhh9Fuiq6pMrJCwFRaouA8436zcikdIpYWWCjU76CRk+i2bHx8EeiSiMGnB85/lZdU3wIJVXHTA=="
+ "resolved" "https://registry.npmjs.org/redux-mock-store/-/redux-mock-store-1.5.4.tgz"
+ "version" "1.5.4"
+ dependencies:
+ "lodash.isplainobject" "^4.0.6"
+
+"redux-thunk@^2.4.1", "redux-thunk@2.4.1":
+ "integrity" "sha512-OOYGNY5Jy2TWvTL1KgAlVy6dcx3siPJ1wTq741EPyUKfn6W6nChdICjZwCd0p8AZBs5kWpZlbkXW2nE/zjUa+Q=="
+ "resolved" "https://registry.npmjs.org/redux-thunk/-/redux-thunk-2.4.1.tgz"
+ "version" "2.4.1"
+
+"redux@^3.0.0 || ^4.0.0", "redux@^4", "redux@^4.0.0", "redux@^4.1.2", "redux@4.1.2":
+ "integrity" "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw=="
+ "resolved" "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz"
+ "version" "4.1.2"
+ dependencies:
+ "@babel/runtime" "^7.9.2"
+
+"regenerate-unicode-properties@^9.0.0":
+ "integrity" "sha512-3E12UeNSPfjrgwjkR81m5J7Aw/T55Tu7nUyZVQYCKEOs+2dkxEY+DpPtZzO4YruuiPb7NkYLVcyJC4+zCbk5pA=="
+ "resolved" "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-9.0.0.tgz"
+ "version" "9.0.0"
+ dependencies:
+ "regenerate" "^1.4.2"
+
+"regenerate@^1.4.2":
+ "integrity" "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A=="
+ "resolved" "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz"
+ "version" "1.4.2"
+
+"regenerator-runtime@^0.10.0":
+ "integrity" "sha1-M2w+/BIgrc7dosn6tntaeVWjNlg="
+ "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz"
+ "version" "0.10.5"
+
+"regenerator-runtime@^0.11.0":
+ "integrity" "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
+ "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz"
+ "version" "0.11.1"
+
+"regenerator-runtime@^0.13.4":
+ "integrity" "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
+ "resolved" "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz"
+ "version" "0.13.9"
+
+"regenerator-transform@^0.14.2":
+ "integrity" "sha512-eOf6vka5IO151Jfsw2NO9WpGX58W6wWmefK3I1zEGr0lOD0u8rwPaNqQL1aRxUaxLeKO3ArNh3VYg1KbaD+FFw=="
+ "resolved" "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.14.5.tgz"
+ "version" "0.14.5"
+ dependencies:
+ "@babel/runtime" "^7.8.4"
+
+"regexp-to-ast@0.4.0":
+ "integrity" "sha512-4qf/7IsIKfSNHQXSwial1IFmfM1Cc/whNBQqRwe0V2stPe7KmN1U0tWQiIx6JiirgSrisjE0eECdNf7Tav1Ntw=="
+ "resolved" "https://registry.npmjs.org/regexp-to-ast/-/regexp-to-ast-0.4.0.tgz"
+ "version" "0.4.0"
+
+"regexp.prototype.flags@^1.2.0", "regexp.prototype.flags@^1.3.1":
+ "integrity" "sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA=="
+ "resolved" "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.3.1.tgz"
+ "version" "1.3.1"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "define-properties" "^1.1.3"
+
+"regexpp@^3.2.0":
+ "integrity" "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg=="
+ "resolved" "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz"
+ "version" "3.2.0"
+
+"regexpu-core@^4.7.1":
+ "integrity" "sha512-1F6bYsoYiz6is+oz70NWur2Vlh9KWtswuRuzJOfeYUrfPX2o8n74AnUVaOGDbUqVGO9fNHu48/pjJO4sNVwsOg=="
+ "resolved" "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz"
+ "version" "4.8.0"
+ dependencies:
+ "regenerate" "^1.4.2"
+ "regenerate-unicode-properties" "^9.0.0"
+ "regjsgen" "^0.5.2"
+ "regjsparser" "^0.7.0"
+ "unicode-match-property-ecmascript" "^2.0.0"
+ "unicode-match-property-value-ecmascript" "^2.0.0"
+
+"regjsgen@^0.5.2":
+ "integrity" "sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A=="
+ "resolved" "https://registry.npmjs.org/regjsgen/-/regjsgen-0.5.2.tgz"
+ "version" "0.5.2"
+
+"regjsparser@^0.7.0":
+ "integrity" "sha512-A4pcaORqmNMDVwUjWoTzuhwMGpP+NykpfqAsEgI1FSH/EzC7lrN5TMd+kN8YCovX+jMpu8eaqXgXPCa0g8FQNQ=="
+ "resolved" "https://registry.npmjs.org/regjsparser/-/regjsparser-0.7.0.tgz"
+ "version" "0.7.0"
+ dependencies:
+ "jsesc" "~0.5.0"
+
+"relateurl@^0.2.7":
+ "integrity" "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk="
+ "resolved" "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz"
+ "version" "0.2.7"
+
+"remove-trailing-separator@^1.0.1":
+ "integrity" "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
+ "resolved" "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz"
+ "version" "1.1.0"
+
+"renderkid@^3.0.0":
+ "integrity" "sha512-q/7VIQA8lmM1hF+jn+sFSPWGlMkSAeNYcPLmDQx2zzuiDfaLrOmumR8iaUKlenFgh0XRPIUeSPlH3A+AW3Z5pg=="
+ "resolved" "https://registry.npmjs.org/renderkid/-/renderkid-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "css-select" "^4.1.3"
+ "dom-converter" "^0.2.0"
+ "htmlparser2" "^6.1.0"
+ "lodash" "^4.17.21"
+ "strip-ansi" "^6.0.1"
+
+"repeating@^2.0.0":
+ "integrity" "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo="
+ "resolved" "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "is-finite" "^1.0.0"
+
+"replace-ext@^1.0.0":
+ "integrity" "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw=="
+ "resolved" "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz"
+ "version" "1.0.1"
+
+"request@^2.74.0":
+ "integrity" "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw=="
+ "resolved" "https://registry.npmjs.org/request/-/request-2.88.2.tgz"
+ "version" "2.88.2"
+ dependencies:
+ "aws-sign2" "~0.7.0"
+ "aws4" "^1.8.0"
+ "caseless" "~0.12.0"
+ "combined-stream" "~1.0.6"
+ "extend" "~3.0.2"
+ "forever-agent" "~0.6.1"
+ "form-data" "~2.3.2"
+ "har-validator" "~5.1.3"
+ "http-signature" "~1.2.0"
+ "is-typedarray" "~1.0.0"
+ "isstream" "~0.1.2"
+ "json-stringify-safe" "~5.0.1"
+ "mime-types" "~2.1.19"
+ "oauth-sign" "~0.9.0"
+ "performance-now" "^2.1.0"
+ "qs" "~6.5.2"
+ "safe-buffer" "^5.1.2"
+ "tough-cookie" "~2.5.0"
+ "tunnel-agent" "^0.6.0"
+ "uuid" "^3.3.2"
+
+"require-directory@^2.1.1":
+ "integrity" "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
+ "resolved" "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
+ "version" "2.1.1"
+
+"require-from-string@^2.0.2":
+ "integrity" "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw=="
+ "resolved" "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz"
+ "version" "2.0.2"
+
+"require-main-filename@^2.0.0":
+ "integrity" "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg=="
+ "resolved" "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz"
+ "version" "2.0.0"
+
+"requires-port@^1.0.0":
+ "integrity" "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8="
+ "resolved" "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz"
+ "version" "1.0.0"
+
+"reselect@^4.1.5":
+ "integrity" "sha512-uVdlz8J7OO+ASpBYoz1Zypgx0KasCY20H+N8JD13oUMtPvSHQuscrHop4KbXrbsBcdB9Ds7lVK7eRkBIfO43vQ=="
+ "resolved" "https://registry.npmjs.org/reselect/-/reselect-4.1.5.tgz"
+ "version" "4.1.5"
+
+"resolve-cwd@^3.0.0":
+ "integrity" "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg=="
+ "resolved" "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "resolve-from" "^5.0.0"
+
+"resolve-from@^4.0.0":
+ "integrity" "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
+ "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz"
+ "version" "4.0.0"
+
+"resolve-from@^5.0.0":
+ "integrity" "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw=="
+ "resolved" "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz"
+ "version" "5.0.0"
+
+"resolve-pathname@^3.0.0":
+ "integrity" "sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng=="
+ "resolved" "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-3.0.0.tgz"
+ "version" "3.0.0"
+
+"resolve.exports@^1.1.0":
+ "integrity" "sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ=="
+ "resolved" "https://registry.npmjs.org/resolve.exports/-/resolve.exports-1.1.0.tgz"
+ "version" "1.1.0"
+
+"resolve@^1.1.6":
+ "integrity" "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA=="
+ "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz"
+ "version" "1.21.0"
+ dependencies:
+ "is-core-module" "^2.8.0"
+ "path-parse" "^1.0.7"
+ "supports-preserve-symlinks-flag" "^1.0.0"
+
+"resolve@^1.10.0":
+ "integrity" "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA=="
+ "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz"
+ "version" "1.21.0"
+ dependencies:
+ "is-core-module" "^2.8.0"
+ "path-parse" "^1.0.7"
+ "supports-preserve-symlinks-flag" "^1.0.0"
+
+"resolve@^1.14.2":
+ "integrity" "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA=="
+ "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz"
+ "version" "1.21.0"
+ dependencies:
+ "is-core-module" "^2.8.0"
+ "path-parse" "^1.0.7"
+ "supports-preserve-symlinks-flag" "^1.0.0"
+
+"resolve@^1.19.0":
+ "integrity" "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA=="
+ "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz"
+ "version" "1.21.0"
+ dependencies:
+ "is-core-module" "^2.8.0"
+ "path-parse" "^1.0.7"
+ "supports-preserve-symlinks-flag" "^1.0.0"
+
+"resolve@^1.20.0":
+ "integrity" "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA=="
+ "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz"
+ "version" "1.21.0"
+ dependencies:
+ "is-core-module" "^2.8.0"
+ "path-parse" "^1.0.7"
+ "supports-preserve-symlinks-flag" "^1.0.0"
+
+"resolve@^1.9.0":
+ "integrity" "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA=="
+ "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz"
+ "version" "1.21.0"
+ dependencies:
+ "is-core-module" "^2.8.0"
+ "path-parse" "^1.0.7"
+ "supports-preserve-symlinks-flag" "^1.0.0"
+
+"resolve@^2.0.0-next.3":
+ "integrity" "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q=="
+ "resolved" "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz"
+ "version" "2.0.0-next.3"
+ dependencies:
+ "is-core-module" "^2.2.0"
+ "path-parse" "^1.0.6"
+
+"resolve@1.1.x":
+ "integrity" "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs="
+ "resolved" "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz"
+ "version" "1.1.7"
+
+"resp-modifier@6.0.2":
+ "integrity" "sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08="
+ "resolved" "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz"
+ "version" "6.0.2"
+ dependencies:
+ "debug" "^2.2.0"
+ "minimatch" "^3.0.2"
+
+"restore-cursor@^1.0.1":
+ "integrity" "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE="
+ "resolved" "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz"
+ "version" "1.0.1"
+ dependencies:
+ "exit-hook" "^1.0.0"
+ "onetime" "^1.0.0"
+
+"restore-cursor@^2.0.0":
+ "integrity" "sha1-n37ih/gv0ybU/RYpI9YhKe7g368="
+ "resolved" "https://registry.npmjs.org/restore-cursor/-/restore-cursor-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "onetime" "^2.0.0"
+ "signal-exit" "^3.0.2"
+
+"restore-cursor@^3.1.0":
+ "integrity" "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA=="
+ "resolved" "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz"
+ "version" "3.1.0"
+ dependencies:
+ "onetime" "^5.1.0"
+ "signal-exit" "^3.0.2"
+
+"ret@~0.1.10":
+ "integrity" "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg=="
+ "resolved" "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz"
+ "version" "0.1.15"
+
+"retry@^0.13.1":
+ "integrity" "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="
+ "resolved" "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz"
+ "version" "0.13.1"
+
+"reusify@^1.0.4":
+ "integrity" "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw=="
+ "resolved" "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz"
+ "version" "1.0.4"
+
+"rimraf@^2.2.8":
+ "integrity" "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="
+ "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz"
+ "version" "2.7.1"
+ dependencies:
+ "glob" "^7.1.3"
+
+"rimraf@^2.6.2":
+ "integrity" "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w=="
+ "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz"
+ "version" "2.7.1"
+ dependencies:
+ "glob" "^7.1.3"
+
+"rimraf@^3.0.0", "rimraf@^3.0.2", "rimraf@3.0.2":
+ "integrity" "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA=="
+ "resolved" "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz"
+ "version" "3.0.2"
+ dependencies:
+ "glob" "^7.1.3"
+
+"rollup-plugin-terser@^7.0.0":
+ "integrity" "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ=="
+ "resolved" "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz"
+ "version" "7.0.2"
+ dependencies:
+ "@babel/code-frame" "^7.10.4"
+ "jest-worker" "^26.2.1"
+ "serialize-javascript" "^4.0.0"
+ "terser" "^5.0.0"
+
+"rollup@^1.20.0 || ^2.0.0", "rollup@^1.20.0||^2.0.0", "rollup@^2.0.0", "rollup@^2.43.1":
+ "integrity" "sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ=="
+ "resolved" "https://registry.npmjs.org/rollup/-/rollup-2.63.0.tgz"
+ "version" "2.63.0"
+ optionalDependencies:
+ "fsevents" "~2.3.2"
+
+"run-async@^0.1.0":
+ "integrity" "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k="
+ "resolved" "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz"
+ "version" "0.1.0"
+ dependencies:
+ "once" "^1.3.0"
+
+"run-async@^2.0.0":
+ "integrity" "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ=="
+ "resolved" "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz"
+ "version" "2.4.1"
+
+"run-async@^2.2.0":
+ "integrity" "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ=="
+ "resolved" "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz"
+ "version" "2.4.1"
+
+"run-parallel@^1.1.9":
+ "integrity" "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA=="
+ "resolved" "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz"
+ "version" "1.2.0"
+ dependencies:
+ "queue-microtask" "^1.2.2"
+
+"rx-lite-aggregates@^4.0.8":
+ "integrity" "sha1-dTuHqJoRyVRnxKwWJsTvxOBcZ74="
+ "resolved" "https://registry.npmjs.org/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz"
+ "version" "4.0.8"
+ dependencies:
+ "rx-lite" "*"
+
+"rx-lite@*", "rx-lite@^3.1.2":
+ "integrity" "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI="
+ "resolved" "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz"
+ "version" "3.1.2"
+
+"rx-lite@^4.0.8":
+ "integrity" "sha1-Cx4Rr4vESDbwSmQH6S2kJGe3lEQ="
+ "resolved" "https://registry.npmjs.org/rx-lite/-/rx-lite-4.0.8.tgz"
+ "version" "4.0.8"
+
+"rx@^4.1.0", "rx@4.1.0":
+ "integrity" "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I="
+ "resolved" "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz"
+ "version" "4.1.0"
+
+"rxjs@^5.5.6":
+ "integrity" "sha512-xx2itnL5sBbqeeiVgNPVuQQ1nC8Jp2WfNJhXWHmElW9YmrpS9UVnNzhP3EH3HFqexO5Tlp8GhYY+WEcqcVMvGw=="
+ "resolved" "https://registry.npmjs.org/rxjs/-/rxjs-5.5.12.tgz"
+ "version" "5.5.12"
+ dependencies:
+ "symbol-observable" "1.0.1"
+
+"rxjs@^6.6.3":
+ "integrity" "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ=="
+ "resolved" "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz"
+ "version" "6.6.7"
+ dependencies:
+ "tslib" "^1.9.0"
+
+"rxjs@^7.1.0":
+ "integrity" "sha512-KExVEeZWxMZnZhUZtsJcFwz8IvPvgu4G2Z2QyqjZQzUGr32KDYuSxrEYO4w3tFFNbfLozcrKUTvTPi+E9ywJkQ=="
+ "resolved" "https://registry.npmjs.org/rxjs/-/rxjs-7.5.1.tgz"
+ "version" "7.5.1"
+ dependencies:
+ "tslib" "^2.1.0"
+
+"safe-buffer@^5.0.1", "safe-buffer@^5.1.0", "safe-buffer@^5.1.1", "safe-buffer@^5.1.2", "safe-buffer@>=5.1.0", "safe-buffer@~5.1.0", "safe-buffer@~5.1.1", "safe-buffer@5.1.2":
+ "integrity" "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+ "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz"
+ "version" "5.1.2"
+
+"safe-buffer@5.2.1":
+ "integrity" "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+ "resolved" "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz"
+ "version" "5.2.1"
+
+"safer-buffer@^2.0.2", "safer-buffer@^2.1.0", "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", "safer-buffer@~2.1.0":
+ "integrity" "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ "resolved" "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz"
+ "version" "2.1.2"
+
+"sanitize-html@^2.3.1":
+ "integrity" "sha512-DzjSz3H5qDntD7s1TcWCSoRPmNR8UmA+y+xZQOvWgjATe2Br9ZW73+vD3Pj6Snrg0RuEuJdXgrKvnYuiuixRkA=="
+ "resolved" "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.6.1.tgz"
+ "version" "2.6.1"
+ dependencies:
+ "deepmerge" "^4.2.2"
+ "escape-string-regexp" "^4.0.0"
+ "htmlparser2" "^6.0.0"
+ "is-plain-object" "^5.0.0"
+ "parse-srcset" "^1.0.2"
+ "postcss" "^8.3.11"
+
+"sass-loader@12.4.0":
+ "integrity" "sha512-7xN+8khDIzym1oL9XyS6zP6Ges+Bo2B2xbPrjdMHEYyV3AQYhd/wXeru++3ODHF0zMjYmVadblSKrPrjEkL8mg=="
+ "resolved" "https://registry.npmjs.org/sass-loader/-/sass-loader-12.4.0.tgz"
+ "version" "12.4.0"
+ dependencies:
+ "klona" "^2.0.4"
+ "neo-async" "^2.6.2"
+
+"sass@^1.3.0", "sass@1.45.2":
+ "integrity" "sha512-cKfs+F9AMPAFlbbTXNsbGvg3y58nV0mXA3E94jqaySKcC8Kq3/8983zVKQ0TLMUrHw7hF9Tnd3Bz9z5Xgtrl9g=="
+ "resolved" "https://registry.npmjs.org/sass/-/sass-1.45.2.tgz"
+ "version" "1.45.2"
+ dependencies:
+ "chokidar" ">=3.0.0 <4.0.0"
+ "immutable" "^4.0.0"
+ "source-map-js" ">=0.6.2 <2.0.0"
+
+"saxes@^5.0.1":
+ "integrity" "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw=="
+ "resolved" "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "xmlchars" "^2.2.0"
+
+"scheduler@^0.20.2":
+ "integrity" "sha512-2eWfGgAqqWFGqtdMmcL5zCMK1U8KlXv8SQFGglL3CEtd0aDVDWgeF/YoCmvln55m5zSk3J/20hTaSBeSObsQDQ=="
+ "resolved" "https://registry.npmjs.org/scheduler/-/scheduler-0.20.2.tgz"
+ "version" "0.20.2"
+ dependencies:
+ "loose-envify" "^1.1.0"
+ "object-assign" "^4.1.1"
+
+"schema-utils@^3.0.0":
+ "integrity" "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw=="
+ "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz"
+ "version" "3.1.1"
+ dependencies:
+ "@types/json-schema" "^7.0.8"
+ "ajv" "^6.12.5"
+ "ajv-keywords" "^3.5.2"
+
+"schema-utils@^3.1.0":
+ "integrity" "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw=="
+ "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz"
+ "version" "3.1.1"
+ dependencies:
+ "@types/json-schema" "^7.0.8"
+ "ajv" "^6.12.5"
+ "ajv-keywords" "^3.5.2"
+
+"schema-utils@^3.1.1":
+ "integrity" "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw=="
+ "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz"
+ "version" "3.1.1"
+ dependencies:
+ "@types/json-schema" "^7.0.8"
+ "ajv" "^6.12.5"
+ "ajv-keywords" "^3.5.2"
+
+"schema-utils@^4.0.0":
+ "integrity" "sha512-1edyXKgh6XnJsJSQ8mKWXnN/BVaIbFMLpouRUrXgVq7WYne5kw3MW7UPhO44uRXQSIpTSXoJbmrR2X0w9kUTyg=="
+ "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "@types/json-schema" "^7.0.9"
+ "ajv" "^8.8.0"
+ "ajv-formats" "^2.1.1"
+ "ajv-keywords" "^5.0.0"
+
+"schema-utils@2.7.0":
+ "integrity" "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A=="
+ "resolved" "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz"
+ "version" "2.7.0"
+ dependencies:
+ "@types/json-schema" "^7.0.4"
+ "ajv" "^6.12.2"
+ "ajv-keywords" "^3.4.1"
+
+"scoped-regex@^1.0.0":
+ "integrity" "sha1-o0a7Gs1CB65wvXwMfKnlZra63bg="
+ "resolved" "https://registry.npmjs.org/scoped-regex/-/scoped-regex-1.0.0.tgz"
+ "version" "1.0.0"
+
+"select-hose@^2.0.0":
+ "integrity" "sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo="
+ "resolved" "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz"
+ "version" "2.0.0"
+
+"selfsigned@^1.10.11":
+ "integrity" "sha512-aVmbPOfViZqOZPgRBT0+3u4yZFHpmnIghLMlAcb5/xhp5ZtB/RVnKhz5vl2M32CLXAqR4kha9zfhNg0Lf/sxKA=="
+ "resolved" "https://registry.npmjs.org/selfsigned/-/selfsigned-1.10.11.tgz"
+ "version" "1.10.11"
+ dependencies:
+ "node-forge" "^0.10.0"
+
+"semver@^5.0.1":
+ "integrity" "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ "resolved" "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz"
+ "version" "5.7.1"
+
+"semver@^6.0.0":
+ "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
+ "version" "6.3.0"
+
+"semver@^6.1.1":
+ "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
+ "version" "6.3.0"
+
+"semver@^6.1.2":
+ "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
+ "version" "6.3.0"
+
+"semver@^6.3.0":
+ "integrity" "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
+ "resolved" "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz"
+ "version" "6.3.0"
+
+"semver@^7.2.1", "semver@^7.3.2", "semver@^7.3.4", "semver@^7.3.5", "semver@7.x":
+ "integrity" "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ=="
+ "resolved" "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz"
+ "version" "7.3.5"
+ dependencies:
+ "lru-cache" "^6.0.0"
+
+"semver@2 || 3 || 4 || 5":
+ "integrity" "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
+ "resolved" "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz"
+ "version" "5.7.1"
+
+"semver@5.4.1":
+ "integrity" "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
+ "resolved" "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz"
+ "version" "5.4.1"
+
+"semver@7.0.0":
+ "integrity" "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A=="
+ "resolved" "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz"
+ "version" "7.0.0"
+
+"send@0.16.2":
+ "integrity" "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw=="
+ "resolved" "https://registry.npmjs.org/send/-/send-0.16.2.tgz"
+ "version" "0.16.2"
+ dependencies:
+ "debug" "2.6.9"
+ "depd" "~1.1.2"
+ "destroy" "~1.0.4"
+ "encodeurl" "~1.0.2"
+ "escape-html" "~1.0.3"
+ "etag" "~1.8.1"
+ "fresh" "0.5.2"
+ "http-errors" "~1.6.2"
+ "mime" "1.4.1"
+ "ms" "2.0.0"
+ "on-finished" "~2.3.0"
+ "range-parser" "~1.2.0"
+ "statuses" "~1.4.0"
+
+"send@0.17.2":
+ "integrity" "sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww=="
+ "resolved" "https://registry.npmjs.org/send/-/send-0.17.2.tgz"
+ "version" "0.17.2"
+ dependencies:
+ "debug" "2.6.9"
+ "depd" "~1.1.2"
+ "destroy" "~1.0.4"
+ "encodeurl" "~1.0.2"
+ "escape-html" "~1.0.3"
+ "etag" "~1.8.1"
+ "fresh" "0.5.2"
+ "http-errors" "1.8.1"
+ "mime" "1.6.0"
+ "ms" "2.1.3"
+ "on-finished" "~2.3.0"
+ "range-parser" "~1.2.1"
+ "statuses" "~1.5.0"
+
+"serialize-javascript@^4.0.0":
+ "integrity" "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw=="
+ "resolved" "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "randombytes" "^2.1.0"
+
+"serialize-javascript@^6.0.0":
+ "integrity" "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag=="
+ "resolved" "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz"
+ "version" "6.0.0"
+ dependencies:
+ "randombytes" "^2.1.0"
+
+"serve-index@^1.9.1", "serve-index@1.9.1":
+ "integrity" "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk="
+ "resolved" "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz"
+ "version" "1.9.1"
+ dependencies:
+ "accepts" "~1.3.4"
+ "batch" "0.6.1"
+ "debug" "2.6.9"
+ "escape-html" "~1.0.3"
+ "http-errors" "~1.6.2"
+ "mime-types" "~2.1.17"
+ "parseurl" "~1.3.2"
+
+"serve-static@1.13.2":
+ "integrity" "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw=="
+ "resolved" "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz"
+ "version" "1.13.2"
+ dependencies:
+ "encodeurl" "~1.0.2"
+ "escape-html" "~1.0.3"
+ "parseurl" "~1.3.2"
+ "send" "0.16.2"
+
+"serve-static@1.14.2":
+ "integrity" "sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ=="
+ "resolved" "https://registry.npmjs.org/serve-static/-/serve-static-1.14.2.tgz"
+ "version" "1.14.2"
+ dependencies:
+ "encodeurl" "~1.0.2"
+ "escape-html" "~1.0.3"
+ "parseurl" "~1.3.3"
+ "send" "0.17.2"
+
+"server-destroy@1.0.1":
+ "integrity" "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0="
+ "resolved" "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz"
+ "version" "1.0.1"
+
+"set-blocking@^2.0.0":
+ "integrity" "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
+ "resolved" "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz"
+ "version" "2.0.0"
+
+"setprototypeof@1.1.0":
+ "integrity" "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ=="
+ "resolved" "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz"
+ "version" "1.1.0"
+
+"setprototypeof@1.2.0":
+ "integrity" "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
+ "resolved" "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz"
+ "version" "1.2.0"
+
+"shallow-clone@^3.0.0":
+ "integrity" "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA=="
+ "resolved" "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz"
+ "version" "3.0.1"
+ dependencies:
+ "kind-of" "^6.0.2"
+
+"shebang-command@^1.2.0":
+ "integrity" "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo="
+ "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz"
+ "version" "1.2.0"
+ dependencies:
+ "shebang-regex" "^1.0.0"
+
+"shebang-command@^2.0.0":
+ "integrity" "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="
+ "resolved" "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "shebang-regex" "^3.0.0"
+
+"shebang-regex@^1.0.0":
+ "integrity" "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM="
+ "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz"
+ "version" "1.0.0"
+
+"shebang-regex@^3.0.0":
+ "integrity" "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
+ "resolved" "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz"
+ "version" "3.0.0"
+
+"shelljs@^0.7.8", "shelljs@0.7.8":
+ "integrity" "sha1-3svPh0sNHl+3LhSxZKloMEjprLM="
+ "resolved" "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz"
+ "version" "0.7.8"
+ dependencies:
+ "glob" "^7.0.0"
+ "interpret" "^1.0.0"
+ "rechoir" "^0.6.2"
+
+"shellwords@^0.1.1":
+ "integrity" "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww=="
+ "resolved" "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz"
+ "version" "0.1.1"
+
+"side-channel@^1.0.4":
+ "integrity" "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw=="
+ "resolved" "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz"
+ "version" "1.0.4"
+ dependencies:
+ "call-bind" "^1.0.0"
+ "get-intrinsic" "^1.0.2"
+ "object-inspect" "^1.9.0"
+
+"signal-exit@^3.0.0", "signal-exit@^3.0.2", "signal-exit@^3.0.3":
+ "integrity" "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ=="
+ "resolved" "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz"
+ "version" "3.0.6"
+
+"simple-progress-webpack-plugin@2.0.0":
+ "integrity" "sha512-Ji8b05YHc9R8iHHbEX8kOqvR2CB8bUqqqP481DbY+j5ImqBhLXk9sXFZZdcSEK3Ld0hZl9i+5CzXWLXzw1NV9g=="
+ "resolved" "https://registry.npmjs.org/simple-progress-webpack-plugin/-/simple-progress-webpack-plugin-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "chalk" "4.1.x"
+ "figures" "3.2.x"
+ "log-update" "4.0.x"
+
+"sinon@12.0.1":
+ "integrity" "sha512-iGu29Xhym33ydkAT+aNQFBINakjq69kKO6ByPvTsm3yyIACfyQttRTP03aBP/I8GfhFmLzrnKwNNkr0ORb1udg=="
+ "resolved" "https://registry.npmjs.org/sinon/-/sinon-12.0.1.tgz"
+ "version" "12.0.1"
+ dependencies:
+ "@sinonjs/commons" "^1.8.3"
+ "@sinonjs/fake-timers" "^8.1.0"
+ "@sinonjs/samsam" "^6.0.2"
+ "diff" "^5.0.0"
+ "nise" "^5.1.0"
+ "supports-color" "^7.2.0"
+
+"sisteransi@^1.0.5":
+ "integrity" "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
+ "resolved" "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz"
+ "version" "1.0.5"
+
+"slash@^3.0.0":
+ "integrity" "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q=="
+ "resolved" "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz"
+ "version" "3.0.0"
+
+"slash@^4.0.0":
+ "integrity" "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew=="
+ "resolved" "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz"
+ "version" "4.0.0"
+
+"slice-ansi@^4.0.0":
+ "integrity" "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ=="
+ "resolved" "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "ansi-styles" "^4.0.0"
+ "astral-regex" "^2.0.0"
+ "is-fullwidth-code-point" "^3.0.0"
+
+"slide@^1.1.5":
+ "integrity" "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
+ "resolved" "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz"
+ "version" "1.1.6"
+
+"socket.io-adapter@~1.1.0":
+ "integrity" "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g=="
+ "resolved" "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz"
+ "version" "1.1.2"
+
+"socket.io-client@^2.4.0", "socket.io-client@2.4.0":
+ "integrity" "sha512-M6xhnKQHuuZd4Ba9vltCLT9oa+YvTsP8j9NcEiLElfIg8KeYPyhWOes6x4t+LTAC8enQbE/995AdTem2uNyKKQ=="
+ "resolved" "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.4.0.tgz"
+ "version" "2.4.0"
+ dependencies:
+ "backo2" "1.0.2"
+ "component-bind" "1.0.0"
+ "component-emitter" "~1.3.0"
+ "debug" "~3.1.0"
+ "engine.io-client" "~3.5.0"
+ "has-binary2" "~1.0.2"
+ "indexof" "0.0.1"
+ "parseqs" "0.0.6"
+ "parseuri" "0.0.6"
+ "socket.io-parser" "~3.3.0"
+ "to-array" "0.1.4"
+
+"socket.io-parser@~3.3.0":
+ "integrity" "sha512-FJvDBuOALxdCI9qwRrO/Rfp9yfndRtc1jSgVgV8FDraihmSP/MLGD5PEuJrNfjALvcQ+vMDM/33AWOYP/JSjDg=="
+ "resolved" "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.3.2.tgz"
+ "version" "3.3.2"
+ dependencies:
+ "component-emitter" "~1.3.0"
+ "debug" "~3.1.0"
+ "isarray" "2.0.1"
+
+"socket.io-parser@~3.4.0":
+ "integrity" "sha512-11hMgzL+WCLWf1uFtHSNvliI++tcRUWdoeYuwIl+Axvwy9z2gQM+7nJyN3STj1tLj5JyIUH8/gpDGxzAlDdi0A=="
+ "resolved" "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.4.1.tgz"
+ "version" "3.4.1"
+ dependencies:
+ "component-emitter" "1.2.1"
+ "debug" "~4.1.0"
+ "isarray" "2.0.1"
+
+"socket.io@2.4.0":
+ "integrity" "sha512-9UPJ1UTvKayuQfVv2IQ3k7tCQC/fboDyIK62i99dAQIyHKaBsNdTpwHLgKJ6guRWxRtC9H+138UwpaGuQO9uWQ=="
+ "resolved" "https://registry.npmjs.org/socket.io/-/socket.io-2.4.0.tgz"
+ "version" "2.4.0"
+ dependencies:
+ "debug" "~4.1.0"
+ "engine.io" "~3.5.0"
+ "has-binary2" "~1.0.2"
+ "socket.io-adapter" "~1.1.0"
+ "socket.io-client" "2.4.0"
+ "socket.io-parser" "~3.4.0"
+
+"sockjs@^0.3.21":
+ "integrity" "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ=="
+ "resolved" "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz"
+ "version" "0.3.24"
+ dependencies:
+ "faye-websocket" "^0.11.3"
+ "uuid" "^8.3.2"
+ "websocket-driver" "^0.7.4"
+
+"sort-object-keys@^1.1.3":
+ "integrity" "sha512-855pvK+VkU7PaKYPc+Jjnmt4EzejQHyhhF33q31qG8x7maDzkeFhAAThdCYay11CISO+qAMwjOBP+fPZe0IPyg=="
+ "resolved" "https://registry.npmjs.org/sort-object-keys/-/sort-object-keys-1.1.3.tgz"
+ "version" "1.1.3"
+
+"sort-package-json@1.53.1":
+ "integrity" "sha512-ltLORrQuuPMpy23YkWCA8fO7zBOxM4P1j9LcGxci4K2Fk8jmSyCA/ATU6CFyy8qR2HQRx4RBYWzoi78FU/Anuw=="
+ "resolved" "https://registry.npmjs.org/sort-package-json/-/sort-package-json-1.53.1.tgz"
+ "version" "1.53.1"
+ dependencies:
+ "detect-indent" "^6.0.0"
+ "detect-newline" "3.1.0"
+ "git-hooks-list" "1.0.3"
+ "globby" "10.0.0"
+ "is-plain-obj" "2.1.0"
+ "sort-object-keys" "^1.1.3"
+
+"source-list-map@^2.0.0":
+ "integrity" "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw=="
+ "resolved" "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz"
+ "version" "2.0.1"
+
+"source-map-js@^0.6.2":
+ "integrity" "sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug=="
+ "resolved" "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz"
+ "version" "0.6.2"
+
+"source-map-js@^1.0.1", "source-map-js@>=0.6.2 <2.0.0":
+ "integrity" "sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA=="
+ "resolved" "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.1.tgz"
+ "version" "1.0.1"
+
+"source-map-loader@3.0.0":
+ "integrity" "sha512-GKGWqWvYr04M7tn8dryIWvb0s8YM41z82iQv01yBtIylgxax0CwvSy6gc2Y02iuXwEfGWRlMicH0nvms9UZphw=="
+ "resolved" "https://registry.npmjs.org/source-map-loader/-/source-map-loader-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "abab" "^2.0.5"
+ "iconv-lite" "^0.6.2"
+ "source-map-js" "^0.6.2"
+
+"source-map-support@^0.5.6", "source-map-support@~0.5.20":
+ "integrity" "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="
+ "resolved" "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz"
+ "version" "0.5.21"
+ dependencies:
+ "buffer-from" "^1.0.0"
+ "source-map" "^0.6.0"
+
+"source-map-url@^0.4.0":
+ "integrity" "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw=="
+ "resolved" "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.1.tgz"
+ "version" "0.4.1"
+
+"source-map@^0.5.0":
+ "integrity" "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
+ "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz"
+ "version" "0.5.7"
+
+"source-map@^0.6.0", "source-map@^0.6.1", "source-map@~0.6.0", "source-map@~0.6.1":
+ "integrity" "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="
+ "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz"
+ "version" "0.6.1"
+
+"source-map@^0.7.3":
+ "integrity" "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
+ "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz"
+ "version" "0.7.3"
+
+"source-map@^0.8.0-beta.0":
+ "integrity" "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA=="
+ "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz"
+ "version" "0.8.0-beta.0"
+ dependencies:
+ "whatwg-url" "^7.0.0"
+
+"source-map@~0.2.0":
+ "integrity" "sha1-2rc/vPwrqBm03gO9b26qSBZLP50="
+ "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz"
+ "version" "0.2.0"
+ dependencies:
+ "amdefine" ">=0.0.4"
+
+"source-map@~0.7.2":
+ "integrity" "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ=="
+ "resolved" "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz"
+ "version" "0.7.3"
+
+"sourcemap-codec@^1.4.4":
+ "integrity" "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA=="
+ "resolved" "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz"
+ "version" "1.4.8"
+
+"sourcemap-istanbul-instrumenter-loader@0.2.0":
+ "integrity" "sha1-j9cuir0W3tWJGKdHTbW7PQ27ys0="
+ "resolved" "https://registry.npmjs.org/sourcemap-istanbul-instrumenter-loader/-/sourcemap-istanbul-instrumenter-loader-0.2.0.tgz"
+ "version" "0.2.0"
+ dependencies:
+ "istanbul" "0.x.x"
+ "loader-utils" "0.x.x"
+ "object-assign" "4.x.x"
+
+"spawn-command@^0.0.2-1":
+ "integrity" "sha1-YvXpRmmBwbeW3Fkpk34RycaSG9A="
+ "resolved" "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2-1.tgz"
+ "version" "0.0.2-1"
+
+"spawn-sync@^1.0.15":
+ "integrity" "sha1-sAeZVX63+wyDdsKdROih6mfldHY="
+ "resolved" "https://registry.npmjs.org/spawn-sync/-/spawn-sync-1.0.15.tgz"
+ "version" "1.0.15"
+ dependencies:
+ "concat-stream" "^1.4.7"
+ "os-shim" "^0.1.2"
+
+"spdx-correct@^3.0.0":
+ "integrity" "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w=="
+ "resolved" "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz"
+ "version" "3.1.1"
+ dependencies:
+ "spdx-expression-parse" "^3.0.0"
+ "spdx-license-ids" "^3.0.0"
+
+"spdx-exceptions@^2.1.0":
+ "integrity" "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A=="
+ "resolved" "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz"
+ "version" "2.3.0"
+
+"spdx-expression-parse@^3.0.0":
+ "integrity" "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q=="
+ "resolved" "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz"
+ "version" "3.0.1"
+ dependencies:
+ "spdx-exceptions" "^2.1.0"
+ "spdx-license-ids" "^3.0.0"
+
+"spdx-license-ids@^3.0.0":
+ "integrity" "sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g=="
+ "resolved" "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.11.tgz"
+ "version" "3.0.11"
+
+"spdy-transport@^3.0.0":
+ "integrity" "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw=="
+ "resolved" "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "debug" "^4.1.0"
+ "detect-node" "^2.0.4"
+ "hpack.js" "^2.1.6"
+ "obuf" "^1.1.2"
+ "readable-stream" "^3.0.6"
+ "wbuf" "^1.7.3"
+
+"spdy@^4.0.2":
+ "integrity" "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA=="
+ "resolved" "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz"
+ "version" "4.0.2"
+ dependencies:
+ "debug" "^4.1.0"
+ "handle-thing" "^2.0.0"
+ "http-deceiver" "^1.2.7"
+ "select-hose" "^2.0.0"
+ "spdy-transport" "^3.0.0"
+
+"sprintf-js@~1.0.2":
+ "integrity" "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+ "resolved" "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
+ "version" "1.0.3"
+
+"sshpk@^1.7.0":
+ "integrity" "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg=="
+ "resolved" "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz"
+ "version" "1.16.1"
+ dependencies:
+ "asn1" "~0.2.3"
+ "assert-plus" "^1.0.0"
+ "bcrypt-pbkdf" "^1.0.0"
+ "dashdash" "^1.12.0"
+ "ecc-jsbn" "~0.1.1"
+ "getpass" "^0.1.1"
+ "jsbn" "~0.1.0"
+ "safer-buffer" "^2.0.2"
+ "tweetnacl" "~0.14.0"
+
+"stable@^0.1.8":
+ "integrity" "sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w=="
+ "resolved" "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz"
+ "version" "0.1.8"
+
+"stack-trace@0.0.x":
+ "integrity" "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA="
+ "resolved" "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz"
+ "version" "0.0.10"
+
+"stack-utils@^2.0.3":
+ "integrity" "sha512-xrQcmYhOsn/1kX+Vraq+7j4oE2j/6BFscZ0etmYg81xuM8Gq0022Pxb8+IqgOFUIaxHs0KaSb7T1+OegiNrNFA=="
+ "resolved" "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz"
+ "version" "2.0.5"
+ dependencies:
+ "escape-string-regexp" "^2.0.0"
+
+"statuses@>= 1.4.0 < 2", "statuses@~1.4.0":
+ "integrity" "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew=="
+ "resolved" "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz"
+ "version" "1.4.0"
+
+"statuses@>= 1.5.0 < 2":
+ "integrity" "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ "resolved" "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz"
+ "version" "1.5.0"
+
+"statuses@~1.3.1":
+ "integrity" "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
+ "resolved" "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz"
+ "version" "1.3.1"
+
+"statuses@~1.5.0":
+ "integrity" "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+ "resolved" "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz"
+ "version" "1.5.0"
+
+"stream-throttle@^0.1.3":
+ "integrity" "sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM="
+ "resolved" "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz"
+ "version" "0.1.3"
+ dependencies:
+ "commander" "^2.2.0"
+ "limiter" "^1.0.5"
+
+"string_decoder@^1.1.1", "string_decoder@~1.1.1":
+ "integrity" "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg=="
+ "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz"
+ "version" "1.1.1"
+ dependencies:
+ "safe-buffer" "~5.1.0"
+
+"string_decoder@~0.10.x":
+ "integrity" "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
+ "resolved" "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+ "version" "0.10.31"
+
+"string-length@^4.0.1":
+ "integrity" "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ=="
+ "resolved" "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz"
+ "version" "4.0.2"
+ dependencies:
+ "char-regex" "^1.0.2"
+ "strip-ansi" "^6.0.0"
+
+"string-template@~0.2.1":
+ "integrity" "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0="
+ "resolved" "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz"
+ "version" "0.2.1"
+
+"string-width@^1.0.1":
+ "integrity" "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M="
+ "resolved" "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "code-point-at" "^1.0.0"
+ "is-fullwidth-code-point" "^1.0.0"
+ "strip-ansi" "^3.0.0"
+
+"string-width@^2.0.0", "string-width@^2.1.0":
+ "integrity" "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw=="
+ "resolved" "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz"
+ "version" "2.1.1"
+ dependencies:
+ "is-fullwidth-code-point" "^2.0.0"
+ "strip-ansi" "^4.0.0"
+
+"string-width@^4.1.0", "string-width@^4.2.0":
+ "integrity" "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="
+ "resolved" "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz"
+ "version" "4.2.3"
+ dependencies:
+ "emoji-regex" "^8.0.0"
+ "is-fullwidth-code-point" "^3.0.0"
+ "strip-ansi" "^6.0.1"
+
+"string.prototype.matchall@^4.0.6":
+ "integrity" "sha512-6WgDX8HmQqvEd7J+G6VtAahhsQIssiZ8zl7zKh1VDMFyL3hRTJP4FTNA3RbIp2TOQ9AYNDcc7e3fH0Qbup+DBg=="
+ "resolved" "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.6.tgz"
+ "version" "4.0.6"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "define-properties" "^1.1.3"
+ "es-abstract" "^1.19.1"
+ "get-intrinsic" "^1.1.1"
+ "has-symbols" "^1.0.2"
+ "internal-slot" "^1.0.3"
+ "regexp.prototype.flags" "^1.3.1"
+ "side-channel" "^1.0.4"
+
+"string.prototype.trimend@^1.0.4":
+ "integrity" "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A=="
+ "resolved" "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz"
+ "version" "1.0.4"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "define-properties" "^1.1.3"
+
+"string.prototype.trimstart@^1.0.4":
+ "integrity" "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw=="
+ "resolved" "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz"
+ "version" "1.0.4"
+ dependencies:
+ "call-bind" "^1.0.2"
+ "define-properties" "^1.1.3"
+
+"stringify-object@^3.3.0":
+ "integrity" "sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw=="
+ "resolved" "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz"
+ "version" "3.3.0"
+ dependencies:
+ "get-own-enumerable-property-symbols" "^3.0.0"
+ "is-obj" "^1.0.1"
+ "is-regexp" "^1.0.0"
+
+"strip-ansi@^3.0.0":
+ "integrity" "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8="
+ "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz"
+ "version" "3.0.1"
+ dependencies:
+ "ansi-regex" "^2.0.0"
+
+"strip-ansi@^4.0.0":
+ "integrity" "sha1-qEeQIusaw2iocTibY1JixQXuNo8="
+ "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "ansi-regex" "^3.0.0"
+
+"strip-ansi@^6.0.0", "strip-ansi@^6.0.1":
+ "integrity" "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="
+ "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz"
+ "version" "6.0.1"
+ dependencies:
+ "ansi-regex" "^5.0.1"
+
+"strip-ansi@^7.0.0":
+ "integrity" "sha512-cXNxvT8dFNRVfhVME3JAe98mkXDYN2O1l7jmcwMnOslDeESg1rF/OZMtK0nRAhiari1unG5cD4jG3rapUAkLbw=="
+ "resolved" "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.0.1.tgz"
+ "version" "7.0.1"
+ dependencies:
+ "ansi-regex" "^6.0.1"
+
+"strip-bom-buf@^1.0.0":
+ "integrity" "sha1-HLRar1dTD0yvhsf3UXnSyaUd1XI="
+ "resolved" "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-1.0.0.tgz"
+ "version" "1.0.0"
+ dependencies:
+ "is-utf8" "^0.2.1"
+
+"strip-bom-stream@^2.0.0":
+ "integrity" "sha1-+H217yYT9paKpUWr/h7HKLaoKco="
+ "resolved" "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "first-chunk-stream" "^2.0.0"
+ "strip-bom" "^2.0.0"
+
+"strip-bom@^2.0.0":
+ "integrity" "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4="
+ "resolved" "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "is-utf8" "^0.2.0"
+
+"strip-bom@^3.0.0":
+ "integrity" "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM="
+ "resolved" "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz"
+ "version" "3.0.0"
+
+"strip-bom@^4.0.0":
+ "integrity" "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w=="
+ "resolved" "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz"
+ "version" "4.0.0"
+
+"strip-comments@^2.0.1":
+ "integrity" "sha512-ZprKx+bBLXv067WTCALv8SSz5l2+XhpYCsVtSqlMnkAXMWDq+/ekVbl1ghqP9rUHTzv6sm/DwCOiYutU/yp1fw=="
+ "resolved" "https://registry.npmjs.org/strip-comments/-/strip-comments-2.0.1.tgz"
+ "version" "2.0.1"
+
+"strip-final-newline@^2.0.0":
+ "integrity" "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="
+ "resolved" "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz"
+ "version" "2.0.0"
+
+"strip-indent@^1.0.1":
+ "integrity" "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI="
+ "resolved" "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz"
+ "version" "1.0.1"
+ dependencies:
+ "get-stdin" "^4.0.1"
+
+"strip-json-comments@^3.1.0", "strip-json-comments@^3.1.1":
+ "integrity" "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="
+ "resolved" "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz"
+ "version" "3.1.1"
+
+"style-loader@3.3.1":
+ "integrity" "sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ=="
+ "resolved" "https://registry.npmjs.org/style-loader/-/style-loader-3.3.1.tgz"
+ "version" "3.3.1"
+
+"stylehacks@^5.0.1":
+ "integrity" "sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA=="
+ "resolved" "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "browserslist" "^4.16.0"
+ "postcss-selector-parser" "^6.0.4"
+
+"supports-color@^2.0.0":
+ "integrity" "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
+ "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+ "version" "2.0.0"
+
+"supports-color@^3.1.0":
+ "integrity" "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY="
+ "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz"
+ "version" "3.2.3"
+ dependencies:
+ "has-flag" "^1.0.0"
+
+"supports-color@^4.0.0":
+ "integrity" "sha1-vnoN5ITexcXN34s9WRJQRJEvY1s="
+ "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-4.5.0.tgz"
+ "version" "4.5.0"
+ dependencies:
+ "has-flag" "^2.0.0"
+
+"supports-color@^5.3.0":
+ "integrity" "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow=="
+ "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz"
+ "version" "5.5.0"
+ dependencies:
+ "has-flag" "^3.0.0"
+
+"supports-color@^7.0.0", "supports-color@^7.1.0", "supports-color@^7.2.0":
+ "integrity" "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw=="
+ "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz"
+ "version" "7.2.0"
+ dependencies:
+ "has-flag" "^4.0.0"
+
+"supports-color@^8.0.0":
+ "integrity" "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="
+ "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
+ "version" "8.1.1"
+ dependencies:
+ "has-flag" "^4.0.0"
+
+"supports-color@^8.1.0":
+ "integrity" "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q=="
+ "resolved" "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz"
+ "version" "8.1.1"
+ dependencies:
+ "has-flag" "^4.0.0"
+
+"supports-hyperlinks@^2.0.0":
+ "integrity" "sha512-6sXEzV5+I5j8Bmq9/vUphGRM/RJNT9SCURJLjwfOg51heRtguGWDzcaBlgAzKhQa0EVNpPEKzQuBwZ8S8WaCeQ=="
+ "resolved" "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.2.0.tgz"
+ "version" "2.2.0"
+ dependencies:
+ "has-flag" "^4.0.0"
+ "supports-color" "^7.0.0"
+
+"supports-preserve-symlinks-flag@^1.0.0":
+ "integrity" "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="
+ "resolved" "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz"
+ "version" "1.0.0"
+
+"svgo@^2.7.0":
+ "integrity" "sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg=="
+ "resolved" "https://registry.npmjs.org/svgo/-/svgo-2.8.0.tgz"
+ "version" "2.8.0"
+ dependencies:
+ "@trysound/sax" "0.2.0"
+ "commander" "^7.2.0"
+ "css-select" "^4.1.3"
+ "css-tree" "^1.1.3"
+ "csso" "^4.2.0"
+ "picocolors" "^1.0.0"
+ "stable" "^0.1.8"
+
+"swagger-ui-dist@4.1.3":
+ "integrity" "sha512-WvfPSfAAMlE/sKS6YkW47nX/hA7StmhYnAHc6wWCXNL0oclwLj6UXv0hQCkLnDgvebi0MEV40SJJpVjKUgH1IQ=="
+ "resolved" "https://registry.npmjs.org/swagger-ui-dist/-/swagger-ui-dist-4.1.3.tgz"
+ "version" "4.1.3"
+
+"symbol-observable@1.0.1":
+ "integrity" "sha1-g0D8RwLDEi310iKI+IKD9RPT/dQ="
+ "resolved" "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.0.1.tgz"
+ "version" "1.0.1"
+
+"symbol-tree@^3.2.4":
+ "integrity" "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
+ "resolved" "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz"
+ "version" "3.2.4"
+
+"tabtab@2.2.2":
+ "integrity" "sha1-egR/FDsBC0y9MfhX6ClhUSy/ThQ="
+ "resolved" "https://registry.npmjs.org/tabtab/-/tabtab-2.2.2.tgz"
+ "version" "2.2.2"
+ dependencies:
+ "debug" "^2.2.0"
+ "inquirer" "^1.0.2"
+ "lodash.difference" "^4.5.0"
+ "lodash.uniq" "^4.5.0"
+ "minimist" "^1.2.0"
+ "mkdirp" "^0.5.1"
+ "npmlog" "^2.0.3"
+ "object-assign" "^4.1.0"
+
+"tapable@^1.0.0":
+ "integrity" "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA=="
+ "resolved" "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz"
+ "version" "1.1.3"
+
+"tapable@^2.0.0":
+ "integrity" "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="
+ "resolved" "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz"
+ "version" "2.2.1"
+
+"tapable@^2.1.1":
+ "integrity" "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="
+ "resolved" "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz"
+ "version" "2.2.1"
+
+"tapable@^2.2.0":
+ "integrity" "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="
+ "resolved" "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz"
+ "version" "2.2.1"
+
+"temp-dir@^2.0.0":
+ "integrity" "sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg=="
+ "resolved" "https://registry.npmjs.org/temp-dir/-/temp-dir-2.0.0.tgz"
+ "version" "2.0.0"
+
+"tempy@^0.6.0":
+ "integrity" "sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw=="
+ "resolved" "https://registry.npmjs.org/tempy/-/tempy-0.6.0.tgz"
+ "version" "0.6.0"
+ dependencies:
+ "is-stream" "^2.0.0"
+ "temp-dir" "^2.0.0"
+ "type-fest" "^0.16.0"
+ "unique-string" "^2.0.0"
+
+"terminal-link@^2.0.0":
+ "integrity" "sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ=="
+ "resolved" "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz"
+ "version" "2.1.1"
+ dependencies:
+ "ansi-escapes" "^4.2.1"
+ "supports-hyperlinks" "^2.0.0"
+
+"terser-webpack-plugin@^5.1.3", "terser-webpack-plugin@5.3.0":
+ "integrity" "sha512-LPIisi3Ol4chwAaPP8toUJ3L4qCM1G0wao7L3qNv57Drezxj6+VEyySpPw4B1HSO2Eg/hDY/MNF5XihCAoqnsQ=="
+ "resolved" "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.0.tgz"
+ "version" "5.3.0"
+ dependencies:
+ "jest-worker" "^27.4.1"
+ "schema-utils" "^3.1.1"
+ "serialize-javascript" "^6.0.0"
+ "source-map" "^0.6.1"
+ "terser" "^5.7.2"
+
+"terser@^5.0.0", "terser@^5.10.0", "terser@^5.7.2":
+ "integrity" "sha512-AMmF99DMfEDiRJfxfY5jj5wNH/bYO09cniSqhfoyxc8sFoYIgkJy86G04UoZU5VjlpnplVu0K6Tx6E9b5+DlHA=="
+ "resolved" "https://registry.npmjs.org/terser/-/terser-5.10.0.tgz"
+ "version" "5.10.0"
+ dependencies:
+ "commander" "^2.20.0"
+ "source-map" "~0.7.2"
+ "source-map-support" "~0.5.20"
+
+"test-exclude@^6.0.0":
+ "integrity" "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w=="
+ "resolved" "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz"
+ "version" "6.0.0"
+ dependencies:
+ "@istanbuljs/schema" "^0.1.2"
+ "glob" "^7.1.4"
+ "minimatch" "^3.0.4"
+
+"text-table@^0.2.0":
+ "integrity" "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
+ "resolved" "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
+ "version" "0.2.0"
+
+"textextensions@^2.5.0":
+ "integrity" "sha512-49WtAWS+tcsy93dRt6P0P3AMD2m5PvXRhuEA0kaXos5ZLlujtYmpmFsB+QvWUSxE1ZsstmYXfQ7L40+EcQgpAQ=="
+ "resolved" "https://registry.npmjs.org/textextensions/-/textextensions-2.6.0.tgz"
+ "version" "2.6.0"
+
+"tfunk@^4.0.0":
+ "integrity" "sha512-eJQ0dGfDIzWNiFNYFVjJ+Ezl/GmwHaFTBTjrtqNPW0S7cuVDBrZrmzUz6VkMeCR4DZFqhd4YtLwsw3i2wYHswQ=="
+ "resolved" "https://registry.npmjs.org/tfunk/-/tfunk-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "chalk" "^1.1.3"
+ "dlv" "^1.1.3"
+
+"thread-loader@3.0.4":
+ "integrity" "sha512-ByaL2TPb+m6yArpqQUZvP+5S1mZtXsEP7nWKKlAUTm7fCml8kB5s1uI3+eHRP2bk5mVYfRSBI7FFf+tWEyLZwA=="
+ "resolved" "https://registry.npmjs.org/thread-loader/-/thread-loader-3.0.4.tgz"
+ "version" "3.0.4"
+ dependencies:
+ "json-parse-better-errors" "^1.0.2"
+ "loader-runner" "^4.1.0"
+ "loader-utils" "^2.0.0"
+ "neo-async" "^2.6.2"
+ "schema-utils" "^3.0.0"
+
+"throat@^6.0.1":
+ "integrity" "sha512-8hmiGIJMDlwjg7dlJ4yKGLK8EsYqKgPWbG3b4wjJddKNwc7N7Dpn08Df4szr/sZdMVeOstrdYSsqzX6BYbcB+w=="
+ "resolved" "https://registry.npmjs.org/throat/-/throat-6.0.1.tgz"
+ "version" "6.0.1"
+
+"throttle-debounce@^2.1.0":
+ "integrity" "sha512-H7oLPV0P7+jgvrk+6mwwwBDmxTaxnu9HMXmloNLXwnNO0ZxZ31Orah2n8lU1eMPvsaowP2CX+USCgyovXfdOFQ=="
+ "resolved" "https://registry.npmjs.org/throttle-debounce/-/throttle-debounce-2.3.0.tgz"
+ "version" "2.3.0"
+
+"through@^2.3.6":
+ "integrity" "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
+ "resolved" "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
+ "version" "2.3.8"
+
+"through2@^2.0.0":
+ "integrity" "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ=="
+ "resolved" "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz"
+ "version" "2.0.5"
+ dependencies:
+ "readable-stream" "~2.3.6"
+ "xtend" "~4.0.1"
+
+"through2@^3.0.0":
+ "integrity" "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ=="
+ "resolved" "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz"
+ "version" "3.0.2"
+ dependencies:
+ "inherits" "^2.0.4"
+ "readable-stream" "2 || 3"
+
+"thunky@^1.0.2":
+ "integrity" "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA=="
+ "resolved" "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz"
+ "version" "1.1.0"
+
+"timed-out@^4.0.0":
+ "integrity" "sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8="
+ "resolved" "https://registry.npmjs.org/timed-out/-/timed-out-4.0.1.tgz"
+ "version" "4.0.1"
+
+"timsort@^0.3.0":
+ "integrity" "sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q="
+ "resolved" "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz"
+ "version" "0.3.0"
+
+"tiny-invariant@^1.0.2":
+ "integrity" "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg=="
+ "resolved" "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz"
+ "version" "1.2.0"
+
+"tiny-warning@^1.0.0", "tiny-warning@^1.0.3":
+ "integrity" "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
+ "resolved" "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz"
+ "version" "1.0.3"
+
+"tmp@^0.0.29":
+ "integrity" "sha1-8lEl/w3Z2jzLDC3Tce4SiLuRKMA="
+ "resolved" "https://registry.npmjs.org/tmp/-/tmp-0.0.29.tgz"
+ "version" "0.0.29"
+ dependencies:
+ "os-tmpdir" "~1.0.1"
+
+"tmp@^0.0.33":
+ "integrity" "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw=="
+ "resolved" "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz"
+ "version" "0.0.33"
+ dependencies:
+ "os-tmpdir" "~1.0.2"
+
+"tmpl@1.0.5":
+ "integrity" "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw=="
+ "resolved" "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz"
+ "version" "1.0.5"
+
+"to-array@0.1.4":
+ "integrity" "sha1-F+bBH3PdTz10zaek/zI46a2b+JA="
+ "resolved" "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz"
+ "version" "0.1.4"
+
+"to-fast-properties@^2.0.0":
+ "integrity" "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4="
+ "resolved" "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz"
+ "version" "2.0.0"
+
+"to-regex-range@^5.0.1":
+ "integrity" "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="
+ "resolved" "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz"
+ "version" "5.0.1"
+ dependencies:
+ "is-number" "^7.0.0"
+
+"toidentifier@1.0.1":
+ "integrity" "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="
+ "resolved" "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz"
+ "version" "1.0.1"
+
+"tough-cookie@^2.0.0":
+ "integrity" "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g=="
+ "resolved" "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz"
+ "version" "2.5.0"
+ dependencies:
+ "psl" "^1.1.28"
+ "punycode" "^2.1.1"
+
+"tough-cookie@^4.0.0":
+ "integrity" "sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg=="
+ "resolved" "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.0.0.tgz"
+ "version" "4.0.0"
+ dependencies:
+ "psl" "^1.1.33"
+ "punycode" "^2.1.1"
+ "universalify" "^0.1.2"
+
+"tough-cookie@~2.5.0":
+ "integrity" "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g=="
+ "resolved" "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz"
+ "version" "2.5.0"
+ dependencies:
+ "psl" "^1.1.28"
+ "punycode" "^2.1.1"
+
+"tr46@^1.0.1":
+ "integrity" "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk="
+ "resolved" "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz"
+ "version" "1.0.1"
+ dependencies:
+ "punycode" "^2.1.0"
+
+"tr46@^2.1.0":
+ "integrity" "sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw=="
+ "resolved" "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz"
+ "version" "2.1.0"
+ dependencies:
+ "punycode" "^2.1.1"
+
+"tree-kill@^1.2.2":
+ "integrity" "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A=="
+ "resolved" "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz"
+ "version" "1.2.2"
+
+"trim-newlines@^1.0.0":
+ "integrity" "sha1-WIeWa7WCpFA6QetST301ARgVphM="
+ "resolved" "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
+ "version" "1.0.0"
+
+"ts-jest@27.1.2":
+ "integrity" "sha512-eSOiJOWq6Hhs6Khzk5wKC5sgWIXgXqOCiIl1+3lfnearu58Hj4QpE5tUhQcA3xtZrELbcvAGCsd6HB8OsaVaTA=="
+ "resolved" "https://registry.npmjs.org/ts-jest/-/ts-jest-27.1.2.tgz"
+ "version" "27.1.2"
+ dependencies:
+ "bs-logger" "0.x"
+ "fast-json-stable-stringify" "2.x"
+ "jest-util" "^27.0.0"
+ "json5" "2.x"
+ "lodash.memoize" "4.x"
+ "make-error" "1.x"
+ "semver" "7.x"
+ "yargs-parser" "20.x"
+
+"ts-loader@9.2.6":
+ "integrity" "sha512-QMTC4UFzHmu9wU2VHZEmWWE9cUajjfcdcws+Gh7FhiO+Dy0RnR1bNz0YCHqhI0yRowCE9arVnNxYHqELOy9Hjw=="
+ "resolved" "https://registry.npmjs.org/ts-loader/-/ts-loader-9.2.6.tgz"
+ "version" "9.2.6"
+ dependencies:
+ "chalk" "^4.1.0"
+ "enhanced-resolve" "^5.0.0"
+ "micromatch" "^4.0.0"
+ "semver" "^7.3.4"
+
+"tslib@^1.8.1":
+ "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
+ "version" "1.14.1"
+
+"tslib@^1.9.0":
+ "integrity" "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
+ "resolved" "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz"
+ "version" "1.14.1"
+
+"tslib@^2.0.3", "tslib@^2.1.0", "tslib@^2.3.1", "tslib@2.3.1":
+ "integrity" "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw=="
+ "resolved" "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz"
+ "version" "2.3.1"
+
+"tsutils@^3.21.0":
+ "integrity" "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA=="
+ "resolved" "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz"
+ "version" "3.21.0"
+ dependencies:
+ "tslib" "^1.8.1"
+
+"tunnel-agent@^0.6.0":
+ "integrity" "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0="
+ "resolved" "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz"
+ "version" "0.6.0"
+ dependencies:
+ "safe-buffer" "^5.0.1"
+
+"tweetnacl@^0.14.3", "tweetnacl@~0.14.0":
+ "integrity" "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
+ "resolved" "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz"
+ "version" "0.14.5"
+
+"type-check@^0.4.0", "type-check@~0.4.0":
+ "integrity" "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew=="
+ "resolved" "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz"
+ "version" "0.4.0"
+ dependencies:
+ "prelude-ls" "^1.2.1"
+
+"type-check@~0.3.2":
+ "integrity" "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I="
+ "resolved" "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz"
+ "version" "0.3.2"
+ dependencies:
+ "prelude-ls" "~1.1.2"
+
+"type-detect@^4.0.8", "type-detect@4.0.8":
+ "integrity" "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g=="
+ "resolved" "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz"
+ "version" "4.0.8"
+
+"type-fest@^0.16.0":
+ "integrity" "sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg=="
+ "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.16.0.tgz"
+ "version" "0.16.0"
+
+"type-fest@^0.20.2":
+ "integrity" "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ=="
+ "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz"
+ "version" "0.20.2"
+
+"type-fest@^0.21.3":
+ "integrity" "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w=="
+ "resolved" "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz"
+ "version" "0.21.3"
+
+"type-is@~1.6.18":
+ "integrity" "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g=="
+ "resolved" "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz"
+ "version" "1.6.18"
+ dependencies:
+ "media-typer" "0.3.0"
+ "mime-types" "~2.1.24"
+
+"typedarray-to-buffer@^3.1.5":
+ "integrity" "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q=="
+ "resolved" "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz"
+ "version" "3.1.5"
+ dependencies:
+ "is-typedarray" "^1.0.0"
+
+"typedarray@^0.0.6":
+ "integrity" "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
+ "resolved" "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
+ "version" "0.0.6"
+
+"typescript@*", "typescript@>= 2.7", "typescript@>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta", "typescript@>=3.8 <5.0", "typescript@4.5.4":
+ "integrity" "sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg=="
+ "resolved" "https://registry.npmjs.org/typescript/-/typescript-4.5.4.tgz"
+ "version" "4.5.4"
+
+"ua-parser-js@1.0.2":
+ "integrity" "sha512-00y/AXhx0/SsnI51fTc0rLRmafiGOM4/O+ny10Ps7f+j/b8p/ZY11ytMgznXkOVo4GQ+KwQG5UQLkLGirsACRg=="
+ "resolved" "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.2.tgz"
+ "version" "1.0.2"
+
+"uglify-js@^3.1.4":
+ "integrity" "sha512-qZukoSxOG0urUTvjc2ERMTcAy+BiFh3weWAkeurLwjrCba73poHmG3E36XEjd/JGukMzwTL7uCxZiAexj8ppvQ=="
+ "resolved" "https://registry.npmjs.org/uglify-js/-/uglify-js-3.14.5.tgz"
+ "version" "3.14.5"
+
+"unbox-primitive@^1.0.1":
+ "integrity" "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw=="
+ "resolved" "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz"
+ "version" "1.0.1"
+ dependencies:
+ "function-bind" "^1.1.1"
+ "has-bigints" "^1.0.1"
+ "has-symbols" "^1.0.2"
+ "which-boxed-primitive" "^1.0.2"
+
+"unicode-canonical-property-names-ecmascript@^2.0.0":
+ "integrity" "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ=="
+ "resolved" "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz"
+ "version" "2.0.0"
+
+"unicode-match-property-ecmascript@^2.0.0":
+ "integrity" "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q=="
+ "resolved" "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "unicode-canonical-property-names-ecmascript" "^2.0.0"
+ "unicode-property-aliases-ecmascript" "^2.0.0"
+
+"unicode-match-property-value-ecmascript@^2.0.0":
+ "integrity" "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw=="
+ "resolved" "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz"
+ "version" "2.0.0"
+
+"unicode-property-aliases-ecmascript@^2.0.0":
+ "integrity" "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ=="
+ "resolved" "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz"
+ "version" "2.0.0"
+
+"unique-string@^2.0.0":
+ "integrity" "sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg=="
+ "resolved" "https://registry.npmjs.org/unique-string/-/unique-string-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "crypto-random-string" "^2.0.0"
+
+"universalify@^0.1.0", "universalify@^0.1.2":
+ "integrity" "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg=="
+ "resolved" "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz"
+ "version" "0.1.2"
+
+"universalify@^2.0.0":
+ "integrity" "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
+ "resolved" "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz"
+ "version" "2.0.0"
+
+"unpipe@~1.0.0", "unpipe@1.0.0":
+ "integrity" "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+ "resolved" "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
+ "version" "1.0.0"
+
+"untildify@^3.0.2":
+ "integrity" "sha512-iSk/J8efr8uPT/Z4eSUywnqyrQU7DSdMfdqK4iWEaUVVmcP5JcnpRqmVMwcwcnmI1ATFNgC5V90u09tBynNFKA=="
+ "resolved" "https://registry.npmjs.org/untildify/-/untildify-3.0.3.tgz"
+ "version" "3.0.3"
+
+"upath@^1.2.0":
+ "integrity" "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="
+ "resolved" "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz"
+ "version" "1.2.0"
+
+"uri-js@^4.2.2":
+ "integrity" "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="
+ "resolved" "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz"
+ "version" "4.4.1"
+ dependencies:
+ "punycode" "^2.1.0"
+
+"url-parse-lax@^1.0.0":
+ "integrity" "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM="
+ "resolved" "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz"
+ "version" "1.0.0"
+ dependencies:
+ "prepend-http" "^1.0.1"
+
+"url-to-options@^1.0.1":
+ "integrity" "sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k="
+ "resolved" "https://registry.npmjs.org/url-to-options/-/url-to-options-1.0.1.tgz"
+ "version" "1.0.1"
+
+"util-deprecate@^1.0.1", "util-deprecate@^1.0.2", "util-deprecate@~1.0.1":
+ "integrity" "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+ "resolved" "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+ "version" "1.0.2"
+
+"utila@~0.4":
+ "integrity" "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw="
+ "resolved" "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz"
+ "version" "0.4.0"
+
+"utils-merge@1.0.1":
+ "integrity" "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+ "resolved" "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz"
+ "version" "1.0.1"
+
+"uuid@^2.0.1":
+ "integrity" "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
+ "resolved" "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz"
+ "version" "2.0.3"
+
+"uuid@^3.0.0":
+ "integrity" "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+ "resolved" "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz"
+ "version" "3.4.0"
+
+"uuid@^3.3.2":
+ "integrity" "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
+ "resolved" "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz"
+ "version" "3.4.0"
+
+"uuid@^8.3.0", "uuid@^8.3.2", "uuid@8.3.2":
+ "integrity" "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
+ "resolved" "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz"
+ "version" "8.3.2"
+
+"v8-compile-cache@^2.0.3":
+ "integrity" "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA=="
+ "resolved" "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz"
+ "version" "2.3.0"
+
+"v8-to-istanbul@^8.1.0":
+ "integrity" "sha512-/PRhfd8aTNp9Ggr62HPzXg2XasNFGy5PBt0Rp04du7/8GNNSgxFL6WBTkgMKSL9bFjH+8kKEG3f37FmxiTqUUA=="
+ "resolved" "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-8.1.0.tgz"
+ "version" "8.1.0"
+ dependencies:
+ "@types/istanbul-lib-coverage" "^2.0.1"
+ "convert-source-map" "^1.6.0"
+ "source-map" "^0.7.3"
+
+"validate-npm-package-license@^3.0.1":
+ "integrity" "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew=="
+ "resolved" "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz"
+ "version" "3.0.4"
+ dependencies:
+ "spdx-correct" "^3.0.0"
+ "spdx-expression-parse" "^3.0.0"
+
+"value-equal@^1.0.1":
+ "integrity" "sha512-NOJ6JZCAWr0zlxZt+xqCHNTEKOsrks2HQd4MqhP1qy4z1SkbEP467eNx6TgDKXMvUOb+OENfJCZwM+16n7fRfw=="
+ "resolved" "https://registry.npmjs.org/value-equal/-/value-equal-1.0.1.tgz"
+ "version" "1.0.1"
+
+"vary@~1.1.2":
+ "integrity" "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+ "resolved" "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz"
+ "version" "1.1.2"
+
+"verror@1.10.0":
+ "integrity" "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA="
+ "resolved" "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz"
+ "version" "1.10.0"
+ dependencies:
+ "assert-plus" "^1.0.0"
+ "core-util-is" "1.0.2"
+ "extsprintf" "^1.2.0"
+
+"vinyl-file@^3.0.0":
+ "integrity" "sha1-sQTZ5ECf+jJfqt1SBkLQo7SIs2U="
+ "resolved" "https://registry.npmjs.org/vinyl-file/-/vinyl-file-3.0.0.tgz"
+ "version" "3.0.0"
+ dependencies:
+ "graceful-fs" "^4.1.2"
+ "pify" "^2.3.0"
+ "strip-bom-buf" "^1.0.0"
+ "strip-bom-stream" "^2.0.0"
+ "vinyl" "^2.0.1"
+
+"vinyl@^2.0.1":
+ "integrity" "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw=="
+ "resolved" "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz"
+ "version" "2.2.1"
+ dependencies:
+ "clone" "^2.1.1"
+ "clone-buffer" "^1.0.0"
+ "clone-stats" "^1.0.0"
+ "cloneable-readable" "^1.0.0"
+ "remove-trailing-separator" "^1.0.1"
+ "replace-ext" "^1.0.0"
+
+"w3c-hr-time@^1.0.2":
+ "integrity" "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ=="
+ "resolved" "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "browser-process-hrtime" "^1.0.0"
+
+"w3c-xmlserializer@^2.0.0":
+ "integrity" "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA=="
+ "resolved" "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "xml-name-validator" "^3.0.0"
+
+"wait-on@6.0.0":
+ "integrity" "sha512-tnUJr9p5r+bEYXPUdRseolmz5XqJTTj98JgOsfBn7Oz2dxfE2g3zw1jE+Mo8lopM3j3et/Mq1yW7kKX6qw7RVw=="
+ "resolved" "https://registry.npmjs.org/wait-on/-/wait-on-6.0.0.tgz"
+ "version" "6.0.0"
+ dependencies:
+ "axios" "^0.21.1"
+ "joi" "^17.4.0"
+ "lodash" "^4.17.21"
+ "minimist" "^1.2.5"
+ "rxjs" "^7.1.0"
+
+"walker@^1.0.7":
+ "integrity" "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ=="
+ "resolved" "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz"
+ "version" "1.0.8"
+ dependencies:
+ "makeerror" "1.0.12"
+
+"warning@^4.0.2":
+ "integrity" "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w=="
+ "resolved" "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz"
+ "version" "4.0.3"
+ dependencies:
+ "loose-envify" "^1.0.0"
+
+"watchpack@^2.3.1":
+ "integrity" "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA=="
+ "resolved" "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz"
+ "version" "2.3.1"
+ dependencies:
+ "glob-to-regexp" "^0.4.1"
+ "graceful-fs" "^4.1.2"
+
+"wbuf@^1.1.0", "wbuf@^1.7.3":
+ "integrity" "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA=="
+ "resolved" "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz"
+ "version" "1.7.3"
+ dependencies:
+ "minimalistic-assert" "^1.0.0"
+
+"webidl-conversions@^4.0.2":
+ "integrity" "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
+ "resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz"
+ "version" "4.0.2"
+
+"webidl-conversions@^5.0.0":
+ "integrity" "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
+ "resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz"
+ "version" "5.0.0"
+
+"webidl-conversions@^6.1.0":
+ "integrity" "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
+ "resolved" "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz"
+ "version" "6.1.0"
+
+"webpack-cli@^4.9.1", "webpack-cli@4.x.x":
+ "integrity" "sha512-JYRFVuyFpzDxMDB+v/nanUdQYcZtqFPGzmlW4s+UkPMFhSpfRNmf1z4AwYcHJVdvEFAM7FFCQdNTpsBYhDLusQ=="
+ "resolved" "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.1.tgz"
+ "version" "4.9.1"
+ dependencies:
+ "@discoveryjs/json-ext" "^0.5.0"
+ "@webpack-cli/configtest" "^1.1.0"
+ "@webpack-cli/info" "^1.4.0"
+ "@webpack-cli/serve" "^1.6.0"
+ "colorette" "^2.0.14"
+ "commander" "^7.0.0"
+ "execa" "^5.0.0"
+ "fastest-levenshtein" "^1.0.12"
+ "import-local" "^3.0.2"
+ "interpret" "^2.2.0"
+ "rechoir" "^0.7.0"
+ "webpack-merge" "^5.7.3"
+
+"webpack-dev-middleware@^5.3.0":
+ "integrity" "sha512-MouJz+rXAm9B1OTOYaJnn6rtD/lWZPy2ufQCH3BPs8Rloh/Du6Jze4p7AeLYHkVi0giJnYLaSGDC7S+GM9arhg=="
+ "resolved" "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.0.tgz"
+ "version" "5.3.0"
+ dependencies:
+ "colorette" "^2.0.10"
+ "memfs" "^3.2.2"
+ "mime-types" "^2.1.31"
+ "range-parser" "^1.2.1"
+ "schema-utils" "^4.0.0"
+
+"webpack-dev-server@4.7.2":
+ "integrity" "sha512-s6yEOSfPpB6g1T2+C5ZOUt5cQOMhjI98IVmmvMNb5cdiqHoxSUfACISHqU/wZy+q4ar/A9jW0pbNj7sa50XRVA=="
+ "resolved" "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.7.2.tgz"
+ "version" "4.7.2"
+ dependencies:
+ "@types/bonjour" "^3.5.9"
+ "@types/connect-history-api-fallback" "^1.3.5"
+ "@types/serve-index" "^1.9.1"
+ "@types/sockjs" "^0.3.33"
+ "@types/ws" "^8.2.2"
+ "ansi-html-community" "^0.0.8"
+ "bonjour" "^3.5.0"
+ "chokidar" "^3.5.2"
+ "colorette" "^2.0.10"
+ "compression" "^1.7.4"
+ "connect-history-api-fallback" "^1.6.0"
+ "default-gateway" "^6.0.3"
+ "del" "^6.0.0"
+ "express" "^4.17.1"
+ "graceful-fs" "^4.2.6"
+ "html-entities" "^2.3.2"
+ "http-proxy-middleware" "^2.0.0"
+ "ipaddr.js" "^2.0.1"
+ "open" "^8.0.9"
+ "p-retry" "^4.5.0"
+ "portfinder" "^1.0.28"
+ "schema-utils" "^4.0.0"
+ "selfsigned" "^1.10.11"
+ "serve-index" "^1.9.1"
+ "sockjs" "^0.3.21"
+ "spdy" "^4.0.2"
+ "strip-ansi" "^7.0.0"
+ "webpack-dev-middleware" "^5.3.0"
+ "ws" "^8.1.0"
+
+"webpack-merge@^5.7.3", "webpack-merge@5.8.0":
+ "integrity" "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q=="
+ "resolved" "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz"
+ "version" "5.8.0"
+ dependencies:
+ "clone-deep" "^4.0.1"
+ "wildcard" "^2.0.0"
+
+"webpack-notifier@1.15.0":
+ "integrity" "sha512-N2V8UMgRB5komdXQRavBsRpw0hPhJq2/SWNOGuhrXpIgRhcMexzkGQysUyGStHLV5hkUlgpRiF7IUXoBqyMmzQ=="
+ "resolved" "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.15.0.tgz"
+ "version" "1.15.0"
+ dependencies:
+ "node-notifier" "^9.0.0"
+ "strip-ansi" "^6.0.0"
+
+"webpack-sources@^1.4.3":
+ "integrity" "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ=="
+ "resolved" "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz"
+ "version" "1.4.3"
+ dependencies:
+ "source-list-map" "^2.0.0"
+ "source-map" "~0.6.1"
+
+"webpack-sources@^3.2.2":
+ "integrity" "sha512-cp5qdmHnu5T8wRg2G3vZZHoJPN14aqQ89SyQ11NpGH5zEMDCclt49rzo+MaRazk7/UeILhAI+/sEtcM+7Fr0nw=="
+ "resolved" "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.2.tgz"
+ "version" "3.2.2"
+
+"webpack@^1 || ^2 || ^3 || ^4 || ^5", "webpack@^4.0.0 || ^5.0.0", "webpack@^4.27.0 || ^5.0.0", "webpack@^4.37.0 || ^5.0.0", "webpack@^4.4.0 || ^5.9.0", "webpack@^5.0.0", "webpack@^5.1.0", "webpack@^5.20.0", "webpack@>= 4", "webpack@>=2.0.0", "webpack@4.x.x || 5.x.x", "webpack@5.65.0":
+ "integrity" "sha512-Q5or2o6EKs7+oKmJo7LaqZaMOlDWQse9Tm5l1WAfU/ujLGN5Pb0SqGeVkN/4bpPmEqEP5RnVhiqsOtWtUVwGRw=="
+ "resolved" "https://registry.npmjs.org/webpack/-/webpack-5.65.0.tgz"
+ "version" "5.65.0"
+ dependencies:
+ "@types/eslint-scope" "^3.7.0"
+ "@types/estree" "^0.0.50"
+ "@webassemblyjs/ast" "1.11.1"
+ "@webassemblyjs/wasm-edit" "1.11.1"
+ "@webassemblyjs/wasm-parser" "1.11.1"
+ "acorn" "^8.4.1"
+ "acorn-import-assertions" "^1.7.6"
+ "browserslist" "^4.14.5"
+ "chrome-trace-event" "^1.0.2"
+ "enhanced-resolve" "^5.8.3"
+ "es-module-lexer" "^0.9.0"
+ "eslint-scope" "5.1.1"
+ "events" "^3.2.0"
+ "glob-to-regexp" "^0.4.1"
+ "graceful-fs" "^4.2.4"
+ "json-parse-better-errors" "^1.0.2"
+ "loader-runner" "^4.2.0"
+ "mime-types" "^2.1.27"
+ "neo-async" "^2.6.2"
+ "schema-utils" "^3.1.0"
+ "tapable" "^2.1.1"
+ "terser-webpack-plugin" "^5.1.3"
+ "watchpack" "^2.3.1"
+ "webpack-sources" "^3.2.2"
+
+"websocket-driver@^0.7.4", "websocket-driver@>=0.5.1":
+ "integrity" "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg=="
+ "resolved" "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz"
+ "version" "0.7.4"
+ dependencies:
+ "http-parser-js" ">=0.5.1"
+ "safe-buffer" ">=5.1.0"
+ "websocket-extensions" ">=0.1.1"
+
+"websocket-extensions@>=0.1.1":
+ "integrity" "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg=="
+ "resolved" "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz"
+ "version" "0.1.4"
+
+"whatwg-encoding@^1.0.5":
+ "integrity" "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw=="
+ "resolved" "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz"
+ "version" "1.0.5"
+ dependencies:
+ "iconv-lite" "0.4.24"
+
+"whatwg-mimetype@^2.3.0":
+ "integrity" "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
+ "resolved" "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz"
+ "version" "2.3.0"
+
+"whatwg-url@^7.0.0":
+ "integrity" "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg=="
+ "resolved" "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz"
+ "version" "7.1.0"
+ dependencies:
+ "lodash.sortby" "^4.7.0"
+ "tr46" "^1.0.1"
+ "webidl-conversions" "^4.0.2"
+
+"whatwg-url@^8.0.0", "whatwg-url@^8.5.0":
+ "integrity" "sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg=="
+ "resolved" "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz"
+ "version" "8.7.0"
+ dependencies:
+ "lodash" "^4.7.0"
+ "tr46" "^2.1.0"
+ "webidl-conversions" "^6.1.0"
+
+"which-boxed-primitive@^1.0.2":
+ "integrity" "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg=="
+ "resolved" "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz"
+ "version" "1.0.2"
+ dependencies:
+ "is-bigint" "^1.0.1"
+ "is-boolean-object" "^1.1.0"
+ "is-number-object" "^1.0.4"
+ "is-string" "^1.0.5"
+ "is-symbol" "^1.0.3"
+
+"which-module@^2.0.0":
+ "integrity" "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
+ "resolved" "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz"
+ "version" "2.0.0"
+
+"which@^1.1.1":
+ "integrity" "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="
+ "resolved" "https://registry.npmjs.org/which/-/which-1.3.1.tgz"
+ "version" "1.3.1"
+ dependencies:
+ "isexe" "^2.0.0"
+
+"which@^1.2.9":
+ "integrity" "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ=="
+ "resolved" "https://registry.npmjs.org/which/-/which-1.3.1.tgz"
+ "version" "1.3.1"
+ dependencies:
+ "isexe" "^2.0.0"
+
+"which@^2.0.1", "which@^2.0.2":
+ "integrity" "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="
+ "resolved" "https://registry.npmjs.org/which/-/which-2.0.2.tgz"
+ "version" "2.0.2"
+ dependencies:
+ "isexe" "^2.0.0"
+
+"wildcard@^2.0.0":
+ "integrity" "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw=="
+ "resolved" "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz"
+ "version" "2.0.0"
+
+"win-release@^1.0.0":
+ "integrity" "sha1-X6VeAr58qTTt/BJmVjLoSbcuUgk="
+ "resolved" "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz"
+ "version" "1.1.1"
+ dependencies:
+ "semver" "^5.0.1"
+
+"winston@2.4.0":
+ "integrity" "sha1-gIBQuT1SZh7Z+2wms/DIJnCLCu4="
+ "resolved" "https://registry.npmjs.org/winston/-/winston-2.4.0.tgz"
+ "version" "2.4.0"
+ dependencies:
+ "async" "~1.0.0"
+ "colors" "1.0.x"
+ "cycle" "1.0.x"
+ "eyes" "0.1.x"
+ "isstream" "0.1.x"
+ "stack-trace" "0.0.x"
+
+"word-wrap@^1.2.3", "word-wrap@~1.2.3":
+ "integrity" "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ=="
+ "resolved" "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz"
+ "version" "1.2.3"
+
+"wordwrap@^1.0.0":
+ "integrity" "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus="
+ "resolved" "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz"
+ "version" "1.0.0"
+
+"workbox-background-sync@6.4.2":
+ "integrity" "sha512-P7c8uG5X2k+DMICH9xeSA9eUlCOjHHYoB42Rq+RtUpuwBxUOflAXR1zdsMWj81LopE4gjKXlTw7BFd1BDAHo7g=="
+ "resolved" "https://registry.npmjs.org/workbox-background-sync/-/workbox-background-sync-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "idb" "^6.1.4"
+ "workbox-core" "6.4.2"
+
+"workbox-broadcast-update@6.4.2":
+ "integrity" "sha512-qnBwQyE0+PWFFc/n4ISXINE49m44gbEreJUYt2ldGH3+CNrLmJ1egJOOyUqqu9R4Eb7QrXcmB34ClXG7S37LbA=="
+ "resolved" "https://registry.npmjs.org/workbox-broadcast-update/-/workbox-broadcast-update-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-core" "6.4.2"
+
+"workbox-build@6.4.2":
+ "integrity" "sha512-WMdYLhDIsuzViOTXDH+tJ1GijkFp5khSYolnxR/11zmfhNDtuo7jof72xPGFy+KRpsz6tug39RhivCj77qqO0w=="
+ "resolved" "https://registry.npmjs.org/workbox-build/-/workbox-build-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "@apideck/better-ajv-errors" "^0.3.1"
+ "@babel/core" "^7.11.1"
+ "@babel/preset-env" "^7.11.0"
+ "@babel/runtime" "^7.11.2"
+ "@rollup/plugin-babel" "^5.2.0"
+ "@rollup/plugin-node-resolve" "^11.2.1"
+ "@rollup/plugin-replace" "^2.4.1"
+ "@surma/rollup-plugin-off-main-thread" "^2.2.3"
+ "ajv" "^8.6.0"
+ "common-tags" "^1.8.0"
+ "fast-json-stable-stringify" "^2.1.0"
+ "fs-extra" "^9.0.1"
+ "glob" "^7.1.6"
+ "lodash" "^4.17.20"
+ "pretty-bytes" "^5.3.0"
+ "rollup" "^2.43.1"
+ "rollup-plugin-terser" "^7.0.0"
+ "source-map" "^0.8.0-beta.0"
+ "source-map-url" "^0.4.0"
+ "stringify-object" "^3.3.0"
+ "strip-comments" "^2.0.1"
+ "tempy" "^0.6.0"
+ "upath" "^1.2.0"
+ "workbox-background-sync" "6.4.2"
+ "workbox-broadcast-update" "6.4.2"
+ "workbox-cacheable-response" "6.4.2"
+ "workbox-core" "6.4.2"
+ "workbox-expiration" "6.4.2"
+ "workbox-google-analytics" "6.4.2"
+ "workbox-navigation-preload" "6.4.2"
+ "workbox-precaching" "6.4.2"
+ "workbox-range-requests" "6.4.2"
+ "workbox-recipes" "6.4.2"
+ "workbox-routing" "6.4.2"
+ "workbox-strategies" "6.4.2"
+ "workbox-streams" "6.4.2"
+ "workbox-sw" "6.4.2"
+ "workbox-window" "6.4.2"
+
+"workbox-cacheable-response@6.4.2":
+ "integrity" "sha512-9FE1W/cKffk1AJzImxgEN0ceWpyz1tqNjZVtA3/LAvYL3AC5SbIkhc7ZCO82WmO9IjTfu8Vut2X/C7ViMSF7TA=="
+ "resolved" "https://registry.npmjs.org/workbox-cacheable-response/-/workbox-cacheable-response-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-core" "6.4.2"
+
+"workbox-core@6.4.2":
+ "integrity" "sha512-1U6cdEYPcajRXiboSlpJx6U7TvhIKbxRRerfepAJu2hniKwJ3DHILjpU/zx3yvzSBCWcNJDoFalf7Vgd7ey/rw=="
+ "resolved" "https://registry.npmjs.org/workbox-core/-/workbox-core-6.4.2.tgz"
+ "version" "6.4.2"
+
+"workbox-expiration@6.4.2":
+ "integrity" "sha512-0hbpBj0tDnW+DZOUmwZqntB/8xrXOgO34i7s00Si/VlFJvvpRKg1leXdHHU8ykoSBd6+F2KDcMP3swoCi5guLw=="
+ "resolved" "https://registry.npmjs.org/workbox-expiration/-/workbox-expiration-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "idb" "^6.1.4"
+ "workbox-core" "6.4.2"
+
+"workbox-google-analytics@6.4.2":
+ "integrity" "sha512-u+gxs3jXovPb1oul4CTBOb+T9fS1oZG+ZE6AzS7l40vnyfJV79DaLBvlpEZfXGv3CjMdV1sT/ltdOrKzo7HcGw=="
+ "resolved" "https://registry.npmjs.org/workbox-google-analytics/-/workbox-google-analytics-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-background-sync" "6.4.2"
+ "workbox-core" "6.4.2"
+ "workbox-routing" "6.4.2"
+ "workbox-strategies" "6.4.2"
+
+"workbox-navigation-preload@6.4.2":
+ "integrity" "sha512-viyejlCtlKsbJCBHwhSBbWc57MwPXvUrc8P7d+87AxBGPU+JuWkT6nvBANgVgFz6FUhCvRC8aYt+B1helo166g=="
+ "resolved" "https://registry.npmjs.org/workbox-navigation-preload/-/workbox-navigation-preload-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-core" "6.4.2"
+
+"workbox-precaching@6.4.2":
+ "integrity" "sha512-CZ6uwFN/2wb4noHVlALL7UqPFbLfez/9S2GAzGAb0Sk876ul9ukRKPJJ6gtsxfE2HSTwqwuyNVa6xWyeyJ1XSA=="
+ "resolved" "https://registry.npmjs.org/workbox-precaching/-/workbox-precaching-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-core" "6.4.2"
+ "workbox-routing" "6.4.2"
+ "workbox-strategies" "6.4.2"
+
+"workbox-range-requests@6.4.2":
+ "integrity" "sha512-SowF3z69hr3Po/w7+xarWfzxJX/3Fo0uSG72Zg4g5FWWnHpq2zPvgbWerBZIa81zpJVUdYpMa3akJJsv+LaO1Q=="
+ "resolved" "https://registry.npmjs.org/workbox-range-requests/-/workbox-range-requests-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-core" "6.4.2"
+
+"workbox-recipes@6.4.2":
+ "integrity" "sha512-/oVxlZFpAjFVbY+3PoGEXe8qyvtmqMrTdWhbOfbwokNFtUZ/JCtanDKgwDv9x3AebqGAoJRvQNSru0F4nG+gWA=="
+ "resolved" "https://registry.npmjs.org/workbox-recipes/-/workbox-recipes-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-cacheable-response" "6.4.2"
+ "workbox-core" "6.4.2"
+ "workbox-expiration" "6.4.2"
+ "workbox-precaching" "6.4.2"
+ "workbox-routing" "6.4.2"
+ "workbox-strategies" "6.4.2"
+
+"workbox-routing@6.4.2":
+ "integrity" "sha512-0ss/n9PAcHjTy4Ad7l2puuod4WtsnRYu9BrmHcu6Dk4PgWeJo1t5VnGufPxNtcuyPGQ3OdnMdlmhMJ57sSrrSw=="
+ "resolved" "https://registry.npmjs.org/workbox-routing/-/workbox-routing-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-core" "6.4.2"
+
+"workbox-strategies@6.4.2":
+ "integrity" "sha512-YXh9E9dZGEO1EiPC3jPe2CbztO5WT8Ruj8wiYZM56XqEJp5YlGTtqRjghV+JovWOqkWdR+amJpV31KPWQUvn1Q=="
+ "resolved" "https://registry.npmjs.org/workbox-strategies/-/workbox-strategies-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-core" "6.4.2"
+
+"workbox-streams@6.4.2":
+ "integrity" "sha512-ROEGlZHGVEgpa5bOZefiJEVsi5PsFjJG9Xd+wnDbApsCO9xq9rYFopF+IRq9tChyYzhBnyk2hJxbQVWphz3sog=="
+ "resolved" "https://registry.npmjs.org/workbox-streams/-/workbox-streams-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "workbox-core" "6.4.2"
+ "workbox-routing" "6.4.2"
+
+"workbox-sw@6.4.2":
+ "integrity" "sha512-A2qdu9TLktfIM5NE/8+yYwfWu+JgDaCkbo5ikrky2c7r9v2X6DcJ+zSLphNHHLwM/0eVk5XVf1mC5HGhYpMhhg=="
+ "resolved" "https://registry.npmjs.org/workbox-sw/-/workbox-sw-6.4.2.tgz"
+ "version" "6.4.2"
+
+"workbox-webpack-plugin@6.4.2":
+ "integrity" "sha512-CiEwM6kaJRkx1cP5xHksn13abTzUqMHiMMlp5Eh/v4wRcedgDTyv6Uo8+Hg9MurRbHDosO5suaPyF9uwVr4/CQ=="
+ "resolved" "https://registry.npmjs.org/workbox-webpack-plugin/-/workbox-webpack-plugin-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "fast-json-stable-stringify" "^2.1.0"
+ "pretty-bytes" "^5.4.1"
+ "source-map-url" "^0.4.0"
+ "upath" "^1.2.0"
+ "webpack-sources" "^1.4.3"
+ "workbox-build" "6.4.2"
+
+"workbox-window@6.4.2":
+ "integrity" "sha512-KVyRKmrJg7iB+uym/B/CnEUEFG9CvnTU1Bq5xpXHbtgD9l+ShDekSl1wYpqw/O0JfeeQVOFb8CiNfvnwWwqnWQ=="
+ "resolved" "https://registry.npmjs.org/workbox-window/-/workbox-window-6.4.2.tgz"
+ "version" "6.4.2"
+ dependencies:
+ "@types/trusted-types" "^2.0.2"
+ "workbox-core" "6.4.2"
+
+"wrap-ansi@^6.2.0":
+ "integrity" "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA=="
+ "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz"
+ "version" "6.2.0"
+ dependencies:
+ "ansi-styles" "^4.0.0"
+ "string-width" "^4.1.0"
+ "strip-ansi" "^6.0.0"
+
+"wrap-ansi@^7.0.0":
+ "integrity" "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="
+ "resolved" "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz"
+ "version" "7.0.0"
+ dependencies:
+ "ansi-styles" "^4.0.0"
+ "string-width" "^4.1.0"
+ "strip-ansi" "^6.0.0"
+
+"wrappy@1":
+ "integrity" "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
+ "resolved" "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
+ "version" "1.0.2"
+
+"write-file-atomic@^1.1.2":
+ "integrity" "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8="
+ "resolved" "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz"
+ "version" "1.3.4"
+ dependencies:
+ "graceful-fs" "^4.1.11"
+ "imurmurhash" "^0.1.4"
+ "slide" "^1.1.5"
+
+"write-file-atomic@^3.0.0":
+ "integrity" "sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q=="
+ "resolved" "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz"
+ "version" "3.0.3"
+ dependencies:
+ "imurmurhash" "^0.1.4"
+ "is-typedarray" "^1.0.0"
+ "signal-exit" "^3.0.2"
+ "typedarray-to-buffer" "^3.1.5"
+
+"ws@^7.4.6":
+ "integrity" "sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA=="
+ "resolved" "https://registry.npmjs.org/ws/-/ws-7.5.6.tgz"
+ "version" "7.5.6"
+
+"ws@^8.1.0":
+ "integrity" "sha512-IHVsKe2pjajSUIl4KYMQOdlyliovpEPquKkqbwswulszzI7r0SfQrxnXdWAEqOlDCLrVSJzo+O1hAwdog2sKSQ=="
+ "resolved" "https://registry.npmjs.org/ws/-/ws-8.4.0.tgz"
+ "version" "8.4.0"
+
+"ws@~7.4.2":
+ "integrity" "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A=="
+ "resolved" "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz"
+ "version" "7.4.6"
+
+"xdg-basedir@^2.0.0":
+ "integrity" "sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I="
+ "resolved" "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz"
+ "version" "2.0.0"
+ dependencies:
+ "os-homedir" "^1.0.0"
+
+"xml-name-validator@^3.0.0":
+ "integrity" "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw=="
+ "resolved" "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz"
+ "version" "3.0.0"
+
+"xml@^1.0.1":
+ "integrity" "sha1-eLpyAgApxbyHuKgaPPzXS0ovweU="
+ "resolved" "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz"
+ "version" "1.0.1"
+
+"xmlchars@^2.2.0":
+ "integrity" "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
+ "resolved" "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz"
+ "version" "2.2.0"
+
+"xmlhttprequest-ssl@~1.6.2":
+ "integrity" "sha512-3XfeQE/wNkvrIktn2Kf0869fC0BN6UpydVasGIeSm2B1Llihf7/0UfZM+eCkOw3P7bP4+qPgqhm7ZoxuJtFU0Q=="
+ "resolved" "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.6.3.tgz"
+ "version" "1.6.3"
+
+"xtend@~4.0.1":
+ "integrity" "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
+ "resolved" "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz"
+ "version" "4.0.2"
+
+"y18n@^4.0.0":
+ "integrity" "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ=="
+ "resolved" "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz"
+ "version" "4.0.3"
+
+"y18n@^5.0.5":
+ "integrity" "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="
+ "resolved" "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz"
+ "version" "5.0.8"
+
+"yallist@^2.1.2":
+ "integrity" "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
+ "resolved" "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz"
+ "version" "2.1.2"
+
+"yallist@^4.0.0":
+ "integrity" "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
+ "resolved" "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz"
+ "version" "4.0.0"
+
+"yaml@^1.10.0", "yaml@^1.10.2", "yaml@^1.7.2":
+ "integrity" "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
+ "resolved" "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz"
+ "version" "1.10.2"
+
+"yargs-parser@^18.1.2":
+ "integrity" "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ=="
+ "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz"
+ "version" "18.1.3"
+ dependencies:
+ "camelcase" "^5.0.0"
+ "decamelize" "^1.2.0"
+
+"yargs-parser@^20.2.2", "yargs-parser@20.x":
+ "integrity" "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w=="
+ "resolved" "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz"
+ "version" "20.2.9"
+
+"yargs@^15.4.1":
+ "integrity" "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A=="
+ "resolved" "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz"
+ "version" "15.4.1"
+ dependencies:
+ "cliui" "^6.0.0"
+ "decamelize" "^1.2.0"
+ "find-up" "^4.1.0"
+ "get-caller-file" "^2.0.1"
+ "require-directory" "^2.1.1"
+ "require-main-filename" "^2.0.0"
+ "set-blocking" "^2.0.0"
+ "string-width" "^4.2.0"
+ "which-module" "^2.0.0"
+ "y18n" "^4.0.0"
+ "yargs-parser" "^18.1.2"
+
+"yargs@^16.2.0":
+ "integrity" "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw=="
+ "resolved" "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz"
+ "version" "16.2.0"
+ dependencies:
+ "cliui" "^7.0.2"
+ "escalade" "^3.1.1"
+ "get-caller-file" "^2.0.5"
+ "require-directory" "^2.1.1"
+ "string-width" "^4.2.0"
+ "y18n" "^5.0.5"
+ "yargs-parser" "^20.2.2"
+
+"yargs@17.1.1":
+ "integrity" "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ=="
+ "resolved" "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz"
+ "version" "17.1.1"
+ dependencies:
+ "cliui" "^7.0.2"
+ "escalade" "^3.1.1"
+ "get-caller-file" "^2.0.5"
+ "require-directory" "^2.1.1"
+ "string-width" "^4.2.0"
+ "y18n" "^5.0.5"
+ "yargs-parser" "^20.2.2"
+
+"yeast@0.1.2":
+ "integrity" "sha1-AI4G2AlDIMNy28L47XagymyKxBk="
+ "resolved" "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz"
+ "version" "0.1.2"
+
+"yeoman-environment@^2.0.3", "yeoman-environment@2.0.5":
+ "integrity" "sha512-6/W7/B54OPHJXob0n0+pmkwFsirC8cokuQkPSmT/D0lCcSxkKtg/BA6ZnjUBIwjuGqmw3DTrT4en++htaUju5g=="
+ "resolved" "https://registry.npmjs.org/yeoman-environment/-/yeoman-environment-2.0.5.tgz"
+ "version" "2.0.5"
+ dependencies:
+ "chalk" "^2.1.0"
+ "debug" "^3.1.0"
+ "diff" "^3.3.1"
+ "escape-string-regexp" "^1.0.2"
+ "globby" "^6.1.0"
+ "grouped-queue" "^0.3.3"
+ "inquirer" "^3.3.0"
+ "is-scoped" "^1.0.0"
+ "lodash" "^4.17.4"
+ "log-symbols" "^2.1.0"
+ "mem-fs" "^1.1.0"
+ "text-table" "^0.2.0"
+ "untildify" "^3.0.2"
+
+"yeoman-generator@2.0.1":
+ "integrity" "sha512-28aWklXHNWwlH1OcRNx1f/oIyAkTBhvzAgpIt5CpQsTAZR4ZDfei83jpNGN46OSkZnZ3enRjFWJqSGWAph04gQ=="
+ "resolved" "https://registry.npmjs.org/yeoman-generator/-/yeoman-generator-2.0.1.tgz"
+ "version" "2.0.1"
+ dependencies:
+ "async" "^2.5.0"
+ "chalk" "^2.1.0"
+ "cli-table" "^0.3.1"
+ "cross-spawn" "^5.1.0"
+ "dargs" "^5.1.0"
+ "dateformat" "^3.0.2"
+ "debug" "^3.1.0"
+ "detect-conflict" "^1.0.0"
+ "error" "^7.0.2"
+ "find-up" "^2.1.0"
+ "github-username" "^4.0.0"
+ "istextorbinary" "^2.1.0"
+ "lodash" "^4.11.1"
+ "make-dir" "^1.0.0"
+ "mem-fs-editor" "^3.0.0"
+ "minimist" "^1.2.0"
+ "pretty-bytes" "^4.0.2"
+ "read-chunk" "^2.1.0"
+ "read-pkg-up" "^2.0.0"
+ "rimraf" "^2.6.2"
+ "run-async" "^2.0.0"
+ "shelljs" "^0.7.8"
+ "text-table" "^0.2.0"
+ "through2" "^2.0.0"
+ "yeoman-environment" "^2.0.3"
diff --git a/target/h2db/db/myapp.mv.db b/target/h2db/db/myapp.mv.db
new file mode 100644
index 000000000..6656c7b6f
Binary files /dev/null and b/target/h2db/db/myapp.mv.db differ
diff --git a/target/h2db/db/myapp.trace.db b/target/h2db/db/myapp.trace.db
new file mode 100644
index 000000000..eafe193b5
--- /dev/null
+++ b/target/h2db/db/myapp.trace.db
@@ -0,0 +1,129 @@
+2022-01-05 16:06:40 jdbc[3]: exception
+org.h2.jdbc.JdbcSQLSyntaxErrorException: Function "VERSION" not found; SQL statement:
+select version() [90022-200]
+ at org.h2.message.DbException.getJdbcSQLException(DbException.java:576)
+ at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
+ at org.h2.message.DbException.get(DbException.java:205)
+ at org.h2.message.DbException.get(DbException.java:181)
+ at org.h2.command.Parser.readJavaFunction(Parser.java:3565)
+ at org.h2.command.Parser.readFunction(Parser.java:3770)
+ at org.h2.command.Parser.readTerm(Parser.java:4305)
+ at org.h2.command.Parser.readFactor(Parser.java:3343)
+ at org.h2.command.Parser.readSum(Parser.java:3330)
+ at org.h2.command.Parser.readConcat(Parser.java:3305)
+ at org.h2.command.Parser.readCondition(Parser.java:3108)
+ at org.h2.command.Parser.readExpression(Parser.java:3059)
+ at org.h2.command.Parser.parseSelectExpressions(Parser.java:2931)
+ at org.h2.command.Parser.parseSelect(Parser.java:2952)
+ at org.h2.command.Parser.parseQuerySub(Parser.java:2817)
+ at org.h2.command.Parser.parseSelectUnion(Parser.java:2649)
+ at org.h2.command.Parser.parseQuery(Parser.java:2620)
+ at org.h2.command.Parser.parsePrepared(Parser.java:868)
+ at org.h2.command.Parser.parse(Parser.java:843)
+ at org.h2.command.Parser.parse(Parser.java:815)
+ at org.h2.command.Parser.prepareCommand(Parser.java:738)
+ at org.h2.engine.Session.prepareLocal(Session.java:657)
+ at org.h2.engine.Session.prepareCommand(Session.java:595)
+ at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1235)
+ at org.h2.jdbc.JdbcStatement.executeQuery(JdbcStatement.java:78)
+ at com.zaxxer.hikari.pool.ProxyStatement.executeQuery(ProxyStatement.java:110)
+ at com.zaxxer.hikari.pool.HikariProxyStatement.executeQuery(HikariProxyStatement.java)
+ at liquibase.database.core.CockroachDatabase.isCorrectDatabaseImplementation(CockroachDatabase.java:38)
+ at liquibase.database.DatabaseFactory.findCorrectDatabaseImplementation(DatabaseFactory.java:101)
+ at liquibase.integration.spring.SpringLiquibase.createDatabase(SpringLiquibase.java:355)
+ at liquibase.integration.spring.SpringLiquibase.createLiquibase(SpringLiquibase.java:322)
+ at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:267)
+ at org.springframework.boot.autoconfigure.liquibase.DataSourceClosingSpringLiquibase.afterPropertiesSet(DataSourceClosingSpringLiquibase.java:46)
+ at tech.jhipster.config.liquibase.AsyncSpringLiquibase.initDb(AsyncSpringLiquibase.java:118)
+ at tech.jhipster.config.liquibase.AsyncSpringLiquibase.lambda$afterPropertiesSet$0(AsyncSpringLiquibase.java:93)
+ at tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor.lambda$createWrappedRunnable$1(ExceptionHandlingAsyncTaskExecutor.java:78)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
+ at java.base/java.lang.Thread.run(Thread.java:829)
+2022-01-05 16:06:41 jdbc[3]: exception
+org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "DATABASECHANGELOGLOCK" not found; SQL statement:
+SELECT COUNT(*) FROM PUBLIC.DATABASECHANGELOGLOCK [42102-200]
+2022-01-05 16:48:08 jdbc[3]: exception
+org.h2.jdbc.JdbcSQLSyntaxErrorException: Function "VERSION" not found; SQL statement:
+select version() [90022-200]
+ at org.h2.message.DbException.getJdbcSQLException(DbException.java:576)
+ at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
+ at org.h2.message.DbException.get(DbException.java:205)
+ at org.h2.message.DbException.get(DbException.java:181)
+ at org.h2.command.Parser.readJavaFunction(Parser.java:3565)
+ at org.h2.command.Parser.readFunction(Parser.java:3770)
+ at org.h2.command.Parser.readTerm(Parser.java:4305)
+ at org.h2.command.Parser.readFactor(Parser.java:3343)
+ at org.h2.command.Parser.readSum(Parser.java:3330)
+ at org.h2.command.Parser.readConcat(Parser.java:3305)
+ at org.h2.command.Parser.readCondition(Parser.java:3108)
+ at org.h2.command.Parser.readExpression(Parser.java:3059)
+ at org.h2.command.Parser.parseSelectExpressions(Parser.java:2931)
+ at org.h2.command.Parser.parseSelect(Parser.java:2952)
+ at org.h2.command.Parser.parseQuerySub(Parser.java:2817)
+ at org.h2.command.Parser.parseSelectUnion(Parser.java:2649)
+ at org.h2.command.Parser.parseQuery(Parser.java:2620)
+ at org.h2.command.Parser.parsePrepared(Parser.java:868)
+ at org.h2.command.Parser.parse(Parser.java:843)
+ at org.h2.command.Parser.parse(Parser.java:815)
+ at org.h2.command.Parser.prepareCommand(Parser.java:738)
+ at org.h2.engine.Session.prepareLocal(Session.java:657)
+ at org.h2.engine.Session.prepareCommand(Session.java:595)
+ at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1235)
+ at org.h2.jdbc.JdbcStatement.executeQuery(JdbcStatement.java:78)
+ at com.zaxxer.hikari.pool.ProxyStatement.executeQuery(ProxyStatement.java:110)
+ at com.zaxxer.hikari.pool.HikariProxyStatement.executeQuery(HikariProxyStatement.java)
+ at liquibase.database.core.CockroachDatabase.isCorrectDatabaseImplementation(CockroachDatabase.java:38)
+ at liquibase.database.DatabaseFactory.findCorrectDatabaseImplementation(DatabaseFactory.java:101)
+ at liquibase.integration.spring.SpringLiquibase.createDatabase(SpringLiquibase.java:355)
+ at liquibase.integration.spring.SpringLiquibase.createLiquibase(SpringLiquibase.java:322)
+ at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:267)
+ at org.springframework.boot.autoconfigure.liquibase.DataSourceClosingSpringLiquibase.afterPropertiesSet(DataSourceClosingSpringLiquibase.java:46)
+ at tech.jhipster.config.liquibase.AsyncSpringLiquibase.initDb(AsyncSpringLiquibase.java:118)
+ at tech.jhipster.config.liquibase.AsyncSpringLiquibase.lambda$afterPropertiesSet$0(AsyncSpringLiquibase.java:93)
+ at tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor.lambda$createWrappedRunnable$1(ExceptionHandlingAsyncTaskExecutor.java:78)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
+ at java.base/java.lang.Thread.run(Thread.java:829)
+2022-01-05 17:30:45 jdbc[3]: exception
+org.h2.jdbc.JdbcSQLSyntaxErrorException: Function "VERSION" not found; SQL statement:
+select version() [90022-200]
+ at org.h2.message.DbException.getJdbcSQLException(DbException.java:576)
+ at org.h2.message.DbException.getJdbcSQLException(DbException.java:429)
+ at org.h2.message.DbException.get(DbException.java:205)
+ at org.h2.message.DbException.get(DbException.java:181)
+ at org.h2.command.Parser.readJavaFunction(Parser.java:3565)
+ at org.h2.command.Parser.readFunction(Parser.java:3770)
+ at org.h2.command.Parser.readTerm(Parser.java:4305)
+ at org.h2.command.Parser.readFactor(Parser.java:3343)
+ at org.h2.command.Parser.readSum(Parser.java:3330)
+ at org.h2.command.Parser.readConcat(Parser.java:3305)
+ at org.h2.command.Parser.readCondition(Parser.java:3108)
+ at org.h2.command.Parser.readExpression(Parser.java:3059)
+ at org.h2.command.Parser.parseSelectExpressions(Parser.java:2931)
+ at org.h2.command.Parser.parseSelect(Parser.java:2952)
+ at org.h2.command.Parser.parseQuerySub(Parser.java:2817)
+ at org.h2.command.Parser.parseSelectUnion(Parser.java:2649)
+ at org.h2.command.Parser.parseQuery(Parser.java:2620)
+ at org.h2.command.Parser.parsePrepared(Parser.java:868)
+ at org.h2.command.Parser.parse(Parser.java:843)
+ at org.h2.command.Parser.parse(Parser.java:815)
+ at org.h2.command.Parser.prepareCommand(Parser.java:738)
+ at org.h2.engine.Session.prepareLocal(Session.java:657)
+ at org.h2.engine.Session.prepareCommand(Session.java:595)
+ at org.h2.jdbc.JdbcConnection.prepareCommand(JdbcConnection.java:1235)
+ at org.h2.jdbc.JdbcStatement.executeQuery(JdbcStatement.java:78)
+ at com.zaxxer.hikari.pool.ProxyStatement.executeQuery(ProxyStatement.java:110)
+ at com.zaxxer.hikari.pool.HikariProxyStatement.executeQuery(HikariProxyStatement.java)
+ at liquibase.database.core.CockroachDatabase.isCorrectDatabaseImplementation(CockroachDatabase.java:38)
+ at liquibase.database.DatabaseFactory.findCorrectDatabaseImplementation(DatabaseFactory.java:101)
+ at liquibase.integration.spring.SpringLiquibase.createDatabase(SpringLiquibase.java:355)
+ at liquibase.integration.spring.SpringLiquibase.createLiquibase(SpringLiquibase.java:322)
+ at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:267)
+ at org.springframework.boot.autoconfigure.liquibase.DataSourceClosingSpringLiquibase.afterPropertiesSet(DataSourceClosingSpringLiquibase.java:46)
+ at tech.jhipster.config.liquibase.AsyncSpringLiquibase.initDb(AsyncSpringLiquibase.java:118)
+ at tech.jhipster.config.liquibase.AsyncSpringLiquibase.lambda$afterPropertiesSet$0(AsyncSpringLiquibase.java:93)
+ at tech.jhipster.async.ExceptionHandlingAsyncTaskExecutor.lambda$createWrappedRunnable$1(ExceptionHandlingAsyncTaskExecutor.java:78)
+ at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
+ at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
+ at java.base/java.lang.Thread.run(Thread.java:829)