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 0000000..6edbb3e Binary files /dev/null and b/alerting-architecture.png differ diff --git a/amqp/build.gradle.kts b/amqp/build.gradle.kts new file mode 100644 index 0000000..835b439 --- /dev/null +++ b/amqp/build.gradle.kts @@ -0,0 +1,19 @@ +import org.springframework.boot.gradle.tasks.bundling.BootJar + +dependencies { + implementation("org.springframework.amqp:spring-amqp") + implementation("org.springframework.amqp:spring-rabbit") + implementation("com.google.code.gson:gson") + implementation("org.projectlombok:lombok") + implementation("org.apache.commons:commons-lang3") + + annotationProcessor("org.projectlombok:lombok") +} + +tasks.getByName("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 0000000..8b194e6 Binary files /dev/null and b/docs/dist/favicon-16x16.png differ diff --git a/docs/dist/favicon-32x32.png b/docs/dist/favicon-32x32.png new file mode 100644 index 0000000..249737f Binary files /dev/null and b/docs/dist/favicon-32x32.png differ diff --git a/docs/dist/oauth2-redirect.html b/docs/dist/oauth2-redirect.html new file mode 100644 index 0000000..64b171f --- /dev/null +++ b/docs/dist/oauth2-redirect.html @@ -0,0 +1,75 @@ + + + + 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 0000000..e708b1c Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ 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")