From 0d1d154c7a729c3d660a3baf54434ca7fa9feaf5 Mon Sep 17 00:00:00 2001 From: Alex Clarke Date: Fri, 16 Feb 2024 17:37:37 -0700 Subject: [PATCH] Open-sourced generic, dynamic POC, RESTful alerting API --- .gitignore | 37 + .jpb/jpb-settings.xml | 6 + alerting-architecture.png | Bin 0 -> 70284 bytes amqp/build.gradle.kts | 19 + .../com/poc/alerting/amqp/AmqpMessage.java | 11 + .../com/poc/alerting/amqp/AmqpResponse.java | 16 + .../com/poc/alerting/amqp/ExceptionType.java | 21 + .../alerting/amqp/GsonMessageConverter.java | 79 ++ .../amqp/MessageDataTransferObject.java | 16 + .../com/poc/alerting/amqp/RabbitSender.java | 50 + .../poc/alerting/amqp/AlertingAmqpMessage.kt | 20 + .../poc/alerting/amqp/AmqpConfiguration.kt | 79 ++ api/build.gradle.kts | 27 + .../com/poc/alerting/api/PropertyCopier.java | 26 + .../com/poc/alerting/api/AlertingApi.kt | 11 + .../api/controller/AlertController.kt | 95 ++ .../api/controller/RecipientController.kt | 77 ++ api/src/main/resources/application.yml | 22 + batch/build.gradle.kts | 29 + .../batch/AccountConsumerManager.java | 52 + .../alerting/batch/ApplicationStartup.java | 67 ++ .../ExclusiveConsumerExceptionLogger.java | 11 + .../com/poc/alerting/batch/QueueCreator.java | 65 ++ .../com/poc/alerting/batch/AccountWorker.kt | 101 ++ .../batch/AutowiringSpringBeanJobFactory.kt | 37 + .../com/poc/alerting/batch/BatchWorker.kt | 16 + .../com/poc/alerting/batch/ConsumerCreator.kt | 31 + .../poc/alerting/batch/WorkerConfiguration.kt | 97 ++ .../poc/alerting/batch/jobs/AlertQueryJob.kt | 50 + .../jobs/ScheduleAlertQueryConfiguration.kt | 33 + batch/src/main/resources/application.yml | 19 + build.gradle.kts | 75 ++ docs/AlertingApi.yaml | 938 ++++++++++++++++++ docs/dist/favicon-16x16.png | Bin 0 -> 665 bytes docs/dist/favicon-32x32.png | Bin 0 -> 628 bytes docs/dist/oauth2-redirect.html | 75 ++ docs/dist/swagger-ui-bundle.js | 3 + docs/dist/swagger-ui-bundle.js.map | 1 + docs/dist/swagger-ui-es-bundle-core.js | 3 + docs/dist/swagger-ui-es-bundle-core.js.map | 1 + docs/dist/swagger-ui-es-bundle.js | 3 + docs/dist/swagger-ui-es-bundle.js.map | 1 + docs/dist/swagger-ui-standalone-preset.js | 3 + docs/dist/swagger-ui-standalone-preset.js.map | 1 + docs/dist/swagger-ui.css | 4 + docs/dist/swagger-ui.css.map | 1 + docs/dist/swagger-ui.js | 3 + docs/dist/swagger-ui.js.map | 1 + docs/index.html | 60 ++ gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 5 + gradlew | 185 ++++ gradlew.bat | 89 ++ lombok.config | 6 + persistence/build.gradle.kts | 27 + .../com/poc/alerting/persistence/H2Config.kt | 23 + .../poc/alerting/persistence/Persistence.kt | 12 + .../poc/alerting/persistence/dto/Account.kt | 22 + .../com/poc/alerting/persistence/dto/Alert.kt | 65 ++ .../alerting/persistence/dto/AlertTypeEnum.kt | 8 + .../poc/alerting/persistence/dto/Recipient.kt | 58 ++ .../persistence/dto/RecipientTypeEnum.kt | 7 + .../repositories/AccountRepository.kt | 10 + .../repositories/AlertRepository.kt | 13 + .../repositories/RecipientRepository.kt | 14 + .../src/main/resources/application.yml | 21 + .../db/migration/V1__Delete_Quartz_Tables.sql | 11 + .../db/migration/V2__Create_Quartz_Schema.sql | 238 +++++ .../migration/V3__Create_Alerting_Schema.sql | 63 ++ settings.gradle.kts | 2 + 70 files changed, 3272 insertions(+) create mode 100644 .gitignore create mode 100644 .jpb/jpb-settings.xml create mode 100644 alerting-architecture.png create mode 100644 amqp/build.gradle.kts create mode 100644 amqp/src/main/java/com/poc/alerting/amqp/AmqpMessage.java create mode 100644 amqp/src/main/java/com/poc/alerting/amqp/AmqpResponse.java create mode 100644 amqp/src/main/java/com/poc/alerting/amqp/ExceptionType.java create mode 100644 amqp/src/main/java/com/poc/alerting/amqp/GsonMessageConverter.java create mode 100644 amqp/src/main/java/com/poc/alerting/amqp/MessageDataTransferObject.java create mode 100644 amqp/src/main/java/com/poc/alerting/amqp/RabbitSender.java create mode 100644 amqp/src/main/kotlin/com/poc/alerting/amqp/AlertingAmqpMessage.kt create mode 100644 amqp/src/main/kotlin/com/poc/alerting/amqp/AmqpConfiguration.kt create mode 100644 api/build.gradle.kts create mode 100644 api/src/main/java/com/poc/alerting/api/PropertyCopier.java create mode 100644 api/src/main/kotlin/com/poc/alerting/api/AlertingApi.kt create mode 100644 api/src/main/kotlin/com/poc/alerting/api/controller/AlertController.kt create mode 100644 api/src/main/kotlin/com/poc/alerting/api/controller/RecipientController.kt create mode 100644 api/src/main/resources/application.yml create mode 100644 batch/build.gradle.kts create mode 100644 batch/src/main/java/com/poc/alerting/batch/AccountConsumerManager.java create mode 100644 batch/src/main/java/com/poc/alerting/batch/ApplicationStartup.java create mode 100644 batch/src/main/java/com/poc/alerting/batch/ExclusiveConsumerExceptionLogger.java create mode 100644 batch/src/main/java/com/poc/alerting/batch/QueueCreator.java create mode 100644 batch/src/main/kotlin/com/poc/alerting/batch/AccountWorker.kt create mode 100644 batch/src/main/kotlin/com/poc/alerting/batch/AutowiringSpringBeanJobFactory.kt create mode 100644 batch/src/main/kotlin/com/poc/alerting/batch/BatchWorker.kt create mode 100644 batch/src/main/kotlin/com/poc/alerting/batch/ConsumerCreator.kt create mode 100644 batch/src/main/kotlin/com/poc/alerting/batch/WorkerConfiguration.kt create mode 100644 batch/src/main/kotlin/com/poc/alerting/batch/jobs/AlertQueryJob.kt create mode 100644 batch/src/main/kotlin/com/poc/alerting/batch/jobs/ScheduleAlertQueryConfiguration.kt create mode 100644 batch/src/main/resources/application.yml create mode 100644 build.gradle.kts create mode 100644 docs/AlertingApi.yaml create mode 100644 docs/dist/favicon-16x16.png create mode 100644 docs/dist/favicon-32x32.png create mode 100644 docs/dist/oauth2-redirect.html create mode 100644 docs/dist/swagger-ui-bundle.js create mode 100644 docs/dist/swagger-ui-bundle.js.map create mode 100644 docs/dist/swagger-ui-es-bundle-core.js create mode 100644 docs/dist/swagger-ui-es-bundle-core.js.map create mode 100644 docs/dist/swagger-ui-es-bundle.js create mode 100644 docs/dist/swagger-ui-es-bundle.js.map create mode 100644 docs/dist/swagger-ui-standalone-preset.js create mode 100644 docs/dist/swagger-ui-standalone-preset.js.map create mode 100644 docs/dist/swagger-ui.css create mode 100644 docs/dist/swagger-ui.css.map create mode 100644 docs/dist/swagger-ui.js create mode 100644 docs/dist/swagger-ui.js.map create mode 100644 docs/index.html create mode 100644 gradle/wrapper/gradle-wrapper.jar create mode 100644 gradle/wrapper/gradle-wrapper.properties create mode 100755 gradlew create mode 100644 gradlew.bat create mode 100644 lombok.config create mode 100644 persistence/build.gradle.kts create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/H2Config.kt create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/Persistence.kt create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Account.kt create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Alert.kt create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/dto/AlertTypeEnum.kt create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Recipient.kt create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/dto/RecipientTypeEnum.kt create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/AccountRepository.kt create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/AlertRepository.kt create mode 100644 persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/RecipientRepository.kt create mode 100644 persistence/src/main/resources/application.yml create mode 100644 persistence/src/main/resources/db/migration/V1__Delete_Quartz_Tables.sql create mode 100644 persistence/src/main/resources/db/migration/V2__Create_Quartz_Schema.sql create mode 100644 persistence/src/main/resources/db/migration/V3__Create_Alerting_Schema.sql create mode 100644 settings.gradle.kts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c2065bc --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +HELP.md +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ diff --git a/.jpb/jpb-settings.xml b/.jpb/jpb-settings.xml new file mode 100644 index 0000000..fb1f21c --- /dev/null +++ b/.jpb/jpb-settings.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/alerting-architecture.png b/alerting-architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..6edbb3e4dfabf78559f0ecd6014ce42107bcd268 GIT binary patch literal 70284 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"bootJar") { + enabled = false +} + +tasks.getByName("jar") { + enabled = true +} diff --git a/amqp/src/main/java/com/poc/alerting/amqp/AmqpMessage.java b/amqp/src/main/java/com/poc/alerting/amqp/AmqpMessage.java new file mode 100644 index 0000000..fcb4a00 --- /dev/null +++ b/amqp/src/main/java/com/poc/alerting/amqp/AmqpMessage.java @@ -0,0 +1,11 @@ +package com.poc.alerting.amqp; + +import java.io.Serializable; + +public interface AmqpMessage extends Serializable { + String correlationId = "correlation-id"; + + String getRoutingKey(); + + String getExchange(); +} diff --git a/amqp/src/main/java/com/poc/alerting/amqp/AmqpResponse.java b/amqp/src/main/java/com/poc/alerting/amqp/AmqpResponse.java new file mode 100644 index 0000000..d5af31c --- /dev/null +++ b/amqp/src/main/java/com/poc/alerting/amqp/AmqpResponse.java @@ -0,0 +1,16 @@ +package com.poc.alerting.amqp; + +import java.io.Serializable; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public abstract class AmqpResponse implements Serializable { + private T value; + private ExceptionType exceptionType; + private String exceptionMessage; + private Integer errorCode; + private String errorDescription; +} diff --git a/amqp/src/main/java/com/poc/alerting/amqp/ExceptionType.java b/amqp/src/main/java/com/poc/alerting/amqp/ExceptionType.java new file mode 100644 index 0000000..d3467bc --- /dev/null +++ b/amqp/src/main/java/com/poc/alerting/amqp/ExceptionType.java @@ -0,0 +1,21 @@ +package com.poc.alerting.amqp; + +public enum ExceptionType { + INVALID_REQUEST_EXCEPTION(400), + INVALID_ACCOUNT_EXCEPTION(403), + NOT_FOUND_EXCEPTION(404), + REQUEST_TIMEOUT_EXCEPTION(408), + CONFLICT_EXCEPTION(409), + UNPROCESSABLE_ENTITY_EXCEPTION(422), + INTERNAL_SERVER_EXCEPTION(500); + + private final int status; + + ExceptionType(final int status) { + this.status = status; + } + + public int getStatus() { + return status; + } +} diff --git a/amqp/src/main/java/com/poc/alerting/amqp/GsonMessageConverter.java b/amqp/src/main/java/com/poc/alerting/amqp/GsonMessageConverter.java new file mode 100644 index 0000000..6beb618 --- /dev/null +++ b/amqp/src/main/java/com/poc/alerting/amqp/GsonMessageConverter.java @@ -0,0 +1,79 @@ +package com.poc.alerting.amqp; + +import java.io.Serializable; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.UUID; + +import org.springframework.amqp.core.Message; +import org.springframework.amqp.core.MessageProperties; +import org.springframework.amqp.support.converter.MessageConversionException; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; + +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class GsonMessageConverter implements MessageConverter { + private static final Gson GSON = new GsonBuilder().setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").create(); + + @Override + public Message toMessage(final Object object, final MessageProperties messageProperties) throws MessageConversionException { + if (!(object instanceof Serializable)) { + throw new MessageConversionException("Message object is not serializable"); + } + + try { + final String json = GSON.toJson(object); + if (json == null) { + throw new MessageConversionException("Unable to serialize the message to JSON"); + } + + LOG.debug("json = {}", json); + + final byte[] bytes = json.getBytes(StandardCharsets.UTF_8); + messageProperties.setContentType(MessageProperties.CONTENT_TYPE_JSON); + messageProperties.setContentEncoding("UTF-8"); + messageProperties.setContentLength(bytes.length); + messageProperties.setTimestamp(new Date()); + messageProperties.setType(object.getClass().getName()); + if (messageProperties.getMessageId() == null) { + messageProperties.setMessageId(UUID.randomUUID().toString()); + } + + return new Message(bytes, messageProperties); + } catch (final Exception e) { + throw new MessageConversionException(e.getMessage(), e); + } + } + + @Override + public Object fromMessage(final Message message) throws MessageConversionException { + final byte[] messageBody = message.getBody(); + if (messageBody == null) { + LOG.warn("No message body found for message: {}", message); + return null; + } + + final MessageProperties messageProperties = message.getMessageProperties(); + final String className = StringUtils.trimAllWhitespace(messageProperties.getType()); + if (StringUtils.isEmpty(className)) { + LOG.error("Could not determine class from message: {}", message); + return null; + } + + try { + final String json = new String(messageBody, StandardCharsets.UTF_8); + LOG.debug("json = {}", json); + return GSON.fromJson(json, Class.forName(className)); + } catch (final Exception e) { + LOG.error("Could not deserialize message: " + message, e); + throw new MessageConversionException(e.getMessage(), e); + } + } +} diff --git a/amqp/src/main/java/com/poc/alerting/amqp/MessageDataTransferObject.java b/amqp/src/main/java/com/poc/alerting/amqp/MessageDataTransferObject.java new file mode 100644 index 0000000..d5e9ea9 --- /dev/null +++ b/amqp/src/main/java/com/poc/alerting/amqp/MessageDataTransferObject.java @@ -0,0 +1,16 @@ +package com.poc.alerting.amqp; + +import java.io.Serializable; + +import org.springframework.amqp.core.Message; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class MessageDataTransferObject implements Serializable { + private String routingKey; + private String exchange; + private Message message; +} diff --git a/amqp/src/main/java/com/poc/alerting/amqp/RabbitSender.java b/amqp/src/main/java/com/poc/alerting/amqp/RabbitSender.java new file mode 100644 index 0000000..20f038b --- /dev/null +++ b/amqp/src/main/java/com/poc/alerting/amqp/RabbitSender.java @@ -0,0 +1,50 @@ +package com.poc.alerting.amqp; + +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +@RequiredArgsConstructor +public class RabbitSender { + private final RabbitTemplate rabbitTemplate; + + public void send(final AmqpMessage amqpMessage) { + try { + LOG.info("Sending message: {}", amqpMessage.toString()); + rabbitTemplate.convertAndSend(amqpMessage.getExchange(), amqpMessage.getRoutingKey(), amqpMessage); + } catch (final Exception e) { + LOG.error("Error sending message, serializing to disk", e); + } + } + + public T sendAndReceive(final AmqpMessage amqpMessage) { + final AmqpResponse amqpResponse = (AmqpResponse) rabbitTemplate.convertSendAndReceive(amqpMessage.getExchange(), amqpMessage.getRoutingKey(), amqpMessage); + final String errorMessage = "Something went wrong"; + if (amqpResponse == null) { + LOG.error(errorMessage); + } + final ExceptionType exceptionType = amqpResponse.getExceptionType(); + if (exceptionType != null) { + final String exceptionMessage = amqpResponse.getExceptionMessage(); + final int statusCode = exceptionType.getStatus(); + if (amqpResponse.getErrorCode() != null) { + final Integer errorCode = amqpResponse.getErrorCode(); + final String errorDescription = amqpResponse.getErrorDescription(); + LOG.error(errorMessage); + } else { + LOG.error(errorMessage); + } + } + return amqpResponse.getValue(); + } + + public void sendWithoutBackup(final AmqpMessage amqpMessage) { + LOG.info("Sending message: {}", amqpMessage.toString()); + rabbitTemplate.convertAndSend(amqpMessage.getExchange(), amqpMessage.getRoutingKey(), amqpMessage); + } +} diff --git a/amqp/src/main/kotlin/com/poc/alerting/amqp/AlertingAmqpMessage.kt b/amqp/src/main/kotlin/com/poc/alerting/amqp/AlertingAmqpMessage.kt new file mode 100644 index 0000000..7192c4e --- /dev/null +++ b/amqp/src/main/kotlin/com/poc/alerting/amqp/AlertingAmqpMessage.kt @@ -0,0 +1,20 @@ +package com.poc.alerting.amqp + +sealed class AlertingAmqpMessage( + val alertId: String, + val accountId: String +): AmqpMessage { + override fun getRoutingKey(): String { + return "account_$accountId" + } + + override fun getExchange(): String { + return "poc_alerting" + } + + class Add(val frequency: String, alertId: String, accountId: String): AlertingAmqpMessage(alertId, accountId) + class Update(val frequency: String, alertId: String, accountId: String): AlertingAmqpMessage(alertId, accountId) + class Delete(alertId: String, accountId: String): AlertingAmqpMessage(alertId, accountId) + class Pause(alertId: String, accountId: String): AlertingAmqpMessage(alertId, accountId) + class Resume(alertId: String, accountId: String): AlertingAmqpMessage(alertId, accountId) +} \ No newline at end of file diff --git a/amqp/src/main/kotlin/com/poc/alerting/amqp/AmqpConfiguration.kt b/amqp/src/main/kotlin/com/poc/alerting/amqp/AmqpConfiguration.kt new file mode 100644 index 0000000..4e27406 --- /dev/null +++ b/amqp/src/main/kotlin/com/poc/alerting/amqp/AmqpConfiguration.kt @@ -0,0 +1,79 @@ +package com.poc.alerting.amqp + +import org.apache.commons.lang3.time.DateUtils.MILLIS_PER_MINUTE +import org.springframework.amqp.core.Binding +import org.springframework.amqp.core.BindingBuilder +import org.springframework.amqp.core.DirectExchange +import org.springframework.amqp.core.Exchange +import org.springframework.amqp.core.ExchangeBuilder +import org.springframework.amqp.core.FanoutExchange +import org.springframework.amqp.core.Queue +import org.springframework.amqp.rabbit.connection.CachingConnectionFactory +import org.springframework.amqp.rabbit.connection.ConnectionFactory +import org.springframework.amqp.rabbit.core.RabbitTemplate +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration + +@Configuration +@ComponentScan(basePackages = ["com.poc.alerting.amqp"]) +open class AmqpConfiguration { + companion object { + const val AMQP_NAME = "poc_alerting" + const val NEW_ACCOUNT = "new_account" + const val FANOUT_NAME = "${AMQP_NAME}_fanout" + } + + @Bean + open fun connectionFactory(): ConnectionFactory { + return CachingConnectionFactory().apply { + virtualHost = "poc" + username = "poc_user" + setPassword("s!mpleP@ssw0rd") + setAddresses("localhost") + } + } + + @Bean + open fun newAccountQueue(): Queue { + return Queue(NEW_ACCOUNT, true) + } + + @Bean + open fun newAccountExchange(): FanoutExchange { + return FanoutExchange(NEW_ACCOUNT) + } + + @Bean + open fun newAccountBinding(newAccountQueue: Queue, newAccountExchange: FanoutExchange): Binding { + return BindingBuilder.bind(newAccountQueue).to(newAccountExchange) + } + + @Bean + open fun pocAlertingExchange(): FanoutExchange { + return FanoutExchange(FANOUT_NAME) + } + + @Bean + open fun directExchange(): DirectExchange { + return ExchangeBuilder.directExchange(AMQP_NAME) + .durable(false) + .withArgument("alternate-exchange", NEW_ACCOUNT) + .build() + } + + @Bean + open fun exchangeBinding(directExchange: Exchange, pocAlertingExchange: FanoutExchange): Binding { + return BindingBuilder.bind(directExchange).to(pocAlertingExchange) + } + + @Bean + open fun rabbitTemplate(connectionFactory: ConnectionFactory, gsonMessageConverter: GsonMessageConverter): RabbitTemplate { + return RabbitTemplate(connectionFactory).apply { + setExchange(FANOUT_NAME) + messageConverter = gsonMessageConverter + setReplyTimeout(MILLIS_PER_MINUTE) + setMandatory(true) + } + } +} \ No newline at end of file diff --git a/api/build.gradle.kts b/api/build.gradle.kts new file mode 100644 index 0000000..962ffe8 --- /dev/null +++ b/api/build.gradle.kts @@ -0,0 +1,27 @@ +import org.springframework.boot.gradle.tasks.bundling.BootJar + +plugins { + id("io.swagger.core.v3.swagger-gradle-plugin") version "2.1.9" + kotlin("plugin.jpa") version "1.5.10" + +} + +tasks.withType { + sourceCompatibility = "1.8" + targetCompatibility = "1.8" +} + +dependencies { + "implementation"(project(":persistence")) + "implementation"(project(":amqp")) + + implementation("org.springframework.boot:spring-boot-starter-aop") + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-tomcat") + implementation("javax.validation:validation-api") +} + +tasks.getByName("bootJar") { + enabled = true + mainClass.set("com.poc.alerting.api.AlertingApi") +} \ No newline at end of file diff --git a/api/src/main/java/com/poc/alerting/api/PropertyCopier.java b/api/src/main/java/com/poc/alerting/api/PropertyCopier.java new file mode 100644 index 0000000..969adf8 --- /dev/null +++ b/api/src/main/java/com/poc/alerting/api/PropertyCopier.java @@ -0,0 +1,26 @@ +package com.poc.alerting.api; + +import java.beans.FeatureDescriptor; +import java.util.List; +import java.util.stream.Stream; + +import org.springframework.beans.BeanUtils; +import org.springframework.beans.BeanWrapper; +import org.springframework.beans.BeanWrapperImpl; + +public final class PropertyCopier { + private PropertyCopier() { + } + + public static void copyNonNullProperties(final Object source, final Object target, final List ignoredProperties) { + BeanUtils.copyProperties(source, target, getNullPropertyNames(source, ignoredProperties)); + } + + private static String[] getNullPropertyNames(final Object source, final List ignoredProperties) { + final BeanWrapper wrappedSource = new BeanWrapperImpl(source); + return Stream.of(wrappedSource.getPropertyDescriptors()) + .map(FeatureDescriptor::getName) + .filter(propertyName -> wrappedSource.getPropertyValue(propertyName) == null || (ignoredProperties != null && ignoredProperties.contains(propertyName))) + .toArray(String[]::new); + } +} diff --git a/api/src/main/kotlin/com/poc/alerting/api/AlertingApi.kt b/api/src/main/kotlin/com/poc/alerting/api/AlertingApi.kt new file mode 100644 index 0000000..5dc3a09 --- /dev/null +++ b/api/src/main/kotlin/com/poc/alerting/api/AlertingApi.kt @@ -0,0 +1,11 @@ +package com.poc.alerting.api + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + +@SpringBootApplication(scanBasePackages = ["com.poc.alerting"]) +open class AlertingApi + +fun main(args: Array) { + runApplication(*args) +} \ No newline at end of file diff --git a/api/src/main/kotlin/com/poc/alerting/api/controller/AlertController.kt b/api/src/main/kotlin/com/poc/alerting/api/controller/AlertController.kt new file mode 100644 index 0000000..38bd1f7 --- /dev/null +++ b/api/src/main/kotlin/com/poc/alerting/api/controller/AlertController.kt @@ -0,0 +1,95 @@ +package com.poc.alerting.api.controller + +import com.poc.alerting.amqp.AlertingAmqpMessage.Add +import com.poc.alerting.amqp.AlertingAmqpMessage.Delete +import com.poc.alerting.amqp.AlertingAmqpMessage.Pause +import com.poc.alerting.amqp.AlertingAmqpMessage.Resume +import com.poc.alerting.amqp.AlertingAmqpMessage.Update +import com.poc.alerting.amqp.RabbitSender +import com.poc.alerting.api.PropertyCopier +import com.poc.alerting.persistence.dto.Alert +import com.poc.alerting.persistence.repositories.AccountRepository +import com.poc.alerting.persistence.repositories.AlertRepository +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import javax.validation.Valid + +@RestController +@Validated +open class AlertController @Autowired constructor( + private val accountRepository: AccountRepository, + private val alertRepository: AlertRepository, + private val rabbitSender: RabbitSender +) { + @PostMapping("/accounts/{account_id}/alerts") + open fun addAlert(@PathVariable("account_id") accountId: String, + @RequestBody body: @Valid Alert + ): ResponseEntity { + val account = accountRepository.findByExtId(accountId) + body.account = account + val alert = alertRepository.save(body).also { + rabbitSender.send(Add(body.frequency, body.extId, accountId)) + } + + return ResponseEntity(alert, HttpStatus.CREATED) + } + + @DeleteMapping("/accounts/{account_id}/alerts/{alert_id}") + open fun deleteAlert(@PathVariable("account_id") accountId: String, + @PathVariable("alert_id") alertId: String + ): ResponseEntity { + rabbitSender.send(Delete(alertId, accountId)) + return ResponseEntity(HttpStatus.OK) + } + + @GetMapping("/accounts/{account_id}/alerts/{alert_id}") + open fun getAlertById( + @PathVariable("account_id") accountId: String, + @PathVariable("alert_id") alertId: String, + @RequestParam(value = "include_recipients", required = false, defaultValue = "false") includeRecipients: @Valid Boolean? + ): ResponseEntity { + return ResponseEntity.ok(alertRepository.findByExtIdAndAccount_ExtId(alertId, accountId)) + } + + @GetMapping("/accounts/{account_id}/alerts") + open fun getListOfAlerts( + @PathVariable("account_id") accountId: String, + @RequestParam(value = "include_recipients", required = false, defaultValue = "false") includeRecipients: @Valid Boolean? + ): ResponseEntity> { + return ResponseEntity.ok(alertRepository.findAllByAccount_ExtId(accountId)) + } + + @PatchMapping("/accounts/{account_id}/alerts/{alert_id}") + open fun updateAlert( + @PathVariable("account_id") accountId: String, + @PathVariable("alert_id") alertId: String, + @RequestBody body: @Valid Alert + ): ResponseEntity { + val existingAlert = alertRepository.findByExtIdAndAccount_ExtId(alertId, accountId) + + rabbitSender.send(Update(body.frequency, alertId, accountId)) + + body.enabled.let { + if (body.enabled.isNotBlank() && body.enabled.toBoolean() != existingAlert.enabled.toBoolean()) { + if (body.enabled.toBoolean()) { + rabbitSender.send(Resume(alertId, accountId)) + } else { + rabbitSender.send(Pause(alertId, accountId)) + } + } + } + + PropertyCopier.copyNonNullProperties(body, existingAlert, null) + return ResponseEntity.ok(alertRepository.save(existingAlert)) + } +} \ No newline at end of file diff --git a/api/src/main/kotlin/com/poc/alerting/api/controller/RecipientController.kt b/api/src/main/kotlin/com/poc/alerting/api/controller/RecipientController.kt new file mode 100644 index 0000000..b708435 --- /dev/null +++ b/api/src/main/kotlin/com/poc/alerting/api/controller/RecipientController.kt @@ -0,0 +1,77 @@ +package com.poc.alerting.api.controller + +import com.poc.alerting.api.PropertyCopier +import com.poc.alerting.persistence.dto.Recipient +import com.poc.alerting.persistence.repositories.RecipientRepository +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.http.HttpStatus +import org.springframework.http.ResponseEntity +import org.springframework.validation.annotation.Validated +import org.springframework.web.bind.annotation.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PatchMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RestController +import javax.validation.Valid + +@RestController +@Validated +open class RecipientController @Autowired constructor( + private val recipientRepository: RecipientRepository +) { + @PostMapping("/accounts/{account_id}/alerts/{alert_id}/recipients") + open fun addRecipient(@PathVariable("account_id") accountId: String, + @PathVariable("alert_id") alertId: String, + @RequestBody body: @Valid MutableList + ): ResponseEntity> { + return ResponseEntity(recipientRepository.saveAll(body), HttpStatus.CREATED) + } + + @DeleteMapping("/accounts/{account_id}/alerts/{alert_id}/recipients/{recipient_id}") + open fun deleteRecipient( + @PathVariable("account_id") accountId: String, + @PathVariable("alert_id") alertId: String, + @PathVariable("recipient_id") recipientId: String + ): ResponseEntity { + recipientRepository.delete(recipientRepository.findByExtIdAndAlert_ExtIdAndAccount_ExtId(recipientId, alertId, accountId)) + return ResponseEntity(HttpStatus.OK) + } + + @GetMapping("/accounts/{account_id}/recipients") + open fun getAllRecipients( + @PathVariable("account_id") accountId: String + ): ResponseEntity> { + return ResponseEntity.ok(recipientRepository.findAllByAccount_ExtId(accountId)) + } + + @GetMapping("/accounts/{account_id}/alerts/{alert_id}/recipients/{recipient_id}") + open fun getRecipient( + @PathVariable("account_id") accountId: String, + @PathVariable("alert_id") alertId: String, + @PathVariable("recipient_id") recipientId: String + ): ResponseEntity { + return ResponseEntity.ok(recipientRepository.findByExtIdAndAlert_ExtIdAndAccount_ExtId(recipientId, alertId, accountId)) + } + + @GetMapping("/accounts/{account_id}/alerts/{alert_id}/recipients") + open fun getRecipientList( + @PathVariable("account_id") accountId: String, + @PathVariable("alert_id") alertId: String + ): ResponseEntity> { + return ResponseEntity.ok(recipientRepository.findAllByAlert_ExtIdAndAccount_ExtId(alertId, accountId)) + } + + @PatchMapping("/accounts/{account_id}/alerts/{alert_id}/recipients/{recipient_id}") + open fun updateRecipient( + @PathVariable("account_id") accountId: String, + @PathVariable("alert_id") alertId: String, + @PathVariable("recipient_id") recipientId: String, + @RequestBody body: @Valid Recipient + ): ResponseEntity { + val existingRecipient = recipientRepository.findByExtIdAndAlert_ExtIdAndAccount_ExtId(recipientId, alertId, accountId) + PropertyCopier.copyNonNullProperties(body, existingRecipient, null) + return ResponseEntity.ok(recipientRepository.save(existingRecipient)) + } +} \ No newline at end of file diff --git a/api/src/main/resources/application.yml b/api/src/main/resources/application.yml new file mode 100644 index 0000000..2d1551d --- /dev/null +++ b/api/src/main/resources/application.yml @@ -0,0 +1,22 @@ +server: + servlet: + contextPath: "/poc/alerting/v1" + port: 8080 +spring: + jackson: + time-zone: UTC + default-property-inclusion: non_null + jpa: + hibernate: + ddl-auto: update + show-sql: true + datasource: + url: "jdbc:h2:tcp://localhost:9091/mem:alerting" + username: "defaultUser" + password: "secret" + application: + name: AlertingApi + main: + allow-bean-definition-overriding: true + profiles: + active: "api" diff --git a/batch/build.gradle.kts b/batch/build.gradle.kts new file mode 100644 index 0000000..2bf80b2 --- /dev/null +++ b/batch/build.gradle.kts @@ -0,0 +1,29 @@ +import org.springframework.boot.gradle.tasks.bundling.BootJar + +dependencies { + "implementation"(project(":persistence")) + "implementation"(project(":amqp")) + + implementation("org.slf4j:slf4j-api") + implementation("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("org.springframework.amqp:spring-amqp") + implementation("org.springframework.amqp:spring-rabbit") + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.springframework.boot:spring-boot-starter-quartz") + implementation("org.springframework:spring-jdbc") + implementation("org.projectlombok:lombok") + implementation("org.apache.commons:commons-lang3") + implementation("org.apache.httpcomponents:fluent-hc") + implementation("com.google.code.gson:gson") + + annotationProcessor("org.projectlombok:lombok") +} + +tasks.getByName("bootJar") { + enabled = true + mainClass.set("com.poc.alerting.batch.BatchWorkerKt") +} + +springBoot { + mainClass.set("com.poc.alerting.batch.BatchWorkerKt") +} diff --git a/batch/src/main/java/com/poc/alerting/batch/AccountConsumerManager.java b/batch/src/main/java/com/poc/alerting/batch/AccountConsumerManager.java new file mode 100644 index 0000000..b8a7ad6 --- /dev/null +++ b/batch/src/main/java/com/poc/alerting/batch/AccountConsumerManager.java @@ -0,0 +1,52 @@ +package com.poc.alerting.batch; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer; +import org.springframework.stereotype.Component; + +import lombok.Getter; +import lombok.extern.slf4j.Slf4j; + +@Component +@Slf4j +public class AccountConsumerManager { + private volatile boolean shuttingDown = false; + @Getter private final Map consumers = new ConcurrentHashMap<>(); + private final Object lifecycleMonitor = new Object(); + + void registerAndStart(final String queueName, final SimpleMessageListenerContainer newListenerContainer) { + synchronized (this.lifecycleMonitor) { + if (shuttingDown) { + LOG.warn("Shutdown process is underway. Not registering consumer for queue {}", queueName); + return; + } + + final SimpleMessageListenerContainer oldListenerContainer = consumers.get(queueName); + if (oldListenerContainer != null) { + oldListenerContainer.stop(); + } + newListenerContainer.start(); + consumers.put(queueName, newListenerContainer); + LOG.info("Registered a new consumer on queue {}", queueName); + } + } + + public void stopConsumers() { + synchronized (this.lifecycleMonitor) { + shuttingDown = true; + LOG.info("Shutting down consumers on queues {}", consumers.keySet()); + consumers.entrySet().parallelStream().forEach(entry -> { + LOG.info("Shutting down consumer on queue {}", entry.getKey()); + try { + entry.getValue().stop(); + } catch (final Exception e) { + LOG.error("Encountered error while stopping consumer on queue " + entry.getKey(), e); + } + }); + + LOG.info("Finished shutting down all consumers"); + } + } +} diff --git a/batch/src/main/java/com/poc/alerting/batch/ApplicationStartup.java b/batch/src/main/java/com/poc/alerting/batch/ApplicationStartup.java new file mode 100644 index 0000000..0b0b250 --- /dev/null +++ b/batch/src/main/java/com/poc/alerting/batch/ApplicationStartup.java @@ -0,0 +1,67 @@ +package com.poc.alerting.batch; + +import java.util.Base64; +import java.util.stream.StreamSupport; + +import org.apache.http.client.fluent.Request; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.amqp.rabbit.connection.ConnectionFactory; +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter; +import org.springframework.amqp.support.converter.MessageConverter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationEventPublisher; +import org.springframework.context.ApplicationListener; +import org.springframework.stereotype.Component; + +import com.google.gson.JsonArray; +import com.google.gson.JsonParser; + +import lombok.AllArgsConstructor; + +@Component +@AllArgsConstructor +public class ApplicationStartup implements ApplicationListener { + ConnectionFactory connectionFactory; + MessageListenerAdapter accountWorkerListenerAdapter; + MessageConverter gsonMessageConverter; + ApplicationEventPublisher applicationEventPublisher; + ConsumerCreator consumerCreator; + + private static final Logger LOG = LoggerFactory.getLogger(ApplicationStartup.class); + + @Override + public void onApplicationEvent(@NotNull final ApplicationReadyEvent event) { + LOG.info("Creating consumers for existing queues"); + try { + + final String rabbitMqUrl = String.format("http://%s:15672/api/exchanges/poc/alerting/bindings/source", "localhost"); + + //auth is kind of a kluge here. Apparently the HttpClient Fluent API doesn't support + //it except by explicitly setting the auth header. + final String json = Request.Get(rabbitMqUrl) + .connectTimeout(1000) + .socketTimeout(1000) + .addHeader("Authorization", "Basic " + getAuthToken()) + .execute().returnContent().asString(); + + final JsonParser parser = new JsonParser(); + final JsonArray array = parser.parse(json).getAsJsonArray(); + + StreamSupport.stream(array.spliterator(), false) + .map(jsonElement -> jsonElement.getAsJsonObject().get("destination").getAsString()) + .forEach(queueName -> consumerCreator.createConsumer(queueName)); + } catch (final Exception e) { + LOG.error("Error create consumers for existing queues", e); + } + } + + private String getAuthToken() { + final String basicPlaintext = "poc" + ":" + "s!mpleP@ssw0rd"; + + final Base64.Encoder encoder = Base64.getEncoder(); + return encoder.encodeToString(basicPlaintext.getBytes()); + } +} diff --git a/batch/src/main/java/com/poc/alerting/batch/ExclusiveConsumerExceptionLogger.java b/batch/src/main/java/com/poc/alerting/batch/ExclusiveConsumerExceptionLogger.java new file mode 100644 index 0000000..a4f189b --- /dev/null +++ b/batch/src/main/java/com/poc/alerting/batch/ExclusiveConsumerExceptionLogger.java @@ -0,0 +1,11 @@ +package com.poc.alerting.batch; + +import org.apache.commons.logging.Log; +import org.springframework.amqp.support.ConditionalExceptionLogger; + +public class ExclusiveConsumerExceptionLogger implements ConditionalExceptionLogger { + @Override + public void log(final Log logger, final String message, final Throwable t) { + //do not log exclusive consumer warnings + } +} diff --git a/batch/src/main/java/com/poc/alerting/batch/QueueCreator.java b/batch/src/main/java/com/poc/alerting/batch/QueueCreator.java new file mode 100644 index 0000000..7ead96e --- /dev/null +++ b/batch/src/main/java/com/poc/alerting/batch/QueueCreator.java @@ -0,0 +1,65 @@ +package com.poc.alerting.batch; + +import java.io.IOException; +import java.util.Properties; +import java.util.concurrent.CompletableFuture; + +import org.apache.commons.lang3.time.DateUtils; +import org.springframework.amqp.core.BindingBuilder; +import org.springframework.amqp.core.DirectExchange; +import org.springframework.amqp.core.Queue; +import org.springframework.amqp.core.QueueBuilder; +import org.springframework.amqp.rabbit.core.RabbitAdmin; +import org.springframework.amqp.rabbit.core.RabbitTemplate; +import org.springframework.stereotype.Component; + +import com.poc.alerting.amqp.AmqpMessage; +import com.poc.alerting.amqp.AmqpResponse; +import com.poc.alerting.amqp.ExceptionType; + +import lombok.AllArgsConstructor; +import lombok.extern.slf4j.Slf4j; + +import static com.poc.alerting.amqp.AmqpConfiguration.AMQP_NAME; +import static com.poc.alerting.batch.WorkerConfiguration.NEW_CONSUMER; + +@Slf4j +@Component +@AllArgsConstructor +public class QueueCreator { + private final RabbitAdmin rabbitAdmin; + private final RabbitTemplate rabbitTemplate; + private final DirectExchange directExchange; + + public AmqpResponse createQueue(final AmqpMessage amqpMessage) throws IOException, ClassNotFoundException { + final String routingKey = amqpMessage.getRoutingKey(); + LOG.info("Attempting to create new queue {}", routingKey); + setupQueueForAccount(routingKey); + final AmqpResponse response = (AmqpResponse) rabbitTemplate.convertSendAndReceive(AMQP_NAME, routingKey, amqpMessage); + if (response != null && ExceptionType.INVALID_ACCOUNT_EXCEPTION.equals(response.getExceptionType())) { + LOG.info("Invalid account, removing queue {}", routingKey); + CompletableFuture.runAsync(() -> rabbitAdmin.deleteQueue(routingKey, false, true)); + } + return response; + } + + private void setupQueueForAccount(final String routingKey) { + final Properties properties = rabbitAdmin.getQueueProperties(routingKey); + if (properties == null) { + final Queue queue = QueueBuilder.nonDurable(routingKey) + .withArgument("x-expires", DateUtils.MILLIS_PER_DAY) + .build(); + + rabbitAdmin.declareQueue(queue); + rabbitAdmin.declareBinding(BindingBuilder.bind(queue).to(directExchange).with(routingKey)); + sendCreateConsumerMessage(routingKey); + } else if ((Integer) properties.get(RabbitAdmin.QUEUE_CONSUMER_COUNT) < 1) { + LOG.info("{} queue already exists. Adding consumer.", routingKey); + sendCreateConsumerMessage(routingKey); + } + } + + private void sendCreateConsumerMessage(final String queueName) { + rabbitTemplate.convertAndSend(NEW_CONSUMER, "", queueName); + } +} diff --git a/batch/src/main/kotlin/com/poc/alerting/batch/AccountWorker.kt b/batch/src/main/kotlin/com/poc/alerting/batch/AccountWorker.kt new file mode 100644 index 0000000..dc1fce0 --- /dev/null +++ b/batch/src/main/kotlin/com/poc/alerting/batch/AccountWorker.kt @@ -0,0 +1,101 @@ +package com.poc.alerting.batch + +import com.poc.alerting.amqp.AlertingAmqpMessage +import com.poc.alerting.amqp.AlertingAmqpMessage.Add +import com.poc.alerting.amqp.AlertingAmqpMessage.Delete +import com.poc.alerting.amqp.AlertingAmqpMessage.Pause +import com.poc.alerting.amqp.AlertingAmqpMessage.Resume +import com.poc.alerting.amqp.AlertingAmqpMessage.Update +import com.poc.alerting.batch.jobs.AlertQueryJob +import com.poc.alerting.batch.jobs.AlertQueryJob.Companion.ACCOUNT_ID +import com.poc.alerting.batch.jobs.AlertQueryJob.Companion.ALERT_ID +import com.poc.alerting.batch.jobs.AlertQueryJob.Companion.CRON +import com.poc.alerting.persistence.dto.Alert +import com.poc.alerting.persistence.repositories.AlertRepository +import org.quartz.CronScheduleBuilder +import org.quartz.JobBuilder +import org.quartz.JobDataMap +import org.quartz.JobDetail +import org.quartz.JobKey +import org.quartz.Scheduler +import org.quartz.Trigger +import org.quartz.TriggerBuilder +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Service +import java.time.ZoneId +import java.util.TimeZone + +@Service +open class AccountWorker @Autowired constructor( + private val alertRepository: AlertRepository, + private val scheduler: Scheduler +){ + fun processMessage(message: AlertingAmqpMessage) { + when (message) { + is Add -> createJob(message.alertId, message.accountId, message.frequency) + is Update -> updateJob(message.alertId, message.accountId, message.frequency) + is Delete -> deleteJob(message.alertId, message.accountId) + is Pause -> pauseJob(message.alertId, message.accountId) + is Resume -> resumeJob(message.alertId, message.accountId) + } + } + + private fun createJob(alertId: String, accountId: String, cron: String): Alert { + val jobDetail = buildJob(alertId, accountId, cron) + val trigger = createTrigger(alertId, jobDetail, cron) + + with (scheduler) { + scheduleJob(jobDetail, trigger) + start() + } + + return alertRepository.findByExtIdAndAccount_Id(alertId, accountId) + } + + private fun updateJob(alertId: String, accountId: String, cron: String): Alert { + scheduler.deleteJob(JobKey.jobKey(alertId, accountId)) + return createJob(alertId, accountId, cron) + } + + private fun deleteJob(alertId: String, accountId: String): Alert { + val alert = alertRepository.findByExtIdAndAccount_Id(alertId, accountId) + scheduler.deleteJob(JobKey.jobKey(alertId, accountId)) + alertRepository.delete(alert) + return alert + } + + private fun pauseJob(alertId: String, accountId: String): Alert { + scheduler.pauseJob(JobKey.jobKey(alertId, accountId)) + return alertRepository.findByExtIdAndAccount_Id(alertId, accountId) + } + + private fun resumeJob(alertId: String, accountId: String): Alert { + scheduler.resumeJob(JobKey.jobKey(alertId, accountId)) + return alertRepository.findByExtIdAndAccount_Id(alertId, accountId) + } + + private fun buildJob(alertId: String, accountId: String, cron: String): JobDetail { + val jobDataMap = JobDataMap() + jobDataMap[ALERT_ID] = alertId + jobDataMap[ACCOUNT_ID] = accountId + jobDataMap[CRON] = cron + return JobBuilder.newJob().ofType(AlertQueryJob::class.java) + .storeDurably() + .withIdentity(alertId, accountId) + .usingJobData(jobDataMap) + .build() + } + + private fun createTrigger(alertId: String, jobDetail: JobDetail, cron: String): Trigger { + return TriggerBuilder.newTrigger() + .forJob(jobDetail) + .withIdentity("${alertId}_trigger") + .withSchedule( + CronScheduleBuilder.cronSchedule(cron) + .withMisfireHandlingInstructionFireAndProceed() + .inTimeZone(TimeZone.getTimeZone(ZoneId.systemDefault())) + ) + .usingJobData("cron", cron) + .build() + } +} \ No newline at end of file diff --git a/batch/src/main/kotlin/com/poc/alerting/batch/AutowiringSpringBeanJobFactory.kt b/batch/src/main/kotlin/com/poc/alerting/batch/AutowiringSpringBeanJobFactory.kt new file mode 100644 index 0000000..48a37aa --- /dev/null +++ b/batch/src/main/kotlin/com/poc/alerting/batch/AutowiringSpringBeanJobFactory.kt @@ -0,0 +1,37 @@ +package com.poc.alerting.batch + +import org.quartz.Job +import org.quartz.SchedulerContext +import org.quartz.spi.TriggerFiredBundle +import org.springframework.beans.MutablePropertyValues +import org.springframework.beans.PropertyAccessorFactory +import org.springframework.context.ApplicationContext +import org.springframework.context.ApplicationContextAware +import org.springframework.scheduling.quartz.SpringBeanJobFactory + + +class AutowiringSpringBeanJobFactory : SpringBeanJobFactory(), ApplicationContextAware { + private var ctx: ApplicationContext? = null + private var schedulerContext: SchedulerContext? = null + override fun setApplicationContext(context: ApplicationContext) { + ctx = context + } + + override fun createJobInstance(bundle: TriggerFiredBundle): Any { + val job: Job = ctx!!.getBean(bundle.jobDetail.jobClass) + val bw = PropertyAccessorFactory.forBeanPropertyAccess(job) + val pvs = MutablePropertyValues() + pvs.addPropertyValues(bundle.jobDetail.jobDataMap) + pvs.addPropertyValues(bundle.trigger.jobDataMap) + if (this.schedulerContext != null) { + pvs.addPropertyValues(this.schedulerContext) + } + bw.setPropertyValues(pvs, true) + return job + } + + override fun setSchedulerContext(schedulerContext: SchedulerContext) { + this.schedulerContext = schedulerContext + super.setSchedulerContext(schedulerContext) + } +} \ No newline at end of file diff --git a/batch/src/main/kotlin/com/poc/alerting/batch/BatchWorker.kt b/batch/src/main/kotlin/com/poc/alerting/batch/BatchWorker.kt new file mode 100644 index 0000000..7b046b3 --- /dev/null +++ b/batch/src/main/kotlin/com/poc/alerting/batch/BatchWorker.kt @@ -0,0 +1,16 @@ +package com.poc.alerting.batch + +import org.springframework.boot.Banner +import org.springframework.boot.WebApplicationType +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.builder.SpringApplicationBuilder + +@SpringBootApplication(scanBasePackages = ["com.poc.alerting"]) +open class BatchWorker + +fun main(args: Array) { + SpringApplicationBuilder().sources(BatchWorker::class.java) + .bannerMode(Banner.Mode.OFF) + .web(WebApplicationType.NONE) + .run(*args) +} \ No newline at end of file diff --git a/batch/src/main/kotlin/com/poc/alerting/batch/ConsumerCreator.kt b/batch/src/main/kotlin/com/poc/alerting/batch/ConsumerCreator.kt new file mode 100644 index 0000000..66e40da --- /dev/null +++ b/batch/src/main/kotlin/com/poc/alerting/batch/ConsumerCreator.kt @@ -0,0 +1,31 @@ +package com.poc.alerting.batch + +import org.apache.commons.lang3.time.DateUtils +import org.springframework.amqp.rabbit.connection.ConnectionFactory +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.context.ApplicationEventPublisher +import org.springframework.stereotype.Component + +@Component +open class ConsumerCreator @Autowired constructor( + private val connectionFactory: ConnectionFactory, + private val accountWorkerListenerAdapter: MessageListenerAdapter, + private val applicationEventPublisher: ApplicationEventPublisher, + private val accountConsumerManager: AccountConsumerManager +){ + fun createConsumer(queueName: String) { + val consumer = SimpleMessageListenerContainer(connectionFactory) + consumer.setExclusive(true) + consumer.setExclusiveConsumerExceptionLogger(ExclusiveConsumerExceptionLogger()) + consumer.setQueueNames(queueName) + consumer.setMessageListener(accountWorkerListenerAdapter) + consumer.setIdleEventInterval(DateUtils.MILLIS_PER_HOUR) + consumer.setApplicationEventPublisher(applicationEventPublisher) + consumer.setDefaultRequeueRejected(false) + consumer.setAutoDeclare(false) + consumer.setShutdownTimeout(DateUtils.MILLIS_PER_SECOND * 10) + accountConsumerManager.registerAndStart(queueName, consumer) + } +} \ No newline at end of file diff --git a/batch/src/main/kotlin/com/poc/alerting/batch/WorkerConfiguration.kt b/batch/src/main/kotlin/com/poc/alerting/batch/WorkerConfiguration.kt new file mode 100644 index 0000000..c7bbe79 --- /dev/null +++ b/batch/src/main/kotlin/com/poc/alerting/batch/WorkerConfiguration.kt @@ -0,0 +1,97 @@ +package com.poc.alerting.batch + +import com.poc.alerting.amqp.AmqpConfiguration.Companion.NEW_ACCOUNT +import com.poc.alerting.amqp.GsonMessageConverter +import org.springframework.amqp.core.Binding +import org.springframework.amqp.core.BindingBuilder +import org.springframework.amqp.core.FanoutExchange +import org.springframework.amqp.core.Queue +import org.springframework.amqp.rabbit.connection.ConnectionFactory +import org.springframework.amqp.rabbit.core.RabbitAdmin +import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer +import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter +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.concurrent.ThreadPoolTaskExecutor +import java.net.InetAddress +import java.util.concurrent.Executor + +@Configuration +@EnableAsync +open class WorkerConfiguration: AsyncConfigurer { + companion object { + const val NEW_CONSUMER = "new_consumer" + } + + @Bean("asyncExecutor") + override fun getAsyncExecutor(): Executor { + return ThreadPoolTaskExecutor() + } + + @Bean + open fun rabbitAdmin(connectionFactory: ConnectionFactory): RabbitAdmin { + return RabbitAdmin(connectionFactory) + } + + @Bean + open fun queueCreatorListenerAdapter(queueCreator: QueueCreator, gsonMessageConverter: GsonMessageConverter): MessageListenerAdapter { + return MessageListenerAdapter(queueCreator, "createQueue").apply { + setMessageConverter(gsonMessageConverter) + } + } + + @Bean + open fun queueCreatorContainer(connectionFactory: ConnectionFactory, queueCreatorListenerAdapter: MessageListenerAdapter, + gsonMessageConverter: GsonMessageConverter): SimpleMessageListenerContainer { + return SimpleMessageListenerContainer(connectionFactory).apply { + setExclusive(true) + setExclusiveConsumerExceptionLogger(ExclusiveConsumerExceptionLogger()) + setQueueNames(NEW_ACCOUNT) + setMessageListener(queueCreatorListenerAdapter) + setDefaultRequeueRejected(false) + } + } + + @Bean + open fun newConsumerExchange(): FanoutExchange { + return FanoutExchange(NEW_CONSUMER) + } + + @Bean + open fun newConsumerQueue(): Queue { + return Queue("${NEW_CONSUMER}_${InetAddress.getLocalHost().hostName}", true) + } + + @Bean + open fun newConsumerBinding(newConsumerQueue: Queue, newConsumerExchange: FanoutExchange): Binding { + return BindingBuilder.bind(newConsumerQueue).to(newConsumerExchange) + } + + @Bean + open fun consumerCreatorListenerAdapter(consumerCreator: ConsumerCreator, gsonMessageConverter: GsonMessageConverter): MessageListenerAdapter { + return MessageListenerAdapter(consumerCreator, "createConsumer").apply { + setMessageConverter(gsonMessageConverter) + } + } + + @Bean + open fun consumerCreatorContainer(connectionFactory: ConnectionFactory, consumerCreatorListenerAdapter: MessageListenerAdapter, + newConsumerQueue: Queue): SimpleMessageListenerContainer { + return SimpleMessageListenerContainer(connectionFactory).apply { + setExclusive(true) + setExclusiveConsumerExceptionLogger(ExclusiveConsumerExceptionLogger()) + setQueues(newConsumerQueue) + setMessageListener(consumerCreatorListenerAdapter) + setDefaultRequeueRejected(false) + } + } + + @Bean + open fun accountWorkerListenerAdapter(accountWorker: AccountWorker, gsonMessageConverter: GsonMessageConverter): MessageListenerAdapter { + return MessageListenerAdapter(accountWorker, "processMessage").apply { + setMessageConverter(gsonMessageConverter) + } + } +} \ No newline at end of file diff --git a/batch/src/main/kotlin/com/poc/alerting/batch/jobs/AlertQueryJob.kt b/batch/src/main/kotlin/com/poc/alerting/batch/jobs/AlertQueryJob.kt new file mode 100644 index 0000000..cdbc420 --- /dev/null +++ b/batch/src/main/kotlin/com/poc/alerting/batch/jobs/AlertQueryJob.kt @@ -0,0 +1,50 @@ +package com.poc.alerting.batch.jobs + +import com.poc.alerting.persistence.repositories.AlertRepository +import org.quartz.Job +import org.quartz.JobExecutionContext +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.stereotype.Component +import java.time.Duration +import java.util.Date + +@Component +open class AlertQueryJob @Autowired constructor( + private val alertRepository: AlertRepository +): Job { + companion object { + const val ALERT_ID = "alertId" + const val CRON = "cron" + const val ACCOUNT_ID = "accountId" + } + + override fun execute(context: JobExecutionContext) { + val data = context.jobDetail.jobDataMap + val alertId = data.getString(ALERT_ID) + val cron = data.getString(CRON) + val accountId = data.getString(ACCOUNT_ID) + + val alert = alertRepository.findByExtIdAndAccount_Id(alertId, accountId) + + with(alert) { + val queryResult = type.query() + println("PERFORMING QUERY for $alertId-$accountId. Running with the following CRON expression: $cron") + if (queryResult >= threshold.toInt()) { + val currentTime = Date() + if (!isTriggered) { + isTriggered = true + } + + notificationSentTimestamp.let { + if (Duration.between(notificationSentTimestamp.toInstant(), currentTime.toInstant()).toSeconds() >= 15) { + println("Alert Triggered!!!!!!!!!!!!!") + notificationSentTimestamp = currentTime + } + } + + lastTriggerTimestamp = currentTime + alertRepository.save(this) + } + } + } +} \ No newline at end of file diff --git a/batch/src/main/kotlin/com/poc/alerting/batch/jobs/ScheduleAlertQueryConfiguration.kt b/batch/src/main/kotlin/com/poc/alerting/batch/jobs/ScheduleAlertQueryConfiguration.kt new file mode 100644 index 0000000..f431fe4 --- /dev/null +++ b/batch/src/main/kotlin/com/poc/alerting/batch/jobs/ScheduleAlertQueryConfiguration.kt @@ -0,0 +1,33 @@ +package com.poc.alerting.batch.jobs + +import com.poc.alerting.batch.AutowiringSpringBeanJobFactory +import org.quartz.spi.JobFactory +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.context.ApplicationContext +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.ComponentScan +import org.springframework.context.annotation.Configuration +import org.springframework.scheduling.quartz.SchedulerFactoryBean +import javax.sql.DataSource + +@Configuration +@ComponentScan +@EnableAutoConfiguration +open class ScheduleAlertQueryConfiguration { + @Bean + open fun jobFactory(applicationContext: ApplicationContext): JobFactory { + return AutowiringSpringBeanJobFactory().apply { + setApplicationContext(applicationContext) + } + } + + @Bean + open fun schedulerFactory(applicationContext: ApplicationContext, dataSource: DataSource, jobFactory: JobFactory): SchedulerFactoryBean { + return SchedulerFactoryBean().apply { + setOverwriteExistingJobs(true) + isAutoStartup = true + setDataSource(dataSource) + setJobFactory(jobFactory) + } + } +} \ No newline at end of file diff --git a/batch/src/main/resources/application.yml b/batch/src/main/resources/application.yml new file mode 100644 index 0000000..ee3927b --- /dev/null +++ b/batch/src/main/resources/application.yml @@ -0,0 +1,19 @@ +server: + port: 0 + servlet: + encoding: + charset: UTF-8 + enabled: true +spring: + profiles: + active: "batch" + datasource: + url: "jdbc:h2:tcp://localhost:9091/mem:alerting;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;" + username: "defaultUser" + password: "secret" + application: + name: BatchWorker + jackson: + time-zone: UTC + main: + allow-bean-definition-overriding: true diff --git a/build.gradle.kts b/build.gradle.kts new file mode 100644 index 0000000..2afe7d9 --- /dev/null +++ b/build.gradle.kts @@ -0,0 +1,75 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +buildscript { + repositories { + mavenCentral() + } +} + +plugins { + `java-library` + id("org.springframework.boot") version "2.5.0" + id("io.spring.dependency-management") version "1.0.11.RELEASE" + kotlin("jvm") version "1.5.10" + kotlin("plugin.spring") version "1.5.10" +} + +repositories { + mavenCentral() +} + +allprojects { + group = "com.poc.alerting" + version = "0.0.1-SNAPSHOT" + + tasks.withType { + sourceCompatibility = "11" + targetCompatibility = "11" + } + + tasks.withType { + kotlinOptions { + freeCompilerArgs = listOf("-Xjsr305=strict", "-Xextended-compiler-checks") + jvmTarget = "11" + } + } +} + +subprojects { + repositories { + mavenCentral() + } + + apply(plugin = "org.jetbrains.kotlin.jvm") + apply(plugin = "org.springframework.boot") + apply(plugin = "io.spring.dependency-management") + apply(plugin = "java") + apply(plugin = "java-library") + + dependencies { + implementation("org.jetbrains.kotlin:kotlin-reflect") + implementation("org.jetbrains.kotlin:kotlin-stdlib-jdk8") + annotationProcessor("org.springframework.boot:spring-boot-configuration-processor") + testImplementation("org.springframework.boot:spring-boot-starter-test") + } + + tasks.withType { + useJUnitPlatform() + } + + configurations.all { + resolutionStrategy { + failOnVersionConflict() + } + } + + sourceSets { + main { + java.srcDir("src/main/kotlin") + } + } +} + +springBoot { + mainClass.set("com.poc.alerting.persistence.Persistence") +} diff --git a/docs/AlertingApi.yaml b/docs/AlertingApi.yaml new file mode 100644 index 0000000..576d498 --- /dev/null +++ b/docs/AlertingApi.yaml @@ -0,0 +1,938 @@ +openapi: 3.0.1 +info: + title: Alerting API + description: 'This is a POC API for a dynamic, reactive alerting system.' + version: 0.0.1 +servers: + - url: http://localhost:8080/poc/alerting/v1 +tags: + - name: Alerts + - name: Recipients +security: + - alerting_auth: + - read + - write +paths: + /accounts/{account_id}/alerts: + get: + tags: + - Alerts + description: Get the list of alerts for an account + summary: Get the list of alerts for an account + operationId: getListOfAlerts + parameters: + - name: account_id + in: path + description: ID of the account to get alerts from. + required: true + schema: + type: integer + format: int64 + example: 1234567 + - name: include_recipients + in: query + description: > + If set to true, then the list of all recipients belonging to each alert will be included in the response. + schema: + type: boolean + default: false + example: true + responses: + 200: + description: Success + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Alert' + example: + - id: "percentageOfDeliveryFailures" + name: "Percentage of Delivery Failures" + threshold: "90" + type: "PERCENTAGE_OF_DELIVERY_FAILURES" + frequency: "15m" + enabled: true + last_triggered: "2021-04-22T16:33:21.959Z" + notification_sent: "2021-04-22T16:33:21.959Z" + is_triggered: true, + reference_time_period: "1 Week" + created: "2021-04-22T16:33:21.959Z" + updated: "2021-04-22T16:33:21.959Z" + updated_by: "someOtherUser" + recipients: + - id: "someUsersEmail" + recipient: "someUser@somedomain.com" + type: "EMAIL" + created: "2021-02-22T16:09:28.139Z" + updated: "2021-04-26T04:01:13.448Z" + updated_by: "someUser" + - id: "someOtherUsersEmail" + recipient: "someOtherUser@somedomain.com" + type: "EMAIL" + created: "2021-03-04T07:17:33.244Z" + updated: "2021-03-04T08:00:54.562Z" + updated_by: "someOtherUser" + - id: "failureThresholdAlert" + name: "Too Many Errors" + threshold: "1820" + type: "FAILURE_THRESHOLD_ALERT" + frequency: "5m" + enabled: false + last_triggered: "2021-04-22T16:33:21.959Z" + notification_sent: "2021-04-22T16:33:21.959Z" + is_triggered: true + reference_time_period: "1 Month" + created: "2021-04-22T16:33:21.959Z" + updated: "2021-04-26T04:01:13.448Z" + updated_by: "someOtherUser" + recipients: + - id: "someUserHttpRecipient" + recipient: "https://some.test.callback.com/callback" + type: "HTTP" + username: "mikeRoweSoft" + password: "iSuPpOrTwInDoWs" + created: "2021-05-19T02:39:12.922Z" + updated: "2021-05-19T02:39:12.922Z" + updated_by: "someUser" + 403: + $ref: '#/components/responses/Forbidden' + security: + - alerting_auth: + - write:alert + - read:alert + + post: + tags: + - Alerts + description: Add an alert to the specified account. + summary: Add an alert to the specified account + operationId: addAlert + parameters: + - name: account_id + in: path + description: ID of an account to add an alert to. + required: true + schema: + type: integer + format: int64 + example: 1234567 + requestBody: + content: + application/json: + schema: + properties: + id: + type: string + description: > + External ID used by users to refer to alert. + If an ID is specified, the ID must be account-unique. + If not provided, it will be automatically generated. + name: + type: string + description: The name of this alert + default: "Default value differs by the alert type" + threshold: + type: string + description: A threshold must be given for a custom alert. + default: "Default value differs by the alert type" + type: + type: string + description: The type of alert being added to the account + enum: + - PERCENTAGE_OF_DELIVERY_FAILURES + - FAILURE_THRESHOLD_ALERT + - HARD_CODED_ALERT_1 + - HARD_CODED_ALERT_2 + frequency: + type: string + description: The frequency of how often the alerting condition is checked. + default: "15m" + enabled: + type: boolean + description: Boolean value denoting whether the alert is enabled or not. + default: true + reference_time_period: + type: string + description: Time period to run the alerting condition against (lags in time series data). + default: "1 Month" + example: + id: "testAlert1" + name: "Too Many Messages Are Being Sent" + threshold: "666" + type: "FAILURE_THRESHOLD_ALERT" + frequency: "5m" + enabled: false + reference_time_period: "1 Week" + required: + - type + responses: + 201: + description: Successfully created new alert + content: + application/json: + schema: + $ref: '#/components/schemas/Alert' + example: + id: "testAlert1" + name: "Too Many Messages Are Being Sent" + threshold: "666" + type: "FAILURE_THRESHOLD_ALERT" + frequency: "15m" + enabled: false + reference_time_period: "1 Week" + created: "2021-04-22T16:33:21.959Z" + updated: "2021-04-22T16:33:21.959Z" + updated_by: "someUser" + 400: + $ref: '#/components/responses/BadRequest' + 403: + $ref: '#/components/responses/Forbidden' + 409: + description: An alert with the specified ID already exists on the given account + 422: + description: > + * Invalid alert request + + * The type was unspecified, or does not exist + security: + - alerting_auth: + - write:alert + - read:alert + + /accounts/{account_id}/alerts/{alert_id}: + get: + tags: + - Alerts + description: Get an alert given an alert ID and account ID. + summary: Get an alert given an alert ID and account ID + operationId: getAlertById + parameters: + - name: account_id + in: path + description: ID of the account to get alerts from. + required: true + schema: + type: integer + format: int64 + example: 1234567 + - name: alert_id + in: path + description: External ID used by users to refer to an alert. + required: true + schema: + type: string + example: "someHardcodedAlert" + - name: include_recipients + in: query + description: > + If set to true, then the list of all recipients belonging to the alert will be included in the response. + schema: + type: boolean + default: false + example: true + responses: + 200: + description: Found alert + content: + application/json: + schema: + $ref: '#/components/schemas/Alert' + example: + id: "someHardcodedAlert" + name: "Percentage of Delivery Failures" + threshold: "90" + type: "PERCENTAGE_OF_DELIVERY_FAILURES" + frequency: "15m" + enabled: true + last_triggered: "2021-04-22T16:33:21.959Z" + notification_sent: "2021-04-22T16:33:21.959Z" + is_triggered: true + reference_time_period: "1 Week" + created: "2021-04-22T16:33:21.959Z" + updated: "2021-04-22T16:33:21.959Z" + updated_by: "someOtherUser" + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFoundAlert' + security: + - alerting_auth: + - write:alerts + - read:alerts + + patch: + tags: + - Alerts + description: > + Update the attributes of an existing alert. Note that if a user attempts to update the type of an alert, the value will be ignored. + summary: Update the attributes of an existing alert + operationId: updateAlert + parameters: + - name: account_id + in: path + description: > + ID of the account that the alert belongs to. This cannot be updated and will be ignored if placed in the payload + required: true + schema: + type: integer + format: int64 + example: 1234567 + - name: alert_id + in: path + description: External ID used by users to refer to an alert. This cannot be updated and will be ignored if placed in the payload + required: true + schema: + type: string + example: "testAlert1" + requestBody: + content: + application/json: + schema: + properties: + name: + type: string + description: A new name for the specified alert + threshold: + type: string + description: A new threshold for the alert + frequency: + type: string + description: The frequency of how often the alerting condition is checked + enabled: + type: boolean + description: Boolean value denoting whether the alert is enabled or not + reference_time_period: + type: string + description: Time period to run the alerting condition against (lags in time series data) + example: + name: "Too Many Messages Are Being Sent" + threshold: "955" + frequency: "15m" + enabled: true + reference_time_period: "1 Month" + responses: + 200: + description: Success + content: + application/json: + schema: + $ref: '#/components/schemas/Alert' + example: + id: "testAlert1" + name: "Too Many Messages Are Being Sent" + threshold: "955" + type: "FAILURE_THRESHOLD_ALERT" + frequency: "15m" + enabled: true + last_triggered: "2021-04-22T16:33:21.959Z" + notification_sent: "2021-04-22T16:33:21.959Z" + is_triggered: false + reference_time_period: "1 Month" + created: "2021-04-22T16:33:21.959Z" + updated: "2021-05-19T12:45:09.127Z" + updated_by: "someUser" + 400: + $ref: '#/components/responses/BadRequest' + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFoundAlert' + 422: + description: > + * Invalid update request + + * User was attempting to update alert type + + * User attempted to update name value to an empty value + + * User attempted to update threshold value to empty value + security: + - alerting_auth: + - write:alerts + - read:alerts + + delete: + tags: + - Alerts + description: > + Remove the specified alert from the account. When an alert is deleted, all recipients belonging to the alert are also removed. + summary: Remove the specified alert from the account + operationId: deleteAlert + parameters: + - name: account_id + in: path + description: ID of the account that the alert exists on. + required: true + schema: + type: integer + format: int64 + example: 1234567 + - name: alert_id + in: path + description: External ID used by users to refer to an alert. + required: true + schema: + type: string + example: "testAlert1" + responses: + 204: + description: Successfully deleted alert + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFoundAlert' + security: + - alerting_auth: + - write:alert + - read:alert + + /accounts/{account_id}/recipients: + get: + tags: + - Recipients + description: Get the list of all recipients on the specified account + summary: Get the list of all recipients on the specified account + operationId: getAllRecipients + parameters: + - name: account_id + in: path + description: ID of the account to get recipients from + required: true + schema: + type: integer + format: int64 + example: 1234567 + responses: + 200: + description: Successfully returned the list of recipients + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Recipient' + example: + - id: "someUsersEmail" + recipient: "someUser@somedomain.com" + type: "EMAIL" + created: "2021-02-22T16:09:28.139Z" + updated: "2021-04-26T04:01:13.448Z" + updated_by: "someUser" + - id: "someOtherUsersEmail" + recipient: "someOtherUser@somedomain.com" + type: "EMAIL" + created: "2021-03-04T07:17:33.244Z" + updated: "2021-03-04T08:00:54.562Z" + updated_by: "someOtherUser" + - id: "someUserHttpRecipient" + recipient: "https://some.test.callback.com/callback" + type: "HTTP" + username: "mikeRoweSoft" + password: "iSuPpOrTwInDoWs" + created: "2021-05-19T02:39:12.922Z" + updated: "2021-05-19T02:39:12.922Z" + updated_by: "someUser" + 403: + $ref: '#/components/responses/Forbidden' + security: + - alerting_auth: + - write:alerts + - read:alerts + + /accounts/{account_id}/alerts/{alert_id}/recipients: + get: + tags: + - Recipients + description: Get the list of recipients for an alert + summary: Get the list of recipients for an alert + operationId: getRecipientList + parameters: + - name: account_id + in: path + description: ID of the account to get recipients from + required: true + schema: + type: integer + format: int64 + example: 1234567 + - name: alert_id + in: path + description: The alert that the recipients belong to + required: true + schema: + type: string + example: "percentageOfDeliveryFailures" + responses: + 200: + description: Successfully returned list of recipients + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Recipient' + example: + - id: "someUsersEmail" + recipient: "someUser@somedomain.com" + type: "EMAIL" + created: "2021-02-22T16:09:28.139Z" + updated: "2021-04-26T04:01:13.448Z" + updated_by: "someUser" + - id: "someOtherUsersEmail" + recipient: "someOtherUser@somedomain.com" + type: "EMAIL" + created: "2021-03-04T07:17:33.244Z" + updated: "2021-03-04T08:00:54.562Z" + updated_by: "someOtherUser" + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFoundAlert' + security: + - alerting_auth: + - write:alerts + - read:alerts + + post: + tags: + - Recipients + description: Add one or more recipients to an alert. Note that no more than 25 recipients can be added to an alert. + summary: Add one or more recipients to an alert + operationId: addRecipient + parameters: + - name: account_id + in: path + description: ID of the account that the recipient exists on. + required: true + schema: + type: integer + format: int64 + example: 1234567 + - name: alert_id + in: path + description: The alert that the recipient(s) will belong to + required: true + schema: + type: string + example: "percentageOfDeliveryFailures" + requestBody: + content: + application/json: + schema: + type: array + items: + type: object + properties: + id: + type: string + description: > + External ID used by users to refer to a recipient. + This must be unique among all recipient IDs given for the specified account. If this field is not provided, an ID is generated. + recipient: + type: string + description: > + Identifier that indicates who is receiving the notification. + + * When the type is SMS, the recipient value must conform to the E.164 format recommendation + + * When the type is EMAIL, the recipient value must conform to RFC-5322 + + * When the type is HTTP, as of RFC 3986, URIs should no longer support credentials. + As a result, all URIs must conform to “http[s]://host[:port]/path?querystring” format. + type: + type: string + enum: + - EMAIL + - SMS + - HTTP + description: The type of the recipient. + username: + type: string + description: > + Username for recipient HTTP webhook authentication. Only applicable to HTTP recipient types. + password: + type: string + description: > + Password for recipient HTTP webhook authentication. Only applicable to HTTP recipient types. + required: + - recipient + - type + example: + - id: "someUserHttpRecipient" + recipient: "https://some.test.callback.com/callback" + type: "HTTP" + username: "mikeRoweSoft" + password: "iSuPpOrTwInDoWs" + - id: "someUsersEmail" + recipient: "someUser@somedomain.com" + type: "EMAIL" + responses: + 201: + description: Successfully created new recipient(s) + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Recipient' + example: + - id: "someUserHttpRecipient" + recipient: "https://some.test.callback.com/callback" + type: "HTTP" + username: "mikeRoweSoft" + password: "iSuPpOrTwInDoWs" + created: "2021-05-19T02:39:12.922Z" + updated: "2021-05-19T02:39:12.922Z" + updated_by: "someUser" + - id: "someUsersEmail" + recipient: "someUser@somedomain.com" + type: "EMAIL" + created: "2021-02-22T16:09:28.139Z" + updated: "2021-02-22T16:09:28.139Z" + updated_by: "someUser" + 400: + $ref: '#/components/responses/BadRequest' + 403: + $ref: '#/components/responses/Forbidden' + 404: + $ref: '#/components/responses/NotFoundAlert' + 409: + description: A recipient with the specified ID already exists on the given account + 422: + description: > + * Invalid recipient request + + * User provided an unsupported type for one or more of the recipients + + * User attempted to add more than 25 recipients to the alert + + * Alert already has the maximum number of recipients + security: + - alerting_auth: + - write:alerts + - read:alerts + + /accounts/{account_id}/alerts/{alert_id}/recipients/{recipient_id}: + get: + tags: + - Recipients + description: Get a recipient given the account ID, alert ID, and recipient ID. + summary: Get a recipient given the account ID, alert ID, and recipient ID + operationId: getRecipient + parameters: + - name: account_id + in: path + description: ID of the account to get recipients from + required: true + schema: + type: integer + format: int64 + example: 1234567 + - name: alert_id + in: path + description: The alert that the recipient belongs to + required: true + schema: + type: string + example: "someHardCodedAlert" + - name: recipient_id + in: path + description: External ID used by users to refer to a recipient + required: true + schema: + type: string + example: "someUsersEmail" + responses: + 200: + description: Found Recipient + content: + application/json: + schema: + $ref: '#/components/schemas/Recipient' + example: + id: "someUsersEmail" + recipient: "someUser@somedomain.com" + type: "EMAIL" + created: "2021-02-22T16:09:28.139Z" + updated: "2021-04-26T04:01:13.448Z" + updated_by: "someUser" + 403: + $ref: '#/components/responses/Forbidden' + 404: + description: > + * Recipient ID is unknown + + * Alert ID is unknown + security: + - alerting_auth: + - write:alerts + - read:alerts + + patch: + tags: + - Recipients + description: Update the attributes of a recipient. + summary: Update the attributes of a recipient + operationId: updateRecipient + parameters: + - name: account_id + in: path + description: ID of the account that the recipient exists on. + required: true + schema: + type: integer + format: int64 + example: 1234567 + - name: alert_id + in: path + description: The alert that the recipient belongs to + required: true + schema: + type: string + example: "someHardCodedAlert" + - name: recipient_id + in: path + description: External ID used by users to refer to a recipient + required: true + schema: + type: string + example: "someUserHttpRecipient" + requestBody: + content: + application/json: + schema: + type: object + properties: + recipient: + type: string + description: > + Identifier that indicates who is receiving the notification. + + * When the type is SMS, the recipient value must conform to the E.164 format recommendation + + * When the type is EMAIL, the recipient value must conform to RFC-5322 + + * When the type is HTTP, as of RFC 3986, URIs should no longer support credentials. + As a result, all URIs must conform to “http[s]://host[:port]/path?querystring” format. + type: + type: string + enum: + - EMAIL + - SMS + - HTTP + description: The type of the recipient + username: + type: string + description: > + Username for recipient HTTP webhook authentication. Only applicable to HTTP recipient types. + password: + type: string + description: > + Password for recipient HTTP webhook authentication. Only applicable to HTTP recipient types. + example: + password: "AppleHQLooksLikeAHalo.Suspicious!" + responses: + 200: + description: Successfully updated recipient + content: + application/json: + schema: + $ref: '#/components/schemas/Recipient' + example: + id: "someUserHttpRecipient" + recipient: "https://some.test.callback.com/callback" + type: "HTTP" + username: "mikeRoweSoft" + password: "AppleHQLooksLikeAHalo.Suspicious!" + created: "2021-05-19T02:39:12.922Z" + updated: "2021-05-19T03:13:59.164Z" + updated_by: "someUser" + 400: + $ref: '#/components/responses/BadRequest' + 403: + $ref: '#/components/responses/Forbidden' + 404: + description: > + * Recipient ID is unknown + + * Alert ID is unknown + 422: + description: > + * Invalid update recipient request + + * Invalid type provided + + * Invalid or unsupported recipient URI given + security: + - alerting_auth: + - write:alerts + - read:alerts + + delete: + tags: + - Recipients + description: Delete a recipient. + summary: Delete a recipient + operationId: deleteRecipient + parameters: + - name: account_id + in: path + description: ID of the account that the recipient exists on + required: true + schema: + type: integer + format: int64 + example: 1234567 + - name: alert_id + in: path + description: The alert that the recipient(s) belong to + required: true + schema: + type: string + example: "someHardCodedAlert" + - name: recipient_id + in: path + description: > + External ID used by users to refer to a recipient. + Multiple recipients can be deleted by specify a comma-separated list of recipient ID's. + required: true + schema: + type: string + example: "someUserHttpRecipient,someUsersEmail" + responses: + 204: + description: Successfully removed recipient(s) + 403: + $ref: '#/components/responses/Forbidden' + 404: + description: > + * One or more recipient IDs are unknown + + * Alert ID is unknown + security: + - alerting_auth: + - write:alerts + - read:alerts + +components: + responses: + Forbidden: + description: > + * Unknown Account + + * User is not allowed to represent the given account + + BadRequest: + description: Request is invalid + + NotFoundAlert: + description: Alert ID is unknown + + schemas: + Alert: + type: object + properties: + id: + type: string + description: Hardcoded or account-unique identifier for the alert + name: + type: string + description: The name of this alert + threshold: + type: string + description: The threshold value associated with this alert + type: + type: string + description: The type of alert. The type will be an enum value matching one of the hard coded alerts. + enum: + - PERCENTAGE_OF_DELIVERY_FAILURES + - FAILURE_THRESHOLD_ALERT + - HARD_CODED_ALERT_1 + - HARD_CODED_ALERT_2 + frequency: + type: string + description: The frequency of how often the alerting condition is checked + enabled: + type: boolean + description: Boolean value denoting whether the alert is enabled or not + last_triggered: + type: string + description: > + Timestamp of when the alert was last triggered, conforming to RFC 3339 format. The time zone is always UTC + notification_sent: + type: string + description: > + Timestamp of when the last notification was sent, conforming to RFC 3339 format. The time zone is always UTC + is_triggered: + type: boolean + description: Boolean value denoting whether the alert is still currently being triggered + reference_time_period: + type: string + description: Time period to run the alerting condition against (lags in time series data) + created: + type: string + description: > + Timestamp of when the alert was created, conforming to RFC 3339 format. + The time zone is always UTC. For the create operation, the updated time will be the same as the created time. + updated: + type: string + description: > + Timestamp of when the alert was last updated, conforming to RFC 3339 format. The time zone is always UTC + updated_by: + type: string + description: The last user to update the alert + recipients: + type: array + description: > + The list of full recipient objects is only returned when the include_recipients parameter is set to true + items: + $ref: '#/components/schemas/Recipient' + + Recipient: + type: object + properties: + id: + type: string + description: Account-unique identifier for the recipient + recipient: + type: string + description: Identifier that indicates who is receiving the notification + type: + type: string + enum: + - EMAIL + - SMS + - HTTP + description: Type of recipient. + username: + type: string + description: > + Username for recipient HTTP webhook authentication. Only applicable to HTTP recipient types. + password: + type: string + description: > + Password for recipient HTTP webhook authentication. Only applicable to HTTP recipient types. + created: + type: string + description: > + Timestamp of when the recipient was created, conforming to RFC 3339 format. The time zone is always UTC. + updated: + type: string + description: > + Timestamp of when the recipient was last updated, conforming to RFC 3339 format. The time zone is always UTC. + For the create operation, the updated time will be the same as the created time. + updated_by: + type: string + description: The last user to update the recipient. + + securitySchemes: + alerting_auth: + type: oauth2 + flows: + authorizationCode: + authorizationUrl: https://login.alexjclarke.com/oauth/authorize + tokenUrl: https://login.alexjclarke.com/oauth/token + scopes: + read:alerts: read your alerts + write:alerts: modify alerts in your account diff --git a/docs/dist/favicon-16x16.png b/docs/dist/favicon-16x16.png new file mode 100644 index 0000000000000000000000000000000000000000..8b194e617af1c135e6b37939591d24ac3a5efa18 GIT binary patch literal 665 zcmV;K0%rY*P)}JKSduyL>)s!A4EhTMMEM%Q;aL6%l#xiZiF>S;#Y{N2Zz%pvTGHJduXuC6Lx-)0EGfRy*N{Tv4i8@4oJ41gw zKzThrcRe|7J~(YYIBq{SYCkn-KQm=N8$CrEK1CcqMI1dv9z#VRL_{D)L|`QmF8}}l zJ9JV`Q}p!p_4f7m_U`WQ@apR4;o;!mnU<7}iG_qr zF(e)x9~BG-3IzcG2M4an0002kNkl41`ZiN1i62V%{PM@Ry|IS_+Yc7{bb`MM~xm(7p4|kMHP&!VGuDW4kFixat zXw43VmgwEvB$hXt_u=vZ>+v4i7E}n~eG6;n4Z=zF1n?T*yg<;W6kOfxpC6nao>VR% z?fpr=asSJ&`L*wu^rLJ5Peq*PB0;alL#XazZCBxJLd&giTfw@!hW167F^`7kobi;( ze<<>qNlP|xy7S1zl@lZNIBR7#o9ybJsptO#%}P0hz~sBp00000NkvXXu0mjfUsDF? literal 0 HcmV?d00001 diff --git a/docs/dist/favicon-32x32.png b/docs/dist/favicon-32x32.png new file mode 100644 index 0000000000000000000000000000000000000000..249737fe44558e679f0b67134e274461d988fa98 GIT binary patch literal 628 zcmV-)0*n2LP)Ma*GM0}OV<074bNCP7P7GVd{iMr*I6y~TMLss@FjvgL~HxU z%Vvj33AwpD(Z4*$Mfx=HaU16axM zt2xG_rloN<$iy9j9I5 + + + Swagger UI: OAuth2 Redirect + + + + + diff --git a/docs/dist/swagger-ui-bundle.js b/docs/dist/swagger-ui-bundle.js new file mode 100644 index 0000000..8ce37c9 --- /dev/null +++ b/docs/dist/swagger-ui-bundle.js @@ -0,0 +1,3 @@ +/*! For license information please see swagger-ui-bundle.js.LICENSE.txt */ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(function(){try{return require("esprima")}catch(e){}}()):"function"==typeof define&&define.amd?define(["esprima"],t):"object"==typeof exports?exports.SwaggerUIBundle=t(function(){try{return require("esprima")}catch(e){}}()):e.SwaggerUIBundle=t(e.esprima)}(this,(function(e){return function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}return n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="/dist",n(n.s=555)}([function(e,t,n){"use strict";e.exports=n(131)},function(e,t,n){e.exports=function(){"use strict";var e=Array.prototype.slice;function t(e,t){t&&(e.prototype=Object.create(t.prototype)),e.prototype.constructor=e}function n(e){return i(e)?e:J(e)}function r(e){return s(e)?e:K(e)}function o(e){return u(e)?e:Y(e)}function a(e){return i(e)&&!c(e)?e:G(e)}function i(e){return!(!e||!e[p])}function s(e){return!(!e||!e[f])}function u(e){return!(!e||!e[h])}function c(e){return s(e)||u(e)}function l(e){return!(!e||!e[d])}t(r,n),t(o,n),t(a,n),n.isIterable=i,n.isKeyed=s,n.isIndexed=u,n.isAssociative=c,n.isOrdered=l,n.Keyed=r,n.Indexed=o,n.Set=a;var p="@@__IMMUTABLE_ITERABLE__@@",f="@@__IMMUTABLE_KEYED__@@",h="@@__IMMUTABLE_INDEXED__@@",d="@@__IMMUTABLE_ORDERED__@@",m="delete",v=5,g=1<>>0;if(""+n!==t||4294967295===n)return NaN;t=n}return t<0?A(e)+t:t}function k(){return!0}function j(e,t,n){return(0===e||void 0!==n&&e<=-n)&&(void 0===t||void 0!==n&&t>=n)}function T(e,t){return P(e,t,0)}function I(e,t){return P(e,t,t)}function P(e,t,n){return void 0===e?n:e<0?Math.max(0,t+e):void 0===t?e:Math.min(t,e)}var N=0,M=1,R=2,D="function"==typeof Symbol&&Symbol.iterator,L="@@iterator",B=D||L;function F(e){this.next=e}function U(e,t,n,r){var o=0===e?t:1===e?n:[t,n];return r?r.value=o:r={value:o,done:!1},r}function q(){return{value:void 0,done:!0}}function z(e){return!!H(e)}function V(e){return e&&"function"==typeof e.next}function W(e){var t=H(e);return t&&t.call(e)}function H(e){var t=e&&(D&&e[D]||e[L]);if("function"==typeof t)return t}function $(e){return e&&"number"==typeof e.length}function J(e){return null==e?ie():i(e)?e.toSeq():ce(e)}function K(e){return null==e?ie().toKeyedSeq():i(e)?s(e)?e.toSeq():e.fromEntrySeq():se(e)}function Y(e){return null==e?ie():i(e)?s(e)?e.entrySeq():e.toIndexedSeq():ue(e)}function G(e){return(null==e?ie():i(e)?s(e)?e.entrySeq():e:ue(e)).toSetSeq()}F.prototype.toString=function(){return"[Iterator]"},F.KEYS=N,F.VALUES=M,F.ENTRIES=R,F.prototype.inspect=F.prototype.toSource=function(){return this.toString()},F.prototype[B]=function(){return this},t(J,n),J.of=function(){return J(arguments)},J.prototype.toSeq=function(){return this},J.prototype.toString=function(){return this.__toString("Seq {","}")},J.prototype.cacheResult=function(){return!this._cache&&this.__iterateUncached&&(this._cache=this.entrySeq().toArray(),this.size=this._cache.length),this},J.prototype.__iterate=function(e,t){return pe(this,e,t,!0)},J.prototype.__iterator=function(e,t){return fe(this,e,t,!0)},t(K,J),K.prototype.toKeyedSeq=function(){return this},t(Y,J),Y.of=function(){return Y(arguments)},Y.prototype.toIndexedSeq=function(){return this},Y.prototype.toString=function(){return this.__toString("Seq [","]")},Y.prototype.__iterate=function(e,t){return pe(this,e,t,!1)},Y.prototype.__iterator=function(e,t){return fe(this,e,t,!1)},t(G,J),G.of=function(){return G(arguments)},G.prototype.toSetSeq=function(){return this},J.isSeq=ae,J.Keyed=K,J.Set=G,J.Indexed=Y;var Z,X,Q,ee="@@__IMMUTABLE_SEQ__@@";function te(e){this._array=e,this.size=e.length}function ne(e){var t=Object.keys(e);this._object=e,this._keys=t,this.size=t.length}function re(e){this._iterable=e,this.size=e.length||e.size}function oe(e){this._iterator=e,this._iteratorCache=[]}function ae(e){return!(!e||!e[ee])}function ie(){return Z||(Z=new te([]))}function se(e){var t=Array.isArray(e)?new te(e).fromEntrySeq():V(e)?new oe(e).fromEntrySeq():z(e)?new re(e).fromEntrySeq():"object"==typeof e?new ne(e):void 0;if(!t)throw new TypeError("Expected Array or iterable object of [k, v] entries, or keyed object: "+e);return t}function ue(e){var t=le(e);if(!t)throw new TypeError("Expected Array or iterable object of values: "+e);return t}function ce(e){var t=le(e)||"object"==typeof e&&new ne(e);if(!t)throw new TypeError("Expected Array or iterable object of values, or keyed object: "+e);return t}function le(e){return $(e)?new te(e):V(e)?new oe(e):z(e)?new re(e):void 0}function pe(e,t,n,r){var o=e._cache;if(o){for(var a=o.length-1,i=0;i<=a;i++){var s=o[n?a-i:i];if(!1===t(s[1],r?s[0]:i,e))return i+1}return i}return e.__iterateUncached(t,n)}function fe(e,t,n,r){var o=e._cache;if(o){var a=o.length-1,i=0;return new F((function(){var e=o[n?a-i:i];return i++>a?q():U(t,r?e[0]:i-1,e[1])}))}return e.__iteratorUncached(t,n)}function he(e,t){return t?de(t,e,"",{"":e}):me(e)}function de(e,t,n,r){return Array.isArray(t)?e.call(r,n,Y(t).map((function(n,r){return de(e,n,r,t)}))):ve(t)?e.call(r,n,K(t).map((function(n,r){return de(e,n,r,t)}))):t}function me(e){return Array.isArray(e)?Y(e).map(me).toList():ve(e)?K(e).map(me).toMap():e}function ve(e){return e&&(e.constructor===Object||void 0===e.constructor)}function ge(e,t){if(e===t||e!=e&&t!=t)return!0;if(!e||!t)return!1;if("function"==typeof e.valueOf&&"function"==typeof t.valueOf){if((e=e.valueOf())===(t=t.valueOf())||e!=e&&t!=t)return!0;if(!e||!t)return!1}return!("function"!=typeof e.equals||"function"!=typeof t.equals||!e.equals(t))}function ye(e,t){if(e===t)return!0;if(!i(t)||void 0!==e.size&&void 0!==t.size&&e.size!==t.size||void 0!==e.__hash&&void 0!==t.__hash&&e.__hash!==t.__hash||s(e)!==s(t)||u(e)!==u(t)||l(e)!==l(t))return!1;if(0===e.size&&0===t.size)return!0;var n=!c(e);if(l(e)){var r=e.entries();return t.every((function(e,t){var o=r.next().value;return o&&ge(o[1],e)&&(n||ge(o[0],t))}))&&r.next().done}var o=!1;if(void 0===e.size)if(void 0===t.size)"function"==typeof e.cacheResult&&e.cacheResult();else{o=!0;var a=e;e=t,t=a}var p=!0,f=t.__iterate((function(t,r){if(n?!e.has(t):o?!ge(t,e.get(r,b)):!ge(e.get(r,b),t))return p=!1,!1}));return p&&e.size===f}function be(e,t){if(!(this instanceof be))return new be(e,t);if(this._value=e,this.size=void 0===t?1/0:Math.max(0,t),0===this.size){if(X)return X;X=this}}function _e(e,t){if(!e)throw new Error(t)}function xe(e,t,n){if(!(this instanceof xe))return new xe(e,t,n);if(_e(0!==n,"Cannot step a Range by 0"),e=e||0,void 0===t&&(t=1/0),n=void 0===n?1:Math.abs(n),tr?q():U(e,o,n[t?r-o++:o++])}))},t(ne,K),ne.prototype.get=function(e,t){return void 0===t||this.has(e)?this._object[e]:t},ne.prototype.has=function(e){return this._object.hasOwnProperty(e)},ne.prototype.__iterate=function(e,t){for(var n=this._object,r=this._keys,o=r.length-1,a=0;a<=o;a++){var i=r[t?o-a:a];if(!1===e(n[i],i,this))return a+1}return a},ne.prototype.__iterator=function(e,t){var n=this._object,r=this._keys,o=r.length-1,a=0;return new F((function(){var i=r[t?o-a:a];return a++>o?q():U(e,i,n[i])}))},ne.prototype[d]=!0,t(re,Y),re.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);var n=W(this._iterable),r=0;if(V(n))for(var o;!(o=n.next()).done&&!1!==e(o.value,r++,this););return r},re.prototype.__iteratorUncached=function(e,t){if(t)return this.cacheResult().__iterator(e,t);var n=W(this._iterable);if(!V(n))return new F(q);var r=0;return new F((function(){var t=n.next();return t.done?t:U(e,r++,t.value)}))},t(oe,Y),oe.prototype.__iterateUncached=function(e,t){if(t)return this.cacheResult().__iterate(e,t);for(var n,r=this._iterator,o=this._iteratorCache,a=0;a=r.length){var t=n.next();if(t.done)return t;r[o]=t.value}return U(e,o,r[o++])}))},t(be,Y),be.prototype.toString=function(){return 0===this.size?"Repeat []":"Repeat [ "+this._value+" "+this.size+" times ]"},be.prototype.get=function(e,t){return this.has(e)?this._value:t},be.prototype.includes=function(e){return ge(this._value,e)},be.prototype.slice=function(e,t){var n=this.size;return j(e,t,n)?this:new be(this._value,I(t,n)-T(e,n))},be.prototype.reverse=function(){return this},be.prototype.indexOf=function(e){return ge(this._value,e)?0:-1},be.prototype.lastIndexOf=function(e){return ge(this._value,e)?this.size:-1},be.prototype.__iterate=function(e,t){for(var n=0;n=0&&t=0&&nn?q():U(e,a++,i)}))},xe.prototype.equals=function(e){return e instanceof xe?this._start===e._start&&this._end===e._end&&this._step===e._step:ye(this,e)},t(we,n),t(Ee,we),t(Se,we),t(Ce,we),we.Keyed=Ee,we.Indexed=Se,we.Set=Ce;var Ae="function"==typeof Math.imul&&-2===Math.imul(4294967295,2)?Math.imul:function(e,t){var n=65535&(e|=0),r=65535&(t|=0);return n*r+((e>>>16)*r+n*(t>>>16)<<16>>>0)|0};function Oe(e){return e>>>1&1073741824|3221225471&e}function ke(e){if(!1===e||null==e)return 0;if("function"==typeof e.valueOf&&(!1===(e=e.valueOf())||null==e))return 0;if(!0===e)return 1;var t=typeof e;if("number"===t){if(e!=e||e===1/0)return 0;var n=0|e;for(n!==e&&(n^=4294967295*e);e>4294967295;)n^=e/=4294967295;return Oe(n)}if("string"===t)return e.length>Fe?je(e):Te(e);if("function"==typeof e.hashCode)return e.hashCode();if("object"===t)return Ie(e);if("function"==typeof e.toString)return Te(e.toString());throw new Error("Value type "+t+" cannot be hashed.")}function je(e){var t=ze[e];return void 0===t&&(t=Te(e),qe===Ue&&(qe=0,ze={}),qe++,ze[e]=t),t}function Te(e){for(var t=0,n=0;n0)switch(e.nodeType){case 1:return e.uniqueID;case 9:return e.documentElement&&e.documentElement.uniqueID}}var Re,De="function"==typeof WeakMap;De&&(Re=new WeakMap);var Le=0,Be="__immutablehash__";"function"==typeof Symbol&&(Be=Symbol(Be));var Fe=16,Ue=255,qe=0,ze={};function Ve(e){_e(e!==1/0,"Cannot perform this action with an infinite size.")}function We(e){return null==e?ot():He(e)&&!l(e)?e:ot().withMutations((function(t){var n=r(e);Ve(n.size),n.forEach((function(e,n){return t.set(n,e)}))}))}function He(e){return!(!e||!e[Je])}t(We,Ee),We.of=function(){var t=e.call(arguments,0);return ot().withMutations((function(e){for(var n=0;n=t.length)throw new Error("Missing value for key: "+t[n]);e.set(t[n],t[n+1])}}))},We.prototype.toString=function(){return this.__toString("Map {","}")},We.prototype.get=function(e,t){return this._root?this._root.get(0,void 0,e,t):t},We.prototype.set=function(e,t){return at(this,e,t)},We.prototype.setIn=function(e,t){return this.updateIn(e,b,(function(){return t}))},We.prototype.remove=function(e){return at(this,e,b)},We.prototype.deleteIn=function(e){return this.updateIn(e,(function(){return b}))},We.prototype.update=function(e,t,n){return 1===arguments.length?e(this):this.updateIn([e],t,n)},We.prototype.updateIn=function(e,t,n){n||(n=t,t=void 0);var r=vt(this,wn(e),t,n);return r===b?void 0:r},We.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._root=null,this.__hash=void 0,this.__altered=!0,this):ot()},We.prototype.merge=function(){return ft(this,void 0,arguments)},We.prototype.mergeWith=function(t){return ft(this,t,e.call(arguments,1))},We.prototype.mergeIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,ot(),(function(e){return"function"==typeof e.merge?e.merge.apply(e,n):n[n.length-1]}))},We.prototype.mergeDeep=function(){return ft(this,ht,arguments)},We.prototype.mergeDeepWith=function(t){var n=e.call(arguments,1);return ft(this,dt(t),n)},We.prototype.mergeDeepIn=function(t){var n=e.call(arguments,1);return this.updateIn(t,ot(),(function(e){return"function"==typeof e.mergeDeep?e.mergeDeep.apply(e,n):n[n.length-1]}))},We.prototype.sort=function(e){return zt(pn(this,e))},We.prototype.sortBy=function(e,t){return zt(pn(this,t,e))},We.prototype.withMutations=function(e){var t=this.asMutable();return e(t),t.wasAltered()?t.__ensureOwner(this.__ownerID):this},We.prototype.asMutable=function(){return this.__ownerID?this:this.__ensureOwner(new S)},We.prototype.asImmutable=function(){return this.__ensureOwner()},We.prototype.wasAltered=function(){return this.__altered},We.prototype.__iterator=function(e,t){return new et(this,e,t)},We.prototype.__iterate=function(e,t){var n=this,r=0;return this._root&&this._root.iterate((function(t){return r++,e(t[1],t[0],n)}),t),r},We.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?rt(this.size,this._root,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},We.isMap=He;var $e,Je="@@__IMMUTABLE_MAP__@@",Ke=We.prototype;function Ye(e,t){this.ownerID=e,this.entries=t}function Ge(e,t,n){this.ownerID=e,this.bitmap=t,this.nodes=n}function Ze(e,t,n){this.ownerID=e,this.count=t,this.nodes=n}function Xe(e,t,n){this.ownerID=e,this.keyHash=t,this.entries=n}function Qe(e,t,n){this.ownerID=e,this.keyHash=t,this.entry=n}function et(e,t,n){this._type=t,this._reverse=n,this._stack=e._root&&nt(e._root)}function tt(e,t){return U(e,t[0],t[1])}function nt(e,t){return{node:e,index:0,__prev:t}}function rt(e,t,n,r){var o=Object.create(Ke);return o.size=e,o._root=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function ot(){return $e||($e=rt(0))}function at(e,t,n){var r,o;if(e._root){var a=w(_),i=w(x);if(r=it(e._root,e.__ownerID,0,void 0,t,n,a,i),!i.value)return e;o=e.size+(a.value?n===b?-1:1:0)}else{if(n===b)return e;o=1,r=new Ye(e.__ownerID,[[t,n]])}return e.__ownerID?(e.size=o,e._root=r,e.__hash=void 0,e.__altered=!0,e):r?rt(o,r):ot()}function it(e,t,n,r,o,a,i,s){return e?e.update(t,n,r,o,a,i,s):a===b?e:(E(s),E(i),new Qe(t,r,[o,a]))}function st(e){return e.constructor===Qe||e.constructor===Xe}function ut(e,t,n,r,o){if(e.keyHash===r)return new Xe(t,r,[e.entry,o]);var a,i=(0===n?e.keyHash:e.keyHash>>>n)&y,s=(0===n?r:r>>>n)&y;return new Ge(t,1<>>=1)i[s]=1&n?t[a++]:void 0;return i[r]=o,new Ze(e,a+1,i)}function ft(e,t,n){for(var o=[],a=0;a>1&1431655765))+(e>>2&858993459))+(e>>4)&252645135,e+=e>>8,127&(e+=e>>16)}function yt(e,t,n,r){var o=r?e:C(e);return o[t]=n,o}function bt(e,t,n,r){var o=e.length+1;if(r&&t+1===o)return e[t]=n,e;for(var a=new Array(o),i=0,s=0;s=xt)return ct(e,u,r,o);var f=e&&e===this.ownerID,h=f?u:C(u);return p?s?c===l-1?h.pop():h[c]=h.pop():h[c]=[r,o]:h.push([r,o]),f?(this.entries=h,this):new Ye(e,h)}},Ge.prototype.get=function(e,t,n,r){void 0===t&&(t=ke(n));var o=1<<((0===e?t:t>>>e)&y),a=this.bitmap;return 0==(a&o)?r:this.nodes[gt(a&o-1)].get(e+v,t,n,r)},Ge.prototype.update=function(e,t,n,r,o,a,i){void 0===n&&(n=ke(r));var s=(0===t?n:n>>>t)&y,u=1<=wt)return pt(e,f,c,s,d);if(l&&!d&&2===f.length&&st(f[1^p]))return f[1^p];if(l&&d&&1===f.length&&st(d))return d;var m=e&&e===this.ownerID,g=l?d?c:c^u:c|u,_=l?d?yt(f,p,d,m):_t(f,p,m):bt(f,p,d,m);return m?(this.bitmap=g,this.nodes=_,this):new Ge(e,g,_)},Ze.prototype.get=function(e,t,n,r){void 0===t&&(t=ke(n));var o=(0===e?t:t>>>e)&y,a=this.nodes[o];return a?a.get(e+v,t,n,r):r},Ze.prototype.update=function(e,t,n,r,o,a,i){void 0===n&&(n=ke(r));var s=(0===t?n:n>>>t)&y,u=o===b,c=this.nodes,l=c[s];if(u&&!l)return this;var p=it(l,e,t+v,n,r,o,a,i);if(p===l)return this;var f=this.count;if(l){if(!p&&--f0&&r=0&&e>>t&y;if(r>=this.array.length)return new kt([],e);var o,a=0===r;if(t>0){var i=this.array[r];if((o=i&&i.removeBefore(e,t-v,n))===i&&a)return this}if(a&&!o)return this;var s=Lt(this,e);if(!a)for(var u=0;u>>t&y;if(o>=this.array.length)return this;if(t>0){var a=this.array[o];if((r=a&&a.removeAfter(e,t-v,n))===a&&o===this.array.length-1)return this}var i=Lt(this,e);return i.array.splice(o+1),r&&(i.array[o]=r),i};var jt,Tt,It={};function Pt(e,t){var n=e._origin,r=e._capacity,o=qt(r),a=e._tail;return i(e._root,e._level,0);function i(e,t,n){return 0===t?s(e,n):u(e,t,n)}function s(e,i){var s=i===o?a&&a.array:e&&e.array,u=i>n?0:n-i,c=r-i;return c>g&&(c=g),function(){if(u===c)return It;var e=t?--c:u++;return s&&s[e]}}function u(e,o,a){var s,u=e&&e.array,c=a>n?0:n-a>>o,l=1+(r-a>>o);return l>g&&(l=g),function(){for(;;){if(s){var e=s();if(e!==It)return e;s=null}if(c===l)return It;var n=t?--l:c++;s=i(u&&u[n],o-v,a+(n<=e.size||t<0)return e.withMutations((function(e){t<0?Ft(e,t).set(0,n):Ft(e,0,t+1).set(t,n)}));t+=e._origin;var r=e._tail,o=e._root,a=w(x);return t>=qt(e._capacity)?r=Dt(r,e.__ownerID,0,t,n,a):o=Dt(o,e.__ownerID,e._level,t,n,a),a.value?e.__ownerID?(e._root=o,e._tail=r,e.__hash=void 0,e.__altered=!0,e):Nt(e._origin,e._capacity,e._level,o,r):e}function Dt(e,t,n,r,o,a){var i,s=r>>>n&y,u=e&&s0){var c=e&&e.array[s],l=Dt(c,t,n-v,r,o,a);return l===c?e:((i=Lt(e,t)).array[s]=l,i)}return u&&e.array[s]===o?e:(E(a),i=Lt(e,t),void 0===o&&s===i.array.length-1?i.array.pop():i.array[s]=o,i)}function Lt(e,t){return t&&e&&t===e.ownerID?e:new kt(e?e.array.slice():[],t)}function Bt(e,t){if(t>=qt(e._capacity))return e._tail;if(t<1<0;)n=n.array[t>>>r&y],r-=v;return n}}function Ft(e,t,n){void 0!==t&&(t|=0),void 0!==n&&(n|=0);var r=e.__ownerID||new S,o=e._origin,a=e._capacity,i=o+t,s=void 0===n?a:n<0?a+n:o+n;if(i===o&&s===a)return e;if(i>=s)return e.clear();for(var u=e._level,c=e._root,l=0;i+l<0;)c=new kt(c&&c.array.length?[void 0,c]:[],r),l+=1<<(u+=v);l&&(i+=l,o+=l,s+=l,a+=l);for(var p=qt(a),f=qt(s);f>=1<p?new kt([],r):h;if(h&&f>p&&iv;g-=v){var b=p>>>g&y;m=m.array[b]=Lt(m.array[b],r)}m.array[p>>>v&y]=h}if(s=f)i-=f,s-=f,u=v,c=null,d=d&&d.removeBefore(r,0,i);else if(i>o||f>>u&y;if(_!==f>>>u&y)break;_&&(l+=(1<o&&(c=c.removeBefore(r,u,i-l)),c&&fa&&(a=c.size),i(u)||(c=c.map((function(e){return he(e)}))),r.push(c)}return a>e.size&&(e=e.setSize(a)),mt(e,t,r)}function qt(e){return e>>v<=g&&i.size>=2*a.size?(r=(o=i.filter((function(e,t){return void 0!==e&&s!==t}))).toKeyedSeq().map((function(e){return e[0]})).flip().toMap(),e.__ownerID&&(r.__ownerID=o.__ownerID=e.__ownerID)):(r=a.remove(t),o=s===i.size-1?i.pop():i.set(s,void 0))}else if(u){if(n===i.get(s)[1])return e;r=a,o=i.set(s,[t,n])}else r=a.set(t,i.size),o=i.set(i.size,[t,n]);return e.__ownerID?(e.size=r.size,e._map=r,e._list=o,e.__hash=void 0,e):Wt(r,o)}function Jt(e,t){this._iter=e,this._useKeys=t,this.size=e.size}function Kt(e){this._iter=e,this.size=e.size}function Yt(e){this._iter=e,this.size=e.size}function Gt(e){this._iter=e,this.size=e.size}function Zt(e){var t=bn(e);return t._iter=e,t.size=e.size,t.flip=function(){return e},t.reverse=function(){var t=e.reverse.apply(this);return t.flip=function(){return e.reverse()},t},t.has=function(t){return e.includes(t)},t.includes=function(t){return e.has(t)},t.cacheResult=_n,t.__iterateUncached=function(t,n){var r=this;return e.__iterate((function(e,n){return!1!==t(n,e,r)}),n)},t.__iteratorUncached=function(t,n){if(t===R){var r=e.__iterator(t,n);return new F((function(){var e=r.next();if(!e.done){var t=e.value[0];e.value[0]=e.value[1],e.value[1]=t}return e}))}return e.__iterator(t===M?N:M,n)},t}function Xt(e,t,n){var r=bn(e);return r.size=e.size,r.has=function(t){return e.has(t)},r.get=function(r,o){var a=e.get(r,b);return a===b?o:t.call(n,a,r,e)},r.__iterateUncached=function(r,o){var a=this;return e.__iterate((function(e,o,i){return!1!==r(t.call(n,e,o,i),o,a)}),o)},r.__iteratorUncached=function(r,o){var a=e.__iterator(R,o);return new F((function(){var o=a.next();if(o.done)return o;var i=o.value,s=i[0];return U(r,s,t.call(n,i[1],s,e),o)}))},r}function Qt(e,t){var n=bn(e);return n._iter=e,n.size=e.size,n.reverse=function(){return e},e.flip&&(n.flip=function(){var t=Zt(e);return t.reverse=function(){return e.flip()},t}),n.get=function(n,r){return e.get(t?n:-1-n,r)},n.has=function(n){return e.has(t?n:-1-n)},n.includes=function(t){return e.includes(t)},n.cacheResult=_n,n.__iterate=function(t,n){var r=this;return e.__iterate((function(e,n){return t(e,n,r)}),!n)},n.__iterator=function(t,n){return e.__iterator(t,!n)},n}function en(e,t,n,r){var o=bn(e);return r&&(o.has=function(r){var o=e.get(r,b);return o!==b&&!!t.call(n,o,r,e)},o.get=function(r,o){var a=e.get(r,b);return a!==b&&t.call(n,a,r,e)?a:o}),o.__iterateUncached=function(o,a){var i=this,s=0;return e.__iterate((function(e,a,u){if(t.call(n,e,a,u))return s++,o(e,r?a:s-1,i)}),a),s},o.__iteratorUncached=function(o,a){var i=e.__iterator(R,a),s=0;return new F((function(){for(;;){var a=i.next();if(a.done)return a;var u=a.value,c=u[0],l=u[1];if(t.call(n,l,c,e))return U(o,r?c:s++,l,a)}}))},o}function tn(e,t,n){var r=We().asMutable();return e.__iterate((function(o,a){r.update(t.call(n,o,a,e),0,(function(e){return e+1}))})),r.asImmutable()}function nn(e,t,n){var r=s(e),o=(l(e)?zt():We()).asMutable();e.__iterate((function(a,i){o.update(t.call(n,a,i,e),(function(e){return(e=e||[]).push(r?[i,a]:a),e}))}));var a=yn(e);return o.map((function(t){return mn(e,a(t))}))}function rn(e,t,n,r){var o=e.size;if(void 0!==t&&(t|=0),void 0!==n&&(n===1/0?n=o:n|=0),j(t,n,o))return e;var a=T(t,o),i=I(n,o);if(a!=a||i!=i)return rn(e.toSeq().cacheResult(),t,n,r);var s,u=i-a;u==u&&(s=u<0?0:u);var c=bn(e);return c.size=0===s?s:e.size&&s||void 0,!r&&ae(e)&&s>=0&&(c.get=function(t,n){return(t=O(this,t))>=0&&ts)return q();var e=o.next();return r||t===M?e:U(t,u-1,t===N?void 0:e.value[1],e)}))},c}function on(e,t,n){var r=bn(e);return r.__iterateUncached=function(r,o){var a=this;if(o)return this.cacheResult().__iterate(r,o);var i=0;return e.__iterate((function(e,o,s){return t.call(n,e,o,s)&&++i&&r(e,o,a)})),i},r.__iteratorUncached=function(r,o){var a=this;if(o)return this.cacheResult().__iterator(r,o);var i=e.__iterator(R,o),s=!0;return new F((function(){if(!s)return q();var e=i.next();if(e.done)return e;var o=e.value,u=o[0],c=o[1];return t.call(n,c,u,a)?r===R?e:U(r,u,c,e):(s=!1,q())}))},r}function an(e,t,n,r){var o=bn(e);return o.__iterateUncached=function(o,a){var i=this;if(a)return this.cacheResult().__iterate(o,a);var s=!0,u=0;return e.__iterate((function(e,a,c){if(!s||!(s=t.call(n,e,a,c)))return u++,o(e,r?a:u-1,i)})),u},o.__iteratorUncached=function(o,a){var i=this;if(a)return this.cacheResult().__iterator(o,a);var s=e.__iterator(R,a),u=!0,c=0;return new F((function(){var e,a,l;do{if((e=s.next()).done)return r||o===M?e:U(o,c++,o===N?void 0:e.value[1],e);var p=e.value;a=p[0],l=p[1],u&&(u=t.call(n,l,a,i))}while(u);return o===R?e:U(o,a,l,e)}))},o}function sn(e,t){var n=s(e),o=[e].concat(t).map((function(e){return i(e)?n&&(e=r(e)):e=n?se(e):ue(Array.isArray(e)?e:[e]),e})).filter((function(e){return 0!==e.size}));if(0===o.length)return e;if(1===o.length){var a=o[0];if(a===e||n&&s(a)||u(e)&&u(a))return a}var c=new te(o);return n?c=c.toKeyedSeq():u(e)||(c=c.toSetSeq()),(c=c.flatten(!0)).size=o.reduce((function(e,t){if(void 0!==e){var n=t.size;if(void 0!==n)return e+n}}),0),c}function un(e,t,n){var r=bn(e);return r.__iterateUncached=function(r,o){var a=0,s=!1;function u(e,c){var l=this;e.__iterate((function(e,o){return(!t||c0}function dn(e,t,r){var o=bn(e);return o.size=new te(r).map((function(e){return e.size})).min(),o.__iterate=function(e,t){for(var n,r=this.__iterator(M,t),o=0;!(n=r.next()).done&&!1!==e(n.value,o++,this););return o},o.__iteratorUncached=function(e,o){var a=r.map((function(e){return e=n(e),W(o?e.reverse():e)})),i=0,s=!1;return new F((function(){var n;return s||(n=a.map((function(e){return e.next()})),s=n.some((function(e){return e.done}))),s?q():U(e,i++,t.apply(null,n.map((function(e){return e.value}))))}))},o}function mn(e,t){return ae(e)?t:e.constructor(t)}function vn(e){if(e!==Object(e))throw new TypeError("Expected [K, V] tuple: "+e)}function gn(e){return Ve(e.size),A(e)}function yn(e){return s(e)?r:u(e)?o:a}function bn(e){return Object.create((s(e)?K:u(e)?Y:G).prototype)}function _n(){return this._iter.cacheResult?(this._iter.cacheResult(),this.size=this._iter.size,this):J.prototype.cacheResult.call(this)}function xn(e,t){return e>t?1:e=0;n--)t={value:arguments[n],next:t};return this.__ownerID?(this.size=e,this._head=t,this.__hash=void 0,this.__altered=!0,this):Kn(e,t)},Vn.prototype.pushAll=function(e){if(0===(e=o(e)).size)return this;Ve(e.size);var t=this.size,n=this._head;return e.reverse().forEach((function(e){t++,n={value:e,next:n}})),this.__ownerID?(this.size=t,this._head=n,this.__hash=void 0,this.__altered=!0,this):Kn(t,n)},Vn.prototype.pop=function(){return this.slice(1)},Vn.prototype.unshift=function(){return this.push.apply(this,arguments)},Vn.prototype.unshiftAll=function(e){return this.pushAll(e)},Vn.prototype.shift=function(){return this.pop.apply(this,arguments)},Vn.prototype.clear=function(){return 0===this.size?this:this.__ownerID?(this.size=0,this._head=void 0,this.__hash=void 0,this.__altered=!0,this):Yn()},Vn.prototype.slice=function(e,t){if(j(e,t,this.size))return this;var n=T(e,this.size);if(I(t,this.size)!==this.size)return Se.prototype.slice.call(this,e,t);for(var r=this.size-n,o=this._head;n--;)o=o.next;return this.__ownerID?(this.size=r,this._head=o,this.__hash=void 0,this.__altered=!0,this):Kn(r,o)},Vn.prototype.__ensureOwner=function(e){return e===this.__ownerID?this:e?Kn(this.size,this._head,e,this.__hash):(this.__ownerID=e,this.__altered=!1,this)},Vn.prototype.__iterate=function(e,t){if(t)return this.reverse().__iterate(e);for(var n=0,r=this._head;r&&!1!==e(r.value,n++,this);)r=r.next;return n},Vn.prototype.__iterator=function(e,t){if(t)return this.reverse().__iterator(e);var n=0,r=this._head;return new F((function(){if(r){var t=r.value;return r=r.next,U(e,n++,t)}return q()}))},Vn.isStack=Wn;var Hn,$n="@@__IMMUTABLE_STACK__@@",Jn=Vn.prototype;function Kn(e,t,n,r){var o=Object.create(Jn);return o.size=e,o._head=t,o.__ownerID=n,o.__hash=r,o.__altered=!1,o}function Yn(){return Hn||(Hn=Kn(0))}function Gn(e,t){var n=function(n){e.prototype[n]=t[n]};return Object.keys(t).forEach(n),Object.getOwnPropertySymbols&&Object.getOwnPropertySymbols(t).forEach(n),e}Jn[$n]=!0,Jn.withMutations=Ke.withMutations,Jn.asMutable=Ke.asMutable,Jn.asImmutable=Ke.asImmutable,Jn.wasAltered=Ke.wasAltered,n.Iterator=F,Gn(n,{toArray:function(){Ve(this.size);var e=new Array(this.size||0);return this.valueSeq().__iterate((function(t,n){e[n]=t})),e},toIndexedSeq:function(){return new Kt(this)},toJS:function(){return this.toSeq().map((function(e){return e&&"function"==typeof e.toJS?e.toJS():e})).__toJS()},toJSON:function(){return this.toSeq().map((function(e){return e&&"function"==typeof e.toJSON?e.toJSON():e})).__toJS()},toKeyedSeq:function(){return new Jt(this,!0)},toMap:function(){return We(this.toKeyedSeq())},toObject:function(){Ve(this.size);var e={};return this.__iterate((function(t,n){e[n]=t})),e},toOrderedMap:function(){return zt(this.toKeyedSeq())},toOrderedSet:function(){return Ln(s(this)?this.valueSeq():this)},toSet:function(){return jn(s(this)?this.valueSeq():this)},toSetSeq:function(){return new Yt(this)},toSeq:function(){return u(this)?this.toIndexedSeq():s(this)?this.toKeyedSeq():this.toSetSeq()},toStack:function(){return Vn(s(this)?this.valueSeq():this)},toList:function(){return St(s(this)?this.valueSeq():this)},toString:function(){return"[Iterable]"},__toString:function(e,t){return 0===this.size?e+t:e+" "+this.toSeq().map(this.__toStringMapper).join(", ")+" "+t},concat:function(){return mn(this,sn(this,e.call(arguments,0)))},includes:function(e){return this.some((function(t){return ge(t,e)}))},entries:function(){return this.__iterator(R)},every:function(e,t){Ve(this.size);var n=!0;return this.__iterate((function(r,o,a){if(!e.call(t,r,o,a))return n=!1,!1})),n},filter:function(e,t){return mn(this,en(this,e,t,!0))},find:function(e,t,n){var r=this.findEntry(e,t);return r?r[1]:n},forEach:function(e,t){return Ve(this.size),this.__iterate(t?e.bind(t):e)},join:function(e){Ve(this.size),e=void 0!==e?""+e:",";var t="",n=!0;return this.__iterate((function(r){n?n=!1:t+=e,t+=null!=r?r.toString():""})),t},keys:function(){return this.__iterator(N)},map:function(e,t){return mn(this,Xt(this,e,t))},reduce:function(e,t,n){var r,o;return Ve(this.size),arguments.length<2?o=!0:r=t,this.__iterate((function(t,a,i){o?(o=!1,r=t):r=e.call(n,r,t,a,i)})),r},reduceRight:function(e,t,n){var r=this.toKeyedSeq().reverse();return r.reduce.apply(r,arguments)},reverse:function(){return mn(this,Qt(this,!0))},slice:function(e,t){return mn(this,rn(this,e,t,!0))},some:function(e,t){return!this.every(tr(e),t)},sort:function(e){return mn(this,pn(this,e))},values:function(){return this.__iterator(M)},butLast:function(){return this.slice(0,-1)},isEmpty:function(){return void 0!==this.size?0===this.size:!this.some((function(){return!0}))},count:function(e,t){return A(e?this.toSeq().filter(e,t):this)},countBy:function(e,t){return tn(this,e,t)},equals:function(e){return ye(this,e)},entrySeq:function(){var e=this;if(e._cache)return new te(e._cache);var t=e.toSeq().map(er).toIndexedSeq();return t.fromEntrySeq=function(){return e.toSeq()},t},filterNot:function(e,t){return this.filter(tr(e),t)},findEntry:function(e,t,n){var r=n;return this.__iterate((function(n,o,a){if(e.call(t,n,o,a))return r=[o,n],!1})),r},findKey:function(e,t){var n=this.findEntry(e,t);return n&&n[0]},findLast:function(e,t,n){return this.toKeyedSeq().reverse().find(e,t,n)},findLastEntry:function(e,t,n){return this.toKeyedSeq().reverse().findEntry(e,t,n)},findLastKey:function(e,t){return this.toKeyedSeq().reverse().findKey(e,t)},first:function(){return this.find(k)},flatMap:function(e,t){return mn(this,cn(this,e,t))},flatten:function(e){return mn(this,un(this,e,!0))},fromEntrySeq:function(){return new Gt(this)},get:function(e,t){return this.find((function(t,n){return ge(n,e)}),void 0,t)},getIn:function(e,t){for(var n,r=this,o=wn(e);!(n=o.next()).done;){var a=n.value;if((r=r&&r.get?r.get(a,b):b)===b)return t}return r},groupBy:function(e,t){return nn(this,e,t)},has:function(e){return this.get(e,b)!==b},hasIn:function(e){return this.getIn(e,b)!==b},isSubset:function(e){return e="function"==typeof e.includes?e:n(e),this.every((function(t){return e.includes(t)}))},isSuperset:function(e){return(e="function"==typeof e.isSubset?e:n(e)).isSubset(this)},keyOf:function(e){return this.findKey((function(t){return ge(t,e)}))},keySeq:function(){return this.toSeq().map(Qn).toIndexedSeq()},last:function(){return this.toSeq().reverse().first()},lastKeyOf:function(e){return this.toKeyedSeq().reverse().keyOf(e)},max:function(e){return fn(this,e)},maxBy:function(e,t){return fn(this,t,e)},min:function(e){return fn(this,e?nr(e):ar)},minBy:function(e,t){return fn(this,t?nr(t):ar,e)},rest:function(){return this.slice(1)},skip:function(e){return this.slice(Math.max(0,e))},skipLast:function(e){return mn(this,this.toSeq().reverse().skip(e).reverse())},skipWhile:function(e,t){return mn(this,an(this,e,t,!0))},skipUntil:function(e,t){return this.skipWhile(tr(e),t)},sortBy:function(e,t){return mn(this,pn(this,t,e))},take:function(e){return this.slice(0,Math.max(0,e))},takeLast:function(e){return mn(this,this.toSeq().reverse().take(e).reverse())},takeWhile:function(e,t){return mn(this,on(this,e,t))},takeUntil:function(e,t){return this.takeWhile(tr(e),t)},valueSeq:function(){return this.toIndexedSeq()},hashCode:function(){return this.__hash||(this.__hash=ir(this))}});var Zn=n.prototype;Zn[p]=!0,Zn[B]=Zn.values,Zn.__toJS=Zn.toArray,Zn.__toStringMapper=rr,Zn.inspect=Zn.toSource=function(){return this.toString()},Zn.chain=Zn.flatMap,Zn.contains=Zn.includes,Gn(r,{flip:function(){return mn(this,Zt(this))},mapEntries:function(e,t){var n=this,r=0;return mn(this,this.toSeq().map((function(o,a){return e.call(t,[a,o],r++,n)})).fromEntrySeq())},mapKeys:function(e,t){var n=this;return mn(this,this.toSeq().flip().map((function(r,o){return e.call(t,r,o,n)})).flip())}});var Xn=r.prototype;function Qn(e,t){return t}function er(e,t){return[t,e]}function tr(e){return function(){return!e.apply(this,arguments)}}function nr(e){return function(){return-e.apply(this,arguments)}}function rr(e){return"string"==typeof e?JSON.stringify(e):String(e)}function or(){return C(arguments)}function ar(e,t){return et?-1:0}function ir(e){if(e.size===1/0)return 0;var t=l(e),n=s(e),r=t?1:0;return sr(e.__iterate(n?t?function(e,t){r=31*r+ur(ke(e),ke(t))|0}:function(e,t){r=r+ur(ke(e),ke(t))|0}:t?function(e){r=31*r+ke(e)|0}:function(e){r=r+ke(e)|0}),r)}function sr(e,t){return t=Ae(t,3432918353),t=Ae(t<<15|t>>>-15,461845907),t=Ae(t<<13|t>>>-13,5),t=Ae((t=(t+3864292196|0)^e)^t>>>16,2246822507),t=Oe((t=Ae(t^t>>>13,3266489909))^t>>>16)}function ur(e,t){return e^t+2654435769+(e<<6)+(e>>2)|0}return Xn[f]=!0,Xn[B]=Zn.entries,Xn.__toJS=Zn.toObject,Xn.__toStringMapper=function(e,t){return JSON.stringify(t)+": "+rr(e)},Gn(o,{toKeyedSeq:function(){return new Jt(this,!1)},filter:function(e,t){return mn(this,en(this,e,t,!1))},findIndex:function(e,t){var n=this.findEntry(e,t);return n?n[0]:-1},indexOf:function(e){var t=this.keyOf(e);return void 0===t?-1:t},lastIndexOf:function(e){var t=this.lastKeyOf(e);return void 0===t?-1:t},reverse:function(){return mn(this,Qt(this,!1))},slice:function(e,t){return mn(this,rn(this,e,t,!1))},splice:function(e,t){var n=arguments.length;if(t=Math.max(0|t,0),0===n||2===n&&!t)return this;e=T(e,e<0?this.count():this.size);var r=this.slice(0,e);return mn(this,1===n?r:r.concat(C(arguments,2),this.slice(e+t)))},findLastIndex:function(e,t){var n=this.findLastEntry(e,t);return n?n[0]:-1},first:function(){return this.get(0)},flatten:function(e){return mn(this,un(this,e,!1))},get:function(e,t){return(e=O(this,e))<0||this.size===1/0||void 0!==this.size&&e>this.size?t:this.find((function(t,n){return n===e}),void 0,t)},has:function(e){return(e=O(this,e))>=0&&(void 0!==this.size?this.size===1/0||e1)try{return decodeURIComponent(t[1])}catch(e){console.error(e)}return null}function Ne(e){return t=e.replace(/\.[^./]*$/,""),Y()(J()(t));var t}function Me(e,t,n,r,a){if(!t)return[];var s=[],u=t.get("nullable"),c=t.get("required"),p=t.get("maximum"),h=t.get("minimum"),d=t.get("type"),m=t.get("format"),g=t.get("maxLength"),b=t.get("minLength"),x=t.get("uniqueItems"),w=t.get("maxItems"),E=t.get("minItems"),S=t.get("pattern"),C=n||!0===c,A=null!=e;if(u&&null===e||!d||!(C||A&&"array"===d||!(!C&&!A)))return[];var O="string"===d&&e,k="array"===d&&l()(e)&&e.length,j="array"===d&&W.a.List.isList(e)&&e.count(),T=[O,k,j,"array"===d&&"string"==typeof e&&e,"file"===d&&e instanceof se.a.File,"boolean"===d&&(e||!1===e),"number"===d&&(e||0===e),"integer"===d&&(e||0===e),"object"===d&&"object"===i()(e)&&null!==e,"object"===d&&"string"==typeof e&&e],I=P()(T).call(T,(function(e){return!!e}));if(C&&!I&&!r)return s.push("Required field is not provided"),s;if("object"===d&&(null===a||"application/json"===a)){var N,M=e;if("string"==typeof e)try{M=JSON.parse(e)}catch(e){return s.push("Parameter string value must be valid JSON"),s}if(t&&t.has("required")&&Se(c.isList)&&c.isList()&&y()(c).call(c,(function(e){void 0===M[e]&&s.push({propKey:e,error:"Required property not found"})})),t&&t.has("properties"))y()(N=t.get("properties")).call(N,(function(e,t){var n=Me(M[t],e,!1,r,a);s.push.apply(s,o()(f()(n).call(n,(function(e){return{propKey:t,error:e}}))))}))}if(S){var R=function(e,t){if(!new RegExp(t).test(e))return"Value must follow pattern "+t}(e,S);R&&s.push(R)}if(E&&"array"===d){var D=function(e,t){var n;if(!e&&t>=1||e&&e.lengtht)return v()(n="Array must not contain more then ".concat(t," item")).call(n,1===t?"":"s")}(e,w);L&&s.push({needRemove:!0,error:L})}if(x&&"array"===d){var B=function(e,t){if(e&&("true"===t||!0===t)){var n=Object(V.fromJS)(e),r=n.toSet();if(e.length>r.size){var o=Object(V.Set)();if(y()(n).call(n,(function(e,t){_()(n).call(n,(function(t){return Se(t.equals)?t.equals(e):t===e})).size>1&&(o=o.add(t))})),0!==o.size)return f()(o).call(o,(function(e){return{index:e,error:"No duplicates allowed."}})).toArray()}}}(e,x);B&&s.push.apply(s,o()(B))}if(g||0===g){var F=function(e,t){var n;if(e.length>t)return v()(n="Value must be no longer than ".concat(t," character")).call(n,1!==t?"s":"")}(e,g);F&&s.push(F)}if(b){var U=function(e,t){var n;if(e.lengtht)return"Value must be less than ".concat(t)}(e,p);q&&s.push(q)}if(h||0===h){var z=function(e,t){if(e2&&void 0!==arguments[2]?arguments[2]:{},r=n.isOAS3,o=void 0!==r&&r,a=n.bypassRequiredCheck,i=void 0!==a&&a,s=e.get("required"),u=Object(le.a)(e,{isOAS3:o}),c=u.schema,l=u.parameterContentMediaType;return Me(t,c,s,i,l)},De=function(e,t,n){if(e&&(!e.xml||!e.xml.name)){if(e.xml=e.xml||{},!e.$$ref)return e.type||e.items||e.properties||e.additionalProperties?'\n\x3c!-- XML example cannot be generated; root element name is undefined --\x3e':null;var r=e.$$ref.match(/\S*\/(\S+)$/);e.xml.name=r[1]}return Object(ie.memoizedCreateXMLExample)(e,t,n)},Le=[{when:/json/,shouldStringifyTypes:["string"]}],Be=["object"],Fe=function(e,t,n,r){var a=Object(ie.memoizedSampleFromSchema)(e,t,r),s=i()(a),u=S()(Le).call(Le,(function(e,t){var r;return t.when.test(n)?v()(r=[]).call(r,o()(e),o()(t.shouldStringifyTypes)):e}),Be);return te()(u,(function(e){return e===s}))?M()(a,null,2):a},Ue=function(e,t,n,r){var o,a=Fe(e,t,n,r);try{"\n"===(o=ve.a.safeDump(ve.a.safeLoad(a),{lineWidth:-1}))[o.length-1]&&(o=T()(o).call(o,0,o.length-1))}catch(e){return console.error(e),"error: could not generate yaml example"}return o.replace(/\t/g," ")},qe=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"",n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:void 0;return e&&Se(e.toJS)&&(e=e.toJS()),r&&Se(r.toJS)&&(r=r.toJS()),/xml/.test(t)?De(e,n,r):/(yaml|yml)/.test(t)?Ue(e,n,t,r):Fe(e,n,t,r)},ze=function(){var e={},t=se.a.location.search;if(!t)return{};if(""!=t){var n=t.substr(1).split("&");for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(r=n[r].split("="),e[decodeURIComponent(r[0])]=r[1]&&decodeURIComponent(r[1])||"")}return e},Ve=function(t){return(t instanceof e?t:e.from(t.toString(),"utf-8")).toString("base64")},We={operationsSorter:{alpha:function(e,t){return e.get("path").localeCompare(t.get("path"))},method:function(e,t){return e.get("method").localeCompare(t.get("method"))}},tagsSorter:{alpha:function(e,t){return e.localeCompare(t)}}},He=function(e){var t=[];for(var n in e){var r=e[n];void 0!==r&&""!==r&&t.push([n,"=",encodeURIComponent(r).replace(/%20/g,"+")].join(""))}return t.join("&")},$e=function(e,t,n){return!!Q()(n,(function(n){return re()(e[n],t[n])}))};function Je(e){return"string"!=typeof e||""===e?"":Object(H.sanitizeUrl)(e)}function Ke(e){return!(!e||D()(e).call(e,"localhost")>=0||D()(e).call(e,"127.0.0.1")>=0||"none"===e)}function Ye(e){if(!W.a.OrderedMap.isOrderedMap(e))return null;if(!e.size)return null;var t=B()(e).call(e,(function(e,t){return U()(t).call(t,"2")&&w()(e.get("content")||{}).length>0})),n=e.get("default")||W.a.OrderedMap(),r=(n.get("content")||W.a.OrderedMap()).keySeq().toJS().length?n:null;return t||r}var Ge=function(e){return"string"==typeof e||e instanceof String?z()(e).call(e).replace(/\s/g,"%20"):""},Ze=function(e){return ce()(Ge(e).replace(/%20/g,"_"))},Xe=function(e){return _()(e).call(e,(function(e,t){return/^x-/.test(t)}))},Qe=function(e){return _()(e).call(e,(function(e,t){return/^pattern|maxLength|minLength|maximum|minimum/.test(t)}))};function et(e,t){var n,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:function(){return!0};if("object"!==i()(e)||l()(e)||null===e||!t)return e;var o=A()({},e);return y()(n=w()(o)).call(n,(function(e){e===t&&r(o[e],e)?delete o[e]:o[e]=et(o[e],t,r)})),o}function tt(e){if("string"==typeof e)return e;if(e&&e.toJS&&(e=e.toJS()),"object"===i()(e)&&null!==e)try{return M()(e,null,2)}catch(t){return String(e)}return null==e?"":e.toString()}function nt(e){return"number"==typeof e?e.toString():e}function rt(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.returnAll,r=void 0!==n&&n,o=t.allowHashes,a=void 0===o||o;if(!W.a.Map.isMap(e))throw new Error("paramToIdentifier: received a non-Im.Map parameter as input");var i,s,u,c=e.get("name"),l=e.get("in"),p=[];e&&e.hashCode&&l&&c&&a&&p.push(v()(i=v()(s="".concat(l,".")).call(s,c,".hash-")).call(i,e.hashCode()));l&&c&&p.push(v()(u="".concat(l,".")).call(u,c));return p.push(c),r?p:p[0]||""}function ot(e,t){var n,r=rt(e,{returnAll:!0});return _()(n=f()(r).call(r,(function(e){return t[e]}))).call(n,(function(e){return void 0!==e}))[0]}function at(){return st(fe()(32).toString("base64"))}function it(e){return st(de()("sha256").update(e).digest("base64"))}function st(e){return e.replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}var ut=function(e){return!e||!(!ye(e)||!e.isEmpty())}}).call(this,n(65).Buffer)},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){var r=n(247);function o(e,t){for(var n=0;n1?t-1:0),r=1;r1&&void 0!==arguments[1]?arguments[1]:r,n=null,a=null;return function(){return o(t,n,arguments)||(a=e.apply(null,arguments)),n=arguments,a}}))},function(e,t,n){e.exports=n(674)},function(e,t,n){var r=n(181),o=n(582);function a(t){return"function"==typeof r&&"symbol"==typeof o?(e.exports=a=function(e){return typeof e},e.exports.default=e.exports,e.exports.__esModule=!0):(e.exports=a=function(e){return e&&"function"==typeof r&&e.constructor===r&&e!==r.prototype?"symbol":typeof e},e.exports.default=e.exports,e.exports.__esModule=!0),a(t)}e.exports=a,e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){e.exports=n(613)},function(e,t,n){e.exports=n(608)},function(e,t,n){e.exports=n(606)},function(e,t,n){"use strict";var r=n(40),o=n(107).f,a=n(369),i=n(33),s=n(110),u=n(70),c=n(54),l=function(e){var t=function(t,n,r){if(this instanceof e){switch(arguments.length){case 0:return new e;case 1:return new e(t);case 2:return new e(t,n)}return new e(t,n,r)}return e.apply(this,arguments)};return t.prototype=e.prototype,t};e.exports=function(e,t){var n,p,f,h,d,m,v,g,y=e.target,b=e.global,_=e.stat,x=e.proto,w=b?r:_?r[y]:(r[y]||{}).prototype,E=b?i:i[y]||(i[y]={}),S=E.prototype;for(f in t)n=!a(b?f:y+(_?".":"#")+f,e.forced)&&w&&c(w,f),d=E[f],n&&(m=e.noTargetGet?(g=o(w,f))&&g.value:w[f]),h=n&&m?m:t[f],n&&typeof d==typeof h||(v=e.bind&&n?s(h,r):e.wrap&&n?l(h):x&&"function"==typeof h?s(Function.call,h):h,(e.sham||h&&h.sham||d&&d.sham)&&u(v,"sham",!0),E[f]=v,x&&(c(i,p=y+"Prototype")||u(i,p,{}),i[p][f]=h,e.real&&S&&!S[f]&&u(S,f,h)))}},function(e,t,n){e.exports=n(611)},function(e,t,n){e.exports=n(408)},function(e,t,n){var r=n(457),o=n(458),a=n(881),i=n(459),s=n(886),u=n(888),c=n(893),l=n(247),p=n(3);function f(e,t){var n=r(e);if(o){var s=o(e);t&&(s=a(s).call(s,(function(t){return i(e,t).enumerable}))),n.push.apply(n,s)}return n}e.exports=function(e){for(var t=1;t>",i=function(){invariant(!1,"ImmutablePropTypes type checking code is stripped in production.")};i.isRequired=i;var s=function(){return i};function u(e){var t=typeof e;return Array.isArray(e)?"array":e instanceof RegExp?"object":e instanceof o.Iterable?"Immutable."+e.toSource().split(" ")[0]:t}function c(e){function t(t,n,r,o,i,s){for(var u=arguments.length,c=Array(u>6?u-6:0),l=6;l4)}function l(e){var t=e.get("swagger");return"string"==typeof t&&i()(t).call(t,"2.0")}function p(e){return function(t,n){return function(r){return n&&n.specSelectors&&n.specSelectors.specJson?c(n.specSelectors.specJson())?u.a.createElement(e,o()({},r,n,{Ori:t})):u.a.createElement(t,r):(console.warn("OAS3 wrapper: couldn't get spec"),null)}}}},function(e,t,n){e.exports=n(602)},function(e,t){e.exports=function(e){try{return!!e()}catch(e){return!0}}},function(e,t,n){"use strict";var r=Object.getOwnPropertySymbols,o=Object.prototype.hasOwnProperty,a=Object.prototype.propertyIsEnumerable;function i(e){if(null==e)throw new TypeError("Object.assign cannot be called with null or undefined");return Object(e)}e.exports=function(){try{if(!Object.assign)return!1;var e=new String("abc");if(e[5]="de","5"===Object.getOwnPropertyNames(e)[0])return!1;for(var t={},n=0;n<10;n++)t["_"+String.fromCharCode(n)]=n;if("0123456789"!==Object.getOwnPropertyNames(t).map((function(e){return t[e]})).join(""))return!1;var r={};return"abcdefghijklmnopqrst".split("").forEach((function(e){r[e]=e})),"abcdefghijklmnopqrst"===Object.keys(Object.assign({},r)).join("")}catch(e){return!1}}()?Object.assign:function(e,t){for(var n,s,u=i(e),c=1;c0){var o=v()(n).call(n,(function(e){return console.error(e),e.line=e.fullPath?_(x,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",y()(e,"message",{enumerable:!0,value:e.message}),e}));a.newThrownErrBatch(o)}return r.updateResolved(t)}))}},Se=[],Ce=G()(u()(f.a.mark((function e(){var t,n,r,o,a,i,s,c,l,p,h,m,g,b,x,E,C,O;return f.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:if(t=Se.system){e.next=4;break}return console.error("debResolveSubtrees: don't have a system to operate on, aborting."),e.abrupt("return");case 4:if(n=t.errActions,r=t.errSelectors,o=t.fn,a=o.resolveSubtree,i=o.fetch,s=o.AST,c=void 0===s?{}:s,l=t.specSelectors,p=t.specActions,a){e.next=8;break}return console.error("Error: Swagger-Client did not provide a `resolveSubtree` method, doing nothing."),e.abrupt("return");case 8:return h=c.getLineNumberForPath?c.getLineNumberForPath:function(){},m=l.specStr(),g=t.getConfigs(),b=g.modelPropertyMacro,x=g.parameterMacro,E=g.requestInterceptor,C=g.responseInterceptor,e.prev=11,e.next=14,_()(Se).call(Se,function(){var e=u()(f.a.mark((function e(t,o){var s,c,p,g,_,O,j,T,I;return f.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return e.next=2,t;case 2:return s=e.sent,c=s.resultMap,p=s.specWithCurrentSubtrees,e.next=7,a(p,o,{baseDoc:l.url(),modelPropertyMacro:b,parameterMacro:x,requestInterceptor:E,responseInterceptor:C});case 7:if(g=e.sent,_=g.errors,O=g.spec,r.allErrors().size&&n.clearBy((function(e){var t;return"thrown"!==e.get("type")||"resolver"!==e.get("source")||!w()(t=e.get("fullPath")).call(t,(function(e,t){return e===o[t]||void 0===o[t]}))})),d()(_)&&_.length>0&&(j=v()(_).call(_,(function(e){return e.line=e.fullPath?h(m,e.fullPath):null,e.path=e.fullPath?e.fullPath.join("."):null,e.level="error",e.type="thrown",e.source="resolver",y()(e,"message",{enumerable:!0,value:e.message}),e})),n.newThrownErrBatch(j)),!O||!l.isOAS3()||"components"!==o[0]||"securitySchemes"!==o[1]){e.next=15;break}return e.next=15,S.a.all(v()(T=A()(I=k()(O)).call(I,(function(e){return"openIdConnect"===e.type}))).call(T,function(){var e=u()(f.a.mark((function e(t){var n,r;return f.a.wrap((function(e){for(;;)switch(e.prev=e.next){case 0:return n={url:t.openIdConnectUrl,requestInterceptor:E,responseInterceptor:C},e.prev=1,e.next=4,i(n);case 4:(r=e.sent)instanceof Error||r.status>=400?console.error(r.statusText+" "+n.url):t.openIdConnectData=JSON.parse(r.text),e.next=11;break;case 8:e.prev=8,e.t0=e.catch(1),console.error(e.t0);case 11:case"end":return e.stop()}}),e,null,[[1,8]])})));return function(t){return e.apply(this,arguments)}}()));case 15:return X()(c,o,O),X()(p,o,O),e.abrupt("return",{resultMap:c,specWithCurrentSubtrees:p});case 18:case"end":return e.stop()}}),e)})));return function(t,n){return e.apply(this,arguments)}}(),S.a.resolve({resultMap:(l.specResolvedSubtree([])||Object(V.Map)()).toJS(),specWithCurrentSubtrees:l.specJson().toJS()}));case 14:O=e.sent,delete Se.system,Se=[],e.next=22;break;case 19:e.prev=19,e.t0=e.catch(11),console.error(e.t0);case 22:p.updateResolvedSubtree([],O.resultMap);case 23:case"end":return e.stop()}}),e,null,[[11,19]])}))),35),Ae=function(e){return function(t){var n;T()(n=v()(Se).call(Se,(function(e){return e.join("@@")}))).call(n,e.join("@@"))>-1||(Se.push(e),Se.system=t,Ce())}};function Oe(e,t,n,r,o){return{type:re,payload:{path:e,value:r,paramName:t,paramIn:n,isXml:o}}}function ke(e,t,n,r){return{type:re,payload:{path:e,param:t,value:n,isXml:r}}}var je=function(e,t){return{type:me,payload:{path:e,value:t}}},Te=function(){return{type:me,payload:{path:[],value:Object(V.Map)()}}},Ie=function(e,t){return{type:ae,payload:{pathMethod:e,isOAS3:t}}},Pe=function(e,t,n,r){return{type:oe,payload:{pathMethod:e,paramName:t,paramIn:n,includeEmptyValue:r}}};function Ne(e){return{type:fe,payload:{pathMethod:e}}}function Me(e,t){return{type:he,payload:{path:e,value:t,key:"consumes_value"}}}function Re(e,t){return{type:he,payload:{path:e,value:t,key:"produces_value"}}}var De=function(e,t,n){return{payload:{path:e,method:t,res:n},type:ie}},Le=function(e,t,n){return{payload:{path:e,method:t,req:n},type:se}},Be=function(e,t,n){return{payload:{path:e,method:t,req:n},type:ue}},Fe=function(e){return{payload:e,type:ce}},Ue=function(e){return function(t){var n,r,o=t.fn,a=t.specActions,i=t.specSelectors,s=t.getConfigs,c=t.oas3Selectors,l=e.pathName,p=e.method,h=e.operation,m=s(),g=m.requestInterceptor,y=m.responseInterceptor,b=h.toJS();h&&h.get("parameters")&&P()(n=A()(r=h.get("parameters")).call(r,(function(e){return e&&!0===e.get("allowEmptyValue")}))).call(n,(function(t){if(i.parameterInclusionSettingFor([l,p],t.get("name"),t.get("in"))){e.parameters=e.parameters||{};var n=Object(Q.B)(t,e.parameters);(!n||n&&0===n.size)&&(e.parameters[t.get("name")]="")}}));if(e.contextUrl=H()(i.url()).toString(),b&&b.operationId?e.operationId=b.operationId:b&&l&&p&&(e.operationId=o.opId(b,l,p)),i.isOAS3()){var _,x=M()(_="".concat(l,":")).call(_,p);e.server=c.selectedServer(x)||c.selectedServer();var w=c.serverVariables({server:e.server,namespace:x}).toJS(),E=c.serverVariables({server:e.server}).toJS();e.serverVariables=D()(w).length?w:E,e.requestContentType=c.requestContentType(l,p),e.responseContentType=c.responseContentType(l,p)||"*/*";var S,C=c.requestBodyValue(l,p),O=c.requestBodyInclusionSetting(l,p);if(C&&C.toJS)e.requestBody=A()(S=v()(C).call(C,(function(e){return V.Map.isMap(e)?e.get("value"):e}))).call(S,(function(e,t){return(d()(e)?0!==e.length:!Object(Q.q)(e))||O.get(t)})).toJS();else e.requestBody=C}var k=B()({},e);k=o.buildRequest(k),a.setRequest(e.pathName,e.method,k);var j=function(){var t=u()(f.a.mark((function t(n){var r,o;return f.a.wrap((function(t){for(;;)switch(t.prev=t.next){case 0:return t.next=2,g.apply(undefined,[n]);case 2:return r=t.sent,o=B()({},r),a.setMutatedRequest(e.pathName,e.method,o),t.abrupt("return",r);case 6:case"end":return t.stop()}}),t)})));return function(e){return t.apply(this,arguments)}}();e.requestInterceptor=j,e.responseInterceptor=y;var T=U()();return o.execute(e).then((function(t){t.duration=U()()-T,a.setResponse(e.pathName,e.method,t)})).catch((function(t){"Failed to fetch"===t.message&&(t.name="",t.message='**Failed to fetch.** \n**Possible Reasons:** \n - CORS \n - Network Failure \n - URL scheme must be "http" or "https" for CORS request.'),a.setResponse(e.pathName,e.method,{error:!0,err:Object($.serializeError)(t)})}))}},qe=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.path,n=e.method,r=i()(e,["path","method"]);return function(e){var a=e.fn.fetch,i=e.specSelectors,s=e.specActions,u=i.specJsonWithResolvedSubtrees().toJS(),c=i.operationScheme(t,n),l=i.contentTypeValues([t,n]).toJS(),p=l.requestContentType,f=l.responseContentType,h=/xml/i.test(p),d=i.parameterValues([t,n],h).toJS();return s.executeRequest(o()(o()({},r),{},{fetch:a,spec:u,pathName:t,method:n,parameters:d,requestContentType:p,scheme:c,responseContentType:f}))}};function ze(e,t){return{type:le,payload:{path:e,method:t}}}function Ve(e,t){return{type:pe,payload:{path:e,method:t}}}function We(e,t,n){return{type:ve,payload:{scheme:e,path:t,method:n}}}},function(e,t,n){var r=n(33),o=n(54),a=n(243),i=n(71).f;e.exports=function(e){var t=r.Symbol||(r.Symbol={});o(t,e)||i(t,e,{value:a.f(e)})}},function(e,t,n){"use strict";var r=n(167),o=["kind","resolve","construct","instanceOf","predicate","represent","defaultStyle","styleAliases"],a=["scalar","sequence","mapping"];e.exports=function(e,t){var n,i;if(t=t||{},Object.keys(t).forEach((function(t){if(-1===o.indexOf(t))throw new r('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')})),this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.defaultStyle=t.defaultStyle||null,this.styleAliases=(n=t.styleAliases||null,i={},null!==n&&Object.keys(n).forEach((function(e){n[e].forEach((function(t){i[String(t)]=e}))})),i),-1===a.indexOf(this.kind))throw new r('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')}},function(e,t,n){var r=n(37);e.exports=!r((function(){return 7!=Object.defineProperty({},1,{get:function(){return 7}})[1]}))},function(e,t,n){var r=n(181),o=n(250),a=n(249),i=n(190);e.exports=function(e,t){var n=void 0!==r&&o(e)||e["@@iterator"];if(!n){if(a(e)||(n=i(e))||t&&e&&"number"==typeof e.length){n&&(e=n);var s=0,u=function(){};return{s:u,n:function(){return s>=e.length?{done:!0}:{done:!1,value:e[s++]}},e:function(e){throw e},f:u}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var c,l=!0,p=!1;return{s:function(){n=n.call(e)},n:function(){var e=n.next();return l=e.done,e},e:function(e){p=!0,c=e},f:function(){try{l||null==n.return||n.return()}finally{if(p)throw c}}}},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){var r=n(45);e.exports=function(e){if(!r(e))throw TypeError(String(e)+" is not an object");return e}},function(e,t){var n=Array.isArray;e.exports=n},function(e,t){var n;n=function(){return this}();try{n=n||new Function("return this")()}catch(e){"object"==typeof window&&(n=window)}e.exports=n},function(e,t,n){var r=n(62),o={}.hasOwnProperty;e.exports=function(e,t){return o.call(r(e),t)}},function(e,t,n){var r=n(458),o=n(460),a=n(898);e.exports=function(e,t){if(null==e)return{};var n,i,s=a(e,t);if(r){var u=r(e);for(i=0;i=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(s[n]=e[n])}return s},e.exports.default=e.exports,e.exports.__esModule=!0},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_SELECTED_SERVER",(function(){return r})),n.d(t,"UPDATE_REQUEST_BODY_VALUE",(function(){return o})),n.d(t,"UPDATE_REQUEST_BODY_VALUE_RETAIN_FLAG",(function(){return a})),n.d(t,"UPDATE_REQUEST_BODY_INCLUSION",(function(){return i})),n.d(t,"UPDATE_ACTIVE_EXAMPLES_MEMBER",(function(){return s})),n.d(t,"UPDATE_REQUEST_CONTENT_TYPE",(function(){return u})),n.d(t,"UPDATE_RESPONSE_CONTENT_TYPE",(function(){return c})),n.d(t,"UPDATE_SERVER_VARIABLE_VALUE",(function(){return l})),n.d(t,"SET_REQUEST_BODY_VALIDATE_ERROR",(function(){return p})),n.d(t,"CLEAR_REQUEST_BODY_VALIDATE_ERROR",(function(){return f})),n.d(t,"CLEAR_REQUEST_BODY_VALUE",(function(){return h})),n.d(t,"setSelectedServer",(function(){return d})),n.d(t,"setRequestBodyValue",(function(){return m})),n.d(t,"setRetainRequestBodyValueFlag",(function(){return v})),n.d(t,"setRequestBodyInclusion",(function(){return g})),n.d(t,"setActiveExamplesMember",(function(){return y})),n.d(t,"setRequestContentType",(function(){return b})),n.d(t,"setResponseContentType",(function(){return _})),n.d(t,"setServerVariableValue",(function(){return x})),n.d(t,"setRequestBodyValidateError",(function(){return w})),n.d(t,"clearRequestBodyValidateError",(function(){return E})),n.d(t,"initRequestBodyValidateError",(function(){return S})),n.d(t,"clearRequestBodyValue",(function(){return C}));var r="oas3_set_servers",o="oas3_set_request_body_value",a="oas3_set_request_body_retain_flag",i="oas3_set_request_body_inclusion",s="oas3_set_active_examples_member",u="oas3_set_request_content_type",c="oas3_set_response_content_type",l="oas3_set_server_variable_value",p="oas3_set_request_body_validate_error",f="oas3_clear_request_body_validate_error",h="oas3_clear_request_body_value";function d(e,t){return{type:r,payload:{selectedServerUrl:e,namespace:t}}}function m(e){var t=e.value,n=e.pathMethod;return{type:o,payload:{value:t,pathMethod:n}}}var v=function(e){var t=e.value,n=e.pathMethod;return{type:a,payload:{value:t,pathMethod:n}}};function g(e){var t=e.value,n=e.pathMethod,r=e.name;return{type:i,payload:{value:t,pathMethod:n,name:r}}}function y(e){var t=e.name,n=e.pathMethod,r=e.contextType,o=e.contextName;return{type:s,payload:{name:t,pathMethod:n,contextType:r,contextName:o}}}function b(e){var t=e.value,n=e.pathMethod;return{type:u,payload:{value:t,pathMethod:n}}}function _(e){var t=e.value,n=e.path,r=e.method;return{type:c,payload:{value:t,path:n,method:r}}}function x(e){var t=e.server,n=e.namespace,r=e.key,o=e.val;return{type:l,payload:{server:t,namespace:n,key:r,val:o}}}var w=function(e){var t=e.path,n=e.method,r=e.validationErrors;return{type:p,payload:{path:t,method:n,validationErrors:r}}},E=function(e){var t=e.path,n=e.method;return{type:f,payload:{path:t,method:n}}},S=function(e){var t=e.pathMethod;return{type:f,payload:{path:t[0],method:t[1]}}},C=function(e){var t=e.pathMethod;return{type:h,payload:{pathMethod:t}}}},function(e,t,n){"use strict";var r=!("undefined"==typeof window||!window.document||!window.document.createElement),o={canUseDOM:r,canUseWorkers:"undefined"!=typeof Worker,canUseEventListeners:r&&!(!window.addEventListener&&!window.attachEvent),canUseViewport:r&&!!window.screen,isInWorker:!r};e.exports=o},function(e,t,n){e.exports=n(677)},function(e,t){e.exports=function(e){var t=typeof e;return null!=e&&("object"==t||"function"==t)}},function(e,t,n){"use strict";n.d(t,"b",(function(){return m})),n.d(t,"e",(function(){return v})),n.d(t,"c",(function(){return y})),n.d(t,"a",(function(){return b})),n.d(t,"d",(function(){return _}));var r=n(50),o=n.n(r),a=n(18),i=n.n(a),s=n(2),u=n.n(s),c=n(59),l=n.n(c),p=n(363),f=n.n(p),h=function(e){return String.prototype.toLowerCase.call(e)},d=function(e){return e.replace(/[^\w]/gi,"_")};function m(e){var t=e.openapi;return!!t&&f()(t,"3")}function v(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:"",r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},o=r.v2OperationIdCompatibilityMode;if(!e||"object"!==i()(e))return null;var a=(e.operationId||"").replace(/\s/g,"");return a.length?d(e.operationId):g(t,n,{v2OperationIdCompatibilityMode:o})}function g(e,t){var n,r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},o=r.v2OperationIdCompatibilityMode;if(o){var a,i,s=u()(a="".concat(t.toLowerCase(),"_")).call(a,e).replace(/[\s!@#$%^&*()_+=[{\]};:<>|./?,\\'""-]/g,"_");return(s=s||u()(i="".concat(e.substring(1),"_")).call(i,t)).replace(/((_){2,})/g,"_").replace(/^(_)*/g,"").replace(/([_])*$/g,"")}return u()(n="".concat(h(t))).call(n,d(e))}function y(e,t){var n;return u()(n="".concat(h(t),"-")).call(n,e)}function b(e,t){return e&&e.paths?function(e,t){return function(e,t,n){if(!e||"object"!==i()(e)||!e.paths||"object"!==i()(e.paths))return null;var r=e.paths;for(var o in r)for(var a in r[o])if("PARAMETERS"!==a.toUpperCase()){var s=r[o][a];if(s&&"object"===i()(s)){var u={spec:e,pathName:o,method:a.toUpperCase(),operation:s},c=t(u);if(n&&c)return u}}return}(e,t,!0)||null}(e,(function(e){var n=e.pathName,r=e.method,o=e.operation;if(!o||"object"!==i()(o))return!1;var a=o.operationId;return[v(o,n,r),y(n,r),a].some((function(e){return e&&e===t}))})):null}function _(e){var t=e.spec,n=t.paths,r={};if(!n||t.$$normalized)return e;for(var a in n){var i=n[a];if(l()(i)){var s=i.parameters,c=function(e){var n=i[e];if(!l()(n))return"continue";var c=v(n,a,e);if(c){r[c]?r[c].push(n):r[c]=[n];var p=r[c];if(p.length>1)p.forEach((function(e,t){var n;e.__originalOperationId=e.__originalOperationId||e.operationId,e.operationId=u()(n="".concat(c)).call(n,t+1)}));else if(void 0!==n.operationId){var f=p[0];f.__originalOperationId=f.__originalOperationId||n.operationId,f.operationId=c}}if("parameters"!==e){var h=[],d={};for(var m in t)"produces"!==m&&"consumes"!==m&&"security"!==m||(d[m]=t[m],h.push(d));if(s&&(d.parameters=s,h.push(d)),h.length){var g,y=o()(h);try{for(y.s();!(g=y.n()).done;){var b=g.value;for(var _ in b)if(n[_]){if("parameters"===_){var x,w=o()(b[_]);try{var E=function(){var e=x.value;n[_].some((function(t){return t.name&&t.name===e.name||t.$ref&&t.$ref===e.$ref||t.$$ref&&t.$$ref===e.$$ref||t===e}))||n[_].push(e)};for(w.s();!(x=w.n()).done;)E()}catch(e){w.e(e)}finally{w.f()}}}else n[_]=b[_]}}catch(e){y.e(e)}finally{y.f()}}}};for(var p in i)c(p)}}return t.$$normalized=!0,e}},function(e,t,n){"use strict";n.r(t),n.d(t,"NEW_THROWN_ERR",(function(){return o})),n.d(t,"NEW_THROWN_ERR_BATCH",(function(){return a})),n.d(t,"NEW_SPEC_ERR",(function(){return i})),n.d(t,"NEW_SPEC_ERR_BATCH",(function(){return s})),n.d(t,"NEW_AUTH_ERR",(function(){return u})),n.d(t,"CLEAR",(function(){return c})),n.d(t,"CLEAR_BY",(function(){return l})),n.d(t,"newThrownErr",(function(){return p})),n.d(t,"newThrownErrBatch",(function(){return f})),n.d(t,"newSpecErr",(function(){return h})),n.d(t,"newSpecErrBatch",(function(){return d})),n.d(t,"newAuthErr",(function(){return m})),n.d(t,"clear",(function(){return v})),n.d(t,"clearBy",(function(){return g}));var r=n(146),o="err_new_thrown_err",a="err_new_thrown_err_batch",i="err_new_spec_err",s="err_new_spec_err_batch",u="err_new_auth_err",c="err_clear",l="err_clear_by";function p(e){return{type:o,payload:Object(r.serializeError)(e)}}function f(e){return{type:a,payload:e}}function h(e){return{type:i,payload:e}}function d(e){return{type:s,payload:e}}function m(e){return{type:u,payload:e}}function v(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return{type:c,payload:e}}function g(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!0};return{type:l,payload:e}}},function(e,t,n){var r=n(109);e.exports=function(e){return Object(r(e))}},function(e,t){"function"==typeof Object.create?e.exports=function(e,t){e.super_=t,e.prototype=Object.create(t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}})}:e.exports=function(e,t){e.super_=t;var n=function(){};n.prototype=t.prototype,e.prototype=new n,e.prototype.constructor=e}},function(e,t,n){var r=n(65),o=r.Buffer;function a(e,t){for(var n in e)t[n]=e[n]}function i(e,t,n){return o(e,t,n)}o.from&&o.alloc&&o.allocUnsafe&&o.allocUnsafeSlow?e.exports=r:(a(r,t),t.Buffer=i),a(o,i),i.from=function(e,t,n){if("number"==typeof e)throw new TypeError("Argument must not be a number");return o(e,t,n)},i.alloc=function(e,t,n){if("number"!=typeof e)throw new TypeError("Argument must be a number");var r=o(e);return void 0!==t?"string"==typeof n?r.fill(t,n):r.fill(t):r.fill(0),r},i.allocUnsafe=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return o(e)},i.allocUnsafeSlow=function(e){if("number"!=typeof e)throw new TypeError("Argument must be a number");return r.SlowBuffer(e)}},function(e,t,n){"use strict";(function(e){var r=n(598),o=n(599),a=n(383);function i(){return u.TYPED_ARRAY_SUPPORT?2147483647:1073741823}function s(e,t){if(i()=i())throw new RangeError("Attempt to allocate Buffer larger than maximum size: 0x"+i().toString(16)+" bytes");return 0|e}function d(e,t){if(u.isBuffer(e))return e.length;if("undefined"!=typeof ArrayBuffer&&"function"==typeof ArrayBuffer.isView&&(ArrayBuffer.isView(e)||e instanceof ArrayBuffer))return e.byteLength;"string"!=typeof e&&(e=""+e);var n=e.length;if(0===n)return 0;for(var r=!1;;)switch(t){case"ascii":case"latin1":case"binary":return n;case"utf8":case"utf-8":case void 0:return q(e).length;case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return 2*n;case"hex":return n>>>1;case"base64":return z(e).length;default:if(r)return q(e).length;t=(""+t).toLowerCase(),r=!0}}function m(e,t,n){var r=!1;if((void 0===t||t<0)&&(t=0),t>this.length)return"";if((void 0===n||n>this.length)&&(n=this.length),n<=0)return"";if((n>>>=0)<=(t>>>=0))return"";for(e||(e="utf8");;)switch(e){case"hex":return T(this,t,n);case"utf8":case"utf-8":return A(this,t,n);case"ascii":return k(this,t,n);case"latin1":case"binary":return j(this,t,n);case"base64":return C(this,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return I(this,t,n);default:if(r)throw new TypeError("Unknown encoding: "+e);e=(e+"").toLowerCase(),r=!0}}function v(e,t,n){var r=e[t];e[t]=e[n],e[n]=r}function g(e,t,n,r,o){if(0===e.length)return-1;if("string"==typeof n?(r=n,n=0):n>2147483647?n=2147483647:n<-2147483648&&(n=-2147483648),n=+n,isNaN(n)&&(n=o?0:e.length-1),n<0&&(n=e.length+n),n>=e.length){if(o)return-1;n=e.length-1}else if(n<0){if(!o)return-1;n=0}if("string"==typeof t&&(t=u.from(t,r)),u.isBuffer(t))return 0===t.length?-1:y(e,t,n,r,o);if("number"==typeof t)return t&=255,u.TYPED_ARRAY_SUPPORT&&"function"==typeof Uint8Array.prototype.indexOf?o?Uint8Array.prototype.indexOf.call(e,t,n):Uint8Array.prototype.lastIndexOf.call(e,t,n):y(e,[t],n,r,o);throw new TypeError("val must be string, number or Buffer")}function y(e,t,n,r,o){var a,i=1,s=e.length,u=t.length;if(void 0!==r&&("ucs2"===(r=String(r).toLowerCase())||"ucs-2"===r||"utf16le"===r||"utf-16le"===r)){if(e.length<2||t.length<2)return-1;i=2,s/=2,u/=2,n/=2}function c(e,t){return 1===i?e[t]:e.readUInt16BE(t*i)}if(o){var l=-1;for(a=n;as&&(n=s-u),a=n;a>=0;a--){for(var p=!0,f=0;fo&&(r=o):r=o;var a=t.length;if(a%2!=0)throw new TypeError("Invalid hex string");r>a/2&&(r=a/2);for(var i=0;i>8,o=n%256,a.push(o),a.push(r);return a}(t,e.length-n),e,n,r)}function C(e,t,n){return 0===t&&n===e.length?r.fromByteArray(e):r.fromByteArray(e.slice(t,n))}function A(e,t,n){n=Math.min(e.length,n);for(var r=[],o=t;o239?4:c>223?3:c>191?2:1;if(o+p<=n)switch(p){case 1:c<128&&(l=c);break;case 2:128==(192&(a=e[o+1]))&&(u=(31&c)<<6|63&a)>127&&(l=u);break;case 3:a=e[o+1],i=e[o+2],128==(192&a)&&128==(192&i)&&(u=(15&c)<<12|(63&a)<<6|63&i)>2047&&(u<55296||u>57343)&&(l=u);break;case 4:a=e[o+1],i=e[o+2],s=e[o+3],128==(192&a)&&128==(192&i)&&128==(192&s)&&(u=(15&c)<<18|(63&a)<<12|(63&i)<<6|63&s)>65535&&u<1114112&&(l=u)}null===l?(l=65533,p=1):l>65535&&(l-=65536,r.push(l>>>10&1023|55296),l=56320|1023&l),r.push(l),o+=p}return function(e){var t=e.length;if(t<=O)return String.fromCharCode.apply(String,e);var n="",r=0;for(;r0&&(e=this.toString("hex",0,n).match(/.{2}/g).join(" "),this.length>n&&(e+=" ... ")),""},u.prototype.compare=function(e,t,n,r,o){if(!u.isBuffer(e))throw new TypeError("Argument must be a Buffer");if(void 0===t&&(t=0),void 0===n&&(n=e?e.length:0),void 0===r&&(r=0),void 0===o&&(o=this.length),t<0||n>e.length||r<0||o>this.length)throw new RangeError("out of range index");if(r>=o&&t>=n)return 0;if(r>=o)return-1;if(t>=n)return 1;if(this===e)return 0;for(var a=(o>>>=0)-(r>>>=0),i=(n>>>=0)-(t>>>=0),s=Math.min(a,i),c=this.slice(r,o),l=e.slice(t,n),p=0;po)&&(n=o),e.length>0&&(n<0||t<0)||t>this.length)throw new RangeError("Attempt to write outside buffer bounds");r||(r="utf8");for(var a=!1;;)switch(r){case"hex":return b(this,e,t,n);case"utf8":case"utf-8":return _(this,e,t,n);case"ascii":return x(this,e,t,n);case"latin1":case"binary":return w(this,e,t,n);case"base64":return E(this,e,t,n);case"ucs2":case"ucs-2":case"utf16le":case"utf-16le":return S(this,e,t,n);default:if(a)throw new TypeError("Unknown encoding: "+r);r=(""+r).toLowerCase(),a=!0}},u.prototype.toJSON=function(){return{type:"Buffer",data:Array.prototype.slice.call(this._arr||this,0)}};var O=4096;function k(e,t,n){var r="";n=Math.min(e.length,n);for(var o=t;or)&&(n=r);for(var o="",a=t;an)throw new RangeError("Trying to access beyond buffer length")}function N(e,t,n,r,o,a){if(!u.isBuffer(e))throw new TypeError('"buffer" argument must be a Buffer instance');if(t>o||te.length)throw new RangeError("Index out of range")}function M(e,t,n,r){t<0&&(t=65535+t+1);for(var o=0,a=Math.min(e.length-n,2);o>>8*(r?o:1-o)}function R(e,t,n,r){t<0&&(t=4294967295+t+1);for(var o=0,a=Math.min(e.length-n,4);o>>8*(r?o:3-o)&255}function D(e,t,n,r,o,a){if(n+r>e.length)throw new RangeError("Index out of range");if(n<0)throw new RangeError("Index out of range")}function L(e,t,n,r,a){return a||D(e,0,n,4),o.write(e,t,n,r,23,4),n+4}function B(e,t,n,r,a){return a||D(e,0,n,8),o.write(e,t,n,r,52,8),n+8}u.prototype.slice=function(e,t){var n,r=this.length;if((e=~~e)<0?(e+=r)<0&&(e=0):e>r&&(e=r),(t=void 0===t?r:~~t)<0?(t+=r)<0&&(t=0):t>r&&(t=r),t0&&(o*=256);)r+=this[e+--t]*o;return r},u.prototype.readUInt8=function(e,t){return t||P(e,1,this.length),this[e]},u.prototype.readUInt16LE=function(e,t){return t||P(e,2,this.length),this[e]|this[e+1]<<8},u.prototype.readUInt16BE=function(e,t){return t||P(e,2,this.length),this[e]<<8|this[e+1]},u.prototype.readUInt32LE=function(e,t){return t||P(e,4,this.length),(this[e]|this[e+1]<<8|this[e+2]<<16)+16777216*this[e+3]},u.prototype.readUInt32BE=function(e,t){return t||P(e,4,this.length),16777216*this[e]+(this[e+1]<<16|this[e+2]<<8|this[e+3])},u.prototype.readIntLE=function(e,t,n){e|=0,t|=0,n||P(e,t,this.length);for(var r=this[e],o=1,a=0;++a=(o*=128)&&(r-=Math.pow(2,8*t)),r},u.prototype.readIntBE=function(e,t,n){e|=0,t|=0,n||P(e,t,this.length);for(var r=t,o=1,a=this[e+--r];r>0&&(o*=256);)a+=this[e+--r]*o;return a>=(o*=128)&&(a-=Math.pow(2,8*t)),a},u.prototype.readInt8=function(e,t){return t||P(e,1,this.length),128&this[e]?-1*(255-this[e]+1):this[e]},u.prototype.readInt16LE=function(e,t){t||P(e,2,this.length);var n=this[e]|this[e+1]<<8;return 32768&n?4294901760|n:n},u.prototype.readInt16BE=function(e,t){t||P(e,2,this.length);var n=this[e+1]|this[e]<<8;return 32768&n?4294901760|n:n},u.prototype.readInt32LE=function(e,t){return t||P(e,4,this.length),this[e]|this[e+1]<<8|this[e+2]<<16|this[e+3]<<24},u.prototype.readInt32BE=function(e,t){return t||P(e,4,this.length),this[e]<<24|this[e+1]<<16|this[e+2]<<8|this[e+3]},u.prototype.readFloatLE=function(e,t){return t||P(e,4,this.length),o.read(this,e,!0,23,4)},u.prototype.readFloatBE=function(e,t){return t||P(e,4,this.length),o.read(this,e,!1,23,4)},u.prototype.readDoubleLE=function(e,t){return t||P(e,8,this.length),o.read(this,e,!0,52,8)},u.prototype.readDoubleBE=function(e,t){return t||P(e,8,this.length),o.read(this,e,!1,52,8)},u.prototype.writeUIntLE=function(e,t,n,r){(e=+e,t|=0,n|=0,r)||N(this,e,t,n,Math.pow(2,8*n)-1,0);var o=1,a=0;for(this[t]=255&e;++a=0&&(a*=256);)this[t+o]=e/a&255;return t+n},u.prototype.writeUInt8=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,1,255,0),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),this[t]=255&e,t+1},u.prototype.writeUInt16LE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):M(this,e,t,!0),t+2},u.prototype.writeUInt16BE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,2,65535,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):M(this,e,t,!1),t+2},u.prototype.writeUInt32LE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t+3]=e>>>24,this[t+2]=e>>>16,this[t+1]=e>>>8,this[t]=255&e):R(this,e,t,!0),t+4},u.prototype.writeUInt32BE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,4,4294967295,0),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):R(this,e,t,!1),t+4},u.prototype.writeIntLE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);N(this,e,t,n,o-1,-o)}var a=0,i=1,s=0;for(this[t]=255&e;++a>0)-s&255;return t+n},u.prototype.writeIntBE=function(e,t,n,r){if(e=+e,t|=0,!r){var o=Math.pow(2,8*n-1);N(this,e,t,n,o-1,-o)}var a=n-1,i=1,s=0;for(this[t+a]=255&e;--a>=0&&(i*=256);)e<0&&0===s&&0!==this[t+a+1]&&(s=1),this[t+a]=(e/i>>0)-s&255;return t+n},u.prototype.writeInt8=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,1,127,-128),u.TYPED_ARRAY_SUPPORT||(e=Math.floor(e)),e<0&&(e=255+e+1),this[t]=255&e,t+1},u.prototype.writeInt16LE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8):M(this,e,t,!0),t+2},u.prototype.writeInt16BE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,2,32767,-32768),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>8,this[t+1]=255&e):M(this,e,t,!1),t+2},u.prototype.writeInt32LE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,4,2147483647,-2147483648),u.TYPED_ARRAY_SUPPORT?(this[t]=255&e,this[t+1]=e>>>8,this[t+2]=e>>>16,this[t+3]=e>>>24):R(this,e,t,!0),t+4},u.prototype.writeInt32BE=function(e,t,n){return e=+e,t|=0,n||N(this,e,t,4,2147483647,-2147483648),e<0&&(e=4294967295+e+1),u.TYPED_ARRAY_SUPPORT?(this[t]=e>>>24,this[t+1]=e>>>16,this[t+2]=e>>>8,this[t+3]=255&e):R(this,e,t,!1),t+4},u.prototype.writeFloatLE=function(e,t,n){return L(this,e,t,!0,n)},u.prototype.writeFloatBE=function(e,t,n){return L(this,e,t,!1,n)},u.prototype.writeDoubleLE=function(e,t,n){return B(this,e,t,!0,n)},u.prototype.writeDoubleBE=function(e,t,n){return B(this,e,t,!1,n)},u.prototype.copy=function(e,t,n,r){if(n||(n=0),r||0===r||(r=this.length),t>=e.length&&(t=e.length),t||(t=0),r>0&&r=this.length)throw new RangeError("sourceStart out of bounds");if(r<0)throw new RangeError("sourceEnd out of bounds");r>this.length&&(r=this.length),e.length-t=0;--o)e[o+t]=this[o+n];else if(a<1e3||!u.TYPED_ARRAY_SUPPORT)for(o=0;o>>=0,n=void 0===n?this.length:n>>>0,e||(e=0),"number"==typeof e)for(a=t;a55295&&n<57344){if(!o){if(n>56319){(t-=3)>-1&&a.push(239,191,189);continue}if(i+1===r){(t-=3)>-1&&a.push(239,191,189);continue}o=n;continue}if(n<56320){(t-=3)>-1&&a.push(239,191,189),o=n;continue}n=65536+(o-55296<<10|n-56320)}else o&&(t-=3)>-1&&a.push(239,191,189);if(o=null,n<128){if((t-=1)<0)break;a.push(n)}else if(n<2048){if((t-=2)<0)break;a.push(n>>6|192,63&n|128)}else if(n<65536){if((t-=3)<0)break;a.push(n>>12|224,n>>6&63|128,63&n|128)}else{if(!(n<1114112))throw new Error("Invalid code point");if((t-=4)<0)break;a.push(n>>18|240,n>>12&63|128,n>>6&63|128,63&n|128)}}return a}function z(e){return r.toByteArray(function(e){if((e=function(e){return e.trim?e.trim():e.replace(/^\s+|\s+$/g,"")}(e).replace(F,"")).length<2)return"";for(;e.length%4!=0;)e+="=";return e}(e))}function V(e,t,n,r){for(var o=0;o=t.length||o>=e.length);++o)t[o+n]=e[o];return o}}).call(this,n(53))},function(e,t,n){var r;!function(){"use strict";var n={}.hasOwnProperty;function o(){for(var e=[],t=0;t0?o(r(e),9007199254740991):0}},function(e,t,n){var r,o,a,i=n(374),s=n(40),u=n(45),c=n(70),l=n(54),p=n(235),f=n(188),h=n(159),d="Object already initialized",m=s.WeakMap;if(i){var v=p.state||(p.state=new m),g=v.get,y=v.has,b=v.set;r=function(e,t){if(y.call(v,e))throw new TypeError(d);return t.facade=e,b.call(v,e,t),t},o=function(e){return g.call(v,e)||{}},a=function(e){return y.call(v,e)}}else{var _=f("state");h[_]=!0,r=function(e,t){if(l(e,_))throw new TypeError(d);return t.facade=e,c(e,_,t),t},o=function(e){return l(e,_)?e[_]:{}},a=function(e){return l(e,_)}}e.exports={set:r,get:o,has:a,enforce:function(e){return a(e)?o(e):r(e,{})},getterFor:function(e){return function(t){var n;if(!u(t)||(n=o(t)).type!==e)throw TypeError("Incompatible receiver, "+e+" required");return n}}}},function(e,t,n){"use strict";function r(e){return function(){return e}}var o=function(){};o.thatReturns=r,o.thatReturnsFalse=r(!1),o.thatReturnsTrue=r(!0),o.thatReturnsNull=r(null),o.thatReturnsThis=function(){return this},o.thatReturnsArgument=function(e){return e},e.exports=o},function(e,t,n){"use strict";var r=n(30),o=n(38),a=n(481),i=n(124),s=n(482),u=n(142),c=n(208),l=n(26),p=[],f=0,h=a.getPooled(),d=!1,m=null;function v(){w.ReactReconcileTransaction&&m||r("123")}var g=[{initialize:function(){this.dirtyComponentsLength=p.length},close:function(){this.dirtyComponentsLength!==p.length?(p.splice(0,this.dirtyComponentsLength),x()):p.length=0}},{initialize:function(){this.callbackQueue.reset()},close:function(){this.callbackQueue.notifyAll()}}];function y(){this.reinitializeTransaction(),this.dirtyComponentsLength=null,this.callbackQueue=a.getPooled(),this.reconcileTransaction=w.ReactReconcileTransaction.getPooled(!0)}function b(e,t){return e._mountOrder-t._mountOrder}function _(e){var t=e.dirtyComponentsLength;t!==p.length&&r("124",t,p.length),p.sort(b),f++;for(var n=0;n",'"',"`"," ","\r","\n","\t"]),l=["'"].concat(c),p=["%","/","?",";","#"].concat(l),f=["/","?","#"],h=/^[+a-z0-9A-Z_-]{0,63}$/,d=/^([+a-z0-9A-Z_-]{0,63})(.*)$/,m={javascript:!0,"javascript:":!0},v={javascript:!0,"javascript:":!0},g={http:!0,https:!0,ftp:!0,gopher:!0,file:!0,"http:":!0,"https:":!0,"ftp:":!0,"gopher:":!0,"file:":!0},y=n(1107);function b(e,t,n){if(e&&o.isObject(e)&&e instanceof a)return e;var r=new a;return r.parse(e,t,n),r}a.prototype.parse=function(e,t,n){if(!o.isString(e))throw new TypeError("Parameter 'url' must be a string, not "+typeof e);var a=e.indexOf("?"),s=-1!==a&&a127?N+="x":N+=P[M];if(!N.match(h)){var D=T.slice(0,O),L=T.slice(O+1),B=P.match(d);B&&(D.push(B[1]),L.unshift(B[2])),L.length&&(b="/"+L.join(".")+b),this.hostname=D.join(".");break}}}this.hostname.length>255?this.hostname="":this.hostname=this.hostname.toLowerCase(),j||(this.hostname=r.toASCII(this.hostname));var F=this.port?":"+this.port:"",U=this.hostname||"";this.host=U+F,this.href+=this.host,j&&(this.hostname=this.hostname.substr(1,this.hostname.length-2),"/"!==b[0]&&(b="/"+b))}if(!m[w])for(O=0,I=l.length;O0)&&n.host.split("@"))&&(n.auth=j.shift(),n.host=n.hostname=j.shift());return n.search=e.search,n.query=e.query,o.isNull(n.pathname)&&o.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.href=n.format(),n}if(!E.length)return n.pathname=null,n.search?n.path="/"+n.search:n.path=null,n.href=n.format(),n;for(var C=E.slice(-1)[0],A=(n.host||e.host||E.length>1)&&("."===C||".."===C)||""===C,O=0,k=E.length;k>=0;k--)"."===(C=E[k])?E.splice(k,1):".."===C?(E.splice(k,1),O++):O&&(E.splice(k,1),O--);if(!x&&!w)for(;O--;O)E.unshift("..");!x||""===E[0]||E[0]&&"/"===E[0].charAt(0)||E.unshift(""),A&&"/"!==E.join("/").substr(-1)&&E.push("");var j,T=""===E[0]||E[0]&&"/"===E[0].charAt(0);S&&(n.hostname=n.host=T?"":E.length?E.shift():"",(j=!!(n.host&&n.host.indexOf("@")>0)&&n.host.split("@"))&&(n.auth=j.shift(),n.host=n.hostname=j.shift()));return(x=x||n.host&&E.length)&&!T&&E.unshift(""),E.length?n.pathname=E.join("/"):(n.pathname=null,n.path=null),o.isNull(n.pathname)&&o.isNull(n.search)||(n.path=(n.pathname?n.pathname:"")+(n.search?n.search:"")),n.auth=e.auth||n.auth,n.slashes=n.slashes||e.slashes,n.href=n.format(),n},a.prototype.parseHost=function(){var e=this.host,t=s.exec(e);t&&(":"!==(t=t[0])&&(this.port=t.substr(1)),e=e.substr(0,e.length-t.length)),e&&(this.hostname=e)}},function(e,t,n){"use strict";n.r(t),n.d(t,"SHOW_AUTH_POPUP",(function(){return h})),n.d(t,"AUTHORIZE",(function(){return d})),n.d(t,"LOGOUT",(function(){return m})),n.d(t,"PRE_AUTHORIZE_OAUTH2",(function(){return v})),n.d(t,"AUTHORIZE_OAUTH2",(function(){return g})),n.d(t,"VALIDATE",(function(){return y})),n.d(t,"CONFIGURE_AUTH",(function(){return b})),n.d(t,"RESTORE_AUTHORIZATION",(function(){return _})),n.d(t,"showDefinitions",(function(){return x})),n.d(t,"authorize",(function(){return w})),n.d(t,"authorizeWithPersistOption",(function(){return E})),n.d(t,"logout",(function(){return S})),n.d(t,"logoutWithPersistOption",(function(){return C})),n.d(t,"preAuthorizeImplicit",(function(){return A})),n.d(t,"authorizeOauth2",(function(){return O})),n.d(t,"authorizeOauth2WithPersistOption",(function(){return k})),n.d(t,"authorizePassword",(function(){return j})),n.d(t,"authorizeApplication",(function(){return T})),n.d(t,"authorizeAccessCodeWithFormParams",(function(){return I})),n.d(t,"authorizeAccessCodeWithBasicAuthentication",(function(){return P})),n.d(t,"authorizeRequest",(function(){return N})),n.d(t,"configureAuth",(function(){return M})),n.d(t,"restoreAuthorization",(function(){return R})),n.d(t,"persistAuthorizationIfNeeded",(function(){return D}));var r=n(18),o=n.n(r),a=n(32),i=n.n(a),s=n(21),u=n.n(s),c=n(96),l=n.n(c),p=n(27),f=n(5),h="show_popup",d="authorize",m="logout",v="pre_authorize_oauth2",g="authorize_oauth2",y="validate",b="configure_auth",_="restore_authorization";function x(e){return{type:h,payload:e}}function w(e){return{type:d,payload:e}}var E=function(e){return function(t){var n=t.authActions;n.authorize(e),n.persistAuthorizationIfNeeded()}};function S(e){return{type:m,payload:e}}var C=function(e){return function(t){var n=t.authActions;n.logout(e),n.persistAuthorizationIfNeeded()}},A=function(e){return function(t){var n=t.authActions,r=t.errActions,o=e.auth,a=e.token,s=e.isValid,u=o.schema,c=o.name,l=u.get("flow");delete p.a.swaggerUIRedirectOauth2,"accessCode"===l||s||r.newAuthErr({authId:c,source:"auth",level:"warning",message:"Authorization may be unsafe, passed state was changed in server Passed state wasn't returned from auth server"}),a.error?r.newAuthErr({authId:c,source:"auth",level:"error",message:i()(a)}):n.authorizeOauth2WithPersistOption({auth:o,token:a})}};function O(e){return{type:g,payload:e}}var k=function(e){return function(t){var n=t.authActions;n.authorizeOauth2(e),n.persistAuthorizationIfNeeded()}},j=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.name,a=e.username,i=e.password,s=e.passwordType,c=e.clientId,l=e.clientSecret,p={grant_type:"password",scope:e.scopes.join(" "),username:a,password:i},h={};switch(s){case"request-body":!function(e,t,n){t&&u()(e,{client_id:t});n&&u()(e,{client_secret:n})}(p,c,l);break;case"basic":h.Authorization="Basic "+Object(f.a)(c+":"+l);break;default:console.warn("Warning: invalid passwordType ".concat(s," was passed, not including client id and secret"))}return n.authorizeRequest({body:Object(f.b)(p),url:r.get("tokenUrl"),name:o,headers:h,query:{},auth:e})}};var T=function(e){return function(t){var n=t.authActions,r=e.schema,o=e.scopes,a=e.name,i=e.clientId,s=e.clientSecret,u={Authorization:"Basic "+Object(f.a)(i+":"+s)},c={grant_type:"client_credentials",scope:o.join(" ")};return n.authorizeRequest({body:Object(f.b)(c),name:a,url:r.get("tokenUrl"),auth:e,headers:u})}},I=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,a=t.name,i=t.clientId,s=t.clientSecret,u=t.codeVerifier,c={grant_type:"authorization_code",code:t.code,client_id:i,client_secret:s,redirect_uri:n,code_verifier:u};return r.authorizeRequest({body:Object(f.b)(c),name:a,url:o.get("tokenUrl"),auth:t})}},P=function(e){var t=e.auth,n=e.redirectUrl;return function(e){var r=e.authActions,o=t.schema,a=t.name,i=t.clientId,s=t.clientSecret,u=t.codeVerifier,c={Authorization:"Basic "+Object(f.a)(i+":"+s)},l={grant_type:"authorization_code",code:t.code,client_id:i,redirect_uri:n,code_verifier:u};return r.authorizeRequest({body:Object(f.b)(l),name:a,url:o.get("tokenUrl"),auth:t,headers:c})}},N=function(e){return function(t){var n,r=t.fn,a=t.getConfigs,s=t.authActions,c=t.errActions,p=t.oas3Selectors,f=t.specSelectors,h=t.authSelectors,d=e.body,m=e.query,v=void 0===m?{}:m,g=e.headers,y=void 0===g?{}:g,b=e.name,_=e.url,x=e.auth,w=(h.getConfigs()||{}).additionalQueryStringParams;if(f.isOAS3()){var E=p.serverEffectiveValue(p.selectedServer());n=l()(_,E,!0)}else n=l()(_,f.url(),!0);"object"===o()(w)&&(n.query=u()({},n.query,w));var S=n.toString(),C=u()({Accept:"application/json, text/plain, */*","Content-Type":"application/x-www-form-urlencoded","X-Requested-With":"XMLHttpRequest"},y);r.fetch({url:S,method:"post",headers:C,query:v,body:d,requestInterceptor:a().requestInterceptor,responseInterceptor:a().responseInterceptor}).then((function(e){var t=JSON.parse(e.data),n=t&&(t.error||""),r=t&&(t.parseError||"");e.ok?n||r?c.newAuthErr({authId:b,level:"error",source:"auth",message:i()(t)}):s.authorizeOauth2WithPersistOption({auth:x,token:t}):c.newAuthErr({authId:b,level:"error",source:"auth",message:e.statusText})})).catch((function(e){var t=new Error(e).message;if(e.response&&e.response.data){var n=e.response.data;try{var r="string"==typeof n?JSON.parse(n):n;r.error&&(t+=", error: ".concat(r.error)),r.error_description&&(t+=", description: ".concat(r.error_description))}catch(e){}}c.newAuthErr({authId:b,level:"error",source:"auth",message:t})}))}};function M(e){return{type:b,payload:e}}function R(e){return{type:_,payload:e}}var D=function(){return function(e){var t=e.authSelectors;if((0,e.getConfigs)().persistAuthorization){var n=t.authorized();localStorage.setItem("authorized",i()(n.toJS()))}}}},function(e,t,n){var r=n(1072);e.exports=function(e){for(var t=1;tS;S++)if((h||S in x)&&(b=w(y=x[S],S,_),e))if(t)A[S]=b;else if(b)switch(e){case 3:return!0;case 5:return y;case 6:return S;case 2:u.call(A,y)}else switch(e){case 4:return!1;case 7:u.call(A,y)}return p?-1:c||l?l:A}};e.exports={forEach:c(0),map:c(1),filter:c(2),some:c(3),every:c(4),find:c(5),findIndex:c(6),filterOut:c(7)}},function(e,t,n){n(161);var r=n(586),o=n(40),a=n(101),i=n(70),s=n(130),u=n(41)("toStringTag");for(var c in r){var l=o[c],p=l&&l.prototype;p&&a(p)!==u&&i(p,u,c),s[c]=s.Array}},function(e,t,n){"use strict";e.exports={current:null}},function(e,t){e.exports=function(e){return null!=e&&"object"==typeof e}},function(e,t){var n,r,o=e.exports={};function a(){throw new Error("setTimeout has not been defined")}function i(){throw new Error("clearTimeout has not been defined")}function s(e){if(n===setTimeout)return setTimeout(e,0);if((n===a||!n)&&setTimeout)return n=setTimeout,setTimeout(e,0);try{return n(e,0)}catch(t){try{return n.call(null,e,0)}catch(t){return n.call(this,e,0)}}}!function(){try{n="function"==typeof setTimeout?setTimeout:a}catch(e){n=a}try{r="function"==typeof clearTimeout?clearTimeout:i}catch(e){r=i}}();var u,c=[],l=!1,p=-1;function f(){l&&u&&(l=!1,u.length?c=u.concat(c):p=-1,c.length&&h())}function h(){if(!l){var e=s(f);l=!0;for(var t=c.length;t;){for(u=c,c=[];++p1)for(var n=1;n0&&"/"!==t[0]}));function Se(e,t,n){var r;t=t||[];var o=xe.apply(void 0,u()(r=[e]).call(r,i()(t))).get("parameters",Object(I.List)());return w()(o).call(o,(function(e,t){var r=n&&"body"===t.get("in")?t.get("value_xml"):t.get("value");return e.set(Object(T.A)(t,{allowHashes:!1}),r)}),Object(I.fromJS)({}))}function Ce(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(I.List.isList(e))return A()(e).call(e,(function(e){return I.Map.isMap(e)&&e.get("in")===t}))}function Ae(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";if(I.List.isList(e))return A()(e).call(e,(function(e){return I.Map.isMap(e)&&e.get("type")===t}))}function Oe(e,t){var n,r;t=t||[];var o=z(e).getIn(u()(n=["paths"]).call(n,i()(t)),Object(I.fromJS)({})),a=e.getIn(u()(r=["meta","paths"]).call(r,i()(t)),Object(I.fromJS)({})),s=ke(e,t),c=o.get("parameters")||new I.List,l=a.get("consumes_value")?a.get("consumes_value"):Ae(c,"file")?"multipart/form-data":Ae(c,"formData")?"application/x-www-form-urlencoded":void 0;return Object(I.fromJS)({requestContentType:l,responseContentType:s})}function ke(e,t){var n,r;t=t||[];var o=z(e).getIn(u()(n=["paths"]).call(n,i()(t)),null);if(null!==o){var a=e.getIn(u()(r=["meta","paths"]).call(r,i()(t),["produces_value"]),null),s=o.getIn(["produces",0],null);return a||s||"application/json"}}function je(e,t){var n;t=t||[];var r=z(e),a=r.getIn(u()(n=["paths"]).call(n,i()(t)),null);if(null!==a){var s=t,c=o()(s,1)[0],l=a.get("produces",null),p=r.getIn(["paths",c,"produces"],null),f=r.getIn(["produces"],null);return l||p||f}}function Te(e,t){var n;t=t||[];var r=z(e),a=r.getIn(u()(n=["paths"]).call(n,i()(t)),null);if(null!==a){var s=t,c=o()(s,1)[0],l=a.get("consumes",null),p=r.getIn(["paths",c,"consumes"],null),f=r.getIn(["consumes"],null);return l||p||f}}var Ie=function(e,t,n){var r=e.get("url").match(/^([a-z][a-z0-9+\-.]*):/),o=k()(r)?r[1]:null;return e.getIn(["scheme",t,n])||e.getIn(["scheme","_defaultScheme"])||o||""},Pe=function(e,t,n){var r;return d()(r=["http","https"]).call(r,Ie(e,t,n))>-1},Ne=function(e,t){var n;t=t||[];var r=e.getIn(u()(n=["meta","paths"]).call(n,i()(t),["parameters"]),Object(I.fromJS)([])),o=!0;return f()(r).call(r,(function(e){var t=e.get("errors");t&&t.count()&&(o=!1)})),o},Me=function(e,t){var n,r,o={requestBody:!1,requestContentType:{}},a=e.getIn(u()(n=["resolvedSubtrees","paths"]).call(n,i()(t),["requestBody"]),Object(I.fromJS)([]));return a.size<1||(a.getIn(["required"])&&(o.requestBody=a.getIn(["required"])),f()(r=a.getIn(["content"]).entrySeq()).call(r,(function(e){var t=e[0];if(e[1].getIn(["schema","required"])){var n=e[1].getIn(["schema","required"]).toJS();o.requestContentType[t]=n}}))),o},Re=function(e,t,n,r){var o;if((n||r)&&n===r)return!0;var a=e.getIn(u()(o=["resolvedSubtrees","paths"]).call(o,i()(t),["requestBody","content"]),Object(I.fromJS)([]));if(a.size<2||!n||!r)return!1;var s=a.getIn([n,"schema","properties"],Object(I.fromJS)([])),c=a.getIn([r,"schema","properties"],Object(I.fromJS)([]));return!!s.equals(c)};function De(e){return I.Map.isMap(e)?e:new I.Map}},function(e,t,n){"use strict";(function(t){var r=n(919),o=n(920),a=/^[A-Za-z][A-Za-z0-9+-.]*:[\\/]+/,i=/^([a-z][a-z0-9.+-]*:)?([\\/]{1,})?([\S\s]*)/i,s=new RegExp("^[\\x09\\x0A\\x0B\\x0C\\x0D\\x20\\xA0\\u1680\\u180E\\u2000\\u2001\\u2002\\u2003\\u2004\\u2005\\u2006\\u2007\\u2008\\u2009\\u200A\\u202F\\u205F\\u3000\\u2028\\u2029\\uFEFF]+");function u(e){return(e||"").toString().replace(s,"")}var c=[["#","hash"],["?","query"],function(e){return e.replace("\\","/")},["/","pathname"],["@","auth",1],[NaN,"host",void 0,1,1],[/:(\d+)$/,"port",void 0,1],[NaN,"hostname",void 0,1,1]],l={hash:1,query:1};function p(e){var n,r=("undefined"!=typeof window?window:void 0!==t?t:"undefined"!=typeof self?self:{}).location||{},o={},i=typeof(e=e||r);if("blob:"===e.protocol)o=new h(unescape(e.pathname),{});else if("string"===i)for(n in o=new h(e,{}),l)delete o[n];else if("object"===i){for(n in e)n in l||(o[n]=e[n]);void 0===o.slashes&&(o.slashes=a.test(e.href))}return o}function f(e){e=u(e);var t=i.exec(e);return{protocol:t[1]?t[1].toLowerCase():"",slashes:!!(t[2]&&t[2].length>=2),rest:t[2]&&1===t[2].length?"/"+t[3]:t[3]}}function h(e,t,n){if(e=u(e),!(this instanceof h))return new h(e,t,n);var a,i,s,l,d,m,v=c.slice(),g=typeof t,y=this,b=0;for("object"!==g&&"string"!==g&&(n=t,t=null),n&&"function"!=typeof n&&(n=o.parse),t=p(t),a=!(i=f(e||"")).protocol&&!i.slashes,y.slashes=i.slashes||a&&t.slashes,y.protocol=i.protocol||t.protocol||"",e=i.rest,i.slashes||(v[3]=[/(.*)/,"pathname"]);b=4?[t[0],t[1],t[2],t[3],"".concat(t[0],".").concat(t[1]),"".concat(t[0],".").concat(t[2]),"".concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[0]),"".concat(t[1],".").concat(t[2]),"".concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[0]),"".concat(t[2],".").concat(t[1]),"".concat(t[2],".").concat(t[3]),"".concat(t[3],".").concat(t[0]),"".concat(t[3],".").concat(t[1]),"".concat(t[3],".").concat(t[2]),"".concat(t[0],".").concat(t[1],".").concat(t[2]),"".concat(t[0],".").concat(t[1],".").concat(t[3]),"".concat(t[0],".").concat(t[2],".").concat(t[1]),"".concat(t[0],".").concat(t[2],".").concat(t[3]),"".concat(t[0],".").concat(t[3],".").concat(t[1]),"".concat(t[0],".").concat(t[3],".").concat(t[2]),"".concat(t[1],".").concat(t[0],".").concat(t[2]),"".concat(t[1],".").concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[2],".").concat(t[0]),"".concat(t[1],".").concat(t[2],".").concat(t[3]),"".concat(t[1],".").concat(t[3],".").concat(t[0]),"".concat(t[1],".").concat(t[3],".").concat(t[2]),"".concat(t[2],".").concat(t[0],".").concat(t[1]),"".concat(t[2],".").concat(t[0],".").concat(t[3]),"".concat(t[2],".").concat(t[1],".").concat(t[0]),"".concat(t[2],".").concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[3],".").concat(t[0]),"".concat(t[2],".").concat(t[3],".").concat(t[1]),"".concat(t[3],".").concat(t[0],".").concat(t[1]),"".concat(t[3],".").concat(t[0],".").concat(t[2]),"".concat(t[3],".").concat(t[1],".").concat(t[0]),"".concat(t[3],".").concat(t[1],".").concat(t[2]),"".concat(t[3],".").concat(t[2],".").concat(t[0]),"".concat(t[3],".").concat(t[2],".").concat(t[1]),"".concat(t[0],".").concat(t[1],".").concat(t[2],".").concat(t[3]),"".concat(t[0],".").concat(t[1],".").concat(t[3],".").concat(t[2]),"".concat(t[0],".").concat(t[2],".").concat(t[1],".").concat(t[3]),"".concat(t[0],".").concat(t[2],".").concat(t[3],".").concat(t[1]),"".concat(t[0],".").concat(t[3],".").concat(t[1],".").concat(t[2]),"".concat(t[0],".").concat(t[3],".").concat(t[2],".").concat(t[1]),"".concat(t[1],".").concat(t[0],".").concat(t[2],".").concat(t[3]),"".concat(t[1],".").concat(t[0],".").concat(t[3],".").concat(t[2]),"".concat(t[1],".").concat(t[2],".").concat(t[0],".").concat(t[3]),"".concat(t[1],".").concat(t[2],".").concat(t[3],".").concat(t[0]),"".concat(t[1],".").concat(t[3],".").concat(t[0],".").concat(t[2]),"".concat(t[1],".").concat(t[3],".").concat(t[2],".").concat(t[0]),"".concat(t[2],".").concat(t[0],".").concat(t[1],".").concat(t[3]),"".concat(t[2],".").concat(t[0],".").concat(t[3],".").concat(t[1]),"".concat(t[2],".").concat(t[1],".").concat(t[0],".").concat(t[3]),"".concat(t[2],".").concat(t[1],".").concat(t[3],".").concat(t[0]),"".concat(t[2],".").concat(t[3],".").concat(t[0],".").concat(t[1]),"".concat(t[2],".").concat(t[3],".").concat(t[1],".").concat(t[0]),"".concat(t[3],".").concat(t[0],".").concat(t[1],".").concat(t[2]),"".concat(t[3],".").concat(t[0],".").concat(t[2],".").concat(t[1]),"".concat(t[3],".").concat(t[1],".").concat(t[0],".").concat(t[2]),"".concat(t[3],".").concat(t[1],".").concat(t[2],".").concat(t[0]),"".concat(t[3],".").concat(t[2],".").concat(t[0],".").concat(t[1]),"".concat(t[3],".").concat(t[2],".").concat(t[1],".").concat(t[0])]:void 0),g[r]}function b(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=arguments.length>2?arguments[2]:void 0,r=e.filter((function(e){return"token"!==e})),o=y(r);return o.reduce((function(e,t){return f()({},e,n[t])}),t)}function _(e){return e.join(" ")}function x(e){var t=e.node,n=e.stylesheet,r=e.style,o=void 0===r?{}:r,a=e.useInlineStyles,i=e.key,s=t.properties,u=t.type,c=t.tagName,l=t.value;if("text"===u)return l;if(c){var p,h=function(e,t){var n=0;return function(r){return n+=1,r.map((function(r,o){return x({node:r,stylesheet:e,useInlineStyles:t,key:"code-segment-".concat(n,"-").concat(o)})}))}}(n,a);if(a){var m=Object.keys(n).reduce((function(e,t){return t.split(".").forEach((function(t){e.includes(t)||e.push(t)})),e}),[]),g=s.className&&s.className.includes("token")?["token"]:[],y=s.className&&g.concat(s.className.filter((function(e){return!m.includes(e)})));p=f()({},s,{className:_(y)||void 0,style:b(s.className,Object.assign({},s.style,o),n)})}else p=f()({},s,{className:_(s.className)});var w=h(t.children);return d.a.createElement(c,v()({key:i},p),w)}}var w=/\n/g;function E(e){var t=e.codeString,n=e.codeStyle,r=e.containerStyle,o=void 0===r?{float:"left",paddingRight:"10px"}:r,a=e.numberStyle,i=void 0===a?{}:a,s=e.startingLineNumber;return d.a.createElement("code",{style:Object.assign({},n,o)},function(e){var t=e.lines,n=e.startingLineNumber,r=e.style;return t.map((function(e,t){var o=t+n;return d.a.createElement("span",{key:"line-".concat(t),className:"react-syntax-highlighter-line-number",style:"function"==typeof r?r(o):r},"".concat(o,"\n"))}))}({lines:t.replace(/\n$/,"").split("\n"),style:i,startingLineNumber:s}))}function S(e,t){return{type:"element",tagName:"span",properties:{key:"line-number--".concat(e),className:["comment","linenumber","react-syntax-highlighter-line-number"],style:t},children:[{type:"text",value:e}]}}function C(e,t,n){var r,o={display:"inline-block",minWidth:(r=n,"".concat(r.toString().length,".25em")),paddingRight:"1em",textAlign:"right",userSelect:"none"},a="function"==typeof e?e(t):e;return f()({},o,a)}function A(e){var t=e.children,n=e.lineNumber,r=e.lineNumberStyle,o=e.largestLineNumber,a=e.showInlineLineNumbers,i=e.lineProps,s=void 0===i?{}:i,u=e.className,c=void 0===u?[]:u,l=e.showLineNumbers,p=e.wrapLongLines,h="function"==typeof s?s(n):s;if(h.className=c,n&&a){var d=C(r,n,o);t.unshift(S(n,d))}return p&l&&(h.style=f()({},h.style,{display:"flex"})),{type:"element",tagName:"span",properties:h,children:t}}function O(e){for(var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[],r=0;r2&&void 0!==arguments[2]?arguments[2]:[];return A({children:e,lineNumber:t,lineNumberStyle:s,largestLineNumber:i,showInlineLineNumbers:o,lineProps:n,className:a,showLineNumbers:r,wrapLongLines:u})}function m(e,t){if(r&&t&&o){var n=C(s,t,i);e.unshift(S(t,n))}return e}function v(e,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];return t||r.length>0?d(e,n,r):m(e,n)}for(var g=function(){var e=l[h],t=e.children[0].value;if(t.match(w)){var n=t.split("\n");n.forEach((function(t,o){var i=r&&p.length+a,s={type:"text",value:"".concat(t,"\n")};if(0===o){var u=v(l.slice(f+1,h).concat(A({children:[s],className:e.properties.className})),i);p.push(u)}else if(o===n.length-1){if(l[h+1]&&l[h+1].children&&l[h+1].children[0]){var c=A({children:[{type:"text",value:"".concat(t)}],className:e.properties.className});l.splice(h+1,0,c)}else{var d=v([s],i,e.properties.className);p.push(d)}}else{var m=v([s],i,e.properties.className);p.push(m)}})),f=h}h++};h .hljs-title":{color:"#88C0D0"},"hljs-keyword":{color:"#81A1C1"},"hljs-literal":{color:"#81A1C1"},"hljs-symbol":{color:"#81A1C1"},"hljs-number":{color:"#B48EAD"},"hljs-regexp":{color:"#EBCB8B"},"hljs-string":{color:"#A3BE8C"},"hljs-title":{color:"#8FBCBB"},"hljs-params":{color:"#D8DEE9"},"hljs-bullet":{color:"#81A1C1"},"hljs-code":{color:"#8FBCBB"},"hljs-emphasis":{fontStyle:"italic"},"hljs-formula":{color:"#8FBCBB"},"hljs-strong":{fontWeight:"bold"},"hljs-link:hover":{textDecoration:"underline"},"hljs-quote":{color:"#4C566A"},"hljs-comment":{color:"#4C566A"},"hljs-doctag":{color:"#8FBCBB"},"hljs-meta":{color:"#5E81AC"},"hljs-meta-keyword":{color:"#5E81AC"},"hljs-meta-string":{color:"#A3BE8C"},"hljs-attr":{color:"#8FBCBB"},"hljs-attribute":{color:"#D8DEE9"},"hljs-builtin-name":{color:"#81A1C1"},"hljs-name":{color:"#81A1C1"},"hljs-section":{color:"#88C0D0"},"hljs-tag":{color:"#81A1C1"},"hljs-variable":{color:"#D8DEE9"},"hljs-template-variable":{color:"#D8DEE9"},"hljs-template-tag":{color:"#5E81AC"},"abnf .hljs-attribute":{color:"#88C0D0"},"abnf .hljs-symbol":{color:"#EBCB8B"},"apache .hljs-attribute":{color:"#88C0D0"},"apache .hljs-section":{color:"#81A1C1"},"arduino .hljs-built_in":{color:"#88C0D0"},"aspectj .hljs-meta":{color:"#D08770"},"aspectj > .hljs-title":{color:"#88C0D0"},"bnf .hljs-attribute":{color:"#8FBCBB"},"clojure .hljs-name":{color:"#88C0D0"},"clojure .hljs-symbol":{color:"#EBCB8B"},"coq .hljs-built_in":{color:"#88C0D0"},"cpp .hljs-meta-string":{color:"#8FBCBB"},"css .hljs-built_in":{color:"#88C0D0"},"css .hljs-keyword":{color:"#D08770"},"diff .hljs-meta":{color:"#8FBCBB"},"ebnf .hljs-attribute":{color:"#8FBCBB"},"glsl .hljs-built_in":{color:"#88C0D0"},"groovy .hljs-meta:not(:first-child)":{color:"#D08770"},"haxe .hljs-meta":{color:"#D08770"},"java .hljs-meta":{color:"#D08770"},"ldif .hljs-attribute":{color:"#8FBCBB"},"lisp .hljs-name":{color:"#88C0D0"},"lua .hljs-built_in":{color:"#88C0D0"},"moonscript .hljs-built_in":{color:"#88C0D0"},"nginx .hljs-attribute":{color:"#88C0D0"},"nginx .hljs-section":{color:"#5E81AC"},"pf .hljs-built_in":{color:"#88C0D0"},"processing .hljs-built_in":{color:"#88C0D0"},"scss .hljs-keyword":{color:"#81A1C1"},"stylus .hljs-keyword":{color:"#81A1C1"},"swift .hljs-meta":{color:"#D08770"},"vim .hljs-built_in":{color:"#88C0D0",fontStyle:"italic"},"yaml .hljs-meta":{color:"#D08770"}},obsidian:{hljs:{display:"block",overflowX:"auto",padding:"0.5em",background:"#282b2e",color:"#e0e2e4"},"hljs-keyword":{color:"#93c763",fontWeight:"bold"},"hljs-selector-tag":{color:"#93c763",fontWeight:"bold"},"hljs-literal":{color:"#93c763",fontWeight:"bold"},"hljs-selector-id":{color:"#93c763"},"hljs-number":{color:"#ffcd22"},"hljs-attribute":{color:"#668bb0"},"hljs-code":{color:"white"},"hljs-class .hljs-title":{color:"white"},"hljs-section":{color:"white",fontWeight:"bold"},"hljs-regexp":{color:"#d39745"},"hljs-link":{color:"#d39745"},"hljs-meta":{color:"#557182"},"hljs-tag":{color:"#8cbbad"},"hljs-name":{color:"#8cbbad",fontWeight:"bold"},"hljs-bullet":{color:"#8cbbad"},"hljs-subst":{color:"#8cbbad"},"hljs-emphasis":{color:"#8cbbad"},"hljs-type":{color:"#8cbbad",fontWeight:"bold"},"hljs-built_in":{color:"#8cbbad"},"hljs-selector-attr":{color:"#8cbbad"},"hljs-selector-pseudo":{color:"#8cbbad"},"hljs-addition":{color:"#8cbbad"},"hljs-variable":{color:"#8cbbad"},"hljs-template-tag":{color:"#8cbbad"},"hljs-template-variable":{color:"#8cbbad"},"hljs-string":{color:"#ec7600"},"hljs-symbol":{color:"#ec7600"},"hljs-comment":{color:"#818e96"},"hljs-quote":{color:"#818e96"},"hljs-deletion":{color:"#818e96"},"hljs-selector-class":{color:"#A082BD"},"hljs-doctag":{fontWeight:"bold"},"hljs-title":{fontWeight:"bold"},"hljs-strong":{fontWeight:"bold"}},"tomorrow-night":{"hljs-comment":{color:"#969896"},"hljs-quote":{color:"#969896"},"hljs-variable":{color:"#cc6666"},"hljs-template-variable":{color:"#cc6666"},"hljs-tag":{color:"#cc6666"},"hljs-name":{color:"#cc6666"},"hljs-selector-id":{color:"#cc6666"},"hljs-selector-class":{color:"#cc6666"},"hljs-regexp":{color:"#cc6666"},"hljs-deletion":{color:"#cc6666"},"hljs-number":{color:"#de935f"},"hljs-built_in":{color:"#de935f"},"hljs-builtin-name":{color:"#de935f"},"hljs-literal":{color:"#de935f"},"hljs-type":{color:"#de935f"},"hljs-params":{color:"#de935f"},"hljs-meta":{color:"#de935f"},"hljs-link":{color:"#de935f"},"hljs-attribute":{color:"#f0c674"},"hljs-string":{color:"#b5bd68"},"hljs-symbol":{color:"#b5bd68"},"hljs-bullet":{color:"#b5bd68"},"hljs-addition":{color:"#b5bd68"},"hljs-title":{color:"#81a2be"},"hljs-section":{color:"#81a2be"},"hljs-keyword":{color:"#b294bb"},"hljs-selector-tag":{color:"#b294bb"},hljs:{display:"block",overflowX:"auto",background:"#1d1f21",color:"#c5c8c6",padding:"0.5em"},"hljs-emphasis":{fontStyle:"italic"},"hljs-strong":{fontWeight:"bold"}}},Q=o()(X),ee=function(e){return i()(Q).call(Q,e)?X[e]:(console.warn("Request style '".concat(e,"' is not available, returning default instead")),Z)}},function(e,t){e.exports=!0},function(e,t,n){var r=n(244),o=n(71).f,a=n(70),i=n(54),s=n(560),u=n(41)("toStringTag");e.exports=function(e,t,n,c){if(e){var l=n?e:e.prototype;i(l,u)||o(l,u,{configurable:!0,value:t}),c&&!r&&a(l,"toString",s)}}},function(e,t,n){var r=n(244),o=n(152),a=n(41)("toStringTag"),i="Arguments"==o(function(){return arguments}());e.exports=r?o:function(e){var t,n,r;return void 0===e?"Undefined":null===e?"Null":"string"==typeof(n=function(e,t){try{return e[t]}catch(e){}}(t=Object(e),a))?n:i?o(t):"Object"==(r=o(t))&&"function"==typeof t.callee?"Arguments":r}},function(e,t,n){"use strict";e.exports=function(e){if("function"!=typeof e)throw new TypeError(e+" is not a function");return e}},function(e,t,n){e.exports=n(685)},function(e,t,n){"use strict";function r(e){return function(e){try{return!!JSON.parse(e)}catch(e){return null}}(e)?"json":null}n.d(t,"a",(function(){return r}))},function(e,t,n){"use strict";n.r(t),n.d(t,"UPDATE_LAYOUT",(function(){return o})),n.d(t,"UPDATE_FILTER",(function(){return a})),n.d(t,"UPDATE_MODE",(function(){return i})),n.d(t,"SHOW",(function(){return s})),n.d(t,"updateLayout",(function(){return u})),n.d(t,"updateFilter",(function(){return c})),n.d(t,"show",(function(){return l})),n.d(t,"changeMode",(function(){return p}));var r=n(5),o="layout_update_layout",a="layout_update_filter",i="layout_update_mode",s="layout_show";function u(e){return{type:o,payload:e}}function c(e){return{type:a,payload:e}}function l(e){var t=!(arguments.length>1&&void 0!==arguments[1])||arguments[1];return e=Object(r.v)(e),{type:s,payload:{thing:e,shown:t}}}function p(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"";return e=Object(r.v)(e),{type:i,payload:{thing:e,mode:t}}}},function(e,t,n){var r=n(428),o=n(165),a=n(197),i=n(52),s=n(117),u=n(198),c=n(164),l=n(256),p=Object.prototype.hasOwnProperty;e.exports=function(e){if(null==e)return!0;if(s(e)&&(i(e)||"string"==typeof e||"function"==typeof e.splice||u(e)||l(e)||a(e)))return!e.length;var t=o(e);if("[object Map]"==t||"[object Set]"==t)return!e.size;if(c(e))return!r(e).length;for(var n in e)if(p.call(e,n))return!1;return!0}},function(e,t,n){var r=n(49),o=n(182),a=n(108),i=n(69),s=n(184),u=n(54),c=n(368),l=Object.getOwnPropertyDescriptor;t.f=r?l:function(e,t){if(e=i(e),t=s(t,!0),c)try{return l(e,t)}catch(e){}if(u(e,t))return a(!o.f.call(e,t),e[t])}},function(e,t){e.exports=function(e,t){return{enumerable:!(1&e),configurable:!(2&e),writable:!(4&e),value:t}}},function(e,t){e.exports=function(e){if(null==e)throw TypeError("Can't call method on "+e);return e}},function(e,t,n){var r=n(78);e.exports=function(e,t,n){if(r(e),void 0===t)return e;switch(n){case 0:return function(){return e.call(t)};case 1:return function(n){return e.call(t,n)};case 2:return function(n,r){return e.call(t,n,r)};case 3:return function(n,r,o){return e.call(t,n,r,o)}}return function(){return e.apply(t,arguments)}}},function(e,t,n){var r,o=n(51),a=n(237),i=n(240),s=n(159),u=n(373),c=n(232),l=n(188),p=l("IE_PROTO"),f=function(){},h=function(e){return" + + + + diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f GIT binary patch literal 59203 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

K7UpUK$>l@ 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 E2O(~oYXATM literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..0f80bbf --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..4f906e0 --- /dev/null +++ b/gradlew @@ -0,0 +1,185 @@ +#!/usr/bin/env sh + +# +# Copyright 2015 the original author or authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin or MSYS, switch paths to Windows format before running java +if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=`expr $i + 1` + done + case $i in + 0) set -- ;; + 1) set -- "$args0" ;; + 2) set -- "$args0" "$args1" ;; + 3) set -- "$args0" "$args1" "$args2" ;; + 4) set -- "$args0" "$args1" "$args2" "$args3" ;; + 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=`save "$@"` + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100644 index 0000000..107acd3 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/lombok.config b/lombok.config new file mode 100644 index 0000000..e8c6713 --- /dev/null +++ b/lombok.config @@ -0,0 +1,6 @@ +config.stopBubbling = true +lombok.accessors.chain = true +lombok.accessors.fluent = false +lombok.addLombokGeneratedAnnotation = true +lombok.data.flagUsage = error +lombok.LOG.fieldName = LOG diff --git a/persistence/build.gradle.kts b/persistence/build.gradle.kts new file mode 100644 index 0000000..8f5ec55 --- /dev/null +++ b/persistence/build.gradle.kts @@ -0,0 +1,27 @@ +import org.springframework.boot.gradle.tasks.bundling.BootJar + +plugins { + id("org.flywaydb.flyway") version "7.9.1" + kotlin("plugin.jpa") version "1.5.10" +} + +dependencies { + "implementation"("org.springframework.boot:spring-boot-starter-data-jpa") + implementation("org.springframework.boot:spring-boot-starter-validation") + implementation("org.springframework.boot:spring-boot-starter-web") + implementation("org.flywaydb:flyway-core") + implementation("org.apache.tomcat:tomcat-jdbc") + implementation("com.h2database:h2:1.4.200") +} + +flyway { + url = "jdbc:h2:mem:alerting" + user = "defaultUser" + password = "secret" + locations = arrayOf("classpath:resources/db/migration") +} + +tasks.getByName("bootJar") { + enabled = true + mainClass.set("com.poc.alerting.persistence.Persistence") +} diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/H2Config.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/H2Config.kt new file mode 100644 index 0000000..e70e76a --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/H2Config.kt @@ -0,0 +1,23 @@ +package com.poc.alerting.persistence + +import org.h2.tools.Server +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.autoconfigure.domain.EntityScan +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Profile +import org.springframework.data.jpa.repository.config.EnableJpaRepositories + +@Configuration +@EnableJpaRepositories("com.poc.alerting.persistence.repositories") +@EntityScan("com.poc.alerting.persistence.dto") +@EnableAutoConfiguration +open class H2Config { + @Bean(initMethod = "start", destroyMethod = "stop") + @Profile("persistence") + open fun inMemoryH2DatabaseServer(): Server { + return Server.createTcpServer( + "-tcp", "-tcpAllowOthers", "-tcpPort", "9091" + ) + } +} \ No newline at end of file diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/Persistence.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/Persistence.kt new file mode 100644 index 0000000..fb3dd22 --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/Persistence.kt @@ -0,0 +1,12 @@ +package com.poc.alerting.persistence + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.runApplication + + +@SpringBootApplication(scanBasePackages = ["com.poc.alerting.persistence"]) +open class Persistence + +fun main(args: Array) { + runApplication(*args) +} diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Account.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Account.kt new file mode 100644 index 0000000..5ad42f0 --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Account.kt @@ -0,0 +1,22 @@ +package com.poc.alerting.persistence.dto + +import javax.persistence.Entity +import javax.persistence.GeneratedValue +import javax.persistence.Id +import javax.validation.constraints.NotBlank +import javax.validation.constraints.Size + +@Entity +data class Account( + @Id + @GeneratedValue + val id: Long, + + @NotBlank + @Size(max = 255) + val name: String, + + @NotBlank + @Size(max = 255) + val extId: String +) diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Alert.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Alert.kt new file mode 100644 index 0000000..c34590d --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Alert.kt @@ -0,0 +1,65 @@ +package com.poc.alerting.persistence.dto + +import org.hibernate.annotations.CreationTimestamp +import org.hibernate.annotations.UpdateTimestamp +import java.util.Date +import javax.persistence.Entity +import javax.persistence.EnumType +import javax.persistence.Enumerated +import javax.persistence.GeneratedValue +import javax.persistence.GenerationType +import javax.persistence.Id +import javax.persistence.ManyToOne +import javax.persistence.Temporal +import javax.persistence.TemporalType +import javax.validation.constraints.NotBlank +import javax.validation.constraints.NotNull +import javax.validation.constraints.Size + +@Entity +data class Alert( + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + val id: Long, + + @NotBlank + @Size(max = 255) + val extId: String, + + @Size(max = 255) + var threshold: String, + + @NotNull + @Enumerated(EnumType.STRING) + val type: AlertTypeEnum, + + @Size(max = 255) + var frequency: String = "", + + var enabled: String = "", + + @Temporal(TemporalType.TIMESTAMP) + var lastTriggerTimestamp: Date, + + @Temporal(TemporalType.TIMESTAMP) + var notificationSentTimestamp: Date, + + var isTriggered: Boolean, + + @Size(max = 255) + var referenceTimePeriod: String, + + @CreationTimestamp + @Temporal(TemporalType.TIMESTAMP) + val created: Date, + + @UpdateTimestamp + @Temporal(TemporalType.TIMESTAMP) + var updated: Date, + + @Size(max = 255) + var updatedBy: String, + + @ManyToOne + var account: Account +) \ No newline at end of file diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/AlertTypeEnum.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/AlertTypeEnum.kt new file mode 100644 index 0000000..1290ef2 --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/AlertTypeEnum.kt @@ -0,0 +1,8 @@ +package com.poc.alerting.persistence.dto + +import kotlin.random.Random + +enum class AlertTypeEnum(val query: () -> Int) { + HARDCODED_ALERT_1({ Random.nextInt(0,1000) }), + HARDCODED_ALERT_2({ Random.nextInt(0,1000) }) +} \ No newline at end of file diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Recipient.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Recipient.kt new file mode 100644 index 0000000..031f881 --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/Recipient.kt @@ -0,0 +1,58 @@ +package com.poc.alerting.persistence.dto + +import org.hibernate.annotations.CreationTimestamp +import org.hibernate.annotations.UpdateTimestamp +import java.util.Date +import javax.persistence.Entity +import javax.persistence.EnumType +import javax.persistence.Enumerated +import javax.persistence.GeneratedValue +import javax.persistence.Id +import javax.persistence.ManyToOne +import javax.persistence.Temporal +import javax.persistence.TemporalType +import javax.validation.constraints.NotBlank +import javax.validation.constraints.NotNull +import javax.validation.constraints.Size + +@Entity +data class Recipient( + @Id + @GeneratedValue + val id: Long, + + @NotBlank + @Size(max = 255) + val extId: String, + + @NotBlank + @Size(max = 255) + val recipient: String, + + @NotNull + @Enumerated(EnumType.STRING) + val type: RecipientTypeEnum, + + @Size(max = 255) + val username: String, + + @Size(max = 255) + val password: String, + + @CreationTimestamp + @Temporal(TemporalType.TIMESTAMP) + val created: Date, + + @UpdateTimestamp + @Temporal(TemporalType.TIMESTAMP) + val updated: Date, + + @Size(max = 255) + val updatedBy: String, + + @ManyToOne + val alert: Alert, + + @ManyToOne + val account: Account +) \ No newline at end of file diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/RecipientTypeEnum.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/RecipientTypeEnum.kt new file mode 100644 index 0000000..2509685 --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/dto/RecipientTypeEnum.kt @@ -0,0 +1,7 @@ +package com.poc.alerting.persistence.dto + +enum class RecipientTypeEnum { + EMAIL, + SMS, + HTTP +} \ No newline at end of file diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/AccountRepository.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/AccountRepository.kt new file mode 100644 index 0000000..ddc9d51 --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/AccountRepository.kt @@ -0,0 +1,10 @@ +package com.poc.alerting.persistence.repositories + +import com.poc.alerting.persistence.dto.Account +import org.springframework.data.jpa.repository.JpaRepository +import org.springframework.stereotype.Repository + +@Repository +interface AccountRepository : JpaRepository { + fun findByExtId(accountExtId: String): Account +} \ No newline at end of file diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/AlertRepository.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/AlertRepository.kt new file mode 100644 index 0000000..572f3df --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/AlertRepository.kt @@ -0,0 +1,13 @@ +package com.poc.alerting.persistence.repositories + +import com.poc.alerting.persistence.dto.Alert +import org.springframework.data.repository.CrudRepository +import org.springframework.data.repository.PagingAndSortingRepository +import org.springframework.stereotype.Repository + +@Repository +interface AlertRepository : CrudRepository, PagingAndSortingRepository { + fun findByExtIdAndAccount_ExtId(alertId: String, accountExtId: String): Alert + + fun findAllByAccount_ExtId(accountExtId: String): List +} diff --git a/persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/RecipientRepository.kt b/persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/RecipientRepository.kt new file mode 100644 index 0000000..7aa8b15 --- /dev/null +++ b/persistence/src/main/kotlin/com/poc/alerting/persistence/repositories/RecipientRepository.kt @@ -0,0 +1,14 @@ +package com.poc.alerting.persistence.repositories + +import com.poc.alerting.persistence.dto.Recipient +import org.springframework.data.repository.CrudRepository +import org.springframework.stereotype.Repository + +@Repository +interface RecipientRepository : CrudRepository { + fun findByExtIdAndAlert_ExtIdAndAccount_ExtId(recipientId: String, alertId: String, accountExtId: String): Recipient + + fun findAllByAccount_ExtId(accountExtId: String): List + + fun findAllByAlert_ExtIdAndAccount_ExtId(alertId: String, accountExtId: String): List +} \ No newline at end of file diff --git a/persistence/src/main/resources/application.yml b/persistence/src/main/resources/application.yml new file mode 100644 index 0000000..1d29672 --- /dev/null +++ b/persistence/src/main/resources/application.yml @@ -0,0 +1,21 @@ +spring: + profiles: + active: "persistence" + datasource: + url: "jdbc:h2:mem:alerting;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE;" + driver-class-name: org.h2.Driver + username: defaultUser + password: secret + jpa: + database-platform: org.hibernate.dialect.H2Dialect + hibernate: + ddl-auto: update + naming: + implicit-strategy: org.springframework.boot.orm.jpa.hibernate.SpringImplicitNamingStrategy + physical-strategy: org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy + h2: + console: + enabled: true + path: /h2-console +server: + port: 8081 \ No newline at end of file diff --git a/persistence/src/main/resources/db/migration/V1__Delete_Quartz_Tables.sql b/persistence/src/main/resources/db/migration/V1__Delete_Quartz_Tables.sql new file mode 100644 index 0000000..2a9c05c --- /dev/null +++ b/persistence/src/main/resources/db/migration/V1__Delete_Quartz_Tables.sql @@ -0,0 +1,11 @@ +DROP TABLE qrtz_calendars IF EXISTS; +DROP TABLE qrtz_cron_triggers IF EXISTS; +DROP TABLE qrtz_fired_triggeres IF EXISTS; +DROP TABLE qrtz_paused_trigger_grps IF EXISTS; +DROP TABLE qrtz_scheduler_state IF EXISTS; +DROP TABLE qrtz_locks IF EXISTS; +DROP TABLE qrtz_job_details IF EXISTS; +DROP TABLE qrtz_simple_triggers IF EXISTS; +DROP TABLE qrtz_simprop_triggers IF EXISTS; +DROP TABLE qrtz_blob_triggers IF EXISTS; +DROP TABLE qrtz_triggers IF EXISTS; diff --git a/persistence/src/main/resources/db/migration/V2__Create_Quartz_Schema.sql b/persistence/src/main/resources/db/migration/V2__Create_Quartz_Schema.sql new file mode 100644 index 0000000..d7c0e9a --- /dev/null +++ b/persistence/src/main/resources/db/migration/V2__Create_Quartz_Schema.sql @@ -0,0 +1,238 @@ +CREATE TABLE QRTZ_CALENDARS ( + SCHED_NAME VARCHAR(120) NOT NULL, + CALENDAR_NAME VARCHAR (200) NOT NULL , + CALENDAR IMAGE NOT NULL +); + +CREATE TABLE QRTZ_CRON_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + CRON_EXPRESSION VARCHAR (120) NOT NULL , + TIME_ZONE_ID VARCHAR (80) +); + +CREATE TABLE QRTZ_FIRED_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + ENTRY_ID VARCHAR (95) NOT NULL , + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + INSTANCE_NAME VARCHAR (200) NOT NULL , + FIRED_TIME BIGINT NOT NULL , + SCHED_TIME BIGINT NOT NULL , + PRIORITY INTEGER NOT NULL , + STATE VARCHAR (16) NOT NULL, + JOB_NAME VARCHAR (200) NULL , + JOB_GROUP VARCHAR (200) NULL , + IS_NONCONCURRENT BOOLEAN NULL , + REQUESTS_RECOVERY BOOLEAN NULL +); + +CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_GROUP VARCHAR (200) NOT NULL +); + +CREATE TABLE QRTZ_SCHEDULER_STATE ( + SCHED_NAME VARCHAR(120) NOT NULL, + INSTANCE_NAME VARCHAR (200) NOT NULL , + LAST_CHECKIN_TIME BIGINT NOT NULL , + CHECKIN_INTERVAL BIGINT NOT NULL +); + +CREATE TABLE QRTZ_LOCKS ( + SCHED_NAME VARCHAR(120) NOT NULL, + LOCK_NAME VARCHAR (40) NOT NULL +); + +CREATE TABLE QRTZ_JOB_DETAILS ( + SCHED_NAME VARCHAR(120) NOT NULL, + JOB_NAME VARCHAR (200) NOT NULL , + JOB_GROUP VARCHAR (200) NOT NULL , + DESCRIPTION VARCHAR (250) NULL , + JOB_CLASS_NAME VARCHAR (250) NOT NULL , + IS_DURABLE BOOLEAN NOT NULL , + IS_NONCONCURRENT BOOLEAN NOT NULL , + IS_UPDATE_DATA BOOLEAN NOT NULL , + REQUESTS_RECOVERY BOOLEAN NOT NULL , + JOB_DATA IMAGE NULL +); + +CREATE TABLE QRTZ_SIMPLE_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + REPEAT_COUNT BIGINT NOT NULL , + REPEAT_INTERVAL BIGINT NOT NULL , + TIMES_TRIGGERED BIGINT NOT NULL +); + +CREATE TABLE QRTZ_SIMPROP_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR(200) NOT NULL, + TRIGGER_GROUP VARCHAR(200) NOT NULL, + STR_PROP_1 VARCHAR(512) NULL, + STR_PROP_2 VARCHAR(512) NULL, + STR_PROP_3 VARCHAR(512) NULL, + INT_PROP_1 INTEGER NULL, + INT_PROP_2 INTEGER NULL, + LONG_PROP_1 BIGINT NULL, + LONG_PROP_2 BIGINT NULL, + DEC_PROP_1 NUMERIC(13,4) NULL, + DEC_PROP_2 NUMERIC(13,4) NULL, + BOOL_PROP_1 BOOLEAN NULL, + BOOL_PROP_2 BOOLEAN NULL +); + +CREATE TABLE QRTZ_BLOB_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + BLOB_DATA IMAGE NULL +); + +CREATE TABLE QRTZ_TRIGGERS ( + SCHED_NAME VARCHAR(120) NOT NULL, + TRIGGER_NAME VARCHAR (200) NOT NULL , + TRIGGER_GROUP VARCHAR (200) NOT NULL , + JOB_NAME VARCHAR (200) NOT NULL , + JOB_GROUP VARCHAR (200) NOT NULL , + DESCRIPTION VARCHAR (250) NULL , + NEXT_FIRE_TIME BIGINT NULL , + PREV_FIRE_TIME BIGINT NULL , + PRIORITY INTEGER NULL , + TRIGGER_STATE VARCHAR (16) NOT NULL , + TRIGGER_TYPE VARCHAR (8) NOT NULL , + START_TIME BIGINT NOT NULL , + END_TIME BIGINT NULL , + CALENDAR_NAME VARCHAR (200) NULL , + MISFIRE_INSTR SMALLINT NULL , + JOB_DATA IMAGE NULL +); + +ALTER TABLE QRTZ_CALENDARS ADD + CONSTRAINT PK_QRTZ_CALENDARS PRIMARY KEY + ( + SCHED_NAME, + CALENDAR_NAME + ); + +ALTER TABLE QRTZ_CRON_TRIGGERS ADD + CONSTRAINT PK_QRTZ_CRON_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_FIRED_TRIGGERS ADD + CONSTRAINT PK_QRTZ_FIRED_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + ENTRY_ID + ); + +ALTER TABLE QRTZ_PAUSED_TRIGGER_GRPS ADD + CONSTRAINT PK_QRTZ_PAUSED_TRIGGER_GRPS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_SCHEDULER_STATE ADD + CONSTRAINT PK_QRTZ_SCHEDULER_STATE PRIMARY KEY + ( + SCHED_NAME, + INSTANCE_NAME + ); + +ALTER TABLE QRTZ_LOCKS ADD + CONSTRAINT PK_QRTZ_LOCKS PRIMARY KEY + ( + SCHED_NAME, + LOCK_NAME + ); + +ALTER TABLE QRTZ_JOB_DETAILS ADD + CONSTRAINT PK_QRTZ_JOB_DETAILS PRIMARY KEY + ( + SCHED_NAME, + JOB_NAME, + JOB_GROUP + ); + +ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD + CONSTRAINT PK_QRTZ_SIMPLE_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD + CONSTRAINT PK_QRTZ_SIMPROP_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_TRIGGERS ADD + CONSTRAINT PK_QRTZ_TRIGGERS PRIMARY KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ); + +ALTER TABLE QRTZ_CRON_TRIGGERS ADD + CONSTRAINT FK_QRTZ_CRON_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) REFERENCES QRTZ_TRIGGERS ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) ON DELETE CASCADE; + + +ALTER TABLE QRTZ_SIMPLE_TRIGGERS ADD + CONSTRAINT FK_QRTZ_SIMPLE_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) REFERENCES QRTZ_TRIGGERS ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) ON DELETE CASCADE; + +ALTER TABLE QRTZ_SIMPROP_TRIGGERS ADD + CONSTRAINT FK_QRTZ_SIMPROP_TRIGGERS_QRTZ_TRIGGERS FOREIGN KEY + ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) REFERENCES QRTZ_TRIGGERS ( + SCHED_NAME, + TRIGGER_NAME, + TRIGGER_GROUP + ) ON DELETE CASCADE; + + +ALTER TABLE QRTZ_TRIGGERS ADD + CONSTRAINT FK_QRTZ_TRIGGERS_QRTZ_JOB_DETAILS FOREIGN KEY + ( + SCHED_NAME, + JOB_NAME, + JOB_GROUP + ) REFERENCES QRTZ_JOB_DETAILS ( + SCHED_NAME, + JOB_NAME, + JOB_GROUP + ); + +COMMIT; \ No newline at end of file diff --git a/persistence/src/main/resources/db/migration/V3__Create_Alerting_Schema.sql b/persistence/src/main/resources/db/migration/V3__Create_Alerting_Schema.sql new file mode 100644 index 0000000..fd3d38e --- /dev/null +++ b/persistence/src/main/resources/db/migration/V3__Create_Alerting_Schema.sql @@ -0,0 +1,63 @@ +CREATE TABLE `account` ( + `id` long PRIMARY KEY, + `name` varchar(255) NOT NULL, + `ext_id` varchar(255) NOT NULL +); + +INSERT INTO `account` +VALUES (1, 'Test Account 1', '1111'), + (2, 'Test Account 2', '2222'); + +CREATE TABLE `alert` ( + `id` long PRIMARY KEY AUTO_INCREMENT, + `ext_id` varchar(255) UNIQUE NOT NULL, + `name` varchar(255), + `threshold` varchar(255), + `type` ENUM ('HARDCODED_ALERT_1', 'HARDCODED_ALERT_2'), + `frequency` varchar(255), + `enabled` boolean default false, + `last_trigger_timestamp` timestamp, + `notification_sent_timestamp` timestamp, + `is_triggered` boolean default false, + `reference_time_period` varchar(255), + `created` timestamp, + `updated` timestamp, + `updated_by` varchar(255), + `account_id` long NOT NULL +); + +INSERT INTO `alert` +VALUES (1, '1111-alert-1', 'Some Test Alert for Account 1111', '90', 'HARDCODED_ALERT_1', '15m', true, '2021-04-22 16:33:21.959', '2021-04-22 16:33:21.959', false, '1 Month', '2021-04-22 16:33:21.959', '2021-04-22 16:33:21.959', 'someUser1', 1), +(2, '1111-alert-2', 'Some Other Test Alert for Account 1111', '666', 'HARDCODED_ALERT_2', '5m', true, null, null, false, '1 Week', '2021-04-22 16:33:21.959', '2021-04-26 04:01:13.448', 'someUser1', 1), +(3, '2222-alert-1', 'Some Test Alert for Account 2222', '90', 'HARDCODED_ALERT_1', '15m', true, '2021-04-22 16:33:21.959', '2021-04-22 16:33:21.959', false, '1 Month', '2021-04-22 16:33:21.959', '2021-04-22 16:33:21.959', 'someOtherUser2', 2), +(4, '2222-alert-2', 'Some Other Test Alert for Account 2222', '666', 'HARDCODED_ALERT_2', '5m', true, null, null, false, '1 Week', '2021-04-22 16:33:21.959', '2021-04-26 04:01:13.448', 'someOtherUser2', 2); + +ALTER TABLE `alert` ADD FOREIGN KEY (`account_id`) REFERENCES `account` (`id`); + +CREATE TABLE `recipient` ( + `id` long PRIMARY KEY AUTO_INCREMENT, + `ext_id` varchar(255) UNIQUE NOT NULL, + `recipient` varchar(255) NOT NULL, + `type` ENUM ('EMAIL', 'SMS', 'HTTP'), + `username` varchar(255), + `password` varchar(255), + `created` timestamp NOT NULL, + `updated` timestamp NOT NULL, + `updated_by` varchar(255) NOT NULL, + `alert_id` long, + `account_id` long +); + +INSERT INTO `recipient` +VALUES (1, 'someUsersEmail-account-1111', 'someUser1@somedomain.com', 'EMAIL', null, null, '2021-02-22 16:09:28.139', '2021-02-22 16:09:28.139', 'someUser1', 1, 1), +(2, 'someOtherUsersEmail-account-1111', 'someOtherUser1@somedomain.com', 'EMAIL', null, null, '2021-03-04 07:17:33.244', '2021-03-04 08:00:54.562', 'someOtherUser1', 1, 1), +(3, 'someUserHttpRecipient-account-1111', 'https://some.test.callback.com/callback1', 'HTTP', 'mikeRoweSoft', 'iSuPpOrTwInDoWs', '2021-05-19 02:39:12.922', '2021-05-19 02:39:12.922', 'someUser1', 2, 1), +(4, 'someUserHttpRecipient-account-2222', 'https://some.test.callback.com/callback2', 'HTTP', 'teriDactyl', 'L1f3F1nd$AWay', '2021-05-19 02:39:12.922', '2021-05-19 02:39:12.922', 'someUser2', 2, 2), +(5, 'someUsersEmail-account-2222', 'someUser2@somedomain.com', 'EMAIL', null, null, '2021-02-22 16:09:28.139', '2021-02-22 16:09:28.139', 'someUser2', 1, 2), +(6, 'someOtherUsersSms-account-2222', '13035552222', 'SMS', null, null, '2021-02-22 16:09:28.139', '2021-02-22 16:09:28.139', 'someOtherUser2', 1, 2); + +ALTER TABLE `recipient` ADD FOREIGN KEY (`alert_id`) REFERENCES `alert` (`id`); + +ALTER TABLE `recipient` ADD FOREIGN KEY (`account_id`) REFERENCES `account` (`id`); + +CREATE SEQUENCE `hibernate_sequence` START WITH 5 INCREMENT BY 1; \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts new file mode 100644 index 0000000..5edc89c --- /dev/null +++ b/settings.gradle.kts @@ -0,0 +1,2 @@ +rootProject.name = "alerting-poc" +include(":persistence", ":amqp", ":api", ":batch")